VirtualBox

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

Last change on this file since 50795 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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