VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/time/timesupA.mac@ 53470

最後變更 在這個檔案從53470是 53470,由 vboxsync 提交於 10 年 前

timesupA.asm: Disabled SUPTscDeltaApply macro invocation, see review comments in code.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 21.7 KB
 
1; $Id: timesupA.mac 53470 2014-12-06 03:55:37Z vboxsync $
2;; @file
3; IPRT - Time using SUPLib, the Assembly Code Template.
4;
5
6;
7; Copyright (C) 2006-2014 Oracle Corporation
8;
9; This file is part of VirtualBox Open Source Edition (OSE), as
10; available from http://www.alldomusa.eu.org. This file is free software;
11; you can redistribute it and/or modify it under the terms of the GNU
12; General Public License (GPL) as published by the Free Software
13; Foundation, in version 2 as it comes in the "COPYING" file of the
14; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16;
17; The contents of this file may alternatively be used under the terms
18; of the Common Development and Distribution License Version 1.0
19; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20; VirtualBox OSE distribution, in which case the provisions of the
21; CDDL are applicable instead of those of the GPL.
22;
23; You may elect to license modified versions of this file under the
24; terms and conditions of either the GPL or the CDDL or both.
25;
26
27%ifdef RT_ARCH_X86
28;;
29; The x86 assembly implementation of the assembly routines.
30;
31; @returns Nanosecond timestamp.
32; @param pData Pointer to the nanosecond timestamp data.
33;
34BEGINPROC rtTimeNanoTSInternalAsm
35 ;
36 ; Variable definitions.
37 ;
38%define pData [ebp + 08h]
39%define u64RetNanoTS_Hi [ebp - 04h]
40%define u64RetNanoTS [ebp - 08h]
41%define u32UpdateIntervalNS [ebp - 0ch]
42%define u32UpdateIntervalTSC [ebp - 10h]
43%define u64TSC_Hi [ebp - 14h]
44%define u64TSC [ebp - 18h]
45%define u64CurNanoTS_Hi [ebp - 1ch]
46%define u64CurNanoTS [ebp - 20h]
47%define u64PrevNanoTS_Hi [ebp - 24h]
48%define u64PrevNanoTS [ebp - 28h]
49%define u32TransactionId [ebp - 2ch]
50%define u32ApicIdPlus [ebp - 30h]
51%define TmpVar [ebp - 34h]
52%define SavedEBX [ebp - 38h]
53%define SavedEDI [ebp - 3ch]
54%define SavedESI [ebp - 40h]
55
56 ;
57 ; Prolog.
58 ;
59 push ebp
60 mov ebp, esp
61 sub esp, 40h
62 mov SavedEBX, ebx
63 mov SavedEDI, edi
64 mov SavedESI, esi
65
66
67 ;;
68 ;; Read the GIP data and the previous value.
69 ;;
70.ReadGip:
71
72
73 ;
74 ; Load pGip and calc pGipCPU, setting u32ApicIdPlus if necessary.
75 ;
76%ifdef IMPORTED_SUPLIB
77 %ifdef IN_RING0
78 mov esi, IMP(g_SUPGlobalInfoPage)
79 %else
80 mov esi, IMP(g_pSUPGlobalInfoPage)
81 mov esi, [esi]
82 %endif
83%else
84 mov esi, [NAME(g_pSUPGlobalInfoPage)]
85%endif
86 or esi, esi
87 jz .Rediscover
88 cmp dword [esi + SUPGLOBALINFOPAGE.u32Magic], SUPGLOBALINFOPAGE_MAGIC
89 jne .Rediscover
90%ifdef ASYNC_GIP
91 ; u8ApicId = ASMGetApicId();
92 mov eax, 1
93 cpuid ; expensive
94 %ifdef NEED_TRANSACTION_ID
95 mov u32ApicIdPlus, ebx
96 %endif
97 ; pGipCpu = &pGip->aCPU[pGip->aiCpuFromApicId[u8ApicId]];
98 shr ebx, 24
99 movzx ebx, word [esi + ebx * 2 + SUPGLOBALINFOPAGE.aiCpuFromApicId]
100 mov eax, SUPGIPCPU_size
101 mul ebx
102 lea edi, [esi + eax + SUPGLOBALINFOPAGE.aCPUs] ; edi == &pGip->aCPU[u8ApicId];
103%else
104 lea edi, [esi + SUPGLOBALINFOPAGE.aCPUs] ; edi == &pGip->aCPU[0];
105%endif
106
107%ifdef NEED_TRANSACTION_ID
108 ;
109 ; Serialized loading of u32TransactionId.
110 ;
111 mov ebx, [edi + SUPGIPCPU.u32TransactionId]
112 mov u32TransactionId, ebx
113 %ifdef USE_LFENCE
114 lfence
115 %else
116 lock xor dword TmpVar, 0
117 %endif
118%endif
119
120 ;
121 ; Load the data and TSC.
122 ;
123 mov eax, [esi + SUPGLOBALINFOPAGE.u32UpdateIntervalNS]
124 mov u32UpdateIntervalNS, eax ; esi is now free
125 mov edx, [edi + SUPGIPCPU.u32UpdateIntervalTSC]
126 mov u32UpdateIntervalTSC, edx
127 rdtsc
128;; @todo r-bird: Deltas are only valid in INVARIANT mode according to SUPDrv.c macro.
129;; edi is pointing to aCpu[0] in INVARIANT and SYNC. Code does more harm than good atm => disabled.
130;; (Just drop the SUPTscDeltaApply macro btw.) Sketched what is needed for invariant in timesupA.asm, more work .cpp files in IPRT and VMM.
131; SUPTscDeltaApply edi ; Apply inter-cpu TSC-delta to have the normalized TSC value in edx:eax
132 mov ecx, [edi + SUPGIPCPU.u64NanoTS]
133 mov u64CurNanoTS, ecx
134 mov esi, [edi + SUPGIPCPU.u64NanoTS + 4]
135 mov u64CurNanoTS_Hi, esi
136 mov ebx, [edi + SUPGIPCPU.u64TSC]
137 mov u64TSC, ebx
138 mov ecx, [edi + SUPGIPCPU.u64TSC + 4]
139 mov u64TSC_Hi, ecx
140
141 ; u64PrevNanoTS = ASMAtomicReadU64(pu64Prev);
142 ; This serializes load/save. And with the dependency on the
143 ; RDTSC result, we try to make sure it has completed as well.
144 mov esi, pData
145 mov esi, [esi + RTTIMENANOTSDATA.pu64Prev]
146 mov ebx, eax
147 mov ecx, edx
148 lock cmpxchg8b [esi]
149 mov u64PrevNanoTS, eax
150 mov u64PrevNanoTS_Hi, edx
151
152%undef SAVED_u64RetNanoTS
153%ifdef NEED_TRANSACTION_ID
154 ;
155 ; Check that the GIP and CPU didn't change.
156 ; We've already serialized all the loads and stores at this point.
157 ;
158 %ifdef ASYNC_GIP
159 mov u64RetNanoTS, ebx
160 mov u64RetNanoTS_Hi, ecx
161 %define SAVED_u64RetNanoTS
162 mov eax, 1
163 cpuid
164 cmp u32ApicIdPlus, ebx
165 jne .ReadGip
166 %endif
167 mov esi, [edi + SUPGIPCPU.u32TransactionId]
168 cmp esi, u32TransactionId
169 jne .ReadGip
170 test esi, 1
171 jnz .ReadGip
172%endif ; NEED_TRANSACTION_ID
173%ifdef SAVED_u64RetNanoTS
174 mov ebx, u64RetNanoTS
175 mov ecx, u64RetNanoTS_Hi
176%endif
177
178 ;;
179 ;; Calc the timestamp.
180 ;;
181 ; u64RetNanoTS -= u64TSC;
182 sub ebx, u64TSC
183 sbb ecx, u64TSC_Hi
184
185 ; if (u64RetNanoTS > u32UpdateIntervalTSC) -> jump
186 or ecx, ecx
187 jnz .OverFlow
188 cmp ebx, u32UpdateIntervalTSC
189 ja .OverFlow
190 mov eax, ebx
191.ContinueCalcs: ; eax <= u32UpdateIntervalTSC
192 mul dword u32UpdateIntervalNS
193 div dword u32UpdateIntervalTSC
194 xor edx, edx
195
196 ; u64RetNanoTS += u64CurNanoTS;
197 add eax, u64CurNanoTS
198 adc edx, u64CurNanoTS_Hi
199
200 ;;
201 ;; Compare it with the previous one.
202 ;;
203 ; if (RT_LIKELY( u64RetNanoTS > u64PrevNanoTS
204 ; && u64RetNanoTS < u64PrevNanoTS + UINT64_C(86000000000000) /* 24h */))
205 ;; @todo optimize this compare (/me too tired).
206 mov ecx, u64PrevNanoTS_Hi
207 mov ebx, u64PrevNanoTS
208 cmp edx, ecx
209 ja .Compare2
210 jb .DeltaPrevTooBig
211 cmp eax, ebx
212 jbe .DeltaPrevTooBig
213
214.Compare2:
215 add ebx, 0x6F736000
216 adc ecx, 0x00004E37
217 cmp edx, ecx
218 jb .CompareDone
219 ja .DeltaPrevTooBig
220 cmp eax, ebx
221 jae .DeltaPrevTooBig
222.CompareDone:
223
224
225 ;;
226 ;; Update the previous value with the u64RetNanoTS value.
227 ;;
228.Update:
229 ; if (RT_LIKELY(ASMAtomicCmpXchgU64(&pData->u64Prev, u64RetNanoTS, u64PrevNanoTS)))
230 mov ebx, eax
231 mov ecx, edx
232 mov esi, pData
233 mov esi, [esi + RTTIMENANOTSDATA.pu64Prev]
234 mov eax, u64PrevNanoTS
235 mov edx, u64PrevNanoTS_Hi
236 lock cmpxchg8b [esi]
237 jnz .UpdateFailed
238
239.Updated:
240 mov eax, ebx
241 mov edx, ecx
242
243.Done:
244 mov esi, SavedESI
245 mov edi, SavedEDI
246 mov ebx, SavedEBX
247 leave
248 ret
249
250
251 ;;
252 ;; We've expired the interval, cap it. If we're here for the 2nd
253 ;; time without any GIP update in-between, the checks against
254 ;; pData->u64Prev below will force 1ns stepping.
255 ;;
256.OverFlow:
257 ; u64Delta = u32UpdateIntervalTSC;
258 mov esi, pData
259 inc dword [esi + RTTIMENANOTSDATA.cExpired]
260 mov eax, u32UpdateIntervalTSC
261 jmp .ContinueCalcs
262
263
264 ;;
265 ;; u64DeltaPrev >= 24h
266 ;;
267 ;; eax:edx = u64RetNanoTS (to be adjusted)
268 ;;
269.DeltaPrevTooBig:
270 ; uint64_t u64DeltaPrev = u64RetNanoTS - u64PrevNanoTS;
271 mov ebx, eax
272 sub ebx, u64PrevNanoTS
273 mov ecx, edx
274 sbb ecx, u64PrevNanoTS_Hi ; ebx:ecx = u64DeltaPrev
275
276 ; else if ( (int64_t)u64DeltaPrev <= 0
277 ; && (int64_t)u64DeltaPrev + u32UpdateIntervalNS * 2 >= 0)
278 ; {
279 ; /* Occasional - u64RetNanoTS is in the recent 'past' relative the previous call. */
280 ; pData->c1nsSteps++;
281 ; u64RetNanoTS = u64PrevNanoTS + 1;
282 ; }
283 mov esi, u32UpdateIntervalNS
284 cmp ecx, 0
285 jl .PrevNotZero2ndTest
286 jg .DeltaPrevNotInRecentPast
287 cmp ebx, 0
288 ja .DeltaPrevNotInRecentPast
289
290.PrevNotZero2ndTest:
291 add esi, esi ; ASSUMES: u32UpdateIntervalNS * 2 <= 32-bit.
292 xor edi, edi
293 add esi, ebx
294 adc edi, ecx
295 test edi, edi
296 js .DeltaPrevNotInRecentPast
297
298.DeltaPrevInRecentPast:
299 mov esi, pData
300 inc dword [esi + RTTIMENANOTSDATA.c1nsSteps]
301 mov eax, u64PrevNanoTS
302 mov edx, u64PrevNanoTS_Hi
303 add eax, 1
304 adc edx, 0
305 jmp .Update
306
307.DeltaPrevNotInRecentPast:
308 ; else if (!u64PrevNanoTS) /* We're resuming (see TMVirtualResume). */
309 ; /* do nothing */;
310 cmp dword u64PrevNanoTS, 0
311 jne .DeltaPrevNotZero
312 cmp dword u64PrevNanoTS_Hi, 0
313 jne .DeltaPrevNotZero
314 jmp .Update
315
316.DeltaPrevNotZero:
317 ; else
318 ; {
319 ; /* Something has gone bust, if negative offset it's real bad. */
320 ; rtTimeNanoTSInternalBitch(pVM,
321 ; }
322
323 ; call C function that does the bitching.
324 mov u64RetNanoTS, eax
325 mov u64RetNanoTS_Hi, edx
326
327 mov edi, u64PrevNanoTS_Hi
328 mov esi, u64PrevNanoTS
329 push edi
330 push esi ; 4 - u64PrevNanoTS
331 push ecx
332 push ebx ; 3 - u64DeltaPrev
333 push edx
334 push eax ; 2 - u64RetNanoTS
335 mov eax, pData
336 push eax ; 1 - pData
337 call dword [eax + RTTIMENANOTSDATA.pfnBad]
338 add esp, 4*7
339
340 mov eax, u64RetNanoTS
341 mov edx, u64RetNanoTS_Hi
342 jmp .Update
343
344
345 ;;
346 ;; Attempt updating the previous value, provided we're still ahead of it.
347 ;;
348 ;; There is no point in recalculating u64NanoTS because we got preempted or if
349 ;; we raced somebody while the GIP was updated, since these are events
350 ;; that might occur at any point in the return path as well.
351 ;;
352 ;; eax:edx = *pData->u64Prev
353 ;; ebx:ecx = u64RetNanoTS
354 ;;
355 ALIGNCODE(16)
356.UpdateFailed:
357 mov edi, pData
358 lock inc dword [edi + RTTIMENANOTSDATA.cUpdateRaces]
359 ; for (i = 0; i < 10; i++)
360 mov edi, 10
361.UpdateLoop:
362 ; if (u64PrevNanoTS >= u64NanoTS)
363 ; break;
364 cmp edx, ecx
365 jg .Updated
366 jne .UpdateLoopLess
367 cmp eax, ebx
368 jae .Updated
369.UpdateLoopLess:
370 ; retry
371 lock cmpxchg8b [esi]
372 jz .Updated
373 dec edi
374 jnz .UpdateLoop
375 jmp .Updated
376
377
378 ;;
379 ;; The GIP is seemingly invalid, redo the discovery.
380 ;;
381.Rediscover:
382 mov eax, pData
383 push eax
384 call [eax + RTTIMENANOTSDATA.pfnRediscover]
385 add esp, 4h
386 jmp .Done
387
388 ;
389 ; Cleanup variables
390 ;
391%undef pData
392%undef u64Delta_Hi
393%undef u64Delta
394%undef u32UpdateIntervalNS
395%undef u32UpdateIntervalTSC
396%undef u64TSC_Hi
397%undef u64TSC
398%undef u64NanoTS_Hi
399%undef u64NanoTS
400%undef u64PrevNanoTS_Hi
401%undef u64PrevNanoTS
402%undef u32TransactionId
403%undef u8ApicId
404
405%else ; AMD64
406
407;;
408; The AMD64 assembly implementation of the assembly routines.
409;
410; @returns Nanosecond timestamp.
411; @param pData gcc:rdi msc:rcx Pointer to the nanosecond timestamp data.
412;
413BEGINPROC rtTimeNanoTSInternalAsm
414 ;
415 ; Define variables and stack frame.
416 ;
417%define SavedRBX [rbp - 08h]
418%define SavedR12 [rbp - 10h]
419%define SavedR13 [rbp - 18h]
420%define SavedRDI [rbp - 20h]
421%define SavedRSI [rbp - 28h]
422%define TmpVar [rbp - 30h]
423%define TmpVar2 [rbp - 38h]
424%ifdef NEED_TRANSACTION_ID
425 %ifdef ASYNC_GIP
426 %define SavedR14 [rbp - 40h]
427 %define SavedR15 [rbp - 48h]
428 %endif
429%endif
430
431%define pData rdi
432
433%define u64TSC rsi
434%define pGip rsi
435%define pGipCPU r8
436%define u32TransactionId r9d
437%define u64CurNanoTS r10
438%define u64PrevNanoTS r11 ; not parameter register
439%define u32UpdateIntervalTSC r12d
440%define u32UpdateIntervalTSC_64 r12
441%define u32UpdateIntervalNS r13d
442%define u32UpdateIntervalNS_64 r13
443%undef u64SavedRetNanoTS
444%undef u32ApicIdPlus
445%ifdef NEED_TRANSACTION_ID
446 %ifdef ASYNC_GIP
447 %define u64SavedRetNanoTS r14
448 %define u32ApicIdPlus r15d
449 %endif
450%endif
451
452 ;
453 ; The prolog.
454 ;
455 push rbp
456 mov rbp, rsp
457%ifdef ASM_CALL64_MSC
458 sub rsp, 50h+20h
459%else
460 sub rsp, 50h
461%endif
462 mov SavedRBX, rbx
463 mov SavedR12, r12
464 mov SavedR13, r13
465%ifdef ASM_CALL64_MSC
466 mov SavedRDI, rdi
467 mov SavedRSI, rsi
468 mov pData, rcx
469%else
470 ;mov pData, rdi - already in rdi.
471%endif
472%ifdef SavedR14
473 mov SavedR14, r14
474%endif
475%ifdef SavedR15
476 mov SavedR15, r15
477%endif
478
479
480 ;;
481 ;; Data fetch loop.
482 ;; We take great pain ensuring that data consistency here.
483 ;;
484.ReadGip:
485
486 ;
487 ; Load pGip and calc pGipCPU, setting u32ApicIdPlus if necessary.
488 ; Finding the GIP is fun...
489 ;
490%ifdef RT_OS_WINDOWS
491 %ifdef IMPORTED_SUPLIB
492 %ifdef IN_RING0
493 mov rax, qword IMP(g_SUPGlobalInfoPage)
494 mov pGip, rax
495 %else
496 mov pGip, [IMP(g_pSUPGlobalInfoPage) wrt rip]
497 mov pGip, [pGip]
498 %endif
499 %else
500 mov pGip, [NAME(g_pSUPGlobalInfoPage) wrt rip]
501 %endif
502%else
503 %ifdef IN_RING0
504 mov rax, qword NAME(g_SUPGlobalInfoPage)
505 mov pGip, rax
506 %else
507 mov pGip, [rel NAME(g_pSUPGlobalInfoPage) wrt ..gotpcrel]
508 mov pGip, [pGip]
509 %endif
510%endif
511 or pGip, pGip
512 jz .Rediscover
513 cmp dword [pGip + SUPGLOBALINFOPAGE.u32Magic], SUPGLOBALINFOPAGE_MAGIC
514 jne .Rediscover
515
516%ifdef ASYNC_GIP
517 ; u8ApicId = ASMGetApicId();
518 mov eax, 1
519 cpuid ; expensive
520 %ifdef NEED_TRANSACTION_ID
521 mov u32ApicIdPlus, ebx
522 %endif
523 ; pGipCpu = &pGip->aCPU[pGip->aiCpuFromApicId[u8ApicId]];
524 shr ebx, 24
525 movzx eax, word [pGip + rbx * 2 + SUPGLOBALINFOPAGE.aiCpuFromApicId]
526 imul eax, SUPGIPCPU_size
527 lea pGipCPU, [pGip + rax + SUPGLOBALINFOPAGE.aCPUs]
528%else
529 lea pGipCPU, [pGip + SUPGLOBALINFOPAGE.aCPUs]
530%endif
531
532%ifdef NEED_TRANSACTION_ID
533 ;
534 ; Serialized loading of u32TransactionId.
535 ;
536 mov u32TransactionId, [pGipCPU + SUPGIPCPU.u32TransactionId]
537 %ifdef USE_LFENCE
538 lfence
539 %else
540 lock xor dword TmpVar, 0
541 %endif
542%endif
543
544 ;
545 ; Load the data and TSC.
546 ;
547 mov u32UpdateIntervalNS, [pGip + SUPGLOBALINFOPAGE.u32UpdateIntervalNS] ; before u64TSC
548 mov u32UpdateIntervalTSC, [pGipCPU + SUPGIPCPU.u32UpdateIntervalTSC]
549 rdtsc
550;; @todo r-bird: Deltas are only valid in INVARIANT mode according to SUPDrv.c macro.
551;; pGipCPU is pointing to aCpu[0] in INVARIANT and SYNC. Code is 32-bit, i.e. inefficient. Code does more harm than good atm => disabled.
552;; (Just drop the SUPTscDeltaApply macro btw.) Sketched what is needed for invariant in timesupA.asm, more work .cpp files in IPRT and VMM.
553; SUPTscDeltaApply pGipCPU
554 mov u64PrevNanoTS, [pData + RTTIMENANOTSDATA.pu64Prev]
555 mov u64PrevNanoTS, [u64PrevNanoTS]
556 shl rdx, 32
557 %ifdef u64SavedRetNanoTS ; doing this here saves a tick or so.
558 mov u64SavedRetNanoTS, rax
559 or u64SavedRetNanoTS, rdx
560 %else
561 or rax, rdx ; rax is u64RetNanoTS.
562 %endif
563 mov u64CurNanoTS, [pGipCPU + SUPGIPCPU.u64NanoTS]
564 mov u64TSC, [pGipCPU + SUPGIPCPU.u64TSC]
565
566%ifdef NEED_TRANSACTION_ID
567 ;
568 ; Check that the GIP and CPU didn't change.
569 ;
570 ; It is crucial that the rdtsc instruction has completed before
571 ; we check the transaction id. The LOCK prefixed instruction with
572 ; dependency on the RDTSC result should do the trick, I think.
573 ; CPUID is serializing, so the async path is safe by default.
574 ;
575 %ifdef ASYNC_GIP
576 mov eax, 1
577 cpuid
578 cmp u32ApicIdPlus, ebx
579 jne .ReadGip
580 %else
581 lock xor qword TmpVar, rax
582 %endif
583 cmp u32TransactionId, [pGipCPU + SUPGIPCPU.u32TransactionId]
584 jne .ReadGip
585 test u32TransactionId, 1
586 jnz .ReadGip
587 %ifdef u64SavedRetNanoTS
588 mov rax, u64SavedRetNanoTS ; rax is u64RetNanoTS.
589 %endif
590%endif ; NEED_TRANSACTION_ID
591
592
593 ;;
594 ;; Calc the timestamp.
595 ;;
596 ; u64RetNanoTS -= u64TSC;
597 sub rax, u64TSC
598 xor edx, edx
599
600 ; if (u64RetNanoTS > u32UpdateIntervalTSC) -> jump
601 cmp rax, u32UpdateIntervalTSC_64
602 ja .OverFlow
603.ContinueCalcs: ; edx = 0; eax <= u32UpdateIntervalTSC
604 mul u32UpdateIntervalNS
605 div u32UpdateIntervalTSC
606
607 ; u64RetNanoTS += u64CurNanoTS;
608 add rax, u64CurNanoTS
609
610
611 ;;
612 ;; Compare it with the previous one.
613 ;;
614 ; if (RT_LIKELY( u64RetNanoTS > u64PrevNanoTS
615 ; && u64RetNanoTS < u64PrevNanoTS + UINT64_C(86000000000000) /* 24h */))
616 ; /* Frequent - less than 24h since last call. */;
617 cmp rax, u64PrevNanoTS
618 jbe .DeltaPrevTooBig
619 mov ecx, 5
620 shl rcx, 44 ; close enough
621 add rcx, u64PrevNanoTS
622 cmp rax, rcx
623 jae .DeltaPrevTooBig
624
625
626 ;;
627 ;; Update the previous value.
628 ;;
629.Update:
630 ; if (RT_LIKELY(ASMAtomicCmpXchgU64(&pData->u64Prev, u64RetNanoTS, u64PrevNanoTS)))
631 mov rbx, [pData + RTTIMENANOTSDATA.pu64Prev]
632 mov rcx, rax
633 mov rax, u64PrevNanoTS
634 lock cmpxchg [rbx], rcx
635 jnz .UpdateFailed
636
637.Updated:
638 mov rax, rcx
639
640.Done:
641 mov rbx, SavedRBX
642 mov r12, SavedR12
643 mov r13, SavedR13
644%ifdef SavedR14
645 mov r14, SavedR14
646%endif
647%ifdef SavedR15
648 mov r15, SavedR15
649%endif
650%ifdef ASM_CALL64_MSC
651 mov rdi, SavedRDI
652 mov rsi, SavedRSI
653%endif
654 leave
655 ret
656
657
658 ;;
659 ;; We've expired the interval, cap it. If we're here for the 2nd
660 ;; time without any GIP update in-between, the checks against
661 ;; pData->u64Prev below will force 1ns stepping.
662 ;;
663ALIGNCODE(16)
664.OverFlow:
665 ; u64RetNanoTS = u32UpdateIntervalTSC;
666 inc dword [pData + RTTIMENANOTSDATA.cExpired]
667 mov eax, u32UpdateIntervalTSC
668 jmp .ContinueCalcs
669
670
671 ;;
672 ;; u64DeltaPrev >= 24h
673 ;;
674 ;; rax = u64RetNanoTS (to be adjusted)
675 ;;
676ALIGNCODE(16)
677.DeltaPrevTooBig:
678 ; uint64_t u64DeltaPrev = u64RetNanoTS - u64PrevNanoTS;
679 mov rbx, rax
680 sub rbx, u64PrevNanoTS
681
682 ; else if ( (int64_t)u64DeltaPrev <= 0
683 ; && (int64_t)u64DeltaPrev + u32UpdateIntervalNS * 2 >= 0)
684 ; {
685 ; /* Occasional - u64NanoTS is in the recent 'past' relative the previous call. */
686 ; pData->c1nsSteps++;
687 ; u64RetNanoTS = u64PrevNanoTS + 1;
688 ; }
689 test rbx, rbx
690 jg .DeltaPrevNotInRecentPast
691
692 lea rdx, [u32UpdateIntervalNS_64 + u32UpdateIntervalNS_64]
693 add rdx, rbx
694 js .DeltaPrevNotInRecentPast
695
696 ; body
697 inc dword [pData + RTTIMENANOTSDATA.c1nsSteps]
698 lea rax, [u64PrevNanoTS + 1]
699 jmp .Update
700
701 ; else if (!u64PrevNanoTS) /* We're resuming (see TMVirtualResume) / first call. */
702 ; /* do nothing */;
703.DeltaPrevNotInRecentPast:
704 or u64PrevNanoTS, u64PrevNanoTS
705 jz .Update
706
707 ; else
708 ; {
709 ; /* Something has gone bust, if negative offset it's real bad. */
710 ; rtTimeNanoTSInternalBitch(pVM,
711 ; }
712
713 ; call C function that does the bitching.
714 mov TmpVar, rax
715 mov TmpVar2, pData
716
717%ifdef ASM_CALL64_MSC
718 mov rcx, pData ; param 1 - pData
719 mov rdx, rax ; param 2 - u64RetNanoTS
720 mov r8, rbx ; param 3 - u64DeltaPrev
721 mov r9, u64PrevNanoTS ; param 4 - u64PrevNanoTS
722%else
723 ;mov rdi, pData - already in rdi; param 1 - pData
724 mov rsi, rax ; param 2 - u64RetNanoTS
725 mov rdx, rbx ; param 3 - u64DeltaPrev
726 mov rcx, u64PrevNanoTS ; param 4 - u64PrevNanoTS
727%endif
728 call qword [pData + RTTIMENANOTSDATA.pfnBad]
729
730 mov rax, TmpVar
731 mov pData, TmpVar2
732 jmp .Update
733
734
735 ;;
736 ;; Attempt updating the previous value, provided we're still ahead of it.
737 ;;
738 ;; There is no point in recalculating u64NanoTS because we got preempted or if
739 ;; we raced somebody while the GIP was updated, since these are events
740 ;; that might occur at any point in the return path as well.
741 ;;
742 ;; rax = *pData->u64Prev;
743 ;; rcx = u64RetNanoTS
744 ;;
745ALIGNCODE(16)
746.UpdateFailed:
747 lock inc dword [pData + RTTIMENANOTSDATA.cUpdateRaces]
748 ; for (i = 0; i < 10; i++)
749 mov edx, 10
750.UpdateLoop:
751 ; if (u64PrevNanoTS >= u64RetNanoTS)
752 ; break;
753 cmp rax, rcx
754 jge .Updated
755.UpdateLoopLess:
756 ; retry
757 lock cmpxchg [rbx], rcx
758 jz .Updated
759 dec edx
760 jnz .UpdateLoop
761 jmp .Updated
762
763
764 ;;
765 ;; The GIP is seemingly invalid, redo the discovery.
766 ;;
767.Rediscover:
768%ifdef ASM_CALL64_MSC
769 mov rcx, pData
770%else
771 ; mov rdi, pData - already in rdi
772%endif
773 call [pData + RTTIMENANOTSDATA.pfnRediscover]
774 jmp .Done
775
776
777 ;
778 ; Cleanup variables
779 ;
780%undef SavedRBX
781%undef SavedR12
782%undef SavedR13
783%undef SavedR14
784%undef SavedR15
785%undef SavedRDI
786%undef SavedRSI
787%undef pData
788%undef TmpVar
789%undef u64TSC
790%undef pGip
791%undef pGipCPU
792%undef u32TransactionId
793%undef u64CurNanoTS
794%undef u64PrevNanoTS
795%undef u32UpdateIntervalTSC
796%undef u32UpdateIntervalTSC_64
797%undef u32UpdateIntervalNS
798%undef u64SavedRetNanoTS
799%undef u32ApicIdPlus
800
801%endif ; AMD64
802ENDPROC rtTimeNanoTSInternalAsm
803
804
805
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette