summaryrefslogtreecommitdiff
path: root/src/VBox/VMM/VMMR3/EM.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/VMM/VMMR3/EM.cpp')
-rw-r--r--src/VBox/VMM/VMMR3/EM.cpp656
1 files changed, 488 insertions, 168 deletions
diff --git a/src/VBox/VMM/VMMR3/EM.cpp b/src/VBox/VMM/VMMR3/EM.cpp
index c8843db1..024cbec1 100644
--- a/src/VBox/VMM/VMMR3/EM.cpp
+++ b/src/VBox/VMM/VMMR3/EM.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * 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;
@@ -21,11 +21,11 @@
* 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, emR3HwAccExecute, and
+ * modes has different inner loops (emR3RawExecute, emR3HmExecute, and
* emR3RemExecute).
*
* The interpreted execution is only used to avoid switching between
- * raw-mode/hwaccm and the recompiler when fielding virtualization traps/faults.
+ * raw-mode/hm and the recompiler when fielding virtualization traps/faults.
* The interpretation is thus implemented as part of EM.
*
* @see grp_em
@@ -41,13 +41,12 @@
#include <VBox/vmm/csam.h>
#include <VBox/vmm/selm.h>
#include <VBox/vmm/trpm.h>
+#include <VBox/vmm/iem.h>
#include <VBox/vmm/iom.h>
#include <VBox/vmm/dbgf.h>
#include <VBox/vmm/pgm.h>
#ifdef VBOX_WITH_REM
# include <VBox/vmm/rem.h>
-#else
-# include <VBox/vmm/iem.h>
#endif
#include <VBox/vmm/tm.h>
#include <VBox/vmm/mm.h>
@@ -55,14 +54,11 @@
#include <VBox/vmm/pdmapi.h>
#include <VBox/vmm/pdmcritsect.h>
#include <VBox/vmm/pdmqueue.h>
-#include <VBox/vmm/hwaccm.h>
+#include <VBox/vmm/hm.h>
#include <VBox/vmm/patm.h>
-#ifdef IEM_VERIFICATION_MODE
-# include <VBox/vmm/iem.h>
-#endif
#include "EMInternal.h"
-#include "internal/em.h"
#include <VBox/vmm/vm.h>
+#include <VBox/vmm/uvm.h>
#include <VBox/vmm/cpumdis.h>
#include <VBox/dis.h>
#include <VBox/disopcode.h>
@@ -79,7 +75,7 @@
* Defined Constants And Macros *
*******************************************************************************/
#if 0 /* Disabled till after 2.1.0 when we've time to test it. */
-#define EM_NOTIFY_HWACCM
+#define EM_NOTIFY_HM
#endif
@@ -91,7 +87,7 @@ static DECLCALLBACK(int) emR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, u
#if defined(LOG_ENABLED) || defined(VBOX_STRICT)
static const char *emR3GetStateName(EMSTATE enmState);
#endif
-static int emR3Debug(PVM pVM, PVMCPU pVCpu, int rc);
+static VBOXSTRICTRC emR3Debug(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rc);
static int emR3RemStep(PVM pVM, PVMCPU pVCpu);
static int emR3RemExecute(PVM pVM, PVMCPU pVCpu, bool *pfFFDone);
int emR3HighPriorityPostForcedActions(PVM pVM, PVMCPU pVCpu, int rc);
@@ -103,7 +99,7 @@ int emR3HighPriorityPostForcedActions(PVM pVM, PVMCPU pVCpu, int rc);
* @returns VBox status code.
* @param pVM Pointer to the VM.
*/
-VMMR3DECL(int) EMR3Init(PVM pVM)
+VMMR3_INT_DECL(int) EMR3Init(PVM pVM)
{
LogFlow(("EMR3Init\n"));
/*
@@ -117,12 +113,39 @@ VMMR3DECL(int) EMR3Init(PVM pVM)
* Init the structure.
*/
pVM->em.s.offVM = RT_OFFSETOF(VM, em.s);
+ PCFGMNODE pCfgRoot = CFGMR3GetRoot(pVM);
+ PCFGMNODE pCfgEM = CFGMR3GetChild(pCfgRoot, "EM");
+
bool fEnabled;
- int rc = CFGMR3QueryBool(CFGMR3GetRoot(pVM), "RawR3Enabled", &fEnabled);
- pVM->fRecompileUser = RT_SUCCESS(rc) ? !fEnabled : false;
- rc = CFGMR3QueryBool(CFGMR3GetRoot(pVM), "RawR0Enabled", &fEnabled);
- pVM->fRecompileSupervisor = RT_SUCCESS(rc) ? !fEnabled : false;
- Log(("EMR3Init: fRecompileUser=%RTbool fRecompileSupervisor=%RTbool\n", pVM->fRecompileUser, pVM->fRecompileSupervisor));
+ int rc = CFGMR3QueryBoolDef(pCfgRoot, "RawR3Enabled", &fEnabled, true);
+ AssertLogRelRCReturn(rc, rc);
+ pVM->fRecompileUser = !fEnabled;
+
+ rc = CFGMR3QueryBoolDef(pCfgRoot, "RawR0Enabled", &fEnabled, true);
+ AssertLogRelRCReturn(rc, rc);
+ pVM->fRecompileSupervisor = !fEnabled;
+
+#ifdef VBOX_WITH_RAW_RING1
+ rc = CFGMR3QueryBoolDef(pCfgRoot, "RawR1Enabled", &pVM->fRawRing1Enabled, false);
+ AssertLogRelRCReturn(rc, rc);
+#else
+ pVM->fRawRing1Enabled = false; /* Disabled by default. */
+#endif
+
+ rc = CFGMR3QueryBoolDef(pCfgEM, "IemExecutesAll", &pVM->em.s.fIemExecutesAll, false);
+ AssertLogRelRCReturn(rc, rc);
+
+ rc = CFGMR3QueryBoolDef(pCfgEM, "TripleFaultReset", &fEnabled, false);
+ AssertLogRelRCReturn(rc, rc);
+ pVM->em.s.fGuruOnTripleFault = !fEnabled;
+ if (!pVM->em.s.fGuruOnTripleFault && pVM->cCpus > 1)
+ {
+ LogRel(("EM: Overriding /EM/TripleFaultReset, must be false on SMP.\n"));
+ pVM->em.s.fGuruOnTripleFault = true;
+ }
+
+ 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
/*
@@ -147,15 +170,18 @@ VMMR3DECL(int) EMR3Init(PVM pVM)
{
PVMCPU pVCpu = &pVM->aCpus[i];
- pVCpu->em.s.offVMCPU = RT_OFFSETOF(VMCPU, em.s);
-
pVCpu->em.s.enmState = (i == 0) ? EMSTATE_NONE : EMSTATE_WAIT_SIPI;
pVCpu->em.s.enmPrevState = EMSTATE_NONE;
pVCpu->em.s.fForceRAW = false;
pVCpu->em.s.pCtx = CPUMQueryGuestCtxPtr(pVCpu);
- pVCpu->em.s.pPatmGCState = PATMR3QueryGCStateHC(pVM);
- AssertMsg(pVCpu->em.s.pPatmGCState, ("PATMR3QueryGCStateHC failed!\n"));
+#ifdef VBOX_WITH_RAW_MODE
+ if (!HMIsEnabled(pVM))
+ {
+ pVCpu->em.s.pPatmGCState = PATMR3QueryGCStateHC(pVM);
+ AssertMsg(pVCpu->em.s.pPatmGCState, ("PATMR3QueryGCStateHC failed!\n"));
+ }
+#endif
/* Force reset of the time slice. */
pVCpu->em.s.u64TimeSliceStart = 0;
@@ -267,6 +293,8 @@ VMMR3DECL(int) EMR3Init(PVM pVM)
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.");
@@ -321,6 +349,8 @@ VMMR3DECL(int) EMR3Init(PVM pVM)
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.");
@@ -356,11 +386,15 @@ VMMR3DECL(int) EMR3Init(PVM pVM)
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->StatCli, "/EM/CPU%d/R3/PrivInst/Cli", "Number of cli instructions.");
- EM_REG_COUNTER_USED(&pStats->StatSti, "/EM/CPU%d/R3/PrivInst/Sti", "Number of sli instructions.");
+ 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
EM_REG_COUNTER_USED(&pStats->StatIn, "/EM/CPU%d/R3/PrivInst/In", "Number of in instructions.");
EM_REG_COUNTER_USED(&pStats->StatOut, "/EM/CPU%d/R3/PrivInst/Out", "Number of out instructions.");
- EM_REG_COUNTER_USED(&pStats->StatIoRestarted, "/EM/CPU%d/R3/PrivInst/IoRestarted", "Number of restarted i/o instructions.");
+# endif
+ EM_REG_COUNTER_USED(&pStats->StatCli, "/EM/CPU%d/R3/PrivInst/Cli", "Number of cli instructions.");
+ EM_REG_COUNTER_USED(&pStats->StatSti, "/EM/CPU%d/R3/PrivInst/Sti", "Number of sli instructions.");
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.");
@@ -388,16 +422,18 @@ VMMR3DECL(int) EMR3Init(PVM pVM)
pVCpu->em.s.pCliStatTree = 0;
/* 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.StatHwAccEntry, "/PROF/CPU%d/EM/HwAccEnter", "Profiling Hardware Accelerated Mode entry overhead.");
- EM_REG_PROFILE(&pVCpu->em.s.StatHwAccExec, "/PROF/CPU%d/EM/HwAccExec", "Profiling Hardware Accelerated Mode execution.");
- EM_REG_PROFILE(&pVCpu->em.s.StatREMEmu, "/PROF/CPU%d/EM/REMEmuSingle", "Profiling single instruction REM execution.");
- EM_REG_PROFILE(&pVCpu->em.s.StatREMExec, "/PROF/CPU%d/EM/REMExec", "Profiling 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.");
+ 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.StatREMExec, "/PROF/CPU%d/EM/REMExec", "Profiling 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 */
@@ -410,6 +446,7 @@ VMMR3DECL(int) EMR3Init(PVM pVM)
EM_REG_PROFILE_ADV(&pVCpu->em.s.StatTotal, "/PROF/CPU%d/EM/Total", "Profiling EMR3ExecuteVM.");
}
+ emR3InitDbg(pVM);
return VINF_SUCCESS;
}
@@ -421,7 +458,7 @@ VMMR3DECL(int) EMR3Init(PVM pVM)
*
* @param pVM Pointer to the VM.
*/
-VMMR3DECL(void) EMR3Relocate(PVM pVM)
+VMMR3_INT_DECL(void) EMR3Relocate(PVM pVM)
{
LogFlow(("EMR3Relocate\n"));
for (VMCPUID i = 0; i < pVM->cCpus; i++)
@@ -440,7 +477,7 @@ VMMR3DECL(void) EMR3Relocate(PVM pVM)
*
* @param pVCpu Pointer to the VMCPU.
*/
-VMMR3DECL(void) EMR3ResetCpu(PVMCPU pVCpu)
+VMMR3_INT_DECL(void) EMR3ResetCpu(PVMCPU pVCpu)
{
pVCpu->em.s.fForceRAW = false;
@@ -460,7 +497,7 @@ VMMR3DECL(void) EMR3ResetCpu(PVMCPU pVCpu)
*
* @param pVM Pointer to the VM.
*/
-VMMR3DECL(void) EMR3Reset(PVM pVM)
+VMMR3_INT_DECL(void) EMR3Reset(PVM pVM)
{
Log(("EMR3Reset: \n"));
for (VMCPUID i = 0; i < pVM->cCpus; i++)
@@ -477,7 +514,7 @@ VMMR3DECL(void) EMR3Reset(PVM pVM)
* @returns VBox status code.
* @param pVM Pointer to the VM.
*/
-VMMR3DECL(int) EMR3Term(PVM pVM)
+VMMR3_INT_DECL(int) EMR3Term(PVM pVM)
{
AssertMsg(pVM->em.s.offVM, ("bad init order!\n"));
@@ -541,9 +578,8 @@ static DECLCALLBACK(int) emR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, u
/*
* Validate version.
*/
- if ( uVersion != EM_SAVED_STATE_VERSION
- && uVersion != EM_SAVED_STATE_VERSION_PRE_MWAIT
- && uVersion != EM_SAVED_STATE_VERSION_PRE_SMP)
+ if ( uVersion > EM_SAVED_STATE_VERSION
+ || uVersion < EM_SAVED_STATE_VERSION_PRE_SMP)
{
AssertMsgFailed(("emR3Load: Invalid version uVersion=%d (current %d)!\n", uVersion, EM_SAVED_STATE_VERSION));
return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
@@ -623,26 +659,31 @@ static DECLCALLBACK(VBOXSTRICTRC) emR3SetExecutionPolicy(PVM pVM, PVMCPU pVCpu,
case EMEXECPOLICY_RECOMPILE_RING3:
pVM->fRecompileUser = pArgs->fEnforce;
break;
+ case EMEXECPOLICY_IEM_ALL:
+ pVM->em.s.fIemExecutesAll = pArgs->fEnforce;
+ break;
default:
AssertFailedReturn(VERR_INVALID_PARAMETER);
}
- Log(("emR3SetExecutionPolicy: fRecompileUser=%RTbool fRecompileSupervisor=%RTbool\n",
- pVM->fRecompileUser, pVM->fRecompileSupervisor));
+ Log(("emR3SetExecutionPolicy: fRecompileUser=%RTbool fRecompileSupervisor=%RTbool fIemExecutesAll=%RTbool\n",
+ pVM->fRecompileUser, pVM->fRecompileSupervisor, pVM->em.s.fIemExecutesAll));
}
/*
- * Force rescheduling if in RAW, HWACCM or REM.
+ * Force rescheduling if in RAW, HM, IEM, or REM.
*/
return pVCpu->em.s.enmState == EMSTATE_RAW
- || pVCpu->em.s.enmState == EMSTATE_HWACC
+ || pVCpu->em.s.enmState == EMSTATE_HM
+ || pVCpu->em.s.enmState == EMSTATE_IEM
|| pVCpu->em.s.enmState == EMSTATE_REM
+ || pVCpu->em.s.enmState == EMSTATE_IEM_THEN_REM
? VINF_EM_RESCHEDULE
: VINF_SUCCESS;
}
/**
- * Changes a the execution scheduling policy.
+ * Changes an execution scheduling policy parameter.
*
* This is used to enable or disable raw-mode / hardware-virtualization
* execution of user and supervisor code.
@@ -651,17 +692,54 @@ static DECLCALLBACK(VBOXSTRICTRC) emR3SetExecutionPolicy(PVM pVM, PVMCPU pVCpu,
* @returns VINF_RESCHEDULE if a rescheduling might be required.
* @returns VERR_INVALID_PARAMETER on an invalid enmMode value.
*
- * @param pVM Pointer to the VM.
+ * @param pUVM The user mode VM handle.
* @param enmPolicy The scheduling policy to change.
* @param fEnforce Whether to enforce the policy or not.
*/
-VMMR3DECL(int) EMR3SetExecutionPolicy(PVM pVM, EMEXECPOLICY enmPolicy, bool fEnforce)
+VMMR3DECL(int) EMR3SetExecutionPolicy(PUVM pUVM, EMEXECPOLICY enmPolicy, bool fEnforce)
{
- VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
+ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
+ VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
AssertReturn(enmPolicy > EMEXECPOLICY_INVALID && enmPolicy < EMEXECPOLICY_END, VERR_INVALID_PARAMETER);
struct EMR3SETEXECPOLICYARGS Args = { enmPolicy, fEnforce };
- return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING, emR3SetExecutionPolicy, &Args);
+ 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.
+ */
+VMMR3DECL(int) EMR3QueryExecutionPolicy(PUVM pUVM, EMEXECPOLICY enmPolicy, bool *pfEnforced)
+{
+ AssertReturn(enmPolicy > EMEXECPOLICY_INVALID && enmPolicy < EMEXECPOLICY_END, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pfEnforced, VERR_INVALID_POINTER);
+ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
+ PVM pVM = pUVM->pVM;
+ VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
+
+ /* No need to bother EMTs with a query. */
+ switch (enmPolicy)
+ {
+ case EMEXECPOLICY_RECOMPILE_RING0:
+ *pfEnforced = pVM->fRecompileSupervisor;
+ break;
+ case EMEXECPOLICY_RECOMPILE_RING3:
+ *pfEnforced = pVM->fRecompileUser;
+ break;
+ case EMEXECPOLICY_IEM_ALL:
+ *pfEnforced = pVM->em.s.fIemExecutesAll;
+ break;
+ default:
+ AssertFailedReturn(VERR_INTERNAL_ERROR_2);
+ }
+
+ return VINF_SUCCESS;
}
@@ -695,16 +773,20 @@ static const char *emR3GetStateName(EMSTATE enmState)
{
case EMSTATE_NONE: return "EMSTATE_NONE";
case EMSTATE_RAW: return "EMSTATE_RAW";
- case EMSTATE_HWACC: return "EMSTATE_HWACC";
+ 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!";
}
}
@@ -719,30 +801,41 @@ static const char *emR3GetStateName(EMSTATE enmState)
* @param pVCpu Pointer to the VMCPU.
* @param rc Current EM VBox status code.
*/
-static int emR3Debug(PVM pVM, PVMCPU pVCpu, int rc)
+static VBOXSTRICTRC emR3Debug(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rc)
{
for (;;)
{
- Log(("emR3Debug: rc=%Rrc\n", rc));
- const int rcLast = rc;
+ Log(("emR3Debug: rc=%Rrc\n", VBOXSTRICTRC_VAL(rc)));
+ const VBOXSTRICTRC rcLast = rc;
/*
* Debug related RC.
*/
- switch (rc)
+ switch (VBOXSTRICTRC_VAL(rc))
{
/*
* Single step an instruction.
*/
case VINF_EM_DBG_STEP:
- if ( pVCpu->em.s.enmState == EMSTATE_DEBUG_GUEST_RAW
- || pVCpu->em.s.enmState == EMSTATE_DEBUG_HYPER
- || pVCpu->em.s.fForceRAW /* paranoia */)
+ if ( pVCpu->em.s.enmState == EMSTATE_DEBUG_GUEST_RAW
+ || pVCpu->em.s.enmState == EMSTATE_DEBUG_HYPER
+ || pVCpu->em.s.fForceRAW /* paranoia */)
+#ifdef VBOX_WITH_RAW_MODE
rc = emR3RawStep(pVM, pVCpu);
+#else
+ AssertLogRelMsgFailedStmt(("Bad EM state."), VERR_EM_INTERNAL_ERROR);
+#endif
+ else if (pVCpu->em.s.enmState == EMSTATE_DEBUG_GUEST_HM)
+ rc = EMR3HmSingleInstruction(pVM, pVCpu, 0 /*fFlags*/);
+#ifdef VBOX_WITH_REM
+ else if (pVCpu->em.s.enmState == EMSTATE_DEBUG_GUEST_REM)
+ rc = emR3RemStep(pVM, pVCpu);
+#endif
else
{
- Assert(pVCpu->em.s.enmState == EMSTATE_DEBUG_GUEST_REM);
- rc = emR3RemStep(pVM, pVCpu);
+ rc = IEMExecOne(pVCpu); /** @todo add dedicated interface... */
+ if (rc == VINF_SUCCESS || rc == VINF_EM_RESCHEDULE)
+ rc = VINF_EM_DBG_STEPPED;
}
break;
@@ -786,8 +879,11 @@ static int emR3Debug(PVM pVM, PVMCPU pVCpu, int rc)
break;
default: /** @todo don't use default for guru, but make special errors code! */
+ {
+ LogRel(("emR3Debug: rc=%Rrc\n", VBOXSTRICTRC_VAL(rc)));
rc = DBGFR3Event(pVM, DBGFEVENT_FATAL_ERROR);
break;
+ }
}
/*
@@ -795,7 +891,7 @@ static int emR3Debug(PVM pVM, PVMCPU pVCpu, int rc)
*/
do
{
- switch (rc)
+ switch (VBOXSTRICTRC_VAL(rc))
{
/*
* Continue the debugging loop.
@@ -822,9 +918,13 @@ static int emR3Debug(PVM pVM, PVMCPU pVCpu, int rc)
case VINF_EM_HALT:
if (pVCpu->em.s.enmState == EMSTATE_DEBUG_HYPER)
{
+#ifdef VBOX_WITH_RAW_MODE
rc = emR3RawResumeHyper(pVM, pVCpu);
if (rc != VINF_SUCCESS && RT_SUCCESS(rc))
continue;
+#else
+ AssertLogRelMsgFailedReturn(("Not implemented\n"), VERR_EM_INTERNAL_ERROR);
+#endif
}
if (rc == VINF_SUCCESS)
rc = VINF_EM_RESCHEDULE;
@@ -835,7 +935,7 @@ static int emR3Debug(PVM pVM, PVMCPU pVCpu, int rc)
* We'll simply turn the thing off since that's the easiest thing to do.
*/
case VERR_DBGF_NOT_ATTACHED:
- switch (rcLast)
+ switch (VBOXSTRICTRC_VAL(rcLast))
{
case VINF_EM_DBG_HYPER_STEPPED:
case VINF_EM_DBG_HYPER_BREAKPOINT:
@@ -879,13 +979,14 @@ static int emR3Debug(PVM pVM, PVMCPU pVCpu, int rc)
* The rest is unexpected, and will keep us here.
*/
default:
- AssertMsgFailed(("Unexpected rc %Rrc!\n", rc));
+ AssertMsgFailed(("Unexpected rc %Rrc!\n", VBOXSTRICTRC_VAL(rc)));
break;
}
} while (false);
} /* debug for ever */
}
+
/**
* Steps recompiled code.
*
@@ -897,7 +998,7 @@ static int emR3Debug(PVM pVM, PVMCPU pVCpu, int rc)
*/
static int emR3RemStep(PVM pVM, PVMCPU pVCpu)
{
- LogFlow(("emR3RemStep: cs:eip=%04x:%08x\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestEIP(pVCpu)));
+ Log3(("emR3RemStep: cs:eip=%04x:%08x\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestEIP(pVCpu)));
#ifdef VBOX_WITH_REM
EMRemLock(pVM);
@@ -917,7 +1018,7 @@ static int emR3RemStep(PVM pVM, PVMCPU pVCpu)
int rc = VBOXSTRICTRC_TODO(IEMExecOne(pVCpu)); NOREF(pVM);
#endif
- LogFlow(("emR3RemStep: returns %Rrc cs:eip=%04x:%08x\n", rc, CPUMGetGuestCS(pVCpu), CPUMGetGuestEIP(pVCpu)));
+ Log3(("emR3RemStep: returns %Rrc cs:eip=%04x:%08x\n", rc, CPUMGetGuestCS(pVCpu), CPUMGetGuestEIP(pVCpu)));
return rc;
}
@@ -972,7 +1073,7 @@ static int emR3RemExecute(PVM pVM, PVMCPU pVCpu, bool *pfFFDone)
STAM_REL_PROFILE_ADV_START(&pVCpu->em.s.StatREMTotal, a);
#if defined(VBOX_STRICT) && defined(DEBUG_bird)
- AssertMsg( VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL)
+ AssertMsg( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL)
|| !MMHyperIsInsideArea(pVM, CPUMGetGuestEIP(pVCpu)), /** @todo @bugref{1419} - get flat address. */
("cs:eip=%RX16:%RX32\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestEIP(pVCpu)));
#endif
@@ -1020,8 +1121,8 @@ static int emR3RemExecute(PVM pVM, PVMCPU pVCpu, bool *pfFFDone)
* 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_ISPENDING(pVM, VM_FF_REQUEST | VM_FF_PDM_QUEUES | VM_FF_DBGF | VM_FF_CHECK_VM_STATE | VM_FF_RESET)
- || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_TIMER | VMCPU_FF_REQUEST))
+ if ( VM_FF_IS_PENDING(pVM, VM_FF_REQUEST | VM_FF_PDM_QUEUES | VM_FF_DBGF | VM_FF_CHECK_VM_STATE | VM_FF_RESET)
+ || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TIMER | VMCPU_FF_REQUEST))
{
LogFlow(("emR3RemExecute: Skipping run, because FF is set. %#x\n", pVM->fGlobalForcedActions));
goto l_REMDoForcedActions;
@@ -1032,7 +1133,7 @@ static int emR3RemExecute(PVM pVM, PVMCPU pVCpu, bool *pfFFDone)
/*
* Execute REM.
*/
- if (RT_LIKELY(EMR3IsExecutionAllowed(pVM, pVCpu)))
+ if (RT_LIKELY(emR3IsExecutionAllowed(pVM, pVCpu)))
{
STAM_PROFILE_START(&pVCpu->em.s.StatREMExec, c);
#ifdef VBOX_WITH_REM
@@ -1055,8 +1156,8 @@ static int emR3RemExecute(PVM pVM, PVMCPU pVCpu, bool *pfFFDone)
* 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.
*/
- if ( VM_FF_ISPENDING(pVM, VM_FF_HIGH_PRIORITY_POST_MASK)
- || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_HIGH_PRIORITY_POST_MASK))
+ if ( VM_FF_IS_PENDING(pVM, VM_FF_HIGH_PRIORITY_POST_MASK)
+ || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HIGH_PRIORITY_POST_MASK))
{
#ifdef VBOX_WITH_REM
fInREMState = emR3RemExecuteSyncBack(pVM, pVCpu);
@@ -1092,9 +1193,11 @@ static int emR3RemExecute(PVM pVM, PVMCPU pVCpu, bool *pfFFDone)
#ifdef VBOX_HIGH_RES_TIMERS_HACK
TMTimerPollVoid(pVM, pVCpu);
#endif
- AssertCompile((VMCPU_FF_ALL_REM_MASK & ~(VMCPU_FF_CSAM_PENDING_ACTION | VMCPU_FF_CSAM_SCAN_PAGE)) & VMCPU_FF_TIMER);
- if ( VM_FF_ISPENDING(pVM, VM_FF_ALL_REM_MASK)
- || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_ALL_REM_MASK & ~(VMCPU_FF_CSAM_PENDING_ACTION | VMCPU_FF_CSAM_SCAN_PAGE)))
+ AssertCompile(VMCPU_FF_ALL_REM_MASK & VMCPU_FF_TIMER);
+ if ( VM_FF_IS_PENDING(pVM, VM_FF_ALL_REM_MASK)
+ || VMCPU_FF_IS_PENDING(pVCpu,
+ VMCPU_FF_ALL_REM_MASK
+ & VM_WHEN_RAW_MODE(~(VMCPU_FF_CSAM_PENDING_ACTION | VMCPU_FF_CSAM_SCAN_PAGE), UINT32_MAX)) )
{
l_REMDoForcedActions:
#ifdef VBOX_WITH_REM
@@ -1141,7 +1244,7 @@ int emR3SingleStepExecRem(PVM pVM, PVMCPU pVCpu, uint32_t cIterations)
for (uint32_t i = 0; i < cIterations; i++)
{
DBGFR3PrgStep(pVCpu);
- DBGFR3DisasInstrCurrentLog(pVCpu, "RSS: ");
+ DBGFR3_DISAS_INSTR_CUR_LOG(pVCpu, "RSS");
emR3RemStep(pVM, pVCpu);
if (emR3Reschedule(pVM, pVCpu, pVCpu->em.s.pCtx) != EMSTATE_REM)
break;
@@ -1156,6 +1259,68 @@ int emR3SingleStepExecRem(PVM pVM, PVMCPU pVCpu, uint32_t cIterations)
/**
+ * 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)
+ */
+static VBOXSTRICTRC emR3ExecuteIemThenRem(PVM pVM, PVMCPU pVCpu, bool *pfFFDone)
+{
+ LogFlow(("emR3ExecuteIemThenRem: %04x:%RGv\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu)));
+ *pfFFDone = false;
+
+ /*
+ * Execute in IEM for a while.
+ */
+ while (pVCpu->em.s.cIemThenRemInstructions < 1024)
+ {
+ VBOXSTRICTRC rcStrict = IEMExecLots(pVCpu);
+ if (rcStrict != VINF_SUCCESS)
+ {
+ if ( rcStrict == VERR_IEM_ASPECT_NOT_IMPLEMENTED
+ || rcStrict == VERR_IEM_INSTR_NOT_IMPLEMENTED)
+ break;
+
+ pVCpu->em.s.cIemThenRemInstructions++;
+ Log(("emR3ExecuteIemThenRem: returns %Rrc after %u instructions\n",
+ VBOXSTRICTRC_VAL(rcStrict), pVCpu->em.s.cIemThenRemInstructions));
+ return rcStrict;
+ }
+ pVCpu->em.s.cIemThenRemInstructions++;
+
+ EMSTATE enmNewState = emR3Reschedule(pVM, pVCpu, pVCpu->em.s.pCtx);
+ if (enmNewState != EMSTATE_REM && enmNewState != EMSTATE_IEM_THEN_REM)
+ {
+ LogFlow(("emR3ExecuteIemThenRem: -> %d (%s) after %u instructions\n",
+ enmNewState, emR3GetStateName(enmNewState), pVCpu->em.s.cIemThenRemInstructions));
+ pVCpu->em.s.enmPrevState = pVCpu->em.s.enmState;
+ pVCpu->em.s.enmState = enmNewState;
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Check for pending actions.
+ */
+ if ( VM_FF_IS_PENDING(pVM, VM_FF_ALL_REM_MASK)
+ || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_ALL_REM_MASK))
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Switch to REM.
+ */
+ Log(("emR3ExecuteIemThenRem: -> EMSTATE_REM (after %u instructions)\n", pVCpu->em.s.cIemThenRemInstructions));
+ pVCpu->em.s.enmState = EMSTATE_REM;
+ return VINF_SUCCESS;
+}
+
+
+/**
* Decides whether to execute RAW, HWACC or REM.
*
* @returns new EM state
@@ -1165,10 +1330,6 @@ int emR3SingleStepExecRem(PVM pVM, PVMCPU pVCpu, uint32_t cIterations)
*/
EMSTATE emR3Reschedule(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
{
-#ifdef IEM_VERIFICATION_MODE
- return EMSTATE_REM;
-#else
-
/*
* When forcing raw-mode execution, things are simple.
*/
@@ -1181,28 +1342,35 @@ EMSTATE emR3Reschedule(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
if (pVCpu->em.s.enmState == EMSTATE_WAIT_SIPI)
return EMSTATE_WAIT_SIPI;
+ /*
+ * Execute everything in IEM?
+ */
+ if (pVM->em.s.fIemExecutesAll)
+ return EMSTATE_IEM;
+
/* !!! THIS MUST BE IN SYNC WITH remR3CanExecuteRaw !!! */
/* !!! THIS MUST BE IN SYNC WITH remR3CanExecuteRaw !!! */
/* !!! THIS MUST BE IN SYNC WITH remR3CanExecuteRaw !!! */
X86EFLAGS EFlags = pCtx->eflags;
- if (HWACCMIsEnabled(pVM))
+ if (HMIsEnabled(pVM))
{
/*
* Hardware accelerated raw-mode:
- *
- * Typically only 32-bits protected mode, with paging enabled, code is
- * allowed here.
*/
if ( EMIsHwVirtExecutionEnabled(pVM)
- && HWACCMR3CanExecuteGuest(pVM, pCtx))
- return EMSTATE_HWACC;
+ && HMR3CanExecuteGuest(pVM, pCtx))
+ 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
}
/*
@@ -1267,8 +1435,17 @@ EMSTATE emR3Reschedule(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
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. */
+ {
+ Log2(("raw r0 mode refused: CPL %d\n", uSS & X86_SEL_RPL));
+ return EMSTATE_REM;
+ }
+ }
/* Only ring 0 supervisor code. */
- if ((uSS & X86_SEL_RPL) != 0)
+ else if ((uSS & X86_SEL_RPL) != 0)
{
Log2(("raw r0 mode refused: CPL %d\n", uSS & X86_SEL_RPL));
return EMSTATE_REM;
@@ -1290,11 +1467,16 @@ EMSTATE emR3Reschedule(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
return EMSTATE_REM;
}
+# ifdef VBOX_WITH_RAW_MODE
if (PATMShouldUseRawMode(pVM, (RTGCPTR)pCtx->eip))
{
Log2(("raw r0 mode forced: patch code\n"));
+# ifdef VBOX_WITH_SAFE_STR
+ Assert(pCtx->tr.Sel);
+# endif
return EMSTATE_RAW;
}
+# endif /* VBOX_WITH_RAW_MODE */
# if !defined(VBOX_ALLOW_IF0) && !defined(VBOX_RUN_INTERRUPT_GATE_HANDLERS)
if (!(EFlags.u32 & X86_EFL_IF))
@@ -1305,12 +1487,14 @@ EMSTATE emR3Reschedule(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
}
# endif
+# ifndef VBOX_WITH_RAW_RING1
/** @todo still necessary??? */
if (EFlags.Bits.u2IOPL != 0)
{
Log2(("raw r0 mode refused: IOPL %d\n", EFlags.Bits.u2IOPL));
return EMSTATE_REM;
}
+# endif
}
/*
@@ -1347,10 +1531,16 @@ EMSTATE emR3Reschedule(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
return EMSTATE_REM;
}
+# ifdef VBOX_WITH_SAFE_STR
+ if (pCtx->tr.Sel == 0)
+ {
+ Log(("Raw mode refused -> TR=0\n"));
+ return EMSTATE_REM;
+ }
+# endif
+
/*Assert(PGMPhysIsA20Enabled(pVCpu));*/
return EMSTATE_RAW;
-#endif /* !IEM_VERIFICATION_MODE */
-
}
@@ -1367,13 +1557,39 @@ int emR3HighPriorityPostForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
{
VBOXVMM_EM_FF_HIGH(pVCpu, pVM->fGlobalForcedActions, pVCpu->fLocalForcedActions, rc);
- if (VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_PDM_CRITSECT))
- PDMCritSectFF(pVCpu);
+ if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_PDM_CRITSECT))
+ PDMCritSectBothFF(pVCpu);
+
+ /* Update CR3 (Nested Paging case for HM). */
+ if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
+ {
+ int rc2 = PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
+ if (RT_FAILURE(rc2))
+ return rc2;
+ Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
+ }
- if (VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_CSAM_PENDING_ACTION))
+ /* Update PAE PDPEs. This must be done *after* PGMUpdateCR3() and used only by the Nested Paging case for HM. */
+ if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
+ {
+ if (CPUMIsGuestInPAEMode(pVCpu))
+ {
+ PX86PDPE pPdpes = HMGetPaePdpes(pVCpu);
+ AssertPtr(pPdpes);
+
+ PGMGstUpdatePaePdpes(pVCpu, pPdpes);
+ Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
+ }
+ else
+ VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
+ }
+
+#ifdef VBOX_WITH_RAW_MODE
+ if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_CSAM_PENDING_ACTION))
CSAMR3DoPendingAction(pVM, pVCpu);
+#endif
- if (VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY))
+ if (VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY))
{
if ( rc > VINF_EM_NO_MEMORY
&& rc <= VINF_EM_LAST)
@@ -1423,13 +1639,13 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
/*
* Post execution chunk first.
*/
- if ( VM_FF_ISPENDING(pVM, VM_FF_NORMAL_PRIORITY_POST_MASK)
- || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_NORMAL_PRIORITY_POST_MASK))
+ if ( VM_FF_IS_PENDING(pVM, VM_FF_NORMAL_PRIORITY_POST_MASK)
+ || (VMCPU_FF_NORMAL_PRIORITY_POST_MASK && VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_NORMAL_PRIORITY_POST_MASK)) )
{
/*
* EMT Rendezvous (must be serviced before termination).
*/
- if (VM_FF_ISPENDING(pVM, VM_FF_EMT_RENDEZVOUS))
+ if (VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS))
{
rc2 = VMMR3EmtRendezvousFF(pVM, pVCpu);
UPDATE_RC();
@@ -1449,7 +1665,7 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
/*
* State change request (cleared by vmR3SetStateLocked).
*/
- if (VM_FF_ISPENDING(pVM, VM_FF_CHECK_VM_STATE))
+ if (VM_FF_IS_PENDING(pVM, VM_FF_CHECK_VM_STATE))
{
VMSTATE enmState = VMR3GetState(pVM);
switch (enmState)
@@ -1473,7 +1689,7 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
/*
* Debugger Facility polling.
*/
- if (VM_FF_ISPENDING(pVM, VM_FF_DBGF))
+ if (VM_FF_IS_PENDING(pVM, VM_FF_DBGF))
{
rc2 = DBGFR3VMMForcedAction(pVM);
UPDATE_RC();
@@ -1482,17 +1698,18 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
/*
* Postponed reset request.
*/
- if (VM_FF_TESTANDCLEAR(pVM, VM_FF_RESET))
+ if (VM_FF_TEST_AND_CLEAR(pVM, VM_FF_RESET))
{
- rc2 = VMR3Reset(pVM);
+ rc2 = VMR3Reset(pVM->pUVM);
UPDATE_RC();
}
+#ifdef VBOX_WITH_RAW_MODE
/*
* CSAM page scanning.
*/
- if ( !VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY)
- && VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_CSAM_SCAN_PAGE))
+ if ( !VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY)
+ && VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_CSAM_SCAN_PAGE))
{
PCPUMCTX pCtx = pVCpu->em.s.pCtx;
@@ -1502,11 +1719,12 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
CSAMR3CheckCodeEx(pVM, CPUMCTX2CORE(pCtx), pCtx->eip);
VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_CSAM_SCAN_PAGE);
}
+#endif
/*
* Out of memory? Putting this after CSAM as it may in theory cause us to run out of memory.
*/
- if (VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY))
+ if (VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY))
{
rc2 = PGMR3PhysAllocateHandyPages(pVM);
UPDATE_RC();
@@ -1516,7 +1734,7 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int 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));
- AssertCompile(VMCPU_FF_NORMAL_PRIORITY_POST_MASK == VMCPU_FF_CSAM_SCAN_PAGE);
+ AssertCompile(VMCPU_FF_NORMAL_PRIORITY_POST_MASK == VM_WHEN_RAW_MODE(VMCPU_FF_CSAM_SCAN_PAGE, 0));
}
/*
@@ -1540,7 +1758,7 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
/*
* EMT Rendezvous (make sure they are handled before the requests).
*/
- if (VM_FF_ISPENDING(pVM, VM_FF_EMT_RENDEZVOUS))
+ if (VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS))
{
rc2 = VMMR3EmtRendezvousFF(pVM, pVCpu);
UPDATE_RC();
@@ -1590,7 +1808,7 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
/* Try not to cause deadlocks. */
if ( pVM->cCpus == 1
|| ( !PGMIsLockOwner(pVM)
- && !IOMIsLockOwner(pVM))
+ && !IOMIsLockWriteOwner(pVM))
)
{
EMRemLock(pVM);
@@ -1608,13 +1826,13 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
* Normal priority then. (per-VCPU)
* (Executed in no particular order.)
*/
- if ( !VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY)
- && VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_NORMAL_PRIORITY_MASK))
+ if ( !VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY)
+ && VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_NORMAL_PRIORITY_MASK))
{
/*
* Requests from other threads.
*/
- if (VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_REQUEST))
+ if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_REQUEST))
{
rc2 = VMR3ReqProcessU(pVM->pUVM, pVCpu->idCpu, false /*fPriorityOnly*/);
if (rc2 == VINF_EM_OFF || rc2 == VINF_EM_TERMINATE || rc2 == VINF_EM_RESET)
@@ -1645,14 +1863,14 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
* High priority pre execution chunk last.
* (Executed in ascending priority order.)
*/
- if ( VM_FF_ISPENDING(pVM, VM_FF_HIGH_PRIORITY_PRE_MASK)
- || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_HIGH_PRIORITY_PRE_MASK))
+ if ( VM_FF_IS_PENDING(pVM, VM_FF_HIGH_PRIORITY_PRE_MASK)
+ || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HIGH_PRIORITY_PRE_MASK))
{
/*
* Timers before interrupts.
*/
- if ( VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_TIMER)
- && !VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY))
+ if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TIMER)
+ && !VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY))
TMR3TimerQueuesDo(pVM);
/*
@@ -1667,8 +1885,8 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
* unlikely, but such timing sensitive problem are not as rare as
* you might think.
*/
- if ( VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
- && !VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY))
+ if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
+ && !VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY))
{
if (CPUMGetGuestRIP(pVCpu) != EMGetInhibitInterruptsPC(pVCpu))
{
@@ -1683,19 +1901,25 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
* Interrupts.
*/
bool fWakeupPending = false;
- if ( !VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY)
- && !VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
- && (!rc || rc >= VINF_EM_RESCHEDULE_HWACC)
+ if ( !VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY)
+ && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
+ && (!rc || rc >= VINF_EM_RESCHEDULE_HM)
&& !TRPMHasTrap(pVCpu) /* an interrupt could already be scheduled for dispatching in the recompiler. */
+#ifdef VBOX_WITH_RAW_MODE
&& PATMAreInterruptsEnabled(pVM)
- && !HWACCMR3IsEventPending(pVCpu))
+#else
+ && (pVCpu->em.s.pCtx->eflags.u32 & X86_EFL_IF)
+#endif
+ && !HMR3IsEventPending(pVCpu))
{
Assert(pVCpu->em.s.enmState != EMSTATE_WAIT_SIPI);
- if (VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
+ if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
{
/* 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 */
rc2 = TRPMR3InjectEvent(pVM, pVCpu, TRPM_HARDWARE_INT);
+ if (pVM->em.s.fIemExecutesAll && (rc2 == VINF_EM_RESCHEDULE_REM || rc2 == VINF_EM_RESCHEDULE_HM || rc2 == VINF_EM_RESCHEDULE_RAW))
+ rc2 = VINF_EM_RESCHEDULE;
#ifdef VBOX_STRICT
rcIrq = rc2;
#endif
@@ -1707,6 +1931,7 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
/** @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. */
else if (REMR3QueryPendingInterrupt(pVM, pVCpu) != REM_NO_PENDING_IRQ)
{
+ Log2(("REMR3QueryPendingInterrupt -> %#x\n", REMR3QueryPendingInterrupt(pVM, pVCpu)));
rc2 = VINF_EM_RESCHEDULE_REM;
UPDATE_RC();
}
@@ -1735,7 +1960,7 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
* EMT Rendezvous (must be serviced before termination).
*/
if ( !fWakeupPending /* don't miss the wakeup from EMSTATE_HALTED! */
- && VM_FF_ISPENDING(pVM, VM_FF_EMT_RENDEZVOUS))
+ && VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS))
{
rc2 = VMMR3EmtRendezvousFF(pVM, pVCpu);
UPDATE_RC();
@@ -1755,7 +1980,7 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
* State change request (cleared by vmR3SetStateLocked).
*/
if ( !fWakeupPending /* don't miss the wakeup from EMSTATE_HALTED! */
- && VM_FF_ISPENDING(pVM, VM_FF_CHECK_VM_STATE))
+ && VM_FF_IS_PENDING(pVM, VM_FF_CHECK_VM_STATE))
{
VMSTATE enmState = VMR3GetState(pVM);
switch (enmState)
@@ -1782,7 +2007,7 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
* at the end rather than the start. Also, VM_FF_TERMINATE has higher priority
* than us since we can terminate without allocating more memory.
*/
- if (VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY))
+ if (VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY))
{
rc2 = PGMR3PhysAllocateHandyPages(pVM);
UPDATE_RC();
@@ -1793,14 +2018,14 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
/*
* If the virtual sync clock is still stopped, make TM restart it.
*/
- if (VM_FF_ISPENDING(pVM, VM_FF_TM_VIRTUAL_SYNC))
+ if (VM_FF_IS_PENDING(pVM, VM_FF_TM_VIRTUAL_SYNC))
TMR3VirtualSyncFF(pVM, pVCpu);
#ifdef DEBUG
/*
* Debug, pause the VM.
*/
- if (VM_FF_ISPENDING(pVM, VM_FF_DEBUG_SUSPEND))
+ if (VM_FF_IS_PENDING(pVM, VM_FF_DEBUG_SUSPEND))
{
VM_FF_CLEAR(pVM, VM_FF_DEBUG_SUSPEND);
Log(("emR3ForcedActions: returns VINF_EM_SUSPEND\n"));
@@ -1810,7 +2035,7 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
/* 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_SELM_SYNC_TSS | VMCPU_FF_TRPM_SYNC_IDT | VMCPU_FF_SELM_SYNC_GDT | VMCPU_FF_SELM_SYNC_LDT | VMCPU_FF_INHIBIT_INTERRUPTS));
+ 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)));
}
#undef UPDATE_RC
@@ -1827,9 +2052,8 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
* @returns true if allowed, false otherwise
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
- *
*/
-VMMR3DECL(bool) EMR3IsExecutionAllowed(PVM pVM, PVMCPU pVCpu)
+bool emR3IsExecutionAllowed(PVM pVM, PVMCPU pVCpu)
{
uint64_t u64UserTime, u64KernelTime;
@@ -1871,7 +2095,7 @@ VMMR3DECL(bool) EMR3IsExecutionAllowed(PVM pVM, PVMCPU pVCpu)
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
*/
-VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
+VMMR3_INT_DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
{
Log(("EMR3ExecuteVM: pVM=%p enmVMState=%d (%s) enmState=%d (%s) enmPrevState=%d (%s) fForceRAW=%RTbool\n",
pVM,
@@ -1909,6 +2133,8 @@ VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
pVCpu->em.s.enmState = pVCpu->em.s.enmPrevState;
else
pVCpu->em.s.enmState = emR3Reschedule(pVM, pVCpu, pVCpu->em.s.pCtx);
+ pVCpu->em.s.cIemThenRemInstructions = 0;
+ Log(("EMR3ExecuteVM: enmState=%s\n", emR3GetStateName(pVCpu->em.s.enmState)));
STAM_REL_PROFILE_ADV_START(&pVCpu->em.s.StatTotal, x);
for (;;)
@@ -1922,15 +2148,16 @@ VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
* Do forced actions.
*/
if ( !fFFDone
+ && RT_SUCCESS(rc)
&& rc != VINF_EM_TERMINATE
&& rc != VINF_EM_OFF
- && ( VM_FF_ISPENDING(pVM, VM_FF_ALL_REM_MASK)
- || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_ALL_REM_MASK)))
+ && ( VM_FF_IS_PENDING(pVM, VM_FF_ALL_REM_MASK)
+ || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_ALL_REM_MASK)))
{
rc = emR3ForcedActions(pVM, pVCpu, rc);
VBOXVMM_EM_FF_ALL_RET(pVCpu, rc);
if ( ( rc == VINF_EM_RESCHEDULE_REM
- || rc == VINF_EM_RESCHEDULE_HWACC)
+ || rc == VINF_EM_RESCHEDULE_HM)
&& pVCpu->em.s.fForceRAW)
rc = VINF_EM_RESCHEDULE_RAW;
}
@@ -1955,24 +2182,46 @@ VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
*/
case VINF_EM_RESCHEDULE_RAW:
Log2(("EMR3ExecuteVM: VINF_EM_RESCHEDULE_RAW: %d -> %d (EMSTATE_RAW)\n", enmOldState, EMSTATE_RAW));
+ Assert(!pVM->em.s.fIemExecutesAll || pVCpu->em.s.enmState != EMSTATE_IEM);
pVCpu->em.s.enmState = EMSTATE_RAW;
break;
/*
* Reschedule - to hardware accelerated raw-mode execution.
*/
- case VINF_EM_RESCHEDULE_HWACC:
- Log2(("EMR3ExecuteVM: VINF_EM_RESCHEDULE_HWACC: %d -> %d (EMSTATE_HWACC)\n", enmOldState, EMSTATE_HWACC));
+ case VINF_EM_RESCHEDULE_HM:
+ Log2(("EMR3ExecuteVM: VINF_EM_RESCHEDULE_HM: %d -> %d (EMSTATE_HM)\n", enmOldState, EMSTATE_HM));
+ Assert(!pVM->em.s.fIemExecutesAll || pVCpu->em.s.enmState != EMSTATE_IEM);
Assert(!pVCpu->em.s.fForceRAW);
- pVCpu->em.s.enmState = EMSTATE_HWACC;
+ pVCpu->em.s.enmState = EMSTATE_HM;
break;
/*
* Reschedule - to recompiled execution.
*/
case VINF_EM_RESCHEDULE_REM:
+#ifdef VBOX_WITH_FIRST_IEM_STEP
+ Assert(!pVM->em.s.fIemExecutesAll || pVCpu->em.s.enmState != EMSTATE_IEM);
+ if (HMIsEnabled(pVM))
+ {
+ Log2(("EMR3ExecuteVM: VINF_EM_RESCHEDULE_REM: %d -> %d (EMSTATE_IEM_THEN_REM)\n",
+ enmOldState, EMSTATE_IEM_THEN_REM));
+ if (pVCpu->em.s.enmState != EMSTATE_IEM_THEN_REM)
+ {
+ pVCpu->em.s.enmState = EMSTATE_IEM_THEN_REM;
+ pVCpu->em.s.cIemThenRemInstructions = 0;
+ }
+ }
+ else
+ {
+ Log2(("EMR3ExecuteVM: VINF_EM_RESCHEDULE_REM: %d -> %d (EMSTATE_REM)\n", enmOldState, EMSTATE_REM));
+ pVCpu->em.s.enmState = EMSTATE_REM;
+ }
+#else
Log2(("EMR3ExecuteVM: VINF_EM_RESCHEDULE_REM: %d -> %d (EMSTATE_REM)\n", enmOldState, EMSTATE_REM));
+ Assert(!pVM->em.s.fIemExecutesAll || pVCpu->em.s.enmState != EMSTATE_IEM);
pVCpu->em.s.enmState = EMSTATE_REM;
+#endif
break;
/*
@@ -1996,6 +2245,8 @@ VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
{
EMSTATE enmState = emR3Reschedule(pVM, pVCpu, pVCpu->em.s.pCtx);
Log2(("EMR3ExecuteVM: VINF_EM_RESCHEDULE: %d -> %d (%s)\n", enmOldState, enmState, emR3GetStateName(enmState)));
+ if (pVCpu->em.s.enmState != enmState && enmState == EMSTATE_IEM_THEN_REM)
+ pVCpu->em.s.cIemThenRemInstructions = 0;
pVCpu->em.s.enmState = enmState;
break;
}
@@ -2038,6 +2289,8 @@ VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
{
EMSTATE enmState = emR3Reschedule(pVM, pVCpu, pVCpu->em.s.pCtx);
Log2(("EMR3ExecuteVM: VINF_EM_RESET: %d -> %d (%s)\n", enmOldState, enmState, emR3GetStateName(enmState)));
+ if (pVCpu->em.s.enmState != enmState && enmState == EMSTATE_IEM_THEN_REM)
+ pVCpu->em.s.cIemThenRemInstructions = 0;
pVCpu->em.s.enmState = enmState;
}
else
@@ -2098,7 +2351,6 @@ VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
* Guest debug events.
*/
case VINF_EM_DBG_STEPPED:
- AssertMsgFailed(("VINF_EM_DBG_STEPPED cannot be here!"));
case VINF_EM_DBG_STOP:
case VINF_EM_DBG_BREAKPOINT:
case VINF_EM_DBG_STEP:
@@ -2107,11 +2359,21 @@ VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
Log2(("EMR3ExecuteVM: %Rrc: %d -> %d\n", rc, enmOldState, EMSTATE_DEBUG_GUEST_RAW));
pVCpu->em.s.enmState = EMSTATE_DEBUG_GUEST_RAW;
}
- else
+ else if (enmOldState == EMSTATE_HM)
+ {
+ Log2(("EMR3ExecuteVM: %Rrc: %d -> %d\n", rc, enmOldState, EMSTATE_DEBUG_GUEST_HM));
+ pVCpu->em.s.enmState = EMSTATE_DEBUG_GUEST_HM;
+ }
+ else if (enmOldState == EMSTATE_REM)
{
Log2(("EMR3ExecuteVM: %Rrc: %d -> %d\n", rc, enmOldState, EMSTATE_DEBUG_GUEST_REM));
pVCpu->em.s.enmState = EMSTATE_DEBUG_GUEST_REM;
}
+ else
+ {
+ Log2(("EMR3ExecuteVM: %Rrc: %d -> %d\n", rc, enmOldState, EMSTATE_DEBUG_GUEST_IEM));
+ pVCpu->em.s.enmState = EMSTATE_DEBUG_GUEST_IEM;
+ }
break;
/*
@@ -2127,6 +2389,22 @@ VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
/*
* Guru mediations.
*/
+ case VINF_EM_TRIPLE_FAULT:
+ if (!pVM->em.s.fGuruOnTripleFault)
+ {
+ Log(("EMR3ExecuteVM: VINF_EM_TRIPLE_FAULT: CPU reset...\n"));
+ Assert(pVM->cCpus == 1);
+ REMR3Reset(pVM);
+ PGMR3ResetCpu(pVM, pVCpu);
+ TRPMR3ResetCpu(pVCpu);
+ CPUMR3ResetCpu(pVM, pVCpu);
+ EMR3ResetCpu(pVCpu);
+ HMR3ResetCpu(pVCpu);
+ pVCpu->em.s.enmState = emR3Reschedule(pVM, pVCpu, pVCpu->em.s.pCtx);
+ Log2(("EMR3ExecuteVM: VINF_EM_TRIPLE_FAULT: %d -> %d\n", rc, enmOldState, pVCpu->em.s.enmState));
+ 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));
pVCpu->em.s.enmState = EMSTATE_GURU_MEDITATION;
@@ -2162,10 +2440,12 @@ VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
if ( enmOldState == EMSTATE_HALTED
&& (pVCpu->em.s.MWait.fWait & EMMWAIT_FLAG_ACTIVE)
&& ( enmNewState == EMSTATE_RAW
- || enmNewState == EMSTATE_HWACC
+ || enmNewState == EMSTATE_HM
|| enmNewState == EMSTATE_REM
+ || enmNewState == EMSTATE_IEM_THEN_REM
|| enmNewState == EMSTATE_DEBUG_GUEST_RAW
- || enmNewState == EMSTATE_DEBUG_GUEST_HWACC
+ || enmNewState == EMSTATE_DEBUG_GUEST_HM
+ || enmNewState == EMSTATE_DEBUG_GUEST_IEM
|| enmNewState == EMSTATE_DEBUG_GUEST_REM) )
{
LogFlow(("EMR3ExecuteVM: Clearing MWAIT\n"));
@@ -2187,39 +2467,66 @@ VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
* Execute raw.
*/
case EMSTATE_RAW:
-#ifndef IEM_VERIFICATION_MODE /* remove later */
+#ifdef VBOX_WITH_RAW_MODE
rc = emR3RawExecute(pVM, pVCpu, &fFFDone);
- break;
+#else
+ AssertLogRelMsgFailed(("%Rrc\n", rc));
+ rc = VERR_EM_INTERNAL_ERROR;
#endif
+ break;
/*
* Execute hardware accelerated raw.
*/
- case EMSTATE_HWACC:
-#ifndef IEM_VERIFICATION_MODE /* remove later */
- rc = emR3HwAccExecute(pVM, pVCpu, &fFFDone);
+ case EMSTATE_HM:
+ rc = emR3HmExecute(pVM, pVCpu, &fFFDone);
break;
-#endif
/*
* Execute recompiled.
*/
case EMSTATE_REM:
-#ifdef IEM_VERIFICATION_MODE
-# if 1
- rc = VBOXSTRICTRC_TODO(IEMExecOne(pVCpu)); fFFDone = false;
-# else
- rc = VBOXSTRICTRC_TODO(REMR3EmulateInstruction(pVM, pVCpu)); fFFDone = false;
- if (rc == VINF_EM_RESCHEDULE)
- rc = VINF_SUCCESS;
-# endif
-#else
rc = emR3RemExecute(pVM, pVCpu, &fFFDone);
-#endif
Log2(("EMR3ExecuteVM: emR3RemExecute -> %Rrc\n", rc));
break;
/*
+ * Execute in the interpreter.
+ */
+ case EMSTATE_IEM:
+ {
+#if 0 /* For testing purposes. */
+ STAM_PROFILE_START(&pVCpu->em.s.StatHmExec, x1);
+ rc = VBOXSTRICTRC_TODO(EMR3HmSingleInstruction(pVM, pVCpu, EM_ONE_INS_FLAGS_RIP_CHANGE));
+ STAM_PROFILE_STOP(&pVCpu->em.s.StatHmExec, x1);
+ 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
+ rc = VBOXSTRICTRC_TODO(IEMExecLots(pVCpu));
+ if (pVM->em.s.fIemExecutesAll)
+ {
+ Assert(rc != VINF_EM_RESCHEDULE_REM);
+ Assert(rc != VINF_EM_RESCHEDULE_RAW);
+ Assert(rc != VINF_EM_RESCHEDULE_HM);
+ }
+ 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:
+ {
+ STAM_PROFILE_START(&pVCpu->em.s.StatIEMThenREM, pIemThenRem);
+ rc = VBOXSTRICTRC_TODO(emR3ExecuteIemThenRem(pVM, pVCpu, &fFFDone));
+ STAM_PROFILE_STOP(&pVCpu->em.s.StatIEMThenREM, pIemThenRem);
+ break;
+ }
+
+ /*
* Application processor execution halted until SIPI.
*/
case EMSTATE_WAIT_SIPI:
@@ -2230,14 +2537,20 @@ VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
case EMSTATE_HALTED:
{
STAM_REL_PROFILE_START(&pVCpu->em.s.StatHalted, y);
+ /* 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))
+ rc = VINF_EM_RESCHEDULE;
/* MWAIT has a special extension where it's woken up when
an interrupt is pending even when IF=0. */
- if ( (pVCpu->em.s.MWait.fWait & (EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0))
- == (EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0))
+ else if ( (pVCpu->em.s.MWait.fWait & (EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0))
+ == (EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0))
{
rc = VMR3WaitHalted(pVM, pVCpu, false /*fIgnoreInterrupts*/);
if ( rc == VINF_SUCCESS
- && VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
+ && VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
{
Log(("EMR3ExecuteVM: Triggering reschedule on pending IRQ after MWAIT\n"));
rc = VINF_EM_RESCHEDULE;
@@ -2262,12 +2575,14 @@ VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
/*
* Debugging in the guest.
*/
- case EMSTATE_DEBUG_GUEST_REM:
case EMSTATE_DEBUG_GUEST_RAW:
+ case EMSTATE_DEBUG_GUEST_HM:
+ case EMSTATE_DEBUG_GUEST_IEM:
+ case EMSTATE_DEBUG_GUEST_REM:
TMR3NotifySuspend(pVM, pVCpu);
- rc = emR3Debug(pVM, pVCpu, rc);
+ rc = VBOXSTRICTRC_TODO(emR3Debug(pVM, pVCpu, rc));
TMR3NotifyResume(pVM, pVCpu);
- Log2(("EMR3ExecuteVM: enmr3Debug -> %Rrc (state %d)\n", rc, pVCpu->em.s.enmState));
+ Log2(("EMR3ExecuteVM: emR3Debug -> %Rrc (state %d)\n", rc, pVCpu->em.s.enmState));
break;
/*
@@ -2278,13 +2593,18 @@ VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
TMR3NotifySuspend(pVM, pVCpu);
STAM_REL_PROFILE_ADV_STOP(&pVCpu->em.s.StatTotal, x);
- rc = emR3Debug(pVM, pVCpu, rc);
- Log2(("EMR3ExecuteVM: enmr3Debug -> %Rrc (state %d)\n", rc, pVCpu->em.s.enmState));
+ rc = VBOXSTRICTRC_TODO(emR3Debug(pVM, pVCpu, rc));
+ Log2(("EMR3ExecuteVM: emR3Debug -> %Rrc (state %d)\n", rc, pVCpu->em.s.enmState));
if (rc != VINF_SUCCESS)
{
- /* switch to guru meditation mode */
- pVCpu->em.s.enmState = EMSTATE_GURU_MEDITATION;
- VMMR3FatalDump(pVM, pVCpu, rc);
+ if (rc == VINF_EM_OFF || rc == VINF_EM_TERMINATE)
+ pVCpu->em.s.enmState = EMSTATE_TERMINATING;
+ else
+ {
+ /* switch to guru meditation mode */
+ pVCpu->em.s.enmState = EMSTATE_GURU_MEDITATION;
+ VMMR3FatalDump(pVM, pVCpu, rc);
+ }
Log(("EMR3ExecuteVM: actually returns %Rrc (state %s / %s)\n", rc, emR3GetStateName(pVCpu->em.s.enmState), emR3GetStateName(enmOldState)));
return rc;
}
@@ -2345,7 +2665,7 @@ VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
*
* @param pVM Pointer to the VM.
*/
-VMMR3DECL(int) EMR3NotifySuspend(PVM pVM)
+VMMR3_INT_DECL(int) EMR3NotifySuspend(PVM pVM)
{
PVMCPU pVCpu = VMMGetCpu(pVM);
@@ -2360,7 +2680,7 @@ VMMR3DECL(int) EMR3NotifySuspend(PVM pVM)
*
* @param pVM Pointer to the VM.
*/
-VMMR3DECL(int) EMR3NotifyResume(PVM pVM)
+VMMR3_INT_DECL(int) EMR3NotifyResume(PVM pVM)
{
PVMCPU pVCpu = VMMGetCpu(pVM);
EMSTATE enmCurState = pVCpu->em.s.enmState;