VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/TMAllCpu.cpp@ 77764

Last change on this file since 77764 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 20.6 KB
Line 
1/* $Id: TMAllCpu.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * TM - Timeout Manager, CPU Time, All Contexts.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_TM
23#include <VBox/vmm/tm.h>
24#include <VBox/vmm/gim.h>
25#include <VBox/vmm/dbgf.h>
26#include <VBox/vmm/nem.h>
27#include <iprt/asm-amd64-x86.h> /* for SUPGetCpuHzFromGIP */
28#include "TMInternal.h"
29#include <VBox/vmm/vm.h>
30#include <VBox/sup.h>
31
32#include <VBox/param.h>
33#include <VBox/err.h>
34#include <iprt/asm-math.h>
35#include <iprt/assert.h>
36#include <VBox/log.h>
37
38
39/**
40 * Gets the raw cpu tick from current virtual time.
41 *
42 * @param pVM The cross context VM structure.
43 * @param fCheckTimers Whether to check timers.
44 */
45DECLINLINE(uint64_t) tmCpuTickGetRawVirtual(PVM pVM, bool fCheckTimers)
46{
47 uint64_t u64;
48 if (fCheckTimers)
49 u64 = TMVirtualSyncGet(pVM);
50 else
51 u64 = TMVirtualSyncGetNoCheck(pVM);
52 return ASMMultU64ByU32DivByU32(u64, pVM->tm.s.cTSCTicksPerSecond, TMCLOCK_FREQ_VIRTUAL);
53}
54
55
56#ifdef IN_RING3
57/**
58 * Used by tmR3CpuTickParavirtEnable and tmR3CpuTickParavirtDisable.
59 *
60 * @param pVM The cross context VM structure.
61 */
62uint64_t tmR3CpuTickGetRawVirtualNoCheck(PVM pVM)
63{
64 return tmCpuTickGetRawVirtual(pVM, false /*fCheckTimers*/);
65}
66#endif
67
68
69/**
70 * Resumes the CPU timestamp counter ticking.
71 *
72 * @returns VBox status code.
73 * @param pVM The cross context VM structure.
74 * @param pVCpu The cross context virtual CPU structure.
75 * @internal
76 */
77int tmCpuTickResume(PVM pVM, PVMCPU pVCpu)
78{
79 if (!pVCpu->tm.s.fTSCTicking)
80 {
81 pVCpu->tm.s.fTSCTicking = true;
82
83 /** @todo Test that pausing and resuming doesn't cause lag! (I.e. that we're
84 * unpaused before the virtual time and stopped after it. */
85 switch (pVM->tm.s.enmTSCMode)
86 {
87 case TMTSCMODE_REAL_TSC_OFFSET:
88 pVCpu->tm.s.offTSCRawSrc = SUPReadTsc() - pVCpu->tm.s.u64TSC;
89 break;
90 case TMTSCMODE_VIRT_TSC_EMULATED:
91 case TMTSCMODE_DYNAMIC:
92 pVCpu->tm.s.offTSCRawSrc = tmCpuTickGetRawVirtual(pVM, false /* don't check for pending timers */)
93 - pVCpu->tm.s.u64TSC;
94 break;
95 case TMTSCMODE_NATIVE_API:
96 pVCpu->tm.s.offTSCRawSrc = 0; /** @todo ?? */
97 /* Looks like this is only used by weird modes and MSR TSC writes. We cannot support either on NEM/win. */
98 break;
99 default:
100 AssertFailedReturn(VERR_IPE_NOT_REACHED_DEFAULT_CASE);
101 }
102 return VINF_SUCCESS;
103 }
104 AssertFailed();
105 return VERR_TM_TSC_ALREADY_TICKING;
106}
107
108
109/**
110 * Resumes the CPU timestamp counter ticking.
111 *
112 * @returns VINF_SUCCESS or VERR_TM_VIRTUAL_TICKING_IPE (asserted).
113 * @param pVM The cross context VM structure.
114 * @param pVCpu The cross context virtual CPU structure.
115 */
116int tmCpuTickResumeLocked(PVM pVM, PVMCPU pVCpu)
117{
118 if (!pVCpu->tm.s.fTSCTicking)
119 {
120 /* TSC must be ticking before calling tmCpuTickGetRawVirtual()! */
121 pVCpu->tm.s.fTSCTicking = true;
122 uint32_t c = ASMAtomicIncU32(&pVM->tm.s.cTSCsTicking);
123 AssertMsgReturn(c <= pVM->cCpus, ("%u vs %u\n", c, pVM->cCpus), VERR_TM_VIRTUAL_TICKING_IPE);
124 if (c == 1)
125 {
126 /* The first VCPU to resume. */
127 uint64_t offTSCRawSrcOld = pVCpu->tm.s.offTSCRawSrc;
128
129 STAM_COUNTER_INC(&pVM->tm.s.StatTSCResume);
130
131 /* When resuming, use the TSC value of the last stopped VCPU to avoid the TSC going back. */
132 switch (pVM->tm.s.enmTSCMode)
133 {
134 case TMTSCMODE_REAL_TSC_OFFSET:
135 pVCpu->tm.s.offTSCRawSrc = SUPReadTsc() - pVM->tm.s.u64LastPausedTSC;
136 break;
137 case TMTSCMODE_VIRT_TSC_EMULATED:
138 case TMTSCMODE_DYNAMIC:
139 pVCpu->tm.s.offTSCRawSrc = tmCpuTickGetRawVirtual(pVM, false /* don't check for pending timers */)
140 - pVM->tm.s.u64LastPausedTSC;
141 break;
142 case TMTSCMODE_NATIVE_API:
143 {
144#ifndef IN_RC
145 int rc = NEMHCResumeCpuTickOnAll(pVM, pVCpu, pVM->tm.s.u64LastPausedTSC);
146 AssertRCReturn(rc, rc);
147 pVCpu->tm.s.offTSCRawSrc = offTSCRawSrcOld = 0;
148#else
149 AssertFailedReturn(VERR_INTERNAL_ERROR_2);
150#endif
151 break;
152 }
153 default:
154 AssertFailedReturn(VERR_IPE_NOT_REACHED_DEFAULT_CASE);
155 }
156
157 /* Calculate the offset addendum for other VCPUs to use. */
158 pVM->tm.s.offTSCPause = pVCpu->tm.s.offTSCRawSrc - offTSCRawSrcOld;
159 }
160 else
161 {
162 /* All other VCPUs (if any). */
163 pVCpu->tm.s.offTSCRawSrc += pVM->tm.s.offTSCPause;
164 }
165 }
166 return VINF_SUCCESS;
167}
168
169
170/**
171 * Pauses the CPU timestamp counter ticking.
172 *
173 * @returns VBox status code.
174 * @param pVCpu The cross context virtual CPU structure.
175 * @internal
176 */
177int tmCpuTickPause(PVMCPU pVCpu)
178{
179 if (pVCpu->tm.s.fTSCTicking)
180 {
181 pVCpu->tm.s.u64TSC = TMCpuTickGetNoCheck(pVCpu);
182 pVCpu->tm.s.fTSCTicking = false;
183 return VINF_SUCCESS;
184 }
185 AssertFailed();
186 return VERR_TM_TSC_ALREADY_PAUSED;
187}
188
189
190/**
191 * Pauses the CPU timestamp counter ticking.
192 *
193 * @returns VBox status code.
194 * @param pVM The cross context VM structure.
195 * @param pVCpu The cross context virtual CPU structure.
196 * @internal
197 */
198int tmCpuTickPauseLocked(PVM pVM, PVMCPU pVCpu)
199{
200 if (pVCpu->tm.s.fTSCTicking)
201 {
202 pVCpu->tm.s.u64TSC = TMCpuTickGetNoCheck(pVCpu);
203 pVCpu->tm.s.fTSCTicking = false;
204
205 uint32_t c = ASMAtomicDecU32(&pVM->tm.s.cTSCsTicking);
206 AssertMsgReturn(c < pVM->cCpus, ("%u vs %u\n", c, pVM->cCpus), VERR_TM_VIRTUAL_TICKING_IPE);
207 if (c == 0)
208 {
209 /* When the last TSC stops, remember the value. */
210 STAM_COUNTER_INC(&pVM->tm.s.StatTSCPause);
211 pVM->tm.s.u64LastPausedTSC = pVCpu->tm.s.u64TSC;
212 }
213 return VINF_SUCCESS;
214 }
215 AssertFailed();
216 return VERR_TM_TSC_ALREADY_PAUSED;
217}
218
219
220#ifdef VBOX_WITH_STATISTICS
221/**
222 * Record why we refused to use offsetted TSC.
223 *
224 * Used by TMCpuTickCanUseRealTSC() and TMCpuTickGetDeadlineAndTscOffset().
225 *
226 * @param pVM The cross context VM structure.
227 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
228 */
229DECLINLINE(void) tmCpuTickRecordOffsettedTscRefusal(PVM pVM, PVMCPU pVCpu)
230{
231 /* Sample the reason for refusing. */
232 if (pVM->tm.s.enmTSCMode != TMTSCMODE_DYNAMIC)
233 STAM_COUNTER_INC(&pVM->tm.s.StatTSCNotFixed);
234 else if (!pVCpu->tm.s.fTSCTicking)
235 STAM_COUNTER_INC(&pVM->tm.s.StatTSCNotTicking);
236 else if (pVM->tm.s.enmTSCMode != TMTSCMODE_REAL_TSC_OFFSET)
237 {
238 if (pVM->tm.s.fVirtualSyncCatchUp)
239 {
240 if (pVM->tm.s.u32VirtualSyncCatchUpPercentage <= 10)
241 STAM_COUNTER_INC(&pVM->tm.s.StatTSCCatchupLE010);
242 else if (pVM->tm.s.u32VirtualSyncCatchUpPercentage <= 25)
243 STAM_COUNTER_INC(&pVM->tm.s.StatTSCCatchupLE025);
244 else if (pVM->tm.s.u32VirtualSyncCatchUpPercentage <= 100)
245 STAM_COUNTER_INC(&pVM->tm.s.StatTSCCatchupLE100);
246 else
247 STAM_COUNTER_INC(&pVM->tm.s.StatTSCCatchupOther);
248 }
249 else if (!pVM->tm.s.fVirtualSyncTicking)
250 STAM_COUNTER_INC(&pVM->tm.s.StatTSCSyncNotTicking);
251 else if (pVM->tm.s.fVirtualWarpDrive)
252 STAM_COUNTER_INC(&pVM->tm.s.StatTSCWarp);
253 }
254}
255#endif /* VBOX_WITH_STATISTICS */
256
257
258/**
259 * Checks if AMD-V / VT-x can use an offsetted hardware TSC or not.
260 *
261 * @returns true/false accordingly.
262 * @param pVM The cross context VM structure.
263 * @param pVCpu The cross context virtual CPU structure.
264 * @param poffRealTsc The offset against the TSC of the current host CPU,
265 * if pfOffsettedTsc is set to true.
266 * @param pfParavirtTsc Where to return whether paravirt TSC is enabled.
267 *
268 * @thread EMT(pVCpu).
269 * @see TMCpuTickGetDeadlineAndTscOffset().
270 */
271VMM_INT_DECL(bool) TMCpuTickCanUseRealTSC(PVM pVM, PVMCPU pVCpu, uint64_t *poffRealTsc, bool *pfParavirtTsc)
272{
273 Assert(pVCpu->tm.s.fTSCTicking || DBGFIsStepping(pVCpu));
274
275 *pfParavirtTsc = pVM->tm.s.fParavirtTscEnabled;
276
277 /*
278 * In real TSC mode it's easy, we just need the delta & offTscRawSrc and
279 * the CPU will add them to RDTSC and RDTSCP at runtime.
280 *
281 * In tmCpuTickGetInternal we do:
282 * SUPReadTsc() - pVCpu->tm.s.offTSCRawSrc;
283 * Where SUPReadTsc() does:
284 * ASMReadTSC() - pGipCpu->i64TscDelta;
285 * Which means tmCpuTickGetInternal actually does:
286 * ASMReadTSC() - pGipCpu->i64TscDelta - pVCpu->tm.s.offTSCRawSrc;
287 * So, the offset to be ADDED to RDTSC[P] is:
288 * offRealTsc = -(pGipCpu->i64TscDelta + pVCpu->tm.s.offTSCRawSrc)
289 */
290 if (pVM->tm.s.enmTSCMode == TMTSCMODE_REAL_TSC_OFFSET)
291 {
292 /** @todo We should negate both deltas! It's soo weird that we do the
293 * exact opposite of what the hardware implements. */
294#ifdef IN_RING3
295 *poffRealTsc = 0 - pVCpu->tm.s.offTSCRawSrc - SUPGetTscDelta();
296#else
297 *poffRealTsc = 0 - pVCpu->tm.s.offTSCRawSrc - SUPGetTscDeltaByCpuSetIndex(pVCpu->iHostCpuSet);
298#endif
299 return true;
300 }
301
302 /*
303 * We require:
304 * 1. A fixed TSC, this is checked at init time.
305 * 2. That the TSC is ticking (we shouldn't be here if it isn't)
306 * 3. Either that we're using the real TSC as time source or
307 * a) we don't have any lag to catch up, and
308 * b) the virtual sync clock hasn't been halted by an expired timer, and
309 * c) we're not using warp drive (accelerated virtual guest time).
310 */
311 if ( pVM->tm.s.enmTSCMode == TMTSCMODE_DYNAMIC
312 && !pVM->tm.s.fVirtualSyncCatchUp
313 && RT_LIKELY(pVM->tm.s.fVirtualSyncTicking)
314 && !pVM->tm.s.fVirtualWarpDrive)
315 {
316 /* The source is the timer synchronous virtual clock. */
317 uint64_t u64Now = tmCpuTickGetRawVirtual(pVM, false /* don't check for pending timers */)
318 - pVCpu->tm.s.offTSCRawSrc;
319 /** @todo When we start collecting statistics on how much time we spend executing
320 * guest code before exiting, we should check this against the next virtual sync
321 * timer timeout. If it's lower than the avg. length, we should trap rdtsc to increase
322 * the chance that we'll get interrupted right after the timer expired. */
323 if (u64Now >= pVCpu->tm.s.u64TSCLastSeen)
324 {
325 *poffRealTsc = u64Now - ASMReadTSC();
326 return true; /** @todo count this? */
327 }
328 }
329
330#ifdef VBOX_WITH_STATISTICS
331 tmCpuTickRecordOffsettedTscRefusal(pVM, pVCpu);
332#endif
333 return false;
334}
335
336
337/**
338 * Calculates the number of host CPU ticks till the next virtual sync deadline.
339 *
340 * @note To save work, this function will not bother calculating the accurate
341 * tick count for deadlines that are more than a second ahead.
342 *
343 * @returns The number of host cpu ticks to the next deadline. Max one second.
344 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
345 * @param cNsToDeadline The number of nano seconds to the next virtual
346 * sync deadline.
347 */
348DECLINLINE(uint64_t) tmCpuCalcTicksToDeadline(PVMCPU pVCpu, uint64_t cNsToDeadline)
349{
350 AssertCompile(TMCLOCK_FREQ_VIRTUAL <= _4G);
351#ifdef IN_RING3
352 RT_NOREF_PV(pVCpu);
353 uint64_t uCpuHz = SUPGetCpuHzFromGip(g_pSUPGlobalInfoPage);
354#else
355 uint64_t uCpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
356#endif
357 if (RT_UNLIKELY(cNsToDeadline >= TMCLOCK_FREQ_VIRTUAL))
358 return uCpuHz;
359 uint64_t cTicks = ASMMultU64ByU32DivByU32(uCpuHz, cNsToDeadline, TMCLOCK_FREQ_VIRTUAL);
360 if (cTicks > 4000)
361 cTicks -= 4000; /* fudge to account for overhead */
362 else
363 cTicks >>= 1;
364 return cTicks;
365}
366
367
368/**
369 * Gets the next deadline in host CPU clock ticks and the TSC offset if we can
370 * use the raw TSC.
371 *
372 * @returns The number of host CPU clock ticks to the next timer deadline.
373 * @param pVM The cross context VM structure.
374 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
375 * @param poffRealTsc The offset against the TSC of the current host CPU,
376 * if pfOffsettedTsc is set to true.
377 * @param pfOffsettedTsc Where to return whether TSC offsetting can be used.
378 * @param pfParavirtTsc Where to return whether paravirt TSC is enabled.
379 *
380 * @thread EMT(pVCpu).
381 * @see TMCpuTickCanUseRealTSC().
382 */
383VMM_INT_DECL(uint64_t) TMCpuTickGetDeadlineAndTscOffset(PVM pVM, PVMCPU pVCpu, uint64_t *poffRealTsc,
384 bool *pfOffsettedTsc, bool *pfParavirtTsc)
385{
386 Assert(pVCpu->tm.s.fTSCTicking || DBGFIsStepping(pVCpu));
387
388 *pfParavirtTsc = pVM->tm.s.fParavirtTscEnabled;
389
390 /*
391 * Same logic as in TMCpuTickCanUseRealTSC.
392 */
393 if (pVM->tm.s.enmTSCMode == TMTSCMODE_REAL_TSC_OFFSET)
394 {
395 /** @todo We should negate both deltas! It's soo weird that we do the
396 * exact opposite of what the hardware implements. */
397#ifdef IN_RING3
398 *poffRealTsc = 0 - pVCpu->tm.s.offTSCRawSrc - SUPGetTscDelta();
399#else
400 *poffRealTsc = 0 - pVCpu->tm.s.offTSCRawSrc - SUPGetTscDeltaByCpuSetIndex(pVCpu->iHostCpuSet);
401#endif
402 *pfOffsettedTsc = true;
403 return tmCpuCalcTicksToDeadline(pVCpu, TMVirtualSyncGetNsToDeadline(pVM));
404 }
405
406 /*
407 * Same logic as in TMCpuTickCanUseRealTSC.
408 */
409 if ( pVM->tm.s.enmTSCMode == TMTSCMODE_DYNAMIC
410 && !pVM->tm.s.fVirtualSyncCatchUp
411 && RT_LIKELY(pVM->tm.s.fVirtualSyncTicking)
412 && !pVM->tm.s.fVirtualWarpDrive)
413 {
414 /* The source is the timer synchronous virtual clock. */
415 uint64_t cNsToDeadline;
416 uint64_t u64NowVirtSync = TMVirtualSyncGetWithDeadlineNoCheck(pVM, &cNsToDeadline);
417 uint64_t u64Now = ASMMultU64ByU32DivByU32(u64NowVirtSync, pVM->tm.s.cTSCTicksPerSecond, TMCLOCK_FREQ_VIRTUAL);
418 u64Now -= pVCpu->tm.s.offTSCRawSrc;
419 *poffRealTsc = u64Now - ASMReadTSC();
420 *pfOffsettedTsc = u64Now >= pVCpu->tm.s.u64TSCLastSeen;
421 return tmCpuCalcTicksToDeadline(pVCpu, cNsToDeadline);
422 }
423
424#ifdef VBOX_WITH_STATISTICS
425 tmCpuTickRecordOffsettedTscRefusal(pVM, pVCpu);
426#endif
427 *pfOffsettedTsc = false;
428 *poffRealTsc = 0;
429 return tmCpuCalcTicksToDeadline(pVCpu, TMVirtualSyncGetNsToDeadline(pVM));
430}
431
432
433/**
434 * Read the current CPU timestamp counter.
435 *
436 * @returns Gets the CPU tsc.
437 * @param pVCpu The cross context virtual CPU structure.
438 * @param fCheckTimers Whether to check timers.
439 */
440DECLINLINE(uint64_t) tmCpuTickGetInternal(PVMCPU pVCpu, bool fCheckTimers)
441{
442 uint64_t u64;
443
444 if (RT_LIKELY(pVCpu->tm.s.fTSCTicking))
445 {
446 PVM pVM = pVCpu->CTX_SUFF(pVM);
447 switch (pVM->tm.s.enmTSCMode)
448 {
449 case TMTSCMODE_REAL_TSC_OFFSET:
450 u64 = SUPReadTsc();
451 break;
452 case TMTSCMODE_VIRT_TSC_EMULATED:
453 case TMTSCMODE_DYNAMIC:
454 u64 = tmCpuTickGetRawVirtual(pVM, fCheckTimers);
455 break;
456#ifndef IN_RC
457 case TMTSCMODE_NATIVE_API:
458 {
459 u64 = 0;
460 int rcNem = NEMHCQueryCpuTick(pVCpu, &u64, NULL);
461 AssertLogRelRCReturn(rcNem, SUPReadTsc());
462 break;
463 }
464#endif
465 default:
466 AssertFailedBreakStmt(u64 = SUPReadTsc());
467 }
468 u64 -= pVCpu->tm.s.offTSCRawSrc;
469
470 /* Always return a value higher than what the guest has already seen. */
471 if (RT_LIKELY(u64 > pVCpu->tm.s.u64TSCLastSeen))
472 pVCpu->tm.s.u64TSCLastSeen = u64;
473 else
474 {
475 STAM_COUNTER_INC(&pVM->tm.s.StatTSCUnderflow);
476 pVCpu->tm.s.u64TSCLastSeen += 64; /** @todo choose a good increment here */
477 u64 = pVCpu->tm.s.u64TSCLastSeen;
478 }
479 }
480 else
481 u64 = pVCpu->tm.s.u64TSC;
482 return u64;
483}
484
485
486/**
487 * Read the current CPU timestamp counter.
488 *
489 * @returns Gets the CPU tsc.
490 * @param pVCpu The cross context virtual CPU structure.
491 */
492VMMDECL(uint64_t) TMCpuTickGet(PVMCPU pVCpu)
493{
494 return tmCpuTickGetInternal(pVCpu, true /* fCheckTimers */);
495}
496
497
498/**
499 * Read the current CPU timestamp counter, don't check for expired timers.
500 *
501 * @returns Gets the CPU tsc.
502 * @param pVCpu The cross context virtual CPU structure.
503 */
504VMM_INT_DECL(uint64_t) TMCpuTickGetNoCheck(PVMCPU pVCpu)
505{
506 return tmCpuTickGetInternal(pVCpu, false /* fCheckTimers */);
507}
508
509
510/**
511 * Sets the current CPU timestamp counter.
512 *
513 * @returns VBox status code.
514 * @param pVM The cross context VM structure.
515 * @param pVCpu The cross context virtual CPU structure.
516 * @param u64Tick The new timestamp value.
517 *
518 * @thread EMT which TSC is to be set.
519 */
520VMM_INT_DECL(int) TMCpuTickSet(PVM pVM, PVMCPU pVCpu, uint64_t u64Tick)
521{
522 VMCPU_ASSERT_EMT(pVCpu);
523 STAM_COUNTER_INC(&pVM->tm.s.StatTSCSet);
524
525 /*
526 * This is easier to do when the TSC is paused since resume will
527 * do all the calculations for us. Actually, we don't need to
528 * call tmCpuTickPause here since we overwrite u64TSC anyway.
529 */
530 bool fTSCTicking = pVCpu->tm.s.fTSCTicking;
531 pVCpu->tm.s.fTSCTicking = false;
532 pVCpu->tm.s.u64TSC = u64Tick;
533 pVCpu->tm.s.u64TSCLastSeen = u64Tick;
534 if (fTSCTicking)
535 tmCpuTickResume(pVM, pVCpu);
536 /** @todo Try help synchronizing it better among the virtual CPUs? */
537
538 return VINF_SUCCESS;
539}
540
541/**
542 * Sets the last seen CPU timestamp counter.
543 *
544 * @returns VBox status code.
545 * @param pVCpu The cross context virtual CPU structure.
546 * @param u64LastSeenTick The last seen timestamp value.
547 *
548 * @thread EMT which TSC is to be set.
549 */
550VMM_INT_DECL(int) TMCpuTickSetLastSeen(PVMCPU pVCpu, uint64_t u64LastSeenTick)
551{
552 VMCPU_ASSERT_EMT(pVCpu);
553
554 LogFlow(("TMCpuTickSetLastSeen %RX64\n", u64LastSeenTick));
555 if (pVCpu->tm.s.u64TSCLastSeen < u64LastSeenTick)
556 pVCpu->tm.s.u64TSCLastSeen = u64LastSeenTick;
557 return VINF_SUCCESS;
558}
559
560/**
561 * Gets the last seen CPU timestamp counter of the guest.
562 *
563 * @returns the last seen TSC.
564 * @param pVCpu The cross context virtual CPU structure.
565 *
566 * @thread EMT(pVCpu).
567 */
568VMM_INT_DECL(uint64_t) TMCpuTickGetLastSeen(PVMCPU pVCpu)
569{
570 VMCPU_ASSERT_EMT(pVCpu);
571
572 return pVCpu->tm.s.u64TSCLastSeen;
573}
574
575
576/**
577 * Get the timestamp frequency.
578 *
579 * @returns Number of ticks per second.
580 * @param pVM The cross context VM structure.
581 */
582VMMDECL(uint64_t) TMCpuTicksPerSecond(PVM pVM)
583{
584 if ( pVM->tm.s.enmTSCMode == TMTSCMODE_REAL_TSC_OFFSET
585 && g_pSUPGlobalInfoPage->u32Mode != SUPGIPMODE_INVARIANT_TSC)
586 {
587#ifdef IN_RING3
588 uint64_t cTSCTicksPerSecond = SUPGetCpuHzFromGip(g_pSUPGlobalInfoPage);
589#elif defined(IN_RING0)
590 uint64_t cTSCTicksPerSecond = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, RTMpCpuIdToSetIndex(RTMpCpuId()));
591#else
592 uint64_t cTSCTicksPerSecond = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, VMMGetCpu(pVM)->iHostCpuSet);
593#endif
594 if (RT_LIKELY(cTSCTicksPerSecond != ~(uint64_t)0))
595 return cTSCTicksPerSecond;
596 }
597 return pVM->tm.s.cTSCTicksPerSecond;
598}
599
600
601/**
602 * Whether the TSC is ticking for the VCPU.
603 *
604 * @returns true if ticking, false otherwise.
605 * @param pVCpu The cross context virtual CPU structure.
606 */
607VMM_INT_DECL(bool) TMCpuTickIsTicking(PVMCPU pVCpu)
608{
609 return pVCpu->tm.s.fTSCTicking;
610}
611
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