EM.cpp revision b1ac43a82a2e4114bc44feb83007a10c99077085
/* $Id$ */
/** @file
* EM - Execution Monitor / Manager.
*/
/*
* Copyright (C) 2006-2013 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.
*/
/** @page pg_em EM - The Execution Monitor / Manager
*
* the right kind of execution (Raw-mode, Hardware Assisted, Recompiled or
* Interpreted), and keeping the CPU states in sync. The function
* EMR3ExecuteVM() is the 'main-loop' of the VM, while each of the execution
* modes has different inner loops (emR3RawExecute, emR3HmExecute, and
* emR3RemExecute).
*
* The interpreted execution is only used to avoid switching between
* The interpretation is thus implemented as part of EM.
*
* @see grp_em
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_EM
#ifdef VBOX_WITH_REM
#endif
#include "EMInternal.h"
#include <VBox/disopcode.h>
#include "VMMTracing.h"
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
#if 0 /* Disabled till after 2.1.0 when we've time to test it. */
#define EM_NOTIFY_HM
#endif
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
#if defined(LOG_ENABLED) || defined(VBOX_STRICT)
#endif
/**
* Initializes the EM.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
*/
{
LogFlow(("EMR3Init\n"));
/*
* Assert alignment and sizes.
*/
AssertCompile(sizeof(pVM->aCpus[0].em.s.u.FatalLongJump) <= sizeof(pVM->aCpus[0].em.s.u.achPaddingFatalLongJump));
/*
* Init the structure.
*/
bool fEnabled;
#ifdef VBOX_WITH_RAW_RING1
#else
#endif
{
LogRel(("EM: Overriding /EM/TripleFaultReset, must be false on SMP.\n"));
}
Log(("EMR3Init: fRecompileUser=%RTbool fRecompileSupervisor=%RTbool fRawRing1Enabled=%RTbool fIemExecutesAll=%RTbool fGuruOnTripleFault=%RTbool\n",
pVM->fRecompileUser, pVM->fRecompileSupervisor, pVM->fRawRing1Enabled, pVM->em.s.fIemExecutesAll, pVM->em.s.fGuruOnTripleFault));
#ifdef VBOX_WITH_REM
/*
* Initialize the REM critical section.
*/
#endif
/*
* Saved state.
*/
if (RT_FAILURE(rc))
return rc;
{
#ifdef VBOX_WITH_RAW_MODE
if (!HMIsEnabled(pVM))
{
}
#endif
/* Force reset of the time slice. */
# define EM_REG_COUNTER(a, b, c) \
rc = STAMR3RegisterF(pVM, a, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, c, b, i); \
# define EM_REG_COUNTER_USED(a, b, c) \
rc = STAMR3RegisterF(pVM, a, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, c, b, i); \
# define EM_REG_PROFILE(a, b, c) \
rc = STAMR3RegisterF(pVM, a, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, c, b, i); \
# define EM_REG_PROFILE_ADV(a, b, c) \
rc = STAMR3RegisterF(pVM, a, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, c, b, i); \
/*
* Statistics.
*/
#ifdef VBOX_WITH_STATISTICS
if (RT_FAILURE(rc))
return rc;
EM_REG_PROFILE(&pStats->StatRZEmulate, "/EM/CPU%d/RZ/Interpret", "Profiling of EMInterpretInstruction.");
EM_REG_PROFILE(&pStats->StatR3Emulate, "/EM/CPU%d/R3/Interpret", "Profiling of EMInterpretInstruction.");
EM_REG_PROFILE(&pStats->StatRZInterpretSucceeded, "/EM/CPU%d/RZ/Interpret/Success", "The number of times an instruction was successfully interpreted.");
EM_REG_PROFILE(&pStats->StatR3InterpretSucceeded, "/EM/CPU%d/R3/Interpret/Success", "The number of times an instruction was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZAnd, "/EM/CPU%d/RZ/Interpret/Success/And", "The number of times AND was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3And, "/EM/CPU%d/R3/Interpret/Success/And", "The number of times AND was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZAdd, "/EM/CPU%d/RZ/Interpret/Success/Add", "The number of times ADD was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Add, "/EM/CPU%d/R3/Interpret/Success/Add", "The number of times ADD was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZAdc, "/EM/CPU%d/RZ/Interpret/Success/Adc", "The number of times ADC was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Adc, "/EM/CPU%d/R3/Interpret/Success/Adc", "The number of times ADC was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZSub, "/EM/CPU%d/RZ/Interpret/Success/Sub", "The number of times SUB was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Sub, "/EM/CPU%d/R3/Interpret/Success/Sub", "The number of times SUB was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZCpuId, "/EM/CPU%d/RZ/Interpret/Success/CpuId", "The number of times CPUID was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3CpuId, "/EM/CPU%d/R3/Interpret/Success/CpuId", "The number of times CPUID was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZDec, "/EM/CPU%d/RZ/Interpret/Success/Dec", "The number of times DEC was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Dec, "/EM/CPU%d/R3/Interpret/Success/Dec", "The number of times DEC was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZHlt, "/EM/CPU%d/RZ/Interpret/Success/Hlt", "The number of times HLT was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Hlt, "/EM/CPU%d/R3/Interpret/Success/Hlt", "The number of times HLT was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZInc, "/EM/CPU%d/RZ/Interpret/Success/Inc", "The number of times INC was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Inc, "/EM/CPU%d/R3/Interpret/Success/Inc", "The number of times INC was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZInvlPg, "/EM/CPU%d/RZ/Interpret/Success/Invlpg", "The number of times INVLPG was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3InvlPg, "/EM/CPU%d/R3/Interpret/Success/Invlpg", "The number of times INVLPG was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZIret, "/EM/CPU%d/RZ/Interpret/Success/Iret", "The number of times IRET was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Iret, "/EM/CPU%d/R3/Interpret/Success/Iret", "The number of times IRET was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZLLdt, "/EM/CPU%d/RZ/Interpret/Success/LLdt", "The number of times LLDT was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3LLdt, "/EM/CPU%d/R3/Interpret/Success/LLdt", "The number of times LLDT was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZLIdt, "/EM/CPU%d/RZ/Interpret/Success/LIdt", "The number of times LIDT was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3LIdt, "/EM/CPU%d/R3/Interpret/Success/LIdt", "The number of times LIDT was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZLGdt, "/EM/CPU%d/RZ/Interpret/Success/LGdt", "The number of times LGDT was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3LGdt, "/EM/CPU%d/R3/Interpret/Success/LGdt", "The number of times LGDT was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZMov, "/EM/CPU%d/RZ/Interpret/Success/Mov", "The number of times MOV was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Mov, "/EM/CPU%d/R3/Interpret/Success/Mov", "The number of times MOV was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZMovCRx, "/EM/CPU%d/RZ/Interpret/Success/MovCRx", "The number of times MOV CRx was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3MovCRx, "/EM/CPU%d/R3/Interpret/Success/MovCRx", "The number of times MOV CRx was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZMovDRx, "/EM/CPU%d/RZ/Interpret/Success/MovDRx", "The number of times MOV DRx was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3MovDRx, "/EM/CPU%d/R3/Interpret/Success/MovDRx", "The number of times MOV DRx was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZOr, "/EM/CPU%d/RZ/Interpret/Success/Or", "The number of times OR was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Or, "/EM/CPU%d/R3/Interpret/Success/Or", "The number of times OR was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZPop, "/EM/CPU%d/RZ/Interpret/Success/Pop", "The number of times POP was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Pop, "/EM/CPU%d/R3/Interpret/Success/Pop", "The number of times POP was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZRdtsc, "/EM/CPU%d/RZ/Interpret/Success/Rdtsc", "The number of times RDTSC was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Rdtsc, "/EM/CPU%d/R3/Interpret/Success/Rdtsc", "The number of times RDTSC was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZRdpmc, "/EM/CPU%d/RZ/Interpret/Success/Rdpmc", "The number of times RDPMC was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Rdpmc, "/EM/CPU%d/R3/Interpret/Success/Rdpmc", "The number of times RDPMC was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZSti, "/EM/CPU%d/RZ/Interpret/Success/Sti", "The number of times STI was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Sti, "/EM/CPU%d/R3/Interpret/Success/Sti", "The number of times STI was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZXchg, "/EM/CPU%d/RZ/Interpret/Success/Xchg", "The number of times XCHG was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Xchg, "/EM/CPU%d/R3/Interpret/Success/Xchg", "The number of times XCHG was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZXor, "/EM/CPU%d/RZ/Interpret/Success/Xor", "The number of times XOR was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Xor, "/EM/CPU%d/R3/Interpret/Success/Xor", "The number of times XOR was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZMonitor, "/EM/CPU%d/RZ/Interpret/Success/Monitor", "The number of times MONITOR was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Monitor, "/EM/CPU%d/R3/Interpret/Success/Monitor", "The number of times MONITOR was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZMWait, "/EM/CPU%d/RZ/Interpret/Success/MWait", "The number of times MWAIT was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3MWait, "/EM/CPU%d/R3/Interpret/Success/MWait", "The number of times MWAIT was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZBtr, "/EM/CPU%d/RZ/Interpret/Success/Btr", "The number of times BTR was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Btr, "/EM/CPU%d/R3/Interpret/Success/Btr", "The number of times BTR was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZBts, "/EM/CPU%d/RZ/Interpret/Success/Bts", "The number of times BTS was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Bts, "/EM/CPU%d/R3/Interpret/Success/Bts", "The number of times BTS was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZBtc, "/EM/CPU%d/RZ/Interpret/Success/Btc", "The number of times BTC was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Btc, "/EM/CPU%d/R3/Interpret/Success/Btc", "The number of times BTC was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZCmpXchg, "/EM/CPU%d/RZ/Interpret/Success/CmpXchg", "The number of times CMPXCHG was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3CmpXchg, "/EM/CPU%d/R3/Interpret/Success/CmpXchg", "The number of times CMPXCHG was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZCmpXchg8b, "/EM/CPU%d/RZ/Interpret/Success/CmpXchg8b", "The number of times CMPXCHG8B was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3CmpXchg8b, "/EM/CPU%d/R3/Interpret/Success/CmpXchg8b", "The number of times CMPXCHG8B was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZXAdd, "/EM/CPU%d/RZ/Interpret/Success/XAdd", "The number of times XADD was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3XAdd, "/EM/CPU%d/R3/Interpret/Success/XAdd", "The number of times XADD was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Rdmsr, "/EM/CPU%d/R3/Interpret/Success/Rdmsr", "The number of times RDMSR was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZRdmsr, "/EM/CPU%d/RZ/Interpret/Success/Rdmsr", "The number of times RDMSR was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Wrmsr, "/EM/CPU%d/R3/Interpret/Success/Wrmsr", "The number of times WRMSR was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZWrmsr, "/EM/CPU%d/RZ/Interpret/Success/Wrmsr", "The number of times WRMSR was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3StosWD, "/EM/CPU%d/R3/Interpret/Success/Stoswd", "The number of times STOSWD was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZStosWD, "/EM/CPU%d/RZ/Interpret/Success/Stoswd", "The number of times STOSWD was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZWbInvd, "/EM/CPU%d/RZ/Interpret/Success/WbInvd", "The number of times WBINVD was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3WbInvd, "/EM/CPU%d/R3/Interpret/Success/WbInvd", "The number of times WBINVD was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZLmsw, "/EM/CPU%d/RZ/Interpret/Success/Lmsw", "The number of times LMSW was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Lmsw, "/EM/CPU%d/R3/Interpret/Success/Lmsw", "The number of times LMSW was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZSmsw, "/EM/CPU%d/RZ/Interpret/Success/Smsw", "The number of times SMSW was successfully interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3Smsw, "/EM/CPU%d/R3/Interpret/Success/Smsw", "The number of times SMSW was successfully interpreted.");
EM_REG_COUNTER(&pStats->StatRZInterpretFailed, "/EM/CPU%d/RZ/Interpret/Failed", "The number of times an instruction was not interpreted.");
EM_REG_COUNTER(&pStats->StatR3InterpretFailed, "/EM/CPU%d/R3/Interpret/Failed", "The number of times an instruction was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedAnd, "/EM/CPU%d/RZ/Interpret/Failed/And", "The number of times AND was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedAnd, "/EM/CPU%d/R3/Interpret/Failed/And", "The number of times AND was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedCpuId, "/EM/CPU%d/RZ/Interpret/Failed/CpuId", "The number of times CPUID was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedCpuId, "/EM/CPU%d/R3/Interpret/Failed/CpuId", "The number of times CPUID was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedDec, "/EM/CPU%d/RZ/Interpret/Failed/Dec", "The number of times DEC was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedDec, "/EM/CPU%d/R3/Interpret/Failed/Dec", "The number of times DEC was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedHlt, "/EM/CPU%d/RZ/Interpret/Failed/Hlt", "The number of times HLT was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedHlt, "/EM/CPU%d/R3/Interpret/Failed/Hlt", "The number of times HLT was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedInc, "/EM/CPU%d/RZ/Interpret/Failed/Inc", "The number of times INC was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedInc, "/EM/CPU%d/R3/Interpret/Failed/Inc", "The number of times INC was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedInvlPg, "/EM/CPU%d/RZ/Interpret/Failed/InvlPg", "The number of times INVLPG was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedInvlPg, "/EM/CPU%d/R3/Interpret/Failed/InvlPg", "The number of times INVLPG was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedIret, "/EM/CPU%d/RZ/Interpret/Failed/Iret", "The number of times IRET was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedIret, "/EM/CPU%d/R3/Interpret/Failed/Iret", "The number of times IRET was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedLLdt, "/EM/CPU%d/RZ/Interpret/Failed/LLdt", "The number of times LLDT was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedLLdt, "/EM/CPU%d/R3/Interpret/Failed/LLdt", "The number of times LLDT was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedLIdt, "/EM/CPU%d/RZ/Interpret/Failed/LIdt", "The number of times LIDT was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedLIdt, "/EM/CPU%d/R3/Interpret/Failed/LIdt", "The number of times LIDT was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedLGdt, "/EM/CPU%d/RZ/Interpret/Failed/LGdt", "The number of times LGDT was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedLGdt, "/EM/CPU%d/R3/Interpret/Failed/LGdt", "The number of times LGDT was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedMov, "/EM/CPU%d/RZ/Interpret/Failed/Mov", "The number of times MOV was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedMov, "/EM/CPU%d/R3/Interpret/Failed/Mov", "The number of times MOV was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedMovCRx, "/EM/CPU%d/RZ/Interpret/Failed/MovCRx", "The number of times MOV CRx was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedMovCRx, "/EM/CPU%d/R3/Interpret/Failed/MovCRx", "The number of times MOV CRx was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedMovDRx, "/EM/CPU%d/RZ/Interpret/Failed/MovDRx", "The number of times MOV DRx was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedMovDRx, "/EM/CPU%d/R3/Interpret/Failed/MovDRx", "The number of times MOV DRx was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedOr, "/EM/CPU%d/RZ/Interpret/Failed/Or", "The number of times OR was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedOr, "/EM/CPU%d/R3/Interpret/Failed/Or", "The number of times OR was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedPop, "/EM/CPU%d/RZ/Interpret/Failed/Pop", "The number of times POP was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedPop, "/EM/CPU%d/R3/Interpret/Failed/Pop", "The number of times POP was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedSti, "/EM/CPU%d/RZ/Interpret/Failed/Sti", "The number of times STI was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedSti, "/EM/CPU%d/R3/Interpret/Failed/Sti", "The number of times STI was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedXchg, "/EM/CPU%d/RZ/Interpret/Failed/Xchg", "The number of times XCHG was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedXchg, "/EM/CPU%d/R3/Interpret/Failed/Xchg", "The number of times XCHG was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedXor, "/EM/CPU%d/RZ/Interpret/Failed/Xor", "The number of times XOR was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedXor, "/EM/CPU%d/R3/Interpret/Failed/Xor", "The number of times XOR was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedMonitor, "/EM/CPU%d/RZ/Interpret/Failed/Monitor", "The number of times MONITOR was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedMonitor, "/EM/CPU%d/R3/Interpret/Failed/Monitor", "The number of times MONITOR was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedMWait, "/EM/CPU%d/RZ/Interpret/Failed/MWait", "The number of times MWAIT was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedMWait, "/EM/CPU%d/R3/Interpret/Failed/MWait", "The number of times MWAIT was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedRdtsc, "/EM/CPU%d/RZ/Interpret/Failed/Rdtsc", "The number of times RDTSC was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedRdtsc, "/EM/CPU%d/R3/Interpret/Failed/Rdtsc", "The number of times RDTSC was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedRdpmc, "/EM/CPU%d/RZ/Interpret/Failed/Rdpmc", "The number of times RDPMC was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedRdpmc, "/EM/CPU%d/R3/Interpret/Failed/Rdpmc", "The number of times RDPMC was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedRdmsr, "/EM/CPU%d/RZ/Interpret/Failed/Rdmsr", "The number of times RDMSR was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedRdmsr, "/EM/CPU%d/R3/Interpret/Failed/Rdmsr", "The number of times RDMSR was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedWrmsr, "/EM/CPU%d/RZ/Interpret/Failed/Wrmsr", "The number of times WRMSR was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedWrmsr, "/EM/CPU%d/R3/Interpret/Failed/Wrmsr", "The number of times WRMSR was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedLmsw, "/EM/CPU%d/RZ/Interpret/Failed/Lmsw", "The number of times LMSW was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedLmsw, "/EM/CPU%d/R3/Interpret/Failed/Lmsw", "The number of times LMSW was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedSmsw, "/EM/CPU%d/RZ/Interpret/Failed/Smsw", "The number of times SMSW was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedSmsw, "/EM/CPU%d/R3/Interpret/Failed/Smsw", "The number of times SMSW was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedMisc, "/EM/CPU%d/RZ/Interpret/Failed/Misc", "The number of times some misc instruction was encountered.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedMisc, "/EM/CPU%d/R3/Interpret/Failed/Misc", "The number of times some misc instruction was encountered.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedAdd, "/EM/CPU%d/RZ/Interpret/Failed/Add", "The number of times ADD was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedAdd, "/EM/CPU%d/R3/Interpret/Failed/Add", "The number of times ADD was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedAdc, "/EM/CPU%d/RZ/Interpret/Failed/Adc", "The number of times ADC was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedAdc, "/EM/CPU%d/R3/Interpret/Failed/Adc", "The number of times ADC was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedBtr, "/EM/CPU%d/RZ/Interpret/Failed/Btr", "The number of times BTR was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedBtr, "/EM/CPU%d/R3/Interpret/Failed/Btr", "The number of times BTR was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedBts, "/EM/CPU%d/RZ/Interpret/Failed/Bts", "The number of times BTS was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedBts, "/EM/CPU%d/R3/Interpret/Failed/Bts", "The number of times BTS was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedBtc, "/EM/CPU%d/RZ/Interpret/Failed/Btc", "The number of times BTC was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedBtc, "/EM/CPU%d/R3/Interpret/Failed/Btc", "The number of times BTC was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedCli, "/EM/CPU%d/RZ/Interpret/Failed/Cli", "The number of times CLI was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedCli, "/EM/CPU%d/R3/Interpret/Failed/Cli", "The number of times CLI was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedCmpXchg, "/EM/CPU%d/RZ/Interpret/Failed/CmpXchg", "The number of times CMPXCHG was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedCmpXchg, "/EM/CPU%d/R3/Interpret/Failed/CmpXchg", "The number of times CMPXCHG was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedCmpXchg8b, "/EM/CPU%d/RZ/Interpret/Failed/CmpXchg8b", "The number of times CMPXCHG8B was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedCmpXchg8b, "/EM/CPU%d/R3/Interpret/Failed/CmpXchg8b", "The number of times CMPXCHG8B was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedXAdd, "/EM/CPU%d/RZ/Interpret/Failed/XAdd", "The number of times XADD was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedXAdd, "/EM/CPU%d/R3/Interpret/Failed/XAdd", "The number of times XADD was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedMovNTPS, "/EM/CPU%d/RZ/Interpret/Failed/MovNTPS", "The number of times MOVNTPS was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedMovNTPS, "/EM/CPU%d/R3/Interpret/Failed/MovNTPS", "The number of times MOVNTPS was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedStosWD, "/EM/CPU%d/RZ/Interpret/Failed/StosWD", "The number of times STOSWD was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedStosWD, "/EM/CPU%d/R3/Interpret/Failed/StosWD", "The number of times STOSWD was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedSub, "/EM/CPU%d/RZ/Interpret/Failed/Sub", "The number of times SUB was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedSub, "/EM/CPU%d/R3/Interpret/Failed/Sub", "The number of times SUB was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedWbInvd, "/EM/CPU%d/RZ/Interpret/Failed/WbInvd", "The number of times WBINVD was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedWbInvd, "/EM/CPU%d/R3/Interpret/Failed/WbInvd", "The number of times WBINVD was not interpreted.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedUserMode, "/EM/CPU%d/RZ/Interpret/Failed/UserMode", "The number of rejections because of CPL.");
EM_REG_COUNTER_USED(&pStats->StatR3FailedUserMode, "/EM/CPU%d/R3/Interpret/Failed/UserMode", "The number of rejections because of CPL.");
EM_REG_COUNTER_USED(&pStats->StatRZFailedPrefix, "/EM/CPU%d/RZ/Interpret/Failed/Prefix", "The number of rejections because of prefix .");
EM_REG_COUNTER_USED(&pStats->StatR3FailedPrefix, "/EM/CPU%d/R3/Interpret/Failed/Prefix", "The number of rejections because of prefix .");
EM_REG_COUNTER_USED(&pStats->StatIoRestarted, "/EM/CPU%d/R3/PrivInst/IoRestarted", "I/O instructions restarted in ring-3.");
# ifdef VBOX_WITH_FIRST_IEM_STEP
EM_REG_COUNTER_USED(&pStats->StatIoIem, "/EM/CPU%d/R3/PrivInst/IoIem", "I/O instructions end to IEM in ring-3.");
# else
# endif
EM_REG_COUNTER_USED(&pStats->StatHlt, "/EM/CPU%d/R3/PrivInst/Hlt", "Number of hlt instructions not handled in GC because of PATM.");
EM_REG_COUNTER_USED(&pStats->StatInvlpg, "/EM/CPU%d/R3/PrivInst/Invlpg", "Number of invlpg instructions.");
EM_REG_COUNTER_USED(&pStats->StatMisc, "/EM/CPU%d/R3/PrivInst/Misc", "Number of misc. instructions.");
EM_REG_COUNTER_USED(&pStats->StatMovWriteCR[0], "/EM/CPU%d/R3/PrivInst/Mov CR0, X", "Number of mov CR0 write instructions.");
EM_REG_COUNTER_USED(&pStats->StatMovWriteCR[1], "/EM/CPU%d/R3/PrivInst/Mov CR1, X", "Number of mov CR1 write instructions.");
EM_REG_COUNTER_USED(&pStats->StatMovWriteCR[2], "/EM/CPU%d/R3/PrivInst/Mov CR2, X", "Number of mov CR2 write instructions.");
EM_REG_COUNTER_USED(&pStats->StatMovWriteCR[3], "/EM/CPU%d/R3/PrivInst/Mov CR3, X", "Number of mov CR3 write instructions.");
EM_REG_COUNTER_USED(&pStats->StatMovWriteCR[4], "/EM/CPU%d/R3/PrivInst/Mov CR4, X", "Number of mov CR4 write instructions.");
EM_REG_COUNTER_USED(&pStats->StatMovReadCR[0], "/EM/CPU%d/R3/PrivInst/Mov X, CR0", "Number of mov CR0 read instructions.");
EM_REG_COUNTER_USED(&pStats->StatMovReadCR[1], "/EM/CPU%d/R3/PrivInst/Mov X, CR1", "Number of mov CR1 read instructions.");
EM_REG_COUNTER_USED(&pStats->StatMovReadCR[2], "/EM/CPU%d/R3/PrivInst/Mov X, CR2", "Number of mov CR2 read instructions.");
EM_REG_COUNTER_USED(&pStats->StatMovReadCR[3], "/EM/CPU%d/R3/PrivInst/Mov X, CR3", "Number of mov CR3 read instructions.");
EM_REG_COUNTER_USED(&pStats->StatMovReadCR[4], "/EM/CPU%d/R3/PrivInst/Mov X, CR4", "Number of mov CR4 read instructions.");
EM_REG_COUNTER_USED(&pStats->StatMovDRx, "/EM/CPU%d/R3/PrivInst/MovDRx", "Number of mov DRx instructions.");
EM_REG_COUNTER_USED(&pStats->StatIret, "/EM/CPU%d/R3/PrivInst/Iret", "Number of iret instructions.");
EM_REG_COUNTER_USED(&pStats->StatMovLgdt, "/EM/CPU%d/R3/PrivInst/Lgdt", "Number of lgdt instructions.");
EM_REG_COUNTER_USED(&pStats->StatMovLidt, "/EM/CPU%d/R3/PrivInst/Lidt", "Number of lidt instructions.");
EM_REG_COUNTER_USED(&pStats->StatMovLldt, "/EM/CPU%d/R3/PrivInst/Lldt", "Number of lldt instructions.");
EM_REG_COUNTER_USED(&pStats->StatSysEnter, "/EM/CPU%d/R3/PrivInst/Sysenter", "Number of sysenter instructions.");
EM_REG_COUNTER_USED(&pStats->StatSysExit, "/EM/CPU%d/R3/PrivInst/Sysexit", "Number of sysexit instructions.");
EM_REG_COUNTER_USED(&pStats->StatSysCall, "/EM/CPU%d/R3/PrivInst/Syscall", "Number of syscall instructions.");
EM_REG_COUNTER_USED(&pStats->StatSysRet, "/EM/CPU%d/R3/PrivInst/Sysret", "Number of sysret instructions.");
EM_REG_COUNTER(&pVCpu->em.s.StatTotalClis, "/EM/CPU%d/Cli/Total", "Total number of cli instructions executed.");
/* these should be considered for release statistics. */
EM_REG_COUNTER(&pVCpu->em.s.StatIOEmu, "/PROF/CPU%d/EM/Emulation/IO", "Profiling of emR3RawExecuteIOInstruction.");
EM_REG_COUNTER(&pVCpu->em.s.StatPrivEmu, "/PROF/CPU%d/EM/Emulation/Priv", "Profiling of emR3RawPrivileged.");
EM_REG_PROFILE(&pVCpu->em.s.StatHmEntry, "/PROF/CPU%d/EM/HmEnter", "Profiling Hardware Accelerated Mode entry overhead.");
EM_REG_PROFILE(&pVCpu->em.s.StatHmExec, "/PROF/CPU%d/EM/HmExec", "Profiling Hardware Accelerated Mode execution.");
EM_REG_PROFILE(&pVCpu->em.s.StatIEMEmu, "/PROF/CPU%d/EM/IEMEmuSingle", "Profiling single instruction IEM execution.");
EM_REG_PROFILE(&pVCpu->em.s.StatIEMThenREM, "/PROF/CPU%d/EM/IEMThenRem", "Profiling IEM-then-REM instruction execution (by IEM).");
EM_REG_PROFILE(&pVCpu->em.s.StatREMEmu, "/PROF/CPU%d/EM/REMEmuSingle", "Profiling single instruction REM execution.");
EM_REG_PROFILE(&pVCpu->em.s.StatREMSync, "/PROF/CPU%d/EM/REMSync", "Profiling REM context syncing.");
EM_REG_PROFILE(&pVCpu->em.s.StatRAWEntry, "/PROF/CPU%d/EM/RAWEnter", "Profiling Raw Mode entry overhead.");
EM_REG_PROFILE(&pVCpu->em.s.StatRAWExec, "/PROF/CPU%d/EM/RAWExec", "Profiling Raw Mode execution.");
EM_REG_PROFILE(&pVCpu->em.s.StatRAWTail, "/PROF/CPU%d/EM/RAWTail", "Profiling Raw Mode tail overhead.");
#endif /* VBOX_WITH_STATISTICS */
EM_REG_COUNTER(&pVCpu->em.s.StatForcedActions, "/PROF/CPU%d/EM/ForcedActions", "Profiling forced action execution.");
EM_REG_COUNTER(&pVCpu->em.s.StatHalted, "/PROF/CPU%d/EM/Halted", "Profiling halted state (VMR3WaitHalted).");
EM_REG_PROFILE_ADV(&pVCpu->em.s.StatCapped, "/PROF/CPU%d/EM/Capped", "Profiling capped state (sleep).");
EM_REG_COUNTER(&pVCpu->em.s.StatREMTotal, "/PROF/CPU%d/EM/REMTotal", "Profiling emR3RemExecute (excluding FFs).");
EM_REG_COUNTER(&pVCpu->em.s.StatRAWTotal, "/PROF/CPU%d/EM/RAWTotal", "Profiling emR3RawExecute (excluding FFs).");
}
return VINF_SUCCESS;
}
/**
* Applies relocations to data and code managed by this
* component. This function will be called at init and
* whenever the VMM need to relocate it self inside the GC.
*
* @param pVM Pointer to the VM.
*/
{
LogFlow(("EMR3Relocate\n"));
{
}
}
/**
* Reset the EM state for a CPU.
*
* Called by EMR3Reset and hot plugging.
*
* @param pVCpu Pointer to the VMCPU.
*/
{
/* VMR3Reset may return VINF_EM_RESET or VINF_EM_SUSPEND, so transition
out of the HALTED state here so that enmPrevState doesn't end up as
HALTED when EMR3Execute returns. */
{
Log(("EMR3ResetCpu: Cpu#%u %s -> %s\n", pVCpu->idCpu, emR3GetStateName(pVCpu->em.s.enmState), pVCpu->idCpu == 0 ? "EMSTATE_NONE" : "EMSTATE_WAIT_SIPI"));
}
}
/**
* Reset notification.
*
* @param pVM Pointer to the VM.
*/
{
Log(("EMR3Reset: \n"));
}
/**
* Terminates the EM.
*
* Termination means cleaning up and freeing all resources,
* the VM it self is at this point powered off or suspended.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
*/
{
#ifdef VBOX_WITH_REM
#endif
return VINF_SUCCESS;
}
/**
* Execute state save operation.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pSSM SSM operation handle.
*/
{
{
/* Save mwait state. */
}
return VINF_SUCCESS;
}
/**
* Execute state load operation.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pSSM SSM operation handle.
* @param uVersion Data layout version.
* @param uPass The data pass.
*/
{
/*
* Validate version.
*/
if ( uVersion > EM_SAVED_STATE_VERSION
{
AssertMsgFailed(("emR3Load: Invalid version uVersion=%d (current %d)!\n", uVersion, EM_SAVED_STATE_VERSION));
}
/*
* Load the saved state.
*/
{
if (RT_FAILURE(rc))
{
}
{
/* Load mwait state. */
}
}
return VINF_SUCCESS;
}
/**
* Argument packet for emR3SetExecutionPolicy.
*/
struct EMR3SETEXECPOLICYARGS
{
bool fEnforce;
};
/**
* @callback_method_impl{FNVMMEMTRENDEZVOUS, Rendezvous callback for EMR3SetExecutionPolicy.}
*/
{
/*
* Only the first CPU changes the variables.
*/
{
{
break;
break;
case EMEXECPOLICY_IEM_ALL:
break;
default:
}
Log(("emR3SetExecutionPolicy: fRecompileUser=%RTbool fRecompileSupervisor=%RTbool fIemExecutesAll=%RTbool\n",
}
/*
* Force rescheduling if in RAW, HM, IEM, or REM.
*/
: VINF_SUCCESS;
}
/**
* Changes an execution scheduling policy parameter.
*
* This is used to enable or disable raw-mode / hardware-virtualization
* execution of user and supervisor code.
*
* @returns VINF_SUCCESS on success.
* @returns VINF_RESCHEDULE if a rescheduling might be required.
* @returns VERR_INVALID_PARAMETER on an invalid enmMode value.
*
* @param pUVM The user mode VM handle.
* @param enmPolicy The scheduling policy to change.
* @param fEnforce Whether to enforce the policy or not.
*/
{
AssertReturn(enmPolicy > EMEXECPOLICY_INVALID && enmPolicy < EMEXECPOLICY_END, VERR_INVALID_PARAMETER);
return VMMR3EmtRendezvous(pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING, emR3SetExecutionPolicy, &Args);
}
/**
* Queries an execution scheduling policy parameter.
*
* @returns VBox status code
* @param pUVM The user mode VM handle.
* @param enmPolicy The scheduling policy to query.
* @param pfEnforced Where to return the current value.
*/
{
AssertReturn(enmPolicy > EMEXECPOLICY_INVALID && enmPolicy < EMEXECPOLICY_END, VERR_INVALID_PARAMETER);
/* No need to bother EMTs with a query. */
switch (enmPolicy)
{
break;
break;
case EMEXECPOLICY_IEM_ALL:
break;
default:
}
return VINF_SUCCESS;
}
/**
* Raise a fatal error.
*
* Safely terminate the VM with full state report and stuff. This function
* will naturally never return.
*
* @param pVCpu Pointer to the VMCPU.
* @param rc VBox status code.
*/
{
AssertReleaseMsgFailed(("longjmp returned!\n"));
}
#if defined(LOG_ENABLED) || defined(VBOX_STRICT)
/**
* Gets the EM state name.
*
* @returns pointer to read only state name,
* @param enmState The state.
*/
{
switch (enmState)
{
case EMSTATE_NONE: return "EMSTATE_NONE";
case EMSTATE_RAW: return "EMSTATE_RAW";
case EMSTATE_HM: return "EMSTATE_HM";
case EMSTATE_IEM: return "EMSTATE_IEM";
case EMSTATE_REM: return "EMSTATE_REM";
case EMSTATE_HALTED: return "EMSTATE_HALTED";
case EMSTATE_WAIT_SIPI: return "EMSTATE_WAIT_SIPI";
case EMSTATE_SUSPENDED: return "EMSTATE_SUSPENDED";
case EMSTATE_TERMINATING: return "EMSTATE_TERMINATING";
case EMSTATE_DEBUG_GUEST_RAW: return "EMSTATE_DEBUG_GUEST_RAW";
case EMSTATE_DEBUG_GUEST_HM: return "EMSTATE_DEBUG_GUEST_HM";
case EMSTATE_DEBUG_GUEST_IEM: return "EMSTATE_DEBUG_GUEST_IEM";
case EMSTATE_DEBUG_GUEST_REM: return "EMSTATE_DEBUG_GUEST_REM";
case EMSTATE_DEBUG_HYPER: return "EMSTATE_DEBUG_HYPER";
case EMSTATE_GURU_MEDITATION: return "EMSTATE_GURU_MEDITATION";
case EMSTATE_IEM_THEN_REM: return "EMSTATE_IEM_THEN_REM";
default: return "Unknown!";
}
}
#endif /* LOG_ENABLED || VBOX_STRICT */
/**
* Debug loop.
*
* @returns VBox status code for EM.
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
* @param rc Current EM VBox status code.
*/
{
for (;;)
{
/*
* Debug related RC.
*/
switch (VBOXSTRICTRC_VAL(rc))
{
/*
* Single step an instruction.
*/
case VINF_EM_DBG_STEP:
#ifdef VBOX_WITH_RAW_MODE
#else
#endif
#ifdef VBOX_WITH_REM
#endif
else
{
}
break;
/*
*/
case VINF_EM_DBG_STEPPED:
break;
case VINF_EM_DBG_BREAKPOINT:
break;
case VINF_EM_DBG_STOP:
break;
break;
break;
RTPrintf("\nVINF_EM_DBG_HYPER_ASSERTION:\n%s%s\n", VMMR3GetRZAssertMsg1(pVM), VMMR3GetRZAssertMsg2(pVM));
rc = DBGFR3EventAssertion(pVM, DBGFEVENT_ASSERTION_HYPER, VMMR3GetRZAssertMsg1(pVM), VMMR3GetRZAssertMsg2(pVM));
break;
/*
* Guru meditation.
*/
case VERR_VMM_RING0_ASSERTION: /** @todo Make a guru meditation event! */
break;
case VERR_REM_TOO_MANY_TRAPS: /** @todo Make a guru meditation event! */
break;
default: /** @todo don't use default for guru, but make special errors code! */
{
break;
}
}
/*
* Process the result.
*/
do
{
switch (VBOXSTRICTRC_VAL(rc))
{
/*
* Continue the debugging loop.
*/
case VINF_EM_DBG_STEP:
case VINF_EM_DBG_STOP:
case VINF_EM_DBG_STEPPED:
case VINF_EM_DBG_BREAKPOINT:
break;
/*
* Resuming execution (in some form) has to be done here if we got
* a hypervisor debug event.
*/
case VINF_SUCCESS:
case VINF_EM_RESUME:
case VINF_EM_SUSPEND:
case VINF_EM_RESCHEDULE:
case VINF_EM_RESCHEDULE_RAW:
case VINF_EM_RESCHEDULE_REM:
case VINF_EM_HALT:
{
#ifdef VBOX_WITH_RAW_MODE
continue;
#else
#endif
}
if (rc == VINF_SUCCESS)
return rc;
/*
* The debugger isn't attached.
* We'll simply turn the thing off since that's the easiest thing to do.
*/
case VERR_DBGF_NOT_ATTACHED:
switch (VBOXSTRICTRC_VAL(rcLast))
{
case VERR_TRPM_PANIC:
case VERR_TRPM_DONT_PANIC:
case VERR_VMM_RING0_ASSERTION:
return rcLast;
}
return VINF_EM_OFF;
/*
* Status codes terminating the VM in one or another sense.
*/
case VINF_EM_TERMINATE:
case VINF_EM_OFF:
case VINF_EM_RESET:
case VINF_EM_NO_MEMORY:
case VINF_EM_RAW_IRET_TRAP:
case VERR_TRPM_PANIC:
case VERR_TRPM_DONT_PANIC:
case VERR_VMM_RING0_ASSERTION:
case VERR_INTERNAL_ERROR:
case VERR_INTERNAL_ERROR_2:
case VERR_INTERNAL_ERROR_3:
case VERR_INTERNAL_ERROR_4:
case VERR_INTERNAL_ERROR_5:
return rc;
/*
* The rest is unexpected, and will keep us here.
*/
default:
break;
}
} while (false);
} /* debug for ever */
}
/**
* Steps recompiled code.
*
* @returns VBox status code. The most important ones are: VINF_EM_STEP_EVENT,
* VINF_EM_RESCHEDULE, VINF_EM_SUSPEND, VINF_EM_RESET and VINF_EM_TERMINATE.
*
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
*/
{
#ifdef VBOX_WITH_REM
/*
* Switch to REM, step instruction, switch back.
*/
if (RT_SUCCESS(rc))
{
}
#else
#endif
Log3(("emR3RemStep: returns %Rrc cs:eip=%04x:%08x\n", rc, CPUMGetGuestCS(pVCpu), CPUMGetGuestEIP(pVCpu)));
return rc;
}
/**
* emR3RemExecute helper that syncs the state back from REM and leave the REM
* critical section.
*
* @returns false - new fInREMState value.
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
*/
{
#ifdef VBOX_WITH_REM
#endif
return false;
}
/**
* Executes recompiled code.
*
* This function contains the recompiler version of the inner
* execution loop (the outer loop being in EMR3ExecuteVM()).
*
* @returns VBox status code. The most important ones are: VINF_EM_RESCHEDULE,
* VINF_EM_SUSPEND, VINF_EM_RESET and VINF_EM_TERMINATE.
*
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
* @param pfFFDone Where to store an indicator telling whether or not
* FFs were done before returning.
*
*/
{
#ifdef LOG_ENABLED
else
Log(("EMR%d: %04X:%08X ESP=%08X IF=%d CR0=%x eflags=%x\n", cpl, pCtx->cs.Sel, pCtx->eip, pCtx->esp, pCtx->eflags.Bits.u1IF, (uint32_t)pCtx->cr0, pCtx->eflags.u));
#endif
#if defined(VBOX_STRICT) && defined(DEBUG_bird)
|| !MMHyperIsInsideArea(pVM, CPUMGetGuestEIP(pVCpu)), /** @todo @bugref{1419} - get flat address. */
#endif
/*
* Spin till we get a forced action which returns anything but VINF_SUCCESS
* or the REM suggests raw-mode execution.
*/
*pfFFDone = false;
#ifdef VBOX_WITH_REM
bool fInREMState = false;
#endif
int rc = VINF_SUCCESS;
for (;;)
{
#ifdef VBOX_WITH_REM
/*
* Lock REM and update the state if not already in sync.
*
* Note! Big lock, but you are not supposed to own any lock when
* coming in here.
*/
if (!fInREMState)
{
/* Flush the recompiler translation blocks if the VCPU has changed,
also force a full CPU state resync. */
{
}
if (RT_FAILURE(rc))
break;
fInREMState = true;
/*
* We might have missed the raising of VMREQ, TIMER and some other
* important FFs while we were busy switching the state. So, check again.
*/
if ( VM_FF_IS_PENDING(pVM, VM_FF_REQUEST | VM_FF_PDM_QUEUES | VM_FF_DBGF | VM_FF_CHECK_VM_STATE | VM_FF_RESET)
{
goto l_REMDoForcedActions;
}
}
#endif
/*
* Execute REM.
*/
{
#ifdef VBOX_WITH_REM
#else
#endif
}
else
{
/* Give up this time slice; virtual time continues */
RTThreadSleep(5);
rc = VINF_SUCCESS;
}
/*
* Deal with high priority post execution FFs before doing anything
* else. Sync back the state and leave the lock to be on the safe side.
*/
{
#ifdef VBOX_WITH_REM
#endif
}
/*
* Process the returned status code.
*/
if (rc != VINF_SUCCESS)
{
break;
if (rc != VINF_REM_INTERRUPED_FF)
{
/*
* Anything which is not known to us means an internal error
* and the termination of the VM!
*/
break;
}
}
/*
* Check and execute forced actions.
*
* Sync back the VM state and leave the lock before calling any of
* these, you never know what's going to happen here.
*/
#ifdef VBOX_HIGH_RES_TIMERS_HACK
#endif
{
#ifdef VBOX_WITH_REM
if (fInREMState)
#endif
if ( rc != VINF_SUCCESS
&& rc != VINF_EM_RESCHEDULE_REM)
{
*pfFFDone = true;
break;
}
}
} /* The Inner Loop, recompiled execution mode version. */
#ifdef VBOX_WITH_REM
/*
* Returning. Sync back the VM state if required.
*/
if (fInREMState)
#endif
return rc;
}
#ifdef DEBUG
{
Log(("Single step BEGIN:\n"));
for (uint32_t i = 0; i < cIterations; i++)
{
break;
}
Log(("Single step END:\n"));
return VINF_EM_RESCHEDULE;
}
#endif /* DEBUG */
/**
* Try execute the problematic code in IEM first, then fall back on REM if there
* is too much of it or if IEM doesn't implement something.
*
* @returns Strict VBox status code from IEMExecLots.
* @param pVM The cross context VM structure.
* @param pVCpu The cross context CPU structure for the calling EMT.
* @param pfFFDone Force flags done indicator.
*
* @thread EMT(pVCpu)
*/
{
*pfFFDone = false;
/*
* Execute in IEM for a while.
*/
{
if (rcStrict != VINF_SUCCESS)
{
break;
Log(("emR3ExecuteIemThenRem: returns %Rrc after %u instructions\n",
return rcStrict;
}
{
LogFlow(("emR3ExecuteIemThenRem: -> %d (%s) after %u instructions\n",
return VINF_SUCCESS;
}
/*
* Check for pending actions.
*/
return VINF_SUCCESS;
}
/*
* Switch to REM.
*/
Log(("emR3ExecuteIemThenRem: -> EMSTATE_REM (after %u instructions)\n", pVCpu->em.s.cIemThenRemInstructions));
return VINF_SUCCESS;
}
/**
* Decides whether to execute RAW, HWACC or REM.
*
* @returns new EM state
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
* @param pCtx Pointer to the guest CPU context.
*/
{
/*
* When forcing raw-mode execution, things are simple.
*/
return EMSTATE_RAW;
/*
* We stay in the wait for SIPI state unless explicitly told otherwise.
*/
return EMSTATE_WAIT_SIPI;
/*
* Execute everything in IEM?
*/
return EMSTATE_IEM;
/* !!! THIS MUST BE IN SYNC WITH remR3CanExecuteRaw !!! */
/* !!! THIS MUST BE IN SYNC WITH remR3CanExecuteRaw !!! */
/* !!! THIS MUST BE IN SYNC WITH remR3CanExecuteRaw !!! */
if (HMIsEnabled(pVM))
{
/*
* Hardware accelerated raw-mode:
*/
return EMSTATE_HM;
/*
* Note! Raw mode and hw accelerated mode are incompatible. The latter
* turns off monitoring features essential for raw mode!
*/
#ifdef VBOX_WITH_FIRST_IEM_STEP
return EMSTATE_IEM_THEN_REM;
#else
return EMSTATE_REM;
#endif
}
/*
* Standard raw-mode:
*
* Here we only support 16 & 32 bits protected mode ring 3 code that has no IO privileges
* or 32 bits protected mode ring 0 code
*
* The tests are ordered by the likelihood of being true during normal execution.
*/
{
return EMSTATE_REM;
}
# ifndef VBOX_RAW_V86
Log2(("raw mode refused: VM_MASK\n"));
return EMSTATE_REM;
}
# endif
/** @todo check up the X86_CR0_AM flag in respect to raw mode!!! We're probably not emulating it right! */
{
//Log2(("raw mode refused: %s%s%s\n", (u32CR0 & X86_CR0_PG) ? "" : " !PG", (u32CR0 & X86_CR0_PE) ? "" : " !PE", (u32CR0 & X86_CR0_AM) ? "" : " !AM"));
return EMSTATE_REM;
}
{
if (!(u32Features & X86_CPUID_FEATURE_EDX_PAE))
return EMSTATE_REM;
}
{
if (!EMIsRawRing3Enabled(pVM))
return EMSTATE_REM;
{
Log2(("raw mode refused: IF (RawR3)\n"));
return EMSTATE_REM;
}
{
Log2(("raw mode refused: CR0.WP + RawR0\n"));
return EMSTATE_REM;
}
}
else
{
if (!EMIsRawRing0Enabled(pVM))
return EMSTATE_REM;
if (EMIsRawRing1Enabled(pVM))
{
/* Only ring 0 and 1 supervisor code. */
if ((uSS & X86_SEL_RPL) == 2) /* ring 1 code is moved into ring 2, so we can't support ring-2 in that case. */
{
return EMSTATE_REM;
}
}
/* Only ring 0 supervisor code. */
else if ((uSS & X86_SEL_RPL) != 0)
{
return EMSTATE_REM;
}
// Let's start with pure 32 bits ring 0 code first
/** @todo What's pure 32-bit mode? flat? */
{
return EMSTATE_REM;
}
/* Write protection must be turned on, or else the guest can overwrite our hypervisor code and data. */
if (!(u32CR0 & X86_CR0_WP))
{
Log2(("raw r0 mode refused: CR0.WP=0!\n"));
return EMSTATE_REM;
}
# ifdef VBOX_WITH_RAW_MODE
{
Log2(("raw r0 mode forced: patch code\n"));
# ifdef VBOX_WITH_SAFE_STR
# endif
return EMSTATE_RAW;
}
# endif /* VBOX_WITH_RAW_MODE */
# if !defined(VBOX_ALLOW_IF0) && !defined(VBOX_RUN_INTERRUPT_GATE_HANDLERS)
{
////Log2(("R0: IF=0 VIF=%d %08X\n", eip, pVMeflags));
//Log2(("RR0: Interrupts turned off; fall back to emulation\n"));
return EMSTATE_REM;
}
# endif
# ifndef VBOX_WITH_RAW_RING1
/** @todo still necessary??? */
{
return EMSTATE_REM;
}
# endif
}
/*
* Stale hidden selectors means raw-mode is unsafe (being very careful).
*/
{
Log2(("raw mode refused: stale CS\n"));
return EMSTATE_REM;
}
{
Log2(("raw mode refused: stale SS\n"));
return EMSTATE_REM;
}
{
Log2(("raw mode refused: stale DS\n"));
return EMSTATE_REM;
}
{
Log2(("raw mode refused: stale ES\n"));
return EMSTATE_REM;
}
{
Log2(("raw mode refused: stale FS\n"));
return EMSTATE_REM;
}
{
Log2(("raw mode refused: stale GS\n"));
return EMSTATE_REM;
}
# ifdef VBOX_WITH_SAFE_STR
{
Log(("Raw mode refused -> TR=0\n"));
return EMSTATE_REM;
}
# endif
/*Assert(PGMPhysIsA20Enabled(pVCpu));*/
return EMSTATE_RAW;
}
/**
* Executes all high priority post execution force actions.
*
* @returns rc or a fatal status code.
*
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
* @param rc The current rc.
*/
{
/* Update CR3 (Nested Paging case for HM). */
{
if (RT_FAILURE(rc2))
return rc2;
}
/* Update PAE PDPEs. This must be done *after* PGMUpdateCR3() and used only by the Nested Paging case for HM. */
{
if (CPUMIsGuestInPAEMode(pVCpu))
{
}
else
}
#ifdef VBOX_WITH_RAW_MODE
#endif
{
if ( rc > VINF_EM_NO_MEMORY
&& rc <= VINF_EM_LAST)
}
return rc;
}
/**
* Executes all pending forced actions.
*
* Forced actions can cause execution delays and execution
* rescheduling. The first we deal with using action priority, so
* that for instance pending timers aren't scheduled and ran until
* right before execution. The rescheduling we deal with using
* return codes. The same goes for VM termination, only in that case
* we exit everything.
*
* @returns VBox status code of equal or greater importance/severity than rc.
* The most important ones are: VINF_EM_RESCHEDULE,
* VINF_EM_SUSPEND, VINF_EM_RESET and VINF_EM_TERMINATE.
*
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
* @param rc The current rc.
*
*/
{
#ifdef VBOX_STRICT
int rcIrq = VINF_SUCCESS;
#endif
int rc2;
#define UPDATE_RC() \
do { \
AssertMsg(rc2 <= 0 || (rc2 >= VINF_EM_FIRST && rc2 <= VINF_EM_LAST), ("Invalid FF return code: %Rra\n", rc2)); \
break; \
} while (0)
/*
* Post execution chunk first.
*/
|| (VMCPU_FF_NORMAL_PRIORITY_POST_MASK && VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_NORMAL_PRIORITY_POST_MASK)) )
{
/*
* EMT Rendezvous (must be serviced before termination).
*/
{
UPDATE_RC();
/** @todo HACK ALERT! The following test is to make sure EM+TM
* is made. We need a better solution for this, or at least make it
* possible to do: (rc >= VINF_EM_FIRST && rc <=
* VINF_EM_SUSPEND). */
{
return rc;
}
}
/*
* State change request (cleared by vmR3SetStateLocked).
*/
{
switch (enmState)
{
case VMSTATE_FATAL_ERROR:
case VMSTATE_FATAL_ERROR_LS:
return VINF_EM_SUSPEND;
case VMSTATE_DESTROYING:
return VINF_EM_TERMINATE;
default:
}
}
/*
* Debugger Facility polling.
*/
{
UPDATE_RC();
}
/*
* Postponed reset request.
*/
{
UPDATE_RC();
}
#ifdef VBOX_WITH_RAW_MODE
/*
* CSAM page scanning.
*/
{
/** @todo: check for 16 or 32 bits code! (D bit in the code selector) */
Log(("Forced action VMCPU_FF_CSAM_SCAN_PAGE\n"));
}
#endif
/*
* Out of memory? Putting this after CSAM as it may in theory cause us to run out of memory.
*/
{
UPDATE_RC();
if (rc == VINF_EM_NO_MEMORY)
return rc;
}
/* check that we got them all */
AssertCompile(VM_FF_NORMAL_PRIORITY_POST_MASK == (VM_FF_CHECK_VM_STATE | VM_FF_DBGF | VM_FF_RESET | VM_FF_PGM_NO_MEMORY | VM_FF_EMT_RENDEZVOUS));
}
/*
* Normal priority then.
* (Executed in no particular order.)
*/
{
/*
* PDM Queues are pending.
*/
/*
* PDM DMA transfers are pending.
*/
/*
* EMT Rendezvous (make sure they are handled before the requests).
*/
{
UPDATE_RC();
/** @todo HACK ALERT! The following test is to make sure EM+TM
* is made. We need a better solution for this, or at least make it
* possible to do: (rc >= VINF_EM_FIRST && rc <=
* VINF_EM_SUSPEND). */
{
return rc;
}
}
/*
* Requests from other threads.
*/
{
{
return rc2;
}
UPDATE_RC();
/** @todo HACK ALERT! The following test is to make sure EM+TM
* is made. We need a better solution for this, or at least make it
* possible to do: (rc >= VINF_EM_FIRST && rc <=
* VINF_EM_SUSPEND). */
{
return rc;
}
}
#ifdef VBOX_WITH_REM
/* Replay the handler notification changes. */
{
/* Try not to cause deadlocks. */
|| ( !PGMIsLockOwner(pVM)
&& !IOMIsLockWriteOwner(pVM))
)
{
}
}
#endif
/* check that we got them all */
AssertCompile(VM_FF_NORMAL_PRIORITY_MASK == (VM_FF_REQUEST | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | VM_FF_REM_HANDLER_NOTIFY | VM_FF_EMT_RENDEZVOUS));
}
/*
* Normal priority then. (per-VCPU)
* (Executed in no particular order.)
*/
{
/*
* Requests from other threads.
*/
{
{
return rc2;
}
UPDATE_RC();
/** @todo HACK ALERT! The following test is to make sure EM+TM
* is made. We need a better solution for this, or at least make it
* possible to do: (rc >= VINF_EM_FIRST && rc <=
* VINF_EM_SUSPEND). */
{
return rc;
}
}
/* check that we got them all */
}
/*
* High priority pre execution chunk last.
* (Executed in ascending priority order.)
*/
{
/*
* Timers before interrupts.
*/
/*
* The instruction following an emulated STI should *always* be executed!
*
* Note! We intentionally don't clear VM_FF_INHIBIT_INTERRUPTS here if
* the eip is the same as the inhibited instr address. Before we
* are able to execute this instruction in raw mode (iret to
* guest code) an external interrupt might force a world switch
* again. Possibly allowing a guest interrupt to be dispatched
* in the process. This could break the guest. Sounds very
* unlikely, but such timing sensitive problem are not as rare as
* you might think.
*/
{
{
Log(("Clearing VMCPU_FF_INHIBIT_INTERRUPTS at %RGv - successor %RGv\n", (RTGCPTR)CPUMGetGuestRIP(pVCpu), EMGetInhibitInterruptsPC(pVCpu)));
}
else
}
/*
* Interrupts.
*/
bool fWakeupPending = false;
&& !TRPMHasTrap(pVCpu) /* an interrupt could already be scheduled for dispatching in the recompiler. */
#ifdef VBOX_WITH_RAW_MODE
#else
#endif
&& !HMR3IsEventPending(pVCpu))
{
{
/* Note: it's important to make sure the return code from TRPMR3InjectEvent isn't ignored! */
/** @todo this really isn't nice, should properly handle this */
if (pVM->em.s.fIemExecutesAll && (rc2 == VINF_EM_RESCHEDULE_REM || rc2 == VINF_EM_RESCHEDULE_HM || rc2 == VINF_EM_RESCHEDULE_RAW))
#ifdef VBOX_STRICT
#endif
UPDATE_RC();
/* Reschedule required: We must not miss the wakeup below! */
fWakeupPending = true;
}
#ifdef VBOX_WITH_REM
/** @todo really ugly; if we entered the hlt state when exiting the recompiler and an interrupt was pending, we previously got stuck in the halted state. */
{
UPDATE_RC();
}
#endif
}
/*
* Allocate handy pages.
*/
{
UPDATE_RC();
}
/*
* Debugger Facility request.
*/
{
UPDATE_RC();
}
/*
* EMT Rendezvous (must be serviced before termination).
*/
if ( !fWakeupPending /* don't miss the wakeup from EMSTATE_HALTED! */
{
UPDATE_RC();
/** @todo HACK ALERT! The following test is to make sure EM+TM thinks the VM is
* solution for this, or at least make it possible to do: (rc >= VINF_EM_FIRST
* && rc >= VINF_EM_SUSPEND). */
{
return rc;
}
}
/*
* State change request (cleared by vmR3SetStateLocked).
*/
if ( !fWakeupPending /* don't miss the wakeup from EMSTATE_HALTED! */
{
switch (enmState)
{
case VMSTATE_FATAL_ERROR:
case VMSTATE_FATAL_ERROR_LS:
return VINF_EM_SUSPEND;
case VMSTATE_DESTROYING:
return VINF_EM_TERMINATE;
default:
}
}
/*
* Out of memory? Since most of our fellow high priority actions may cause us
* to run out of memory, we're employing VM_FF_IS_PENDING_EXCEPT and putting this
* at the end rather than the start. Also, VM_FF_TERMINATE has higher priority
* than us since we can terminate without allocating more memory.
*/
{
UPDATE_RC();
if (rc == VINF_EM_NO_MEMORY)
return rc;
}
/*
* If the virtual sync clock is still stopped, make TM restart it.
*/
#ifdef DEBUG
/*
* Debug, pause the VM.
*/
{
Log(("emR3ForcedActions: returns VINF_EM_SUSPEND\n"));
return VINF_EM_SUSPEND;
}
#endif
/* check that we got them all */
AssertCompile(VM_FF_HIGH_PRIORITY_PRE_MASK == (VM_FF_TM_VIRTUAL_SYNC | VM_FF_DBGF | VM_FF_CHECK_VM_STATE | VM_FF_DEBUG_SUSPEND | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY | VM_FF_EMT_RENDEZVOUS));
AssertCompile(VMCPU_FF_HIGH_PRIORITY_PRE_MASK == (VMCPU_FF_TIMER | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC | VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_INHIBIT_INTERRUPTS | VM_WHEN_RAW_MODE(VMCPU_FF_SELM_SYNC_TSS | VMCPU_FF_TRPM_SYNC_IDT | VMCPU_FF_SELM_SYNC_GDT | VMCPU_FF_SELM_SYNC_LDT, 0)));
}
return rc;
}
/**
* Check if the preset execution time cap restricts guest execution scheduling.
*
* @returns true if allowed, false otherwise
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
*/
{
{
{
/* New time slice. */
}
Log2(("emR3IsExecutionAllowed: start=%RX64 startexec=%RX64 exec=%RX64 (cap=%x)\n", pVCpu->em.s.u64TimeSliceStart, pVCpu->em.s.u64TimeSliceStartExec, pVCpu->em.s.u64TimeSliceExec, (EM_TIME_SLICE * pVM->uCpuExecutionCap) / 100));
return false;
}
return true;
}
/**
* Execute VM.
*
* This function is the main loop of the VM. The emulation thread
* calls this function when the VM has been successfully constructed
* and we're ready for executing the VM.
*
* Returning from this function means that the VM is turned off or
* suspended (state already saved) and deconstruction is next in line.
*
* All interaction from other thread are done using forced actions
* and signaling of the wait object.
*
* @returns VBox status code, informational status codes may indicate failure.
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
*/
{
Log(("EMR3ExecuteVM: pVM=%p enmVMState=%d (%s) enmState=%d (%s) enmPrevState=%d (%s) fForceRAW=%RTbool\n",
pVM,
if (rc == 0)
{
/*
* Start the virtual time.
*/
/*
* The Outer Main Loop.
*/
bool fFFDone = false;
/* Reschedule right away to start in the right state. */
rc = VINF_SUCCESS;
/* If resuming after a pause or a state load, restore the previous
state or else we'll start executing code. Else, just reschedule. */
else
for (;;)
{
/*
* Before we can schedule anything (we're here because
* scheduling is required) we must service any pending
* forced actions to avoid any pending action causing
* immediate rescheduling upon entering an inner loop
*
* Do forced actions.
*/
if ( !fFFDone
&& RT_SUCCESS(rc)
&& rc != VINF_EM_TERMINATE
&& rc != VINF_EM_OFF
{
if ( ( rc == VINF_EM_RESCHEDULE_REM
|| rc == VINF_EM_RESCHEDULE_HM)
}
else if (fFFDone)
fFFDone = false;
/*
* Now what to do?
*/
switch (rc)
{
/*
* Keep doing what we're currently doing.
*/
case VINF_SUCCESS:
break;
/*
* Reschedule - to raw-mode execution.
*/
case VINF_EM_RESCHEDULE_RAW:
Log2(("EMR3ExecuteVM: VINF_EM_RESCHEDULE_RAW: %d -> %d (EMSTATE_RAW)\n", enmOldState, EMSTATE_RAW));
break;
/*
* Reschedule - to hardware accelerated raw-mode execution.
*/
case VINF_EM_RESCHEDULE_HM:
break;
/*
* Reschedule - to recompiled execution.
*/
case VINF_EM_RESCHEDULE_REM:
#ifdef VBOX_WITH_FIRST_IEM_STEP
if (HMIsEnabled(pVM))
{
Log2(("EMR3ExecuteVM: VINF_EM_RESCHEDULE_REM: %d -> %d (EMSTATE_IEM_THEN_REM)\n",
{
}
}
else
{
Log2(("EMR3ExecuteVM: VINF_EM_RESCHEDULE_REM: %d -> %d (EMSTATE_REM)\n", enmOldState, EMSTATE_REM));
}
#else
Log2(("EMR3ExecuteVM: VINF_EM_RESCHEDULE_REM: %d -> %d (EMSTATE_REM)\n", enmOldState, EMSTATE_REM));
#endif
break;
/*
* Resume.
*/
case VINF_EM_RESUME:
/* Don't reschedule in the halted or wait for SIPI case. */
{
break;
}
/* fall through and get scheduled. */
/*
* Reschedule.
*/
case VINF_EM_RESCHEDULE:
{
Log2(("EMR3ExecuteVM: VINF_EM_RESCHEDULE: %d -> %d (%s)\n", enmOldState, enmState, emR3GetStateName(enmState)));
break;
}
/*
* Halted.
*/
case VINF_EM_HALT:
break;
/*
* Switch to the wait for SIPI state (application processor only)
*/
case VINF_EM_WAIT_SIPI:
break;
/*
* Suspend.
*/
case VINF_EM_SUSPEND:
break;
/*
* Reset.
* We might end up doing a double reset for now, we'll have to clean up the mess later.
*/
case VINF_EM_RESET:
{
{
Log2(("EMR3ExecuteVM: VINF_EM_RESET: %d -> %d (%s)\n", enmOldState, enmState, emR3GetStateName(enmState)));
}
else
{
/* All other VCPUs go into the wait for SIPI state. */
}
break;
}
/*
* Power Off.
*/
case VINF_EM_OFF:
return rc;
/*
* Terminate the VM.
*/
case VINF_EM_TERMINATE:
return rc;
/*
* Out of memory, suspend the VM and stuff.
*/
case VINF_EM_NO_MEMORY:
N_("Unable to allocate and lock memory. The virtual machine will be paused. Please close applications to free up memory or close the VM"));
if (rc != VINF_EM_SUSPEND)
{
if (RT_SUCCESS_NP(rc))
{
}
}
return rc;
/*
* Guest debug events.
*/
case VINF_EM_DBG_STEPPED:
case VINF_EM_DBG_STOP:
case VINF_EM_DBG_BREAKPOINT:
case VINF_EM_DBG_STEP:
if (enmOldState == EMSTATE_RAW)
{
}
else if (enmOldState == EMSTATE_HM)
{
}
else if (enmOldState == EMSTATE_REM)
{
}
else
{
}
break;
/*
* Hypervisor debug events.
*/
break;
/*
* Triple fault.
*/
case VINF_EM_TRIPLE_FAULT:
{
Log(("EMR3ExecuteVM: VINF_EM_TRIPLE_FAULT: CPU reset...\n"));
break;
}
/* Else fall through and trigger a guru. */
case VERR_VMM_RING0_ASSERTION:
Log(("EMR3ExecuteVM: %Rrc: %d -> %d (EMSTATE_GURU_MEDITATION)\n", rc, enmOldState, EMSTATE_GURU_MEDITATION));
break;
/*
* Any error code showing up here other than the ones we
* know and process above are considered to be FATAL.
*
* Unknown warnings and informational status codes are also
* included in this.
*/
default:
if (RT_SUCCESS_NP(rc))
{
}
Log(("EMR3ExecuteVM: %Rrc: %d -> %d (EMSTATE_GURU_MEDITATION)\n", rc, enmOldState, EMSTATE_GURU_MEDITATION));
break;
}
/*
* Act on state transition.
*/
if (enmOldState != enmNewState)
{
/* Clear MWait flags. */
if ( enmOldState == EMSTATE_HALTED
&& ( enmNewState == EMSTATE_RAW
|| enmNewState == EMSTATE_HM
|| enmNewState == EMSTATE_REM
|| enmNewState == EMSTATE_DEBUG_GUEST_REM) )
{
LogFlow(("EMR3ExecuteVM: Clearing MWAIT\n"));
}
}
else
/*
* Act on the new state.
*/
switch (enmNewState)
{
/*
* Execute raw.
*/
case EMSTATE_RAW:
#ifdef VBOX_WITH_RAW_MODE
#else
#endif
break;
/*
* Execute hardware accelerated raw.
*/
case EMSTATE_HM:
break;
/*
* Execute recompiled.
*/
case EMSTATE_REM:
break;
/*
* Execute in the interpreter.
*/
case EMSTATE_IEM:
{
#if 0 /* For testing purposes. */
if (rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_RESCHEDULE_HM || rc == VINF_EM_RESCHEDULE_REM || rc == VINF_EM_RESCHEDULE_RAW)
rc = VINF_SUCCESS;
else if (rc == VERR_EM_CANNOT_EXEC_GUEST)
#endif
{
}
fFFDone = false;
break;
}
/*
* Execute in IEM, hoping we can quickly switch aback to HM
* or RAW execution. If our hopes fail, we go to REM.
*/
case EMSTATE_IEM_THEN_REM:
{
break;
}
/*
* Application processor execution halted until SIPI.
*/
case EMSTATE_WAIT_SIPI:
/* no break */
/*
* hlt - execution halted until interrupt.
*/
case EMSTATE_HALTED:
{
/* If HM (or someone else) store a pending interrupt in
TRPM, it must be dispatched ASAP without any halting.
Anything pending in TRPM has been accepted and the CPU
should already be the right state to receive it. */
if (TRPMHasTrap(pVCpu))
/* MWAIT has a special extension where it's woken up when
an interrupt is pending even when IF=0. */
{
if ( rc == VINF_SUCCESS
{
Log(("EMR3ExecuteVM: Triggering reschedule on pending IRQ after MWAIT\n"));
}
}
else
{
if ( rc == VINF_SUCCESS
{
}
}
break;
}
/*
* Suspended - return to VM.cpp.
*/
case EMSTATE_SUSPENDED:
Log(("EMR3ExecuteVM: actually returns %Rrc (state %s / %s)\n", rc, emR3GetStateName(pVCpu->em.s.enmState), emR3GetStateName(enmOldState)));
return VINF_EM_SUSPEND;
/*
* Debugging in the guest.
*/
case EMSTATE_DEBUG_GUEST_RAW:
case EMSTATE_DEBUG_GUEST_HM:
case EMSTATE_DEBUG_GUEST_IEM:
case EMSTATE_DEBUG_GUEST_REM:
break;
/*
* Debugging in the hypervisor.
*/
case EMSTATE_DEBUG_HYPER:
{
if (rc != VINF_SUCCESS)
{
else
{
/* switch to guru meditation mode */
}
Log(("EMR3ExecuteVM: actually returns %Rrc (state %s / %s)\n", rc, emR3GetStateName(pVCpu->em.s.enmState), emR3GetStateName(enmOldState)));
return rc;
}
break;
}
/*
* Guru meditation takes place in the debugger.
*/
case EMSTATE_GURU_MEDITATION:
{
Log(("EMR3ExecuteVM: actually returns %Rrc (state %s / %s)\n", rc, emR3GetStateName(pVCpu->em.s.enmState), emR3GetStateName(enmOldState)));
return rc;
}
/*
* The states we don't expect here.
*/
case EMSTATE_NONE:
case EMSTATE_TERMINATING:
default:
Log(("EMR3ExecuteVM: actually returns %Rrc (state %s / %s)\n", rc, emR3GetStateName(pVCpu->em.s.enmState), emR3GetStateName(enmOldState)));
return VERR_EM_INTERNAL_ERROR;
}
} /* The Outer Main Loop */
}
else
{
/*
* Fatal error.
*/
Log(("EMR3ExecuteVM: returns %Rrc because of longjmp / fatal error; (state %s / %s)\n", rc, emR3GetStateName(pVCpu->em.s.enmState), emR3GetStateName(pVCpu->em.s.enmPrevState)));
/** @todo change the VM state! */
return rc;
}
/* (won't ever get here). */
AssertFailed();
}
/**
* Notify EM of a state change (used by FTM)
*
* @param pVM Pointer to the VM.
*/
{
return VINF_SUCCESS;
}
/**
* Notify EM of a state change (used by FTM)
*
* @param pVM Pointer to the VM.
*/
{
return VINF_SUCCESS;
}