timesupA.mac revision 1e40f57c72c881067b0314f898e1004211bb7650
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef RT_ARCH_X86
1e40f57c72c881067b0314f898e1004211bb7650vboxsync; The x86 assembly implementation of the assembly routines.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync; @returns Nanosecond timestamp.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync; @param pData Pointer to the nanosecond timestamp data.
1e40f57c72c881067b0314f898e1004211bb7650vboxsyncBEGINPROC rtTimeNanoTSInternalAsm
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Variable definitions.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define pData [ebp + 08h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u64RetNanoTS_Hi [ebp - 04h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u64RetNanoTS [ebp - 08h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u32UpdateIntervalNS [ebp - 0ch]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u32UpdateIntervalTSC [ebp - 10h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u64TSC_Hi [ebp - 14h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u64TSC [ebp - 18h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u64CurNanoTS_Hi [ebp - 1ch]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u64CurNanoTS [ebp - 20h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u64PrevNanoTS_Hi [ebp - 24h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u64PrevNanoTS [ebp - 28h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u32TransactionId [ebp - 2ch]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u32ApicIdPlus [ebp - 30h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define TmpVar [ebp - 34h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define SavedEBX [ebp - 38h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define SavedEDI [ebp - 3ch]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define SavedESI [ebp - 40h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ebp, esp
1e40f57c72c881067b0314f898e1004211bb7650vboxsync sub esp, 40h
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov SavedEBX, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov SavedEDI, edi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov SavedESI, esi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; Read the GIP data and the previous value.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Load pGip and calc pGipCPU, setting u32ApicIdPlus if necessary.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov esi, [NAME(g_pSUPGlobalInfoPage)]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync or esi, esi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jz .Rediscover
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp dword [esi + SUPGLOBALINFOPAGE.u32Magic], SUPGLOBALINFOPAGE_MAGIC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jne .Rediscover
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef ASYNC_GIP
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; u8ApicId = ASMGetApicId();
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cpuid ; expensive
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %ifdef NEED_TRANSACTION_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u32ApicIdPlus, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; pGipCpu = &pGip->aCPU[u8ApicId];
1e40f57c72c881067b0314f898e1004211bb7650vboxsync shr ebx, 24
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov eax, SUPGIPCPU_size
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lea edi, [esi + eax + SUPGLOBALINFOPAGE.aCPUs] ; edi == &pGip->aCPU[u8ApicId];
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lea edi, [esi + SUPGLOBALINFOPAGE.aCPUs] ; edi == &pGip->aCPU[0];
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef NEED_TRANSACTION_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Serialized loading of u32TransactionId.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u32TransactionId, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %ifdef USE_LFENCE
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lock xor dword TmpVar, 0
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Load the data and TSC.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov eax, [esi + SUPGLOBALINFOPAGE.u32UpdateIntervalNS]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u32UpdateIntervalNS, eax ; esi is now free
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u32UpdateIntervalTSC, edx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ecx, [edi + SUPGIPCPU.u64NanoTS]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64CurNanoTS, ecx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov esi, [edi + SUPGIPCPU.u64NanoTS + 4]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64CurNanoTS_Hi, esi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ebx, [edi + SUPGIPCPU.u64TSC]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64TSC, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ecx, [edi + SUPGIPCPU.u64TSC + 4]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64TSC_Hi, ecx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; u64PrevNanoTS = ASMAtomicReadU64(pu64Prev);
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; This serializes load/save. And with the dependency on the
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; RDTSC result, we try to make sure it has completed as well.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov esi, pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ebx, eax
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ecx, edx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lock cmpxchg8b [esi + RTTIMENANOTSDATA.u64Prev]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64PrevNanoTS, eax
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64PrevNanoTS_Hi, edx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef SAVED_u64RetNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef NEED_TRANSACTION_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Check that the GIP and CPU didn't change.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; We've already serialized all the loads and stores at this point.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %ifdef ASYNC_GIP
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64RetNanoTS, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64RetNanoTS_Hi, ecx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %define SAVED_u64RetNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp u32ApicIdPlus, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jne .ReadGip
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp esi, u32TransactionId
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jne .ReadGip
1e40f57c72c881067b0314f898e1004211bb7650vboxsync test esi, 1
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jnz .ReadGip
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%endif ; NEED_TRANSACTION_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef SAVED_u64RetNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ebx, u64RetNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ecx, u64RetNanoTS_Hi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; Calc the timestamp.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; u64RetNanoTS -= u64TSC;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync sub ebx, u64TSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync sbb ecx, u64TSC_Hi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; if (u64RetNanoTS > u32UpdateIntervalTSC) -> jump
1e40f57c72c881067b0314f898e1004211bb7650vboxsync or ecx, ecx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jnz .OverFlow
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp ebx, u32UpdateIntervalTSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ja .OverFlow
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov eax, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.ContinueCalcs: ; eax <= u32UpdateIntervalTSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mul dword u32UpdateIntervalNS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync div dword u32UpdateIntervalTSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync xor edx, edx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; u64RetNanoTS += u64CurNanoTS;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync add eax, u64CurNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync adc edx, u64CurNanoTS_Hi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; Compare it with the previous one.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; if (RT_LIKELY( u64RetNanoTS > u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; && u64RetNanoTS < u64PrevNanoTS + UINT64_C(86000000000000) /* 24h */))
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; @todo optimize this compare (/me too tired).
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ecx, u64PrevNanoTS_Hi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ebx, u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp edx, ecx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ja .Compare2
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jb .DeltaPrevTooBig
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp eax, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jbe .DeltaPrevTooBig
1e40f57c72c881067b0314f898e1004211bb7650vboxsync add ebx, 0x6F736000
1e40f57c72c881067b0314f898e1004211bb7650vboxsync adc ecx, 0x00004E37
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp edx, ecx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jb .CompareDone
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ja .DeltaPrevTooBig
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp eax, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jae .DeltaPrevTooBig
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.CompareDone:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; Update the previous value with the u64RetNanoTS value.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; if (RT_LIKELY(ASMAtomicCmpXchgU64(&pData->u64Prev, u64RetNanoTS, u64PrevNanoTS)))
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ebx, eax
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ecx, edx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov esi, pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov eax, u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov edx, u64PrevNanoTS_Hi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lock cmpxchg8b [esi + RTTIMENANOTSDATA.u64Prev]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jnz .UpdateFailed
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov eax, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov edx, ecx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov esi, SavedESI
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov edi, SavedEDI
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ebx, SavedEBX
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; We've expired the interval, cap it. If we're here for the 2nd
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; time without any GIP update inbetween, the checks against
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; pData->u64Prev below will force 1ns stepping.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; u64Delta = u32UpdateIntervalTSC;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov esi, pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync inc dword [esi + RTTIMENANOTSDATA.cExpired]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov eax, u32UpdateIntervalTSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jmp .ContinueCalcs
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; u64DeltaPrev >= 24h
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; eax:edx = u64RetNanoTS (to be adjusted)
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.DeltaPrevTooBig:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; uint64_t u64DeltaPrev = u64RetNanoTS - u64PrevNanoTS;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ebx, eax
1e40f57c72c881067b0314f898e1004211bb7650vboxsync sub ebx, u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ecx, edx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync sbb ecx, u64PrevNanoTS_Hi ; ebx:ecx = u64DeltaPrev
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; else if ( (int64_t)u64DeltaPrev <= 0
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; && (int64_t)u64DeltaPrev + u32UpdateIntervalNS * 2 >= 0)
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; /* Occasional - u64RetNanoTS is in the recent 'past' relative the previous call. */
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; pData->c1nsSteps++;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; u64RetNanoTS = u64PrevNanoTS + 1;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov esi, u32UpdateIntervalNS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jl .PrevNotZero2ndTest
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jg .DeltaPrevNotInRecentPast
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ja .DeltaPrevNotInRecentPast
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.PrevNotZero2ndTest:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync add esi, esi ; ASSUMES: u32UpdateIntervalNS * 2 <= 32-bit.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync xor edi, edi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync add esi, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync adc edi, ecx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync test edi, edi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync js .DeltaPrevNotInRecentPast
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.DeltaPrevInRecentPast:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov esi, pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync inc dword [esi + RTTIMENANOTSDATA.c1nsSteps]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov eax, u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov edx, u64PrevNanoTS_Hi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jmp .Update
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.DeltaPrevNotInRecentPast:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; else if (!u64PrevNanoTS) /* We're resuming (see TMVirtualResume). */
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; /* do nothing */;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp dword u64PrevNanoTS, 0
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jne .DeltaPrevNotZero
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp dword u64PrevNanoTS_Hi, 0
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jne .DeltaPrevNotZero
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jmp .Update
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.DeltaPrevNotZero:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; /* Something has gone bust, if negative offset it's real bad. */
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; rtTimeNanoTSInternalBitch(pVM,
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; call C function that does the bitching.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64RetNanoTS, eax
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64RetNanoTS_Hi, edx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov edi, u64PrevNanoTS_Hi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov esi, u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync push esi ; 4 - u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync push ebx ; 3 - u64DeltaPrev
1e40f57c72c881067b0314f898e1004211bb7650vboxsync push eax ; 2 - u64RetNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov eax, pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync push eax ; 1 - pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync call dword [eax + RTTIMENANOTSDATA.pfnBad]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync add esp, 4*7
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov eax, u64RetNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov edx, u64RetNanoTS_Hi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jmp .Update
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; Attempt updating the previous value, provided we're still ahead of it.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; There is no point in recalculating u64NanoTS because we got preemted or if
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; we raced somebody while the GIP was updated, since these are events
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; that might occure at any point in the return path as well.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; eax:edx = *pData->u64Prev
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; ebx:ecx = u64RetNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ALIGNCODE(16)
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.UpdateFailed:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov edi, pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lock inc dword [edi + RTTIMENANOTSDATA.cUpdateRaces]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; for (i = 0; i < 10; i++)
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov edi, 10
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.UpdateLoop:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; if (u64PrevNanoTS >= u64NanoTS)
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp edx, ecx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jg .Updated
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jne .UpdateLoopLess
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp eax, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jae .Updated
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.UpdateLoopLess:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lock cmpxchg8b [esi]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jz .Updated
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jnz .UpdateLoop
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jmp .Updated
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; The GIP is seemingly invalid, redo the discovery.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.Rediscover:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov eax, pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync add esp, 4h
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Cleanup variables
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u64Delta_Hi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u64Delta
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u32UpdateIntervalNS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u32UpdateIntervalTSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u64TSC_Hi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u64TSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u64NanoTS_Hi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u64NanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u64PrevNanoTS_Hi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u32TransactionId
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u8ApicId
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%else ; AMD64
1e40f57c72c881067b0314f898e1004211bb7650vboxsync; The AMD64 assembly implementation of the assembly routines.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync; @returns Nanosecond timestamp.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync; @param pData gcc:rdi msc:rcx Pointer to the nanosecond timestamp data.
1e40f57c72c881067b0314f898e1004211bb7650vboxsyncBEGINPROC rtTimeNanoTSInternalAsm
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Define variables and stack frame.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define SavedRBX [rbp - 08h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define SavedR12 [rbp - 10h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define SavedR13 [rbp - 18h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define SavedRDI [rbp - 20h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define SavedRSI [rbp - 28h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define TmpVar [rbp - 30h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define TmpVar2 [rbp - 38h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef NEED_TRANSACTION_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %ifdef ASYNC_GIP
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %define SavedR14 [rbp - 40h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %define SavedR15 [rbp - 48h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define pData rdi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u64TSC rsi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define pGip rsi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define pGipCPU r8
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u32TransactionId r9d
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u64CurNanoTS r10
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u64PrevNanoTS r11 ; not parameter register
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u32UpdateIntervalTSC r12d
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u32UpdateIntervalTSC_64 r12
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u32UpdateIntervalNS r13d
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define u32UpdateIntervalNS_64 r13
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u64SavedRetNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u32ApicIdPlus
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef NEED_TRANSACTION_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %ifdef ASYNC_GIP
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %define u64SavedRetNanoTS r14
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %define u32ApicIdPlus r15d
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; The prolog.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rbp, rsp
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef ASM_CALL64_MSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync sub rsp, 50h+20h
1e40f57c72c881067b0314f898e1004211bb7650vboxsync sub rsp, 50h
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov SavedRBX, rbx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov SavedR12, r12
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov SavedR13, r13
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef ASM_CALL64_MSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov SavedRDI, rdi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov SavedRSI, rsi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov pData, rcx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;mov pData, rdi - already in rdi.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef SavedR14
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov SavedR14, r14
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef SavedR15
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov SavedR15, r15
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; Data fetch loop.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; We take great pain ensuring that data consitency here.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Load pGip and calc pGipCPU, setting u32ApicIdPlus if necessary.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef ASYNC_GIP
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; u8ApicId = ASMGetApicId();
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cpuid ; expensive
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %ifdef NEED_TRANSACTION_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u32ApicIdPlus, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; pGipCpu = &pGip->aCPU[u8ApicId];
1e40f57c72c881067b0314f898e1004211bb7650vboxsync shr ebx, 24
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov eax, SUPGIPCPU_size
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov pGip, [NAME(g_pSUPGlobalInfoPage) wrt rip]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lea pGipCPU, [pGip + rax + SUPGLOBALINFOPAGE.aCPUs]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync; lea pGipCPU, [pGip + SUPGLOBALINFOPAGE.aCPUs]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync; lea pGipCPU, [pGipCPU + rax]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov pGip, [NAME(g_pSUPGlobalInfoPage) wrt rip]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lea pGipCPU, [pGip + SUPGLOBALINFOPAGE.aCPUs]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync or pGip, pGip
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jz .Rediscover
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp dword [pGip + SUPGLOBALINFOPAGE.u32Magic], SUPGLOBALINFOPAGE_MAGIC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jne .Rediscover
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef NEED_TRANSACTION_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Serialized loading of u32TransactionId.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u32TransactionId, [pGipCPU + SUPGIPCPU.u32TransactionId]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %ifdef USE_LFENCE
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lock xor dword TmpVar, 0
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Load the data and TSC.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u32UpdateIntervalNS, [pGip + SUPGLOBALINFOPAGE.u32UpdateIntervalNS] ; before u64TSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u32UpdateIntervalTSC, [pGipCPU + SUPGIPCPU.u32UpdateIntervalTSC]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64PrevNanoTS, [pData + RTTIMENANOTSDATA.u64Prev]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync shl rdx, 32
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %ifdef u64SavedRetNanoTS ; doing this here saves a tick or so.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64SavedRetNanoTS, rax
1e40f57c72c881067b0314f898e1004211bb7650vboxsync or u64SavedRetNanoTS, rdx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync or rax, rdx ; rax is u64RetNanoTS.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64CurNanoTS, [pGipCPU + SUPGIPCPU.u64NanoTS]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64TSC, [pGipCPU + SUPGIPCPU.u64TSC]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef NEED_TRANSACTION_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Check that the GIP and CPU didn't change.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; It is crucial that the rdtsc instruction has completed before
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; we check the transaction id. The LOCK prefixed instruction with
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; dependency on the RDTSC result should do the trick, I think.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; CPUID is serializing, so the async path is safe by default.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %ifdef ASYNC_GIP
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp u32ApicIdPlus, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jne .ReadGip
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lock xor qword TmpVar, rax
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp u32TransactionId, [pGipCPU + SUPGIPCPU.u32TransactionId]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jne .ReadGip
1e40f57c72c881067b0314f898e1004211bb7650vboxsync test u32TransactionId, 1
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jnz .ReadGip
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %ifdef u64SavedRetNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rax, u64SavedRetNanoTS ; rax is u64RetNanoTS.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%endif ; NEED_TRANSACTION_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; Calc the timestamp.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; u64RetNanoTS -= u64TSC;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync sub rax, u64TSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync xor edx, edx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; if (u64RetNanoTS > u32UpdateIntervalTSC) -> jump
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp rax, u32UpdateIntervalTSC_64
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ja .OverFlow
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.ContinueCalcs: ; edx = 0; eax <= u32UpdateIntervalTSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mul u32UpdateIntervalNS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync div u32UpdateIntervalTSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; u64RetNanoTS += u64CurNanoTS;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync add rax, u64CurNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; Compare it with the previous one.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; if (RT_LIKELY( u64RetNanoTS > u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; && u64RetNanoTS < u64PrevNanoTS + UINT64_C(86000000000000) /* 24h */))
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; /* Frequent - less than 24h since last call. */;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp rax, u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jbe .DeltaPrevTooBig
1e40f57c72c881067b0314f898e1004211bb7650vboxsync shl rcx, 44 ; close enough
1e40f57c72c881067b0314f898e1004211bb7650vboxsync add rcx, u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp rax, rcx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jae .DeltaPrevTooBig
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; Update the previous value.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; if (RT_LIKELY(ASMAtomicCmpXchgU64(&pData->u64Prev, u64RetNanoTS, u64PrevNanoTS)))
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rcx, rax
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rax, u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lock cmpxchg [pData + RTTIMENANOTSDATA.u64Prev], rcx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jnz .UpdateFailed
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rax, rcx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rbx, SavedRBX
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov r12, SavedR12
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov r13, SavedR13
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef SavedR14
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov r14, SavedR14
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef SavedR15
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov r15, SavedR15
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef ASM_CALL64_MSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rdi, SavedRDI
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rsi, SavedRSI
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; We've expired the interval, cap it. If we're here for the 2nd
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; time without any GIP update inbetween, the checks against
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; pData->u64Prev below will force 1ns stepping.
1e40f57c72c881067b0314f898e1004211bb7650vboxsyncALIGNCODE(16)
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; u64RetNanoTS = u32UpdateIntervalTSC;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync inc dword [pData + RTTIMENANOTSDATA.cExpired]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov eax, u32UpdateIntervalTSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jmp .ContinueCalcs
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; u64DeltaPrev >= 24h
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; rax = u64RetNanoTS (to be adjusted)
1e40f57c72c881067b0314f898e1004211bb7650vboxsyncALIGNCODE(16)
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.DeltaPrevTooBig:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; uint64_t u64DeltaPrev = u64RetNanoTS - u64PrevNanoTS;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rbx, rax
1e40f57c72c881067b0314f898e1004211bb7650vboxsync sub rbx, u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; else if ( (int64_t)u64DeltaPrev <= 0
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; && (int64_t)u64DeltaPrev + u32UpdateIntervalNS * 2 >= 0)
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; /* Occasional - u64NanoTS is in the recent 'past' relative the previous call. */
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; pData->c1nsSteps++;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; u64RetNanoTS = u64PrevNanoTS + 1;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync test rbx, rbx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jg .DeltaPrevNotInRecentPast
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lea rdx, [u32UpdateIntervalNS_64 + u32UpdateIntervalNS_64]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync add rdx, rbx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync js .DeltaPrevNotInRecentPast
1e40f57c72c881067b0314f898e1004211bb7650vboxsync inc dword [pData + RTTIMENANOTSDATA.c1nsSteps]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lea rax, [u64PrevNanoTS + 1]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jmp .Update
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; else if (!u64PrevNanoTS) /* We're resuming (see TMVirtualResume) / first call. */
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; /* do nothing */;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.DeltaPrevNotInRecentPast:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync or u64PrevNanoTS, u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; /* Something has gone bust, if negative offset it's real bad. */
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; rtTimeNanoTSInternalBitch(pVM,
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; call C function that does the bitching.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov TmpVar, rax
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov TmpVar2, pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef ASM_CALL64_MSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rcx, pData ; param 1 - pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rdx, rax ; param 2 - u64RetNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov r8, rbx ; param 3 - u64DeltaPrev
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov r9, u64PrevNanoTS ; param 4 - u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;mov rdi, pData - already in rdi; param 1 - pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rsi, rax ; param 2 - u64RetNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rdx, rbx ; param 3 - u64DeltaPrev
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rcx, u64PrevNanoTS ; param 4 - u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync call qword [pData + RTTIMENANOTSDATA.pfnBad]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rax, TmpVar
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov pData, TmpVar2
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jmp .Update
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; Attempt updating the previous value, provided we're still ahead of it.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; There is no point in recalculating u64NanoTS because we got preemted or if
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; we raced somebody while the GIP was updated, since these are events
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; that might occure at any point in the return path as well.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; rax = *pData->u64Prev;
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; rcx = u64RetNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsyncALIGNCODE(16)
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.UpdateFailed:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lock inc dword [pData + RTTIMENANOTSDATA.cUpdateRaces]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; for (i = 0; i < 10; i++)
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ebx, 10
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.UpdateLoop:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; if (u64PrevNanoTS >= u64RetNanoTS)
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp rax, rcx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jge .Updated
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.UpdateLoopLess:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lock cmpxchg [pData + RTTIMENANOTSDATA.u64Prev], rcx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jz .Updated
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jnz .UpdateLoop
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jmp .Updated
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; The GIP is seemingly invalid, redo the discovery.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.Rediscover:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef ASM_CALL64_MSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rcx, pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; mov rdi, pData - already in rdi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Cleanup variables
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef SavedRBX
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef SavedR12
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef SavedR13
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef SavedR14
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef SavedR15
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef SavedRDI
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef SavedRSI
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef TmpVar
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u64TSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef pGipCPU
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u32TransactionId
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u64CurNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u64PrevNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u32UpdateIntervalTSC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u32UpdateIntervalTSC_64
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u32UpdateIntervalNS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u64SavedRetNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%undef u32ApicIdPlus
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%endif ; AMD64
1e40f57c72c881067b0314f898e1004211bb7650vboxsyncENDPROC rtTimeNanoTSInternalAsm