9ae4ea547111829e80548cfee4c972e62c0da811vboxsync; IPRT - Time using SUPLib, the Assembly Code Template.
c0e374304cebe77219b2abc0b6796e72e452c4ddvboxsync; Copyright (C) 2006-2014 Oracle Corporation
41c64c31741f70e00de94130927dd5d85ed360a0vboxsync; This file is part of VirtualBox Open Source Edition (OSE), as
41c64c31741f70e00de94130927dd5d85ed360a0vboxsync; available from http://www.virtualbox.org. This file is free software;
41c64c31741f70e00de94130927dd5d85ed360a0vboxsync; you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync; General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync; Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync; The contents of this file may alternatively be used under the terms
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync; of the Common Development and Distribution License Version 1.0
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync; VirtualBox OSE distribution, in which case the provisions of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync; CDDL are applicable instead of those of the GPL.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync; You may elect to license modified versions of this file under the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync; terms and conditions of either the GPL or the CDDL or both.
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.
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync ; Load pGip.
a4a232fa546df3af50f9389873b521028eed4cdevboxsync%ifdef IMPORTED_SUPLIB
6bc1d32c5bf2ae1e9d714d09a7c116e5b75e1eb5vboxsync %ifdef IN_RING0
6bc1d32c5bf2ae1e9d714d09a7c116e5b75e1eb5vboxsync mov esi, IMP(g_SUPGlobalInfoPage)
a4a232fa546df3af50f9389873b521028eed4cdevboxsync mov esi, IMP(g_pSUPGlobalInfoPage)
a4a232fa546df3af50f9389873b521028eed4cdevboxsync mov esi, [esi]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov esi, [NAME(g_pSUPGlobalInfoPage)]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync or esi, esi
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jz .Rediscover
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp dword [esi + SUPGLOBALINFOPAGE.u32Magic], SUPGLOBALINFOPAGE_MAGIC
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jne .Rediscover
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync ; Calc pGipCPU, setting u32ApicIdPlus if necessary.
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync%ifdef NEED_APIC_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; u8ApicId = ASMGetApicId();
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cpuid ; expensive
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %ifdef NEED_TRANSACTION_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u32ApicIdPlus, ebx
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync ; pGipCpu/pGipCpuDelta = &pGip->aCPU[pGip->aiCpuFromApicId[u8ApicId]];
1e40f57c72c881067b0314f898e1004211bb7650vboxsync shr ebx, 24
cd7a8c034836a94a0c4f0adf9764f9ed661cdd01vboxsync movzx ebx, word [esi + ebx * 2 + SUPGLOBALINFOPAGE.aiCpuFromApicId]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov eax, SUPGIPCPU_size
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lea edi, [esi + eax + SUPGLOBALINFOPAGE.aCPUs] ; edi == &pGip->aCPU[u8ApicId];
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef NEED_TRANSACTION_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Serialized loading of u32TransactionId.
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %ifdef ASYNC_GIP
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov ebx, [esi + SUPGLOBALINFOPAGE.aCPUs + SUPGIPCPU.u32TransactionId]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u32TransactionId, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %ifdef USE_LFENCE
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lock xor dword TmpVar, 0
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync ; Load the data and TSC with delta applied.
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov eax, [esi + SUPGLOBALINFOPAGE.u32UpdateIntervalNS]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov u32UpdateIntervalNS, eax
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync%ifdef ASYNC_GIP ; esi is now free.
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov edx, [esi + SUPGLOBALINFOPAGE.aCPUs + SUPGIPCPU.u32UpdateIntervalTSC]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u32UpdateIntervalTSC, edx
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync%ifdef WITH_TSC_DELTA
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync cmp dword [edi + SUPGIPCPU.i64TSCDelta], 0xffffffff
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync je .TscDeltaPossiblyInvalid
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync.TscDeltaValid:
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync sub eax, dword [edi + SUPGIPCPU.i64TSCDelta]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync sbb edx, dword [edi + SUPGIPCPU.i64TSCDelta + 4]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync.TscDeltaNotValid: ; edi is now free.
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync%ifdef ASYNC_GIP
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ecx, [edi + SUPGIPCPU.u64NanoTS]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov esi, [edi + SUPGIPCPU.u64NanoTS + 4]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov ecx, [esi + SUPGLOBALINFOPAGE.aCPUs + SUPGIPCPU.u64NanoTS]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov ebx, [esi + SUPGLOBALINFOPAGE.aCPUs + SUPGIPCPU.u64NanoTS + 4]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov u64CurNanoTS, ecx
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov u64CurNanoTS_Hi, ebx
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync%ifdef ASYNC_GIP
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov ecx, [edi + SUPGIPCPU.u64TSC]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov ebx, [edi + SUPGIPCPU.u64TSC + 4]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov ecx, [esi + SUPGLOBALINFOPAGE.aCPUs + SUPGIPCPU.u64TSC]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov ebx, [esi + SUPGLOBALINFOPAGE.aCPUs + SUPGIPCPU.u64TSC + 4]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov u64TSC, ecx
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov u64TSC_Hi, ebx
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.
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync%ifdef ASYNC_GIP
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov esi, pData
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov edi, pData
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ebx, eax
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov ecx, edx
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync%ifdef ASYNC_GIP
b92634cd549ff80a3b9136227345237116ccd4favboxsync lock cmpxchg8b [esi]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync lock cmpxchg8b [edi]
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.
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %ifdef NEED_APIC_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64RetNanoTS, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64RetNanoTS_Hi, ecx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %define SAVED_u64RetNanoTS
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp u32ApicIdPlus, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jne .ReadGip
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %ifdef ASYNC_GIP
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov esi, [esi + SUPGLOBALINFOPAGE.aCPUs + SUPGIPCPU.u32TransactionId]
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
b92634cd549ff80a3b9136227345237116ccd4favboxsync lock cmpxchg8b [esi]
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
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync ;; time without any GIP update in-between, 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.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync ;; There is no point in recalculating u64NanoTS because we got preempted or if
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; we raced somebody while the GIP was updated, since these are events
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync ;; that might occur 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
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync%ifdef WITH_TSC_DELTA
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync ;; Unlikely branch for when we think the TSC delta might be invalid.
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync.TscDeltaPossiblyInvalid:
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync cmp dword [edi + SUPGIPCPU.i64TSCDelta + 4], 0x7fffffff
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync jne .TscDeltaValid
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync jmp .TscDeltaNotValid
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
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %ifdef NEED_APIC_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %define SavedR14 [rbp - 40h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %define SavedR15 [rbp - 48h]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%define pData rdi
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync%ifdef ASYNC_GIP
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %define u64TSC rsi
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %define pGip rsi
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %ifdef NEED_APIC_ID
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %define pGipCPU r8
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %define u64TSC r8
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %define pGip rsi
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %ifdef NEED_APIC_ID
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %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
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %ifdef NEED_APIC_ID
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.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync ;; We take great pain ensuring that data consistency here.
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync ; Load pGip - finding the GIP is fun...
a4a232fa546df3af50f9389873b521028eed4cdevboxsync%ifdef RT_OS_WINDOWS
a4a232fa546df3af50f9389873b521028eed4cdevboxsync %ifdef IMPORTED_SUPLIB
a4a232fa546df3af50f9389873b521028eed4cdevboxsync %ifdef IN_RING0
a4a232fa546df3af50f9389873b521028eed4cdevboxsync mov rax, qword IMP(g_SUPGlobalInfoPage)
a4a232fa546df3af50f9389873b521028eed4cdevboxsync mov pGip, rax
a4a232fa546df3af50f9389873b521028eed4cdevboxsync mov pGip, [IMP(g_pSUPGlobalInfoPage) wrt rip]
a4a232fa546df3af50f9389873b521028eed4cdevboxsync mov pGip, [pGip]
a4a232fa546df3af50f9389873b521028eed4cdevboxsync mov pGip, [NAME(g_pSUPGlobalInfoPage) wrt rip]
a4a232fa546df3af50f9389873b521028eed4cdevboxsync %ifdef IN_RING0
a4a232fa546df3af50f9389873b521028eed4cdevboxsync mov rax, qword NAME(g_SUPGlobalInfoPage)
a4a232fa546df3af50f9389873b521028eed4cdevboxsync mov pGip, rax
a4a232fa546df3af50f9389873b521028eed4cdevboxsync mov pGip, [rel NAME(g_pSUPGlobalInfoPage) wrt ..gotpcrel]
a4a232fa546df3af50f9389873b521028eed4cdevboxsync mov pGip, [pGip]
a4a232fa546df3af50f9389873b521028eed4cdevboxsync or pGip, pGip
a4a232fa546df3af50f9389873b521028eed4cdevboxsync jz .Rediscover
a4a232fa546df3af50f9389873b521028eed4cdevboxsync cmp dword [pGip + SUPGLOBALINFOPAGE.u32Magic], SUPGLOBALINFOPAGE_MAGIC
a4a232fa546df3af50f9389873b521028eed4cdevboxsync jne .Rediscover
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync ; pGipCPU, setting u32ApicIdPlus if necessary.
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync%ifdef NEED_APIC_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; u8ApicId = ASMGetApicId();
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cpuid ; expensive
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %ifdef NEED_TRANSACTION_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u32ApicIdPlus, ebx
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync ; pGipCPU = &pGip->aCPU[pGip->aiCpuFromApicId[u8ApicId]];
1e40f57c72c881067b0314f898e1004211bb7650vboxsync shr ebx, 24
cd7a8c034836a94a0c4f0adf9764f9ed661cdd01vboxsync movzx eax, word [pGip + rbx * 2 + SUPGLOBALINFOPAGE.aiCpuFromApicId]
dd8f19fe611a226bfffca18f5b2e40510d11a2edvboxsync imul eax, SUPGIPCPU_size
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lea pGipCPU, [pGip + rax + SUPGLOBALINFOPAGE.aCPUs]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync%ifdef NEED_TRANSACTION_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Serialized loading of u32TransactionId.
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %ifdef ASYNC_GIP
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u32TransactionId, [pGipCPU + SUPGIPCPU.u32TransactionId]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov u32TransactionId, [pGip + SUPGLOBALINFOPAGE.aCPUs + SUPGIPCPU.u32TransactionId]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync %ifdef USE_LFENCE
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lock xor dword TmpVar, 0
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; Load the data and TSC.
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov u32UpdateIntervalNS, [pGip + SUPGLOBALINFOPAGE.u32UpdateIntervalNS]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync%ifdef ASYNC_GIP
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u32UpdateIntervalTSC, [pGipCPU + SUPGIPCPU.u32UpdateIntervalTSC]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov u32UpdateIntervalTSC, [pGip + SUPGLOBALINFOPAGE.aCPUs + SUPGIPCPU.u32UpdateIntervalTSC]
b92634cd549ff80a3b9136227345237116ccd4favboxsync mov u64PrevNanoTS, [pData + RTTIMENANOTSDATA.pu64Prev]
b92634cd549ff80a3b9136227345237116ccd4favboxsync mov u64PrevNanoTS, [u64PrevNanoTS]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync shl rdx, 32
1e40f57c72c881067b0314f898e1004211bb7650vboxsync or rax, rdx ; rax is u64RetNanoTS.
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync%ifdef WITH_TSC_DELTA
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov rdx, [pGipCPU + SUPGIPCPU.i64TSCDelta]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov u64CurNanoTS, 0x7fffffffffffffff ; INT64_MAX - temporarily borrowing u64CurNanoTS
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync cmp rdx, u64CurNanoTS
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync je .TscDeltaNotValid
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync sub rax, rdx
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync.TscDeltaNotValid:
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync%ifdef u64SavedRetNanoTS ; doing this here may save a tick or so?
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov u64SavedRetNanoTS, rax
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync%ifdef ASYNC_GIP
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov u64CurNanoTS, [pGipCPU + SUPGIPCPU.u64NanoTS]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov u64TSC, [pGipCPU + SUPGIPCPU.u64TSC] ; transhes pGIP!
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov u64CurNanoTS, [pGip + SUPGLOBALINFOPAGE.aCPUs + SUPGIPCPU.u64NanoTS]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync mov u64TSC, [pGip + SUPGLOBALINFOPAGE.aCPUs + SUPGIPCPU.u64TSC] ; trashes pGipCPU!
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.
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %ifdef NEED_APIC_ID
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp u32ApicIdPlus, ebx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jne .ReadGip
1e40f57c72c881067b0314f898e1004211bb7650vboxsync lock xor qword TmpVar, rax
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync %ifdef ASYNC_GIP
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp u32TransactionId, [pGipCPU + SUPGIPCPU.u32TransactionId]
443b47b0e450919f5012681d9ec4cdccc1ebab08vboxsync cmp u32TransactionId, [pGip + SUPGLOBALINFOPAGE.aCPUs + 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)))
b92634cd549ff80a3b9136227345237116ccd4favboxsync mov rbx, [pData + RTTIMENANOTSDATA.pu64Prev]
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rcx, rax
1e40f57c72c881067b0314f898e1004211bb7650vboxsync mov rax, u64PrevNanoTS
b92634cd549ff80a3b9136227345237116ccd4favboxsync lock cmpxchg [rbx], 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
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync ;; time without any GIP update in-between, 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.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync ;; There is no point in recalculating u64NanoTS because we got preempted or if
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ;; we raced somebody while the GIP was updated, since these are events
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync ;; that might occur 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++)
b92634cd549ff80a3b9136227345237116ccd4favboxsync mov edx, 10
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.UpdateLoop:
1e40f57c72c881067b0314f898e1004211bb7650vboxsync ; if (u64PrevNanoTS >= u64RetNanoTS)
1e40f57c72c881067b0314f898e1004211bb7650vboxsync cmp rax, rcx
1e40f57c72c881067b0314f898e1004211bb7650vboxsync jge .Updated
1e40f57c72c881067b0314f898e1004211bb7650vboxsync.UpdateLoopLess:
b92634cd549ff80a3b9136227345237116ccd4favboxsync lock cmpxchg [rbx], 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