VirtualBox

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

Last change on this file since 20008 was 8272, checked in by vboxsync, 17 years ago

rebranding: IPRT files again (missing bits)

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

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