1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
|
/* $Id: TMInternal.h $ */
/** @file
* TM - Internal header file.
*/
/*
* Copyright (C) 2006-2020 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#ifndef VMM_INCLUDED_SRC_include_TMInternal_h
#define VMM_INCLUDED_SRC_include_TMInternal_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif
#include <VBox/cdefs.h>
#include <VBox/types.h>
#include <iprt/time.h>
#include <iprt/timer.h>
#include <iprt/assert.h>
#include <VBox/vmm/stam.h>
#include <VBox/vmm/pdmcritsect.h>
RT_C_DECLS_BEGIN
/** @defgroup grp_tm_int Internal
* @ingroup grp_tm
* @internal
* @{
*/
/** Frequency of the real clock. */
#define TMCLOCK_FREQ_REAL UINT32_C(1000)
/** Frequency of the virtual clock. */
#define TMCLOCK_FREQ_VIRTUAL UINT32_C(1000000000)
/**
* Timer type.
*/
typedef enum TMTIMERTYPE
{
/** Device timer. */
TMTIMERTYPE_DEV = 1,
/** USB device timer. */
TMTIMERTYPE_USB,
/** Driver timer. */
TMTIMERTYPE_DRV,
/** Internal timer . */
TMTIMERTYPE_INTERNAL,
/** External timer. */
TMTIMERTYPE_EXTERNAL
} TMTIMERTYPE;
/**
* Timer state
*/
typedef enum TMTIMERSTATE
{
/** Timer is stopped. */
TMTIMERSTATE_STOPPED = 1,
/** Timer is active. */
TMTIMERSTATE_ACTIVE,
/** Timer is expired, getting expire and unlinking. */
TMTIMERSTATE_EXPIRED_GET_UNLINK,
/** Timer is expired and is being delivered. */
TMTIMERSTATE_EXPIRED_DELIVER,
/** Timer is stopped but still in the active list.
* Currently in the ScheduleTimers list. */
TMTIMERSTATE_PENDING_STOP,
/** Timer is stopped but needs unlinking from the ScheduleTimers list.
* Currently in the ScheduleTimers list. */
TMTIMERSTATE_PENDING_STOP_SCHEDULE,
/** Timer is being modified and will soon be pending scheduling.
* Currently in the ScheduleTimers list. */
TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE,
/** Timer is pending scheduling.
* Currently in the ScheduleTimers list. */
TMTIMERSTATE_PENDING_SCHEDULE,
/** Timer is being modified and will soon be pending rescheduling.
* Currently in the ScheduleTimers list and the active list. */
TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE,
/** Timer is modified and is now pending rescheduling.
* Currently in the ScheduleTimers list and the active list. */
TMTIMERSTATE_PENDING_RESCHEDULE,
/** Timer is being destroyed. */
TMTIMERSTATE_DESTROY,
/** Timer is free. */
TMTIMERSTATE_FREE
} TMTIMERSTATE;
/** Predicate that returns true if the give state is pending scheduling or
* rescheduling of any kind. Will reference the argument more than once! */
#define TMTIMERSTATE_IS_PENDING_SCHEDULING(enmState) \
( (enmState) <= TMTIMERSTATE_PENDING_RESCHEDULE \
&& (enmState) >= TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE)
/**
* Internal representation of a timer.
*
* For correct serialization (without the use of semaphores and
* other blocking/slow constructs) certain rules applies to updating
* this structure:
* - For thread other than EMT only u64Expire, enmState and pScheduleNext*
* are changeable. Everything else is out of bounds.
* - Updating of u64Expire timer can only happen in the TMTIMERSTATE_STOPPED
* and TMTIMERSTATE_PENDING_RESCHEDULING_SET_EXPIRE states.
* - Timers in the TMTIMERSTATE_EXPIRED state are only accessible from EMT.
* - Actual destruction of a timer can only be done at scheduling time.
*/
typedef struct TMTIMER
{
/** Expire time. */
volatile uint64_t u64Expire;
/** Clock to apply to u64Expire. */
TMCLOCK enmClock;
/** Timer callback type. */
TMTIMERTYPE enmType;
/** Type specific data. */
union
{
/** TMTIMERTYPE_DEV. */
struct
{
/** Callback. */
R3PTRTYPE(PFNTMTIMERDEV) pfnTimer;
/** Device instance. */
PPDMDEVINSR3 pDevIns;
} Dev;
/** TMTIMERTYPE_DEV. */
struct
{
/** Callback. */
R3PTRTYPE(PFNTMTIMERUSB) pfnTimer;
/** USB device instance. */
PPDMUSBINS pUsbIns;
} Usb;
/** TMTIMERTYPE_DRV. */
struct
{
/** Callback. */
R3PTRTYPE(PFNTMTIMERDRV) pfnTimer;
/** Device instance. */
R3PTRTYPE(PPDMDRVINS) pDrvIns;
} Drv;
/** TMTIMERTYPE_INTERNAL. */
struct
{
/** Callback. */
R3PTRTYPE(PFNTMTIMERINT) pfnTimer;
} Internal;
/** TMTIMERTYPE_EXTERNAL. */
struct
{
/** Callback. */
R3PTRTYPE(PFNTMTIMEREXT) pfnTimer;
} External;
} u;
/** Timer state. */
volatile TMTIMERSTATE enmState;
/** Timer relative offset to the next timer in the schedule list. */
int32_t volatile offScheduleNext;
/** Timer relative offset to the next timer in the chain. */
int32_t offNext;
/** Timer relative offset to the previous timer in the chain. */
int32_t offPrev;
/** Pointer to the VM the timer belongs to - R3 Ptr. */
PVMR3 pVMR3;
/** Pointer to the VM the timer belongs to - R0 Ptr. */
R0PTRTYPE(PVMCC) pVMR0;
/** Pointer to the VM the timer belongs to - RC Ptr. */
PVMRC pVMRC;
/** The timer frequency hint. This is 0 if not hint was given. */
uint32_t volatile uHzHint;
/** User argument. */
RTR3PTR pvUser;
/** The critical section associated with the lock. */
R3PTRTYPE(PPDMCRITSECT) pCritSect;
/** Pointer to the next timer in the list of created or free timers. (TM::pTimers or TM::pFree) */
PTMTIMERR3 pBigNext;
/** Pointer to the previous timer in the list of all created timers. (TM::pTimers) */
PTMTIMERR3 pBigPrev;
/** Pointer to the timer description. */
R3PTRTYPE(const char *) pszDesc;
#if HC_ARCH_BITS == 32
uint32_t padding0; /**< pad structure to multiple of 8 bytes. */
#endif
#ifdef VBOX_WITH_STATISTICS
STAMPROFILE StatTimer;
STAMPROFILE StatCritSectEnter;
STAMCOUNTER StatGet;
STAMCOUNTER StatSetAbsolute;
STAMCOUNTER StatSetRelative;
STAMCOUNTER StatStop;
#endif
} TMTIMER;
AssertCompileMemberSize(TMTIMER, enmState, sizeof(uint32_t));
/**
* Updates a timer state in the correct atomic manner.
*/
#if 1
# define TM_SET_STATE(pTimer, state) \
ASMAtomicWriteU32((uint32_t volatile *)&(pTimer)->enmState, state)
#else
# define TM_SET_STATE(pTimer, state) \
do { \
uint32_t uOld1 = (pTimer)->enmState; \
Log(("%s: %p: %d -> %d\n", __FUNCTION__, (pTimer), (pTimer)->enmState, state)); \
uint32_t uOld2 = ASMAtomicXchgU32((uint32_t volatile *)&(pTimer)->enmState, state); \
Assert(uOld1 == uOld2); \
} while (0)
#endif
/**
* Tries to updates a timer state in the correct atomic manner.
*/
#if 1
# define TM_TRY_SET_STATE(pTimer, StateNew, StateOld, fRc) \
(fRc) = ASMAtomicCmpXchgU32((uint32_t volatile *)&(pTimer)->enmState, StateNew, StateOld)
#else
# define TM_TRY_SET_STATE(pTimer, StateNew, StateOld, fRc) \
do { (fRc) = ASMAtomicCmpXchgU32((uint32_t volatile *)&(pTimer)->enmState, StateNew, StateOld); \
Log(("%s: %p: %d -> %d %RTbool\n", __FUNCTION__, (pTimer), StateOld, StateNew, fRc)); \
} while (0)
#endif
/** Get the previous timer. */
#define TMTIMER_GET_PREV(pTimer) ((PTMTIMER)((pTimer)->offPrev ? (intptr_t)(pTimer) + (pTimer)->offPrev : 0))
/** Get the next timer. */
#define TMTIMER_GET_NEXT(pTimer) ((PTMTIMER)((pTimer)->offNext ? (intptr_t)(pTimer) + (pTimer)->offNext : 0))
/** Set the previous timer link. */
#define TMTIMER_SET_PREV(pTimer, pPrev) ((pTimer)->offPrev = (pPrev) ? (intptr_t)(pPrev) - (intptr_t)(pTimer) : 0)
/** Set the next timer link. */
#define TMTIMER_SET_NEXT(pTimer, pNext) ((pTimer)->offNext = (pNext) ? (intptr_t)(pNext) - (intptr_t)(pTimer) : 0)
/**
* A timer queue.
*
* This is allocated on the hyper heap.
*/
typedef struct TMTIMERQUEUE
{
/** The cached expire time for this queue.
* Updated by EMT when scheduling the queue or modifying the head timer.
* Assigned UINT64_MAX when there is no head timer. */
uint64_t u64Expire;
/** Doubly linked list of active timers.
*
* When no scheduling is pending, this list is will be ordered by expire time (ascending).
* Access is serialized by only letting the emulation thread (EMT) do changes.
*
* The offset is relative to the queue structure.
*/
int32_t offActive;
/** List of timers pending scheduling of some kind.
*
* Timer stats allowed in the list are TMTIMERSTATE_PENDING_STOPPING,
* TMTIMERSTATE_PENDING_DESTRUCTION, TMTIMERSTATE_PENDING_STOPPING_DESTRUCTION,
* TMTIMERSTATE_PENDING_RESCHEDULING and TMTIMERSTATE_PENDING_SCHEDULE.
*
* The offset is relative to the queue structure.
*/
int32_t volatile offSchedule;
/** The clock for this queue. */
TMCLOCK enmClock;
/** Pad the structure up to 32 bytes. */
uint32_t au32Padding[3];
} TMTIMERQUEUE;
/** Pointer to a timer queue. */
typedef TMTIMERQUEUE *PTMTIMERQUEUE;
/** Get the head of the active timer list. */
#define TMTIMER_GET_HEAD(pQueue) ((PTMTIMER)((pQueue)->offActive ? (intptr_t)(pQueue) + (pQueue)->offActive : 0))
/** Set the head of the active timer list. */
#define TMTIMER_SET_HEAD(pQueue, pHead) ((pQueue)->offActive = pHead ? (intptr_t)pHead - (intptr_t)(pQueue) : 0)
/**
* CPU load data set.
* Mainly used by tmR3CpuLoadTimer.
*/
typedef struct TMCPULOADSTATE
{
/** The percent of the period spent executing guest code. */
uint8_t cPctExecuting;
/** The percent of the period spent halted. */
uint8_t cPctHalted;
/** The percent of the period spent on other things. */
uint8_t cPctOther;
/** Explicit alignment padding */
uint8_t au8Alignment[1];
/** Index into aHistory of the current entry. */
uint16_t volatile idxHistory;
/** Number of valid history entries before idxHistory. */
uint16_t volatile cHistoryEntries;
/** Previous cNsTotal value. */
uint64_t cNsPrevTotal;
/** Previous cNsExecuting value. */
uint64_t cNsPrevExecuting;
/** Previous cNsHalted value. */
uint64_t cNsPrevHalted;
/** Data for the last 30 min (given an interval of 1 second). */
struct
{
uint8_t cPctExecuting;
/** The percent of the period spent halted. */
uint8_t cPctHalted;
/** The percent of the period spent on other things. */
uint8_t cPctOther;
} aHistory[30*60];
} TMCPULOADSTATE;
AssertCompileSizeAlignment(TMCPULOADSTATE, 8);
AssertCompileMemberAlignment(TMCPULOADSTATE, cNsPrevTotal, 8);
/** Pointer to a CPU load data set. */
typedef TMCPULOADSTATE *PTMCPULOADSTATE;
/**
* TSC mode.
*
* The main modes of how TM implements the TSC clock (TMCLOCK_TSC).
*/
typedef enum TMTSCMODE
{
/** The guest TSC is an emulated, virtual TSC. */
TMTSCMODE_VIRT_TSC_EMULATED = 1,
/** The guest TSC is an offset of the real TSC. */
TMTSCMODE_REAL_TSC_OFFSET,
/** The guest TSC is dynamically derived through emulating or offsetting. */
TMTSCMODE_DYNAMIC,
/** The native API provides it. */
TMTSCMODE_NATIVE_API
} TMTSCMODE;
AssertCompileSize(TMTSCMODE, sizeof(uint32_t));
/**
* Converts a TM pointer into a VM pointer.
* @returns Pointer to the VM structure the TM is part of.
* @param pTM Pointer to TM instance data.
*/
#define TM2VM(pTM) ( (PVM)((char*)pTM - pTM->offVM) )
/**
* TM VM Instance data.
* Changes to this must checked against the padding of the cfgm union in VM!
*/
typedef struct TM
{
/** Offset to the VM structure.
* See TM2VM(). */
RTUINT offVM;
/** The current TSC mode of the VM.
* Config variable: Mode (string). */
TMTSCMODE enmTSCMode;
/** The original TSC mode of the VM. */
TMTSCMODE enmOriginalTSCMode;
/** Alignment padding. */
uint32_t u32Alignment0;
/** Whether the TSC is tied to the execution of code.
* Config variable: TSCTiedToExecution (bool) */
bool fTSCTiedToExecution;
/** Modifier for fTSCTiedToExecution which pauses the TSC while halting if true.
* Config variable: TSCNotTiedToHalt (bool) */
bool fTSCNotTiedToHalt;
/** Whether TM TSC mode switching is allowed at runtime. */
bool fTSCModeSwitchAllowed;
/** Whether the guest has enabled use of paravirtualized TSC. */
bool fParavirtTscEnabled;
/** The ID of the virtual CPU that normally runs the timers. */
VMCPUID idTimerCpu;
/** The number of CPU clock ticks per second (TMCLOCK_TSC).
* Config variable: TSCTicksPerSecond (64-bit unsigned int)
* The config variable implies @c enmTSCMode would be
* TMTSCMODE_VIRT_TSC_EMULATED. */
uint64_t cTSCTicksPerSecond;
/** The TSC difference introduced by pausing the VM. */
uint64_t offTSCPause;
/** The TSC value when the last TSC was paused. */
uint64_t u64LastPausedTSC;
/** CPU TSCs ticking indicator (one for each VCPU). */
uint32_t volatile cTSCsTicking;
/** Virtual time ticking enabled indicator (counter for each VCPU). (TMCLOCK_VIRTUAL) */
uint32_t volatile cVirtualTicking;
/** Virtual time is not running at 100%. */
bool fVirtualWarpDrive;
/** Virtual timer synchronous time ticking enabled indicator (bool). (TMCLOCK_VIRTUAL_SYNC) */
bool volatile fVirtualSyncTicking;
/** Virtual timer synchronous time catch-up active. */
bool volatile fVirtualSyncCatchUp;
/** Alignment padding. */
bool afAlignment1[1];
/** WarpDrive percentage.
* 100% is normal (fVirtualSyncNormal == true). When other than 100% we apply
* this percentage to the raw time source for the period it's been valid in,
* i.e. since u64VirtualWarpDriveStart. */
uint32_t u32VirtualWarpDrivePercentage;
/** The offset of the virtual clock relative to it's timesource.
* Only valid if fVirtualTicking is set. */
uint64_t u64VirtualOffset;
/** The guest virtual time when fVirtualTicking is cleared. */
uint64_t u64Virtual;
/** When the Warp drive was started or last adjusted.
* Only valid when fVirtualWarpDrive is set. */
uint64_t u64VirtualWarpDriveStart;
/** The previously returned nano TS.
* This handles TSC drift on SMP systems and expired interval.
* This is a valid range u64NanoTS to u64NanoTS + 1000000000 (ie. 1sec). */
uint64_t volatile u64VirtualRawPrev;
/** The ring-3 data structure for the RTTimeNanoTS workers used by tmVirtualGetRawNanoTS. */
RTTIMENANOTSDATAR3 VirtualGetRawDataR3;
/** The ring-0 data structure for the RTTimeNanoTS workers used by tmVirtualGetRawNanoTS. */
RTTIMENANOTSDATAR0 VirtualGetRawDataR0;
/** The ring-0 data structure for the RTTimeNanoTS workers used by tmVirtualGetRawNanoTS. */
RTTIMENANOTSDATARC VirtualGetRawDataRC;
/** Pointer to the ring-3 tmVirtualGetRawNanoTS worker function. */
R3PTRTYPE(PFNTIMENANOTSINTERNAL) pfnVirtualGetRawR3;
/** Pointer to the ring-0 tmVirtualGetRawNanoTS worker function. */
R0PTRTYPE(PFNTIMENANOTSINTERNAL) pfnVirtualGetRawR0;
/** Pointer to the raw-mode tmVirtualGetRawNanoTS worker function. */
RCPTRTYPE(PFNTIMENANOTSINTERNAL) pfnVirtualGetRawRC;
/** Alignment. */
RTRCPTR AlignmentRCPtr;
/** The guest virtual timer synchronous time when fVirtualSyncTicking is cleared.
* When fVirtualSyncTicking is set it holds the last time returned to
* the guest (while the lock was held). */
uint64_t volatile u64VirtualSync;
/** The offset of the timer synchronous virtual clock (TMCLOCK_VIRTUAL_SYNC) relative
* to the virtual clock (TMCLOCK_VIRTUAL).
* (This is accessed by the timer thread and must be updated atomically.) */
uint64_t volatile offVirtualSync;
/** The offset into offVirtualSync that's been irrevocably given up by failed catch-up attempts.
* Thus the current lag is offVirtualSync - offVirtualSyncGivenUp. */
uint64_t offVirtualSyncGivenUp;
/** The TMCLOCK_VIRTUAL at the previous TMVirtualGetSync call when catch-up is active. */
uint64_t volatile u64VirtualSyncCatchUpPrev;
/** The current catch-up percentage. */
uint32_t volatile u32VirtualSyncCatchUpPercentage;
/** How much slack when processing timers. */
uint32_t u32VirtualSyncScheduleSlack;
/** When to stop catch-up. */
uint64_t u64VirtualSyncCatchUpStopThreshold;
/** When to give up catch-up. */
uint64_t u64VirtualSyncCatchUpGiveUpThreshold;
/** @def TM_MAX_CATCHUP_PERIODS
* The number of catchup rates. */
#define TM_MAX_CATCHUP_PERIODS 10
/** The aggressiveness of the catch-up relative to how far we've lagged behind.
* The idea is to have increasing catch-up percentage as the lag increases. */
struct TMCATCHUPPERIOD
{
uint64_t u64Start; /**< When this period starts. (u64VirtualSyncOffset). */
uint32_t u32Percentage; /**< The catch-up percent to apply. */
uint32_t u32Alignment; /**< Structure alignment */
} aVirtualSyncCatchUpPeriods[TM_MAX_CATCHUP_PERIODS];
/** The current max timer Hz hint. */
uint32_t volatile uMaxHzHint;
/** Whether to recalulate the HzHint next time its queried. */
bool volatile fHzHintNeedsUpdating;
/** Alignment */
bool afAlignment2[3];
/** @cfgm{/TM/HostHzMax, uint32_t, Hz, 0, UINT32_MAX, 20000}
* The max host Hz frequency hint returned by TMCalcHostTimerFrequency. */
uint32_t cHostHzMax;
/** @cfgm{/TM/HostHzFudgeFactorTimerCpu, uint32_t, Hz, 0, UINT32_MAX, 111}
* The number of Hz TMCalcHostTimerFrequency adds for the timer CPU. */
uint32_t cPctHostHzFudgeFactorTimerCpu;
/** @cfgm{/TM/HostHzFudgeFactorOtherCpu, uint32_t, Hz, 0, UINT32_MAX, 110}
* The number of Hz TMCalcHostTimerFrequency adds for the other CPUs. */
uint32_t cPctHostHzFudgeFactorOtherCpu;
/** @cfgm{/TM/HostHzFudgeFactorCatchUp100, uint32_t, Hz, 0, UINT32_MAX, 300}
* The fudge factor (expressed in percent) that catch-up percentages below
* 100% is multiplied by. */
uint32_t cPctHostHzFudgeFactorCatchUp100;
/** @cfgm{/TM/HostHzFudgeFactorCatchUp200, uint32_t, Hz, 0, UINT32_MAX, 250}
* The fudge factor (expressed in percent) that catch-up percentages
* 100%-199% is multiplied by. */
uint32_t cPctHostHzFudgeFactorCatchUp200;
/** @cfgm{/TM/HostHzFudgeFactorCatchUp400, uint32_t, Hz, 0, UINT32_MAX, 200}
* The fudge factor (expressed in percent) that catch-up percentages
* 200%-399% is multiplied by. */
uint32_t cPctHostHzFudgeFactorCatchUp400;
/** The UTC offset in ns.
* This is *NOT* for converting UTC to local time. It is for converting real
* world UTC time to VM UTC time. This feature is indented for doing date
* testing of software and similar.
* @todo Implement warpdrive on UTC. */
int64_t offUTC;
/** The last value TMR3UtcNow returned. */
int64_t volatile nsLastUtcNow;
/** File to touch on UTC jump. */
R3PTRTYPE(char *) pszUtcTouchFileOnJump;
/** Just to avoid dealing with 32-bit alignment trouble. */
R3PTRTYPE(char *) pszAlignment2b;
/** Timer queues for the different clock types - R3 Ptr */
R3PTRTYPE(PTMTIMERQUEUE) paTimerQueuesR3;
/** Timer queues for the different clock types - R0 Ptr */
R0PTRTYPE(PTMTIMERQUEUE) paTimerQueuesR0;
/** Timer queues for the different clock types - RC Ptr */
RCPTRTYPE(PTMTIMERQUEUE) paTimerQueuesRC;
/** Pointer to our RC mapping of the GIP. */
RCPTRTYPE(void *) pvGIPRC;
/** Pointer to our R3 mapping of the GIP. */
R3PTRTYPE(void *) pvGIPR3;
/** Pointer to a singly linked list of free timers.
* This chain is using the TMTIMER::pBigNext members.
* Only accessible from the emulation thread. */
PTMTIMERR3 pFree;
/** Pointer to a doubly linked list of created timers.
* This chain is using the TMTIMER::pBigNext and TMTIMER::pBigPrev members.
* Only accessible from the emulation thread. */
PTMTIMERR3 pCreated;
/** The schedule timer timer handle (runtime timer).
* This timer will do frequent check on pending queue schedules and
* raise VM_FF_TIMER to pull EMTs attention to them.
*/
R3PTRTYPE(PRTTIMER) pTimer;
/** Interval in milliseconds of the pTimer timer. */
uint32_t u32TimerMillies;
/** Indicates that queues are being run. */
bool volatile fRunningQueues;
/** Indicates that the virtual sync queue is being run. */
bool volatile fRunningVirtualSyncQueue;
/** Alignment */
bool afAlignment3[2];
/** Lock serializing access to the timer lists. */
PDMCRITSECT TimerCritSect;
/** Lock serializing access to the VirtualSync clock and the associated
* timer queue. */
PDMCRITSECT VirtualSyncLock;
/** CPU load state for all the virtual CPUs (tmR3CpuLoadTimer). */
TMCPULOADSTATE CpuLoad;
/** TMR3TimerQueuesDo
* @{ */
STAMPROFILE StatDoQueues;
STAMPROFILEADV aStatDoQueues[TMCLOCK_MAX];
/** @} */
/** tmSchedule
* @{ */
STAMPROFILE StatScheduleOneRZ;
STAMPROFILE StatScheduleOneR3;
STAMCOUNTER StatScheduleSetFF;
STAMCOUNTER StatPostponedR3;
STAMCOUNTER StatPostponedRZ;
/** @} */
/** Read the time
* @{ */
STAMCOUNTER StatVirtualGet;
STAMCOUNTER StatVirtualGetSetFF;
STAMCOUNTER StatVirtualSyncGet;
STAMCOUNTER StatVirtualSyncGetAdjLast;
STAMCOUNTER StatVirtualSyncGetELoop;
STAMCOUNTER StatVirtualSyncGetExpired;
STAMCOUNTER StatVirtualSyncGetLockless;
STAMCOUNTER StatVirtualSyncGetLocked;
STAMCOUNTER StatVirtualSyncGetSetFF;
STAMCOUNTER StatVirtualPause;
STAMCOUNTER StatVirtualResume;
/** @} */
/** TMTimerPoll
* @{ */
STAMCOUNTER StatPoll;
STAMCOUNTER StatPollAlreadySet;
STAMCOUNTER StatPollELoop;
STAMCOUNTER StatPollMiss;
STAMCOUNTER StatPollRunning;
STAMCOUNTER StatPollSimple;
STAMCOUNTER StatPollVirtual;
STAMCOUNTER StatPollVirtualSync;
/** @} */
/** TMTimerSet sans virtual sync timers.
* @{ */
STAMCOUNTER StatTimerSet;
STAMCOUNTER StatTimerSetOpt;
STAMPROFILE StatTimerSetRZ;
STAMPROFILE StatTimerSetR3;
STAMCOUNTER StatTimerSetStStopped;
STAMCOUNTER StatTimerSetStExpDeliver;
STAMCOUNTER StatTimerSetStActive;
STAMCOUNTER StatTimerSetStPendStop;
STAMCOUNTER StatTimerSetStPendStopSched;
STAMCOUNTER StatTimerSetStPendSched;
STAMCOUNTER StatTimerSetStPendResched;
STAMCOUNTER StatTimerSetStOther;
/** @} */
/** TMTimerSet on virtual sync timers.
* @{ */
STAMCOUNTER StatTimerSetVs;
STAMPROFILE StatTimerSetVsRZ;
STAMPROFILE StatTimerSetVsR3;
STAMCOUNTER StatTimerSetVsStStopped;
STAMCOUNTER StatTimerSetVsStExpDeliver;
STAMCOUNTER StatTimerSetVsStActive;
/** @} */
/** TMTimerSetRelative sans virtual sync timers
* @{ */
STAMCOUNTER StatTimerSetRelative;
STAMPROFILE StatTimerSetRelativeRZ;
STAMPROFILE StatTimerSetRelativeR3;
STAMCOUNTER StatTimerSetRelativeOpt;
STAMCOUNTER StatTimerSetRelativeStStopped;
STAMCOUNTER StatTimerSetRelativeStExpDeliver;
STAMCOUNTER StatTimerSetRelativeStActive;
STAMCOUNTER StatTimerSetRelativeStPendStop;
STAMCOUNTER StatTimerSetRelativeStPendStopSched;
STAMCOUNTER StatTimerSetRelativeStPendSched;
STAMCOUNTER StatTimerSetRelativeStPendResched;
STAMCOUNTER StatTimerSetRelativeStOther;
/** @} */
/** TMTimerSetRelative on virtual sync timers.
* @{ */
STAMCOUNTER StatTimerSetRelativeVs;
STAMPROFILE StatTimerSetRelativeVsRZ;
STAMPROFILE StatTimerSetRelativeVsR3;
STAMCOUNTER StatTimerSetRelativeVsStStopped;
STAMCOUNTER StatTimerSetRelativeVsStExpDeliver;
STAMCOUNTER StatTimerSetRelativeVsStActive;
/** @} */
/** TMTimerStop sans virtual sync.
* @{ */
STAMPROFILE StatTimerStopRZ;
STAMPROFILE StatTimerStopR3;
/** @} */
/** TMTimerStop on virtual sync timers.
* @{ */
STAMPROFILE StatTimerStopVsRZ;
STAMPROFILE StatTimerStopVsR3;
/** @} */
/** VirtualSync - Running and Catching Up
* @{ */
STAMCOUNTER StatVirtualSyncRun;
STAMCOUNTER StatVirtualSyncRunRestart;
STAMPROFILE StatVirtualSyncRunSlack;
STAMCOUNTER StatVirtualSyncRunStop;
STAMCOUNTER StatVirtualSyncRunStoppedAlready;
STAMCOUNTER StatVirtualSyncGiveUp;
STAMCOUNTER StatVirtualSyncGiveUpBeforeStarting;
STAMPROFILEADV StatVirtualSyncCatchup;
STAMCOUNTER aStatVirtualSyncCatchupInitial[TM_MAX_CATCHUP_PERIODS];
STAMCOUNTER aStatVirtualSyncCatchupAdjust[TM_MAX_CATCHUP_PERIODS];
/** @} */
/** TMR3VirtualSyncFF (non dedicated EMT). */
STAMPROFILE StatVirtualSyncFF;
/** The timer callback. */
STAMCOUNTER StatTimerCallbackSetFF;
STAMCOUNTER StatTimerCallback;
/** Calls to TMCpuTickSet. */
STAMCOUNTER StatTSCSet;
/** TSC starts and stops. */
STAMCOUNTER StatTSCPause;
STAMCOUNTER StatTSCResume;
/** @name Reasons for refusing TSC offsetting in TMCpuTickCanUseRealTSC.
* @{ */
STAMCOUNTER StatTSCNotFixed;
STAMCOUNTER StatTSCNotTicking;
STAMCOUNTER StatTSCCatchupLE010;
STAMCOUNTER StatTSCCatchupLE025;
STAMCOUNTER StatTSCCatchupLE100;
STAMCOUNTER StatTSCCatchupOther;
STAMCOUNTER StatTSCWarp;
STAMCOUNTER StatTSCUnderflow;
STAMCOUNTER StatTSCSyncNotTicking;
/** @} */
} TM;
/** Pointer to TM VM instance data. */
typedef TM *PTM;
/**
* TM VMCPU Instance data.
* Changes to this must checked against the padding of the tm union in VM!
*/
typedef struct TMCPU
{
/** Offset to the VMCPU structure.
* See TMCPU2VM(). */
RTUINT offVMCPU;
/** CPU timestamp ticking enabled indicator (bool). (RDTSC) */
bool fTSCTicking;
bool afAlignment0[3]; /**< alignment padding */
/** The offset between the host tick (TSC/virtual depending on the TSC mode) and
* the guest tick. */
uint64_t offTSCRawSrc;
/** The guest TSC when fTicking is cleared. */
uint64_t u64TSC;
/** The last seen TSC by the guest. */
uint64_t u64TSCLastSeen;
#ifndef VBOX_WITHOUT_NS_ACCOUNTING
/** The nanosecond timestamp of the CPU start or resume.
* This is recalculated when the VM is started so that
* cNsTotal = RTTimeNanoTS() - u64NsTsStartCpu. */
uint64_t u64NsTsStartTotal;
/** The nanosecond timestamp of the last start-execute notification. */
uint64_t u64NsTsStartExecuting;
/** The nanosecond timestamp of the last start-halt notification. */
uint64_t u64NsTsStartHalting;
/** The cNsXXX generation. */
uint32_t volatile uTimesGen;
/** Explicit alignment padding. */
uint32_t u32Alignment;
/** The number of nanoseconds total run time.
* @remarks This is updated when cNsExecuting and cNsHalted are updated. */
uint64_t cNsTotal;
/** The number of nanoseconds spent executing. */
uint64_t cNsExecuting;
/** The number of nanoseconds being halted. */
uint64_t cNsHalted;
/** The number of nanoseconds spent on other things.
* @remarks This is updated when cNsExecuting and cNsHalted are updated. */
uint64_t cNsOther;
/** The number of halts. */
uint64_t cPeriodsHalted;
/** The number of guest execution runs. */
uint64_t cPeriodsExecuting;
# if defined(VBOX_WITH_STATISTICS) || defined(VBOX_WITH_NS_ACCOUNTING_STATS)
/** Resettable version of cNsTotal. */
STAMCOUNTER StatNsTotal;
/** Resettable version of cNsExecuting. */
STAMPROFILE StatNsExecuting;
/** Long execution intervals. */
STAMPROFILE StatNsExecLong;
/** Short execution intervals . */
STAMPROFILE StatNsExecShort;
/** Tiny execution intervals . */
STAMPROFILE StatNsExecTiny;
/** Resettable version of cNsHalted. */
STAMPROFILE StatNsHalted;
/** Resettable version of cNsOther. */
STAMPROFILE StatNsOther;
# endif
/** CPU load state for this virtual CPU (tmR3CpuLoadTimer). */
TMCPULOADSTATE CpuLoad;
#endif
} TMCPU;
/** Pointer to TM VMCPU instance data. */
typedef TMCPU *PTMCPU;
const char *tmTimerState(TMTIMERSTATE enmState);
void tmTimerQueueSchedule(PVM pVM, PTMTIMERQUEUE pQueue);
#ifdef VBOX_STRICT
void tmTimerQueuesSanityChecks(PVM pVM, const char *pszWhere);
#endif
uint64_t tmR3CpuTickGetRawVirtualNoCheck(PVM pVM);
int tmCpuTickPause(PVMCPUCC pVCpu);
int tmCpuTickPauseLocked(PVMCC pVM, PVMCPUCC pVCpu);
int tmCpuTickResume(PVMCC pVM, PVMCPUCC pVCpu);
int tmCpuTickResumeLocked(PVMCC pVM, PVMCPUCC pVCpu);
int tmVirtualPauseLocked(PVMCC pVM);
int tmVirtualResumeLocked(PVMCC pVM);
DECLCALLBACK(DECLEXPORT(void)) tmVirtualNanoTSBad(PRTTIMENANOTSDATA pData, uint64_t u64NanoTS,
uint64_t u64DeltaPrev, uint64_t u64PrevNanoTS);
DECLCALLBACK(DECLEXPORT(uint64_t)) tmVirtualNanoTSRediscover(PRTTIMENANOTSDATA pData);
DECLCALLBACK(DECLEXPORT(uint64_t)) tmVirtualNanoTSBadCpuIndex(PRTTIMENANOTSDATA pData, uint16_t idApic,
uint16_t iCpuSet, uint16_t iGipCpu);
/**
* Try take the timer lock, wait in ring-3 return VERR_SEM_BUSY in R0/RC.
*
* @retval VINF_SUCCESS on success (always in ring-3).
* @retval VERR_SEM_BUSY in RC and R0 if the semaphore is busy.
*
* @param a_pVM Pointer to the VM.
*
* @remarks The virtual sync timer queue requires the virtual sync lock.
*/
#define TM_LOCK_TIMERS(a_pVM) PDMCritSectEnter(&(a_pVM)->tm.s.TimerCritSect, VERR_SEM_BUSY)
/**
* Try take the timer lock, no waiting.
*
* @retval VINF_SUCCESS on success.
* @retval VERR_SEM_BUSY if busy.
*
* @param a_pVM Pointer to the VM.
*
* @remarks The virtual sync timer queue requires the virtual sync lock.
*/
#define TM_TRY_LOCK_TIMERS(a_pVM) PDMCritSectTryEnter(&(a_pVM)->tm.s.TimerCritSect)
/** Lock the timers (sans the virtual sync queue). */
#define TM_UNLOCK_TIMERS(a_pVM) do { PDMCritSectLeave(&(a_pVM)->tm.s.TimerCritSect); } while (0)
/** Checks that the caller owns the timer lock. */
#define TM_ASSERT_TIMER_LOCK_OWNERSHIP(a_pVM) \
Assert(PDMCritSectIsOwner(&(a_pVM)->tm.s.TimerCritSect))
/** @} */
RT_C_DECLS_END
#endif /* !VMM_INCLUDED_SRC_include_TMInternal_h */
|