/* $Id$ */
/** @file
* TM - Timeout Manager, CPU Time, All Contexts.
*/
/*
* Copyright (C) 2006-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* 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.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include "TMInternal.h"
#include <iprt/asm-math.h>
/**
* Gets the raw cpu tick from current virtual time.
*/
{
if (fCheckTimers)
else
return u64;
}
#ifdef IN_RING3
/**
* Used by tmR3CpuTickParavirtEnable and tmR3CpuTickParavirtDisable.
*/
{
}
#endif
/**
* Resumes the CPU timestamp counter ticking.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
* @internal
*/
{
{
/** @todo Test that pausing and resuming doesn't cause lag! (I.e. that we're
* unpaused before the virtual time and stopped after it. */
else
return VINF_SUCCESS;
}
AssertFailed();
return VERR_TM_TSC_ALREADY_TICKING;
}
/**
* Resumes the CPU timestamp counter ticking.
*
* @returns VINF_SUCCESS or VERR_TM_VIRTUAL_TICKING_IPE (asserted).
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VCPU.
*/
{
{
/* TSC must be ticking before calling tmCpuTickGetRawVirtual()! */
if (c == 1)
{
/* The first VCPU to resume. */
/* When resuming, use the TSC value of the last stopped VCPU to avoid the TSC going back. */
else
/* Calculate the offset for other VCPUs to use. */
}
else
{
/* All other VCPUs (if any). */
}
}
return VINF_SUCCESS;
}
/**
* Pauses the CPU timestamp counter ticking.
*
* @returns VBox status code.
* @param pVCpu Pointer to the VMCPU.
* @internal
*/
{
{
return VINF_SUCCESS;
}
AssertFailed();
return VERR_TM_TSC_ALREADY_PAUSED;
}
/**
* Pauses the CPU timestamp counter ticking.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
* @internal
*/
{
{
if (c == 0)
{
/* When the last TSC stops, remember the value. */
}
return VINF_SUCCESS;
}
AssertFailed();
return VERR_TM_TSC_ALREADY_PAUSED;
}
/**
* Record why we refused to use offsetted TSC.
*
* Used by TMCpuTickCanUseRealTSC() and TMCpuTickGetDeadlineAndTscOffset().
*
* @param pVM Pointer to the VM.
* @param pVCpu The current CPU.
*/
{
/* Sample the reason for refusing. */
{
{
else
}
}
}
/**
* Checks if AMD-V / VT-x can use an offsetted hardware TSC or not.
*
* @param pVM Pointer to the cross context VM structure.
* @param pVCpu Pointer to the VMCPU.
* @param poffRealTsc The offset against the TSC of the current host CPU,
* if pfOffsettedTsc is set to true.
* @param pfParavirtTsc Where to return whether paravirt TSC is enabled.
*
* @thread EMT(pVCpu).
* @see TMCpuTickGetDeadlineAndTscOffset().
*/
VMM_INT_DECL(bool) TMCpuTickCanUseRealTSC(PVM pVM, PVMCPU pVCpu, uint64_t *poffRealTsc, bool *pfParavirtTsc)
{
/*
* In real TSC mode it's easy, we just need the delta & offTscRawSrc and
* the CPU will add them to RDTSC and RDTSCP at runtime.
*
* In tmCpuTickGetInternal we do:
* SUPReadTsc() - pVCpu->tm.s.offTSCRawSrc;
* Where SUPReadTsc() does:
* ASMReadTSC() - pGipCpu->i64TscDelta;
* Which means tmCpuTickGetInternal actually does:
* ASMReadTSC() - pGipCpu->i64TscDelta - pVCpu->tm.s.offTSCRawSrc;
* So, the offset to be ADDED to RDTSC[P] is:
* offRealTsc = -(pGipCpu->i64TscDelta + pVCpu->tm.s.offTSCRawSrc)
*/
{
/** @todo We should negate both deltas! It's soo weird that we do the
* exact opposite of what the hardware implements. */
#ifdef IN_RING3
#else
#endif
return true;
}
/*
* We require:
* 1. A fixed TSC, this is checked at init time.
* 2. That the TSC is ticking (we shouldn't be here if it isn't)
* 3. Either that we're using the real TSC as time source or
* a) we don't have any lag to catch up, and
* b) the virtual sync clock hasn't been halted by an expired timer, and
* c) we're not using warp drive (accelerated virtual guest time).
*/
{
/* The source is the timer synchronous virtual clock. */
/** @todo When we start collecting statistics on how much time we spend executing
* guest code before exiting, we should check this against the next virtual sync
* timer timeout. If it's lower than the avg. length, we should trap rdtsc to increase
* the chance that we'll get interrupted right after the timer expired. */
{
return true; /** @todo count this? */
}
}
#ifdef VBOX_WITH_STATISTICS
#endif
return false;
}
/**
* Calculates the number of host CPU ticks till the next virtual sync deadline.
*
* @note To save work, this function will not bother calculating the accurate
* tick count for deadlines that are more than a second ahead.
*
* @returns The number of host cpu ticks to the next deadline. Max one second.
* @param pVCpu The current CPU.
* @param cNsToDeadline The number of nano seconds to the next virtual
* sync deadline.
*/
{
#ifdef IN_RING3
#else
#endif
return uCpuHz;
if (cTicks > 4000)
else
cTicks >>= 1;
return cTicks;
}
/**
* Gets the next deadline in host CPU clock ticks and the TSC offset if we can
* use the raw TSC.
*
* @returns The number of host CPU clock ticks to the next timer deadline.
* @param pVM Pointer to the cross context VM structure.
* @param pVCpu The current CPU.
* @param poffRealTsc The offset against the TSC of the current host CPU,
* if pfOffsettedTsc is set to true.
* @param pfOffsettedTsc Where to return whether TSC offsetting can be used.
* @param pfParavirtTsc Where to return whether paravirt TSC is enabled.
*
* @thread EMT(pVCpu).
* @see TMCpuTickCanUseRealTSC().
*/
VMM_INT_DECL(uint64_t) TMCpuTickGetDeadlineAndTscOffset(PVM pVM, PVMCPU pVCpu, uint64_t *poffRealTsc,
bool *pfOffsettedTsc, bool *pfParavirtTsc)
{
/*
* Same logic as in TMCpuTickCanUseRealTSC.
*/
{
/** @todo We should negate both deltas! It's soo weird that we do the
* exact opposite of what the hardware implements. */
#ifdef IN_RING3
#else
#endif
*pfOffsettedTsc = true;
}
/*
* Same logic as in TMCpuTickCanUseRealTSC.
*/
{
/* The source is the timer synchronous virtual clock. */
}
#ifdef VBOX_WITH_STATISTICS
#endif
*pfOffsettedTsc = false;
*poffRealTsc = 0;
}
/**
* Read the current CPU timestamp counter.
*
* @returns Gets the CPU tsc.
* @param pVCpu Pointer to the VMCPU.
*/
{
{
u64 = SUPReadTsc();
else
/* Always return a value higher than what the guest has already seen. */
else
{
}
}
else
return u64;
}
/**
* Read the current CPU timestamp counter.
*
* @returns Gets the CPU tsc.
* @param pVCpu Pointer to the VMCPU.
*/
{
}
/**
* Read the current CPU timestamp counter, don't check for expired timers.
*
* @returns Gets the CPU tsc.
* @param pVCpu Pointer to the VMCPU.
*/
{
}
/**
* Sets the current CPU timestamp counter.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
* @param u64Tick The new timestamp value.
*
* @thread EMT which TSC is to be set.
*/
{
/*
* This is easier to do when the TSC is paused since resume will
* do all the calculations for us. Actually, we don't need to
* call tmCpuTickPause here since we overwrite u64TSC anyway.
*/
if (fTSCTicking)
/** @todo Try help synchronizing it better among the virtual CPUs? */
return VINF_SUCCESS;
}
/**
* Sets the last seen CPU timestamp counter.
*
* @returns VBox status code.
* @param pVCpu Pointer to the VMCPU.
* @param u64LastSeenTick The last seen timestamp value.
*
* @thread EMT which TSC is to be set.
*/
{
return VINF_SUCCESS;
}
/**
* Gets the last seen CPU timestamp counter of the guest.
*
* @returns the last seen TSC.
* @param pVCpu Pointer to the VMCPU.
*
* @thread EMT(pVCpu).
*/
{
}
/**
* Get the timestamp frequency.
*
* @returns Number of ticks per second.
* @param pVM The VM.
*/
{
{
#ifdef IN_RING3
uint64_t cTSCTicksPerSecond = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, RTMpCpuIdToSetIndex(RTMpCpuId()));
#else
uint64_t cTSCTicksPerSecond = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, VMMGetCpu(pVM)->iHostCpuSet);
#endif
return cTSCTicksPerSecond;
}
}
/**
* Whether the TSC is ticking for the VCPU.
*
* @returns true if ticking, false otherwise.
* @param pVCpu Pointer to the VMCPU.
*/
{
}