diff options
Diffstat (limited to 'src/VBox/VMM/VMMAll/EMAll.cpp')
| -rw-r--r-- | src/VBox/VMM/VMMAll/EMAll.cpp | 725 |
1 files changed, 396 insertions, 329 deletions
diff --git a/src/VBox/VMM/VMMAll/EMAll.cpp b/src/VBox/VMM/VMMAll/EMAll.cpp index 565aacab..4c4a595b 100644 --- a/src/VBox/VMM/VMMAll/EMAll.cpp +++ b/src/VBox/VMM/VMMAll/EMAll.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 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; @@ -33,7 +33,7 @@ #include "EMInternal.h" #include <VBox/vmm/vm.h> #include <VBox/vmm/vmm.h> -#include <VBox/vmm/hwaccm.h> +#include <VBox/vmm/hm.h> #include <VBox/vmm/tm.h> #include <VBox/vmm/pdmapi.h> #include <VBox/param.h> @@ -55,6 +55,11 @@ //# define VBOX_COMPARE_IEM_LAST #endif +#ifdef VBOX_WITH_RAW_RING1 +# define EM_EMULATE_SMSW +#endif + + /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ @@ -117,7 +122,7 @@ static size_t g_cbIemWrote; * @returns Current status. * @param pVCpu Pointer to the VMCPU. */ -VMMDECL(EMSTATE) EMGetState(PVMCPU pVCpu) +VMM_INT_DECL(EMSTATE) EMGetState(PVMCPU pVCpu) { return pVCpu->em.s.enmState; } @@ -127,7 +132,7 @@ VMMDECL(EMSTATE) EMGetState(PVMCPU pVCpu) * * @param pVCpu Pointer to the VMCPU. */ -VMMDECL(void) EMSetState(PVMCPU pVCpu, EMSTATE enmNewState) +VMM_INT_DECL(void) EMSetState(PVMCPU pVCpu, EMSTATE enmNewState) { /* Only allowed combination: */ Assert(pVCpu->em.s.enmState == EMSTATE_WAIT_SIPI && enmNewState == EMSTATE_HALTED); @@ -175,13 +180,15 @@ VMMDECL(RTGCUINTPTR) EMGetInhibitInterruptsPC(PVMCPU pVCpu) * @param rax The content of RAX. * @param rcx The content of RCX. * @param rdx The content of RDX. + * @param GCPhys The physical address corresponding to rax. */ -VMM_INT_DECL(int) EMMonitorWaitPrepare(PVMCPU pVCpu, uint64_t rax, uint64_t rcx, uint64_t rdx) +VMM_INT_DECL(int) EMMonitorWaitPrepare(PVMCPU pVCpu, uint64_t rax, uint64_t rcx, uint64_t rdx, RTGCPHYS GCPhys) { pVCpu->em.s.MWait.uMonitorRAX = rax; pVCpu->em.s.MWait.uMonitorRCX = rcx; pVCpu->em.s.MWait.uMonitorRDX = rdx; pVCpu->em.s.MWait.fWait |= EMMWAIT_FLAG_MONITOR_ACTIVE; + /** @todo Make use of GCPhys. */ /** @todo Complete MONITOR implementation. */ return VINF_SUCCESS; } @@ -211,23 +218,25 @@ VMM_INT_DECL(int) EMMonitorWaitPerform(PVMCPU pVCpu, uint64_t rax, uint64_t rcx) /** - * Determine if we should continue after encountering a hlt or mwait - * instruction. + * Determine if we should continue after encountering a mwait instruction. * * Clears MWAIT flags if returning @c true. * - * @returns boolean + * @returns true if we should continue, false if we should halt. * @param pVCpu Pointer to the VMCPU. * @param pCtx Current CPU context. */ -VMM_INT_DECL(bool) EMShouldContinueAfterHalt(PVMCPU pVCpu, PCPUMCTX pCtx) +VMM_INT_DECL(bool) EMMonitorWaitShouldContinue(PVMCPU pVCpu, PCPUMCTX pCtx) { if ( pCtx->eflags.Bits.u1IF || ( (pVCpu->em.s.MWait.fWait & (EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0)) == (EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0)) ) { - pVCpu->em.s.MWait.fWait &= ~(EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0); - return !!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))) + { + pVCpu->em.s.MWait.fWait &= ~(EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0); + return true; + } } return false; @@ -235,6 +244,21 @@ VMM_INT_DECL(bool) EMShouldContinueAfterHalt(PVMCPU pVCpu, PCPUMCTX pCtx) /** + * Determine if we should continue after encountering a hlt instruction. + * + * @returns true if we should continue, false if we should halt. + * @param pVCpu Pointer to the VMCPU. + * @param pCtx Current CPU context. + */ +VMM_INT_DECL(bool) EMShouldContinueAfterHalt(PVMCPU pVCpu, PCPUMCTX pCtx) +{ + if (pCtx->eflags.Bits.u1IF) + return !!VMCPU_FF_IS_PENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)); + return false; +} + + +/** * Locks REM execution to a single VCPU. * * @param pVM Pointer to the VM. @@ -246,7 +270,7 @@ VMMDECL(void) EMRemLock(PVM pVM) return; /* early init */ Assert(!PGMIsLockOwner(pVM)); - Assert(!IOMIsLockOwner(pVM)); + Assert(!IOMIsLockWriteOwner(pVM)); int rc = PDMCritSectEnter(&pVM->em.s.CritSectREM, VERR_SEM_BUSY); AssertRCSuccess(rc); #endif @@ -294,7 +318,7 @@ VMMDECL(bool) EMRemIsLockOwner(PVM pVM) * @returns VBox status code * @param pVM Pointer to the VM. */ -VMMDECL(int) EMRemTryLock(PVM pVM) +VMM_INT_DECL(int) EMRemTryLock(PVM pVM) { #ifdef VBOX_WITH_REM if (!PDMCritSectIsInitialized(&pVM->em.s.CritSectREM)) @@ -328,7 +352,7 @@ static DECLCALLBACK(int) emReadBytes(PDISCPUSTATE pDis, uint8_t offInstr, uint8_ else if (cbToRead < cbMinRead) cbToRead = cbMinRead; -#if defined(IN_RC) || defined(IN_RING3) +#if defined(VBOX_WITH_RAW_MODE) && (defined(IN_RC) || defined(IN_RING3)) /* * We might be called upon to interpret an instruction in a patch. */ @@ -377,9 +401,9 @@ static DECLCALLBACK(int) emReadBytes(PDISCPUSTATE pDis, uint8_t offInstr, uint8_ */ if (rc == VERR_PAGE_TABLE_NOT_PRESENT || rc == VERR_PAGE_NOT_PRESENT) { - HWACCMInvalidatePage(pVCpu, uSrcAddr); + HMInvalidatePage(pVCpu, uSrcAddr); if (((uSrcAddr + cbToRead - 1) >> PAGE_SHIFT) != (uSrcAddr >> PAGE_SHIFT)) - HWACCMInvalidatePage(pVCpu, uSrcAddr + cbToRead - 1); + HMInvalidatePage(pVCpu, uSrcAddr + cbToRead - 1); } #endif } @@ -403,14 +427,13 @@ DECLINLINE(int) emDisCoreOne(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, RTGCUINTP * * @returns VBox status code, see SELMToFlatEx and EMInterpretDisasOneEx for * details. - * @retval VERR_EM_INTERNAL_DISAS_ERROR on DISCoreOneEx failure. * * @param pVM Pointer to the VM. * @param pVCpu Pointer to the VMCPU. * @param pDis Where to return the parsed instruction info. * @param pcbInstr Where to return the instruction size. (optional) */ -VMMDECL(int) EMInterpretDisasCurrent(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, unsigned *pcbInstr) +VMM_INT_DECL(int) EMInterpretDisasCurrent(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, unsigned *pcbInstr) { PCPUMCTXCORE pCtxCore = CPUMCTX2CORE(CPUMQueryGuestCtxPtr(pVCpu)); RTGCPTR GCPtrInstr; @@ -437,7 +460,6 @@ VMMDECL(int) EMInterpretDisasCurrent(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, u * This is used by internally by the interpreter and by trap/access handlers. * * @returns VBox status code. - * @retval VERR_EM_INTERNAL_DISAS_ERROR on DISCoreOneEx failure. * * @param pVM Pointer to the VM. * @param pVCpu Pointer to the VMCPU. @@ -446,8 +468,8 @@ VMMDECL(int) EMInterpretDisasCurrent(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, u * @param pDis Where to return the parsed instruction info. * @param pcbInstr Where to return the instruction size. (optional) */ -VMMDECL(int) EMInterpretDisasOneEx(PVM pVM, PVMCPU pVCpu, RTGCUINTPTR GCPtrInstr, PCCPUMCTXCORE pCtxCore, - PDISCPUSTATE pDis, unsigned *pcbInstr) +VMM_INT_DECL(int) EMInterpretDisasOneEx(PVM pVM, PVMCPU pVCpu, RTGCUINTPTR GCPtrInstr, PCCPUMCTXCORE pCtxCore, + PDISCPUSTATE pDis, unsigned *pcbInstr) { Assert(pCtxCore == CPUMGetGuestCtxCore(pVCpu)); DISCPUMODE enmCpuMode = CPUMGetGuestDisMode(pVCpu); @@ -456,8 +478,8 @@ VMMDECL(int) EMInterpretDisasOneEx(PVM pVM, PVMCPU pVCpu, RTGCUINTPTR GCPtrInstr int rc = DISInstrWithReader(GCPtrInstr, enmCpuMode, emReadBytes, pVCpu, pDis, pcbInstr); if (RT_SUCCESS(rc)) return VINF_SUCCESS; - AssertMsgFailed(("DISCoreOne failed to GCPtrInstr=%RGv rc=%Rrc\n", GCPtrInstr, rc)); - return VERR_EM_INTERNAL_DISAS_ERROR; + AssertMsg(rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("DISCoreOne failed to GCPtrInstr=%RGv rc=%Rrc\n", GCPtrInstr, rc)); + return rc; } @@ -679,7 +701,7 @@ static void emCompareWithIem(PVMCPU pVCpu, PCCPUMCTX pEmCtx, PCCPUMCTX pIemCtx, * Architecture System Developers Manual, Vol 3, 5.5) so we don't need * to worry about e.g. invalid modrm combinations (!) */ -VMMDECL(VBOXSTRICTRC) EMInterpretInstruction(PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault) +VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstruction(PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault) { Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); LogFlow(("EMInterpretInstruction %RGv fault %RGv\n", (RTGCPTR)pRegFrame->rip, pvFault)); @@ -808,7 +830,7 @@ VMMDECL(VBOXSTRICTRC) EMInterpretInstruction(PVMCPU pVCpu, PCPUMCTXCORE pRegFram * Architecture System Developers Manual, Vol 3, 5.5) so we don't need * to worry about e.g. invalid modrm combinations (!) */ -VMMDECL(VBOXSTRICTRC) EMInterpretInstructionEx(PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbWritten) +VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstructionEx(PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbWritten) { LogFlow(("EMInterpretInstructionEx %RGv fault %RGv\n", (RTGCPTR)pRegFrame->rip, pvFault)); Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); @@ -950,8 +972,8 @@ VMMDECL(VBOXSTRICTRC) EMInterpretInstructionEx(PVMCPU pVCpu, PCPUMCTXCORE pRegFr * @todo At this time we do NOT check if the instruction overwrites vital information. * Make sure this can't happen!! (will add some assertions/checks later) */ -VMMDECL(VBOXSTRICTRC) EMInterpretInstructionDisasState(PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, - RTGCPTR pvFault, EMCODETYPE enmCodeType) +VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstructionDisasState(PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, + RTGCPTR pvFault, EMCODETYPE enmCodeType) { LogFlow(("EMInterpretInstructionDisasState %RGv fault %RGv\n", (RTGCPTR)pRegFrame->rip, pvFault)); Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); @@ -1028,7 +1050,7 @@ VMMDECL(VBOXSTRICTRC) EMInterpretInstructionDisasState(PVMCPU pVCpu, PDISCPUSTAT #endif } -#if defined(IN_RC) /*&& defined(VBOX_WITH_PATM)*/ +#ifdef IN_RC DECLINLINE(int) emRCStackRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, void *pvDst, RTGCPTR GCPtrSrc, uint32_t cb) { @@ -1048,7 +1070,7 @@ DECLINLINE(int) emRCStackRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, void * @param pRegFrame The register frame. * */ -VMMDECL(int) EMInterpretIretV86ForPatm(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) +VMM_INT_DECL(int) EMInterpretIretV86ForPatm(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) { RTGCUINTPTR pIretStack = (RTGCUINTPTR)pRegFrame->esp; RTGCUINTPTR eip, cs, esp, ss, eflags, ds, es, fs, gs, uMask; @@ -1094,7 +1116,74 @@ VMMDECL(int) EMInterpretIretV86ForPatm(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegF return VINF_SUCCESS; } -#endif /* IN_RC && VBOX_WITH_PATM */ +/** + * IRET Emulation. + */ +static int emInterpretIret(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize) +{ +#ifdef VBOX_WITH_RAW_RING1 + NOREF(pvFault); NOREF(pcbSize); + if (EMIsRawRing1Enabled(pVM)) + { + RTGCUINTPTR pIretStack = (RTGCUINTPTR)pRegFrame->esp; + RTGCUINTPTR eip, cs, esp, ss, eflags, uMask; + int rc; + uint32_t cpl, rpl; + + /* We only execute 32-bits protected mode code in raw mode, so no need to bother to check for 16-bits code here. */ + /* @todo: we don't verify all the edge cases that generate #GP faults */ + + Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); + Assert(!CPUMIsGuestIn64BitCode(pVCpu)); + /** @todo Rainy day: Test what happens when VERR_EM_INTERPRETER is returned by + * this function. Fear that it may guru on us, thus not converted to + * IEM. */ + + rc = emRCStackRead(pVM, pVCpu, pRegFrame, &eip, (RTGCPTR)pIretStack , 4); + rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &cs, (RTGCPTR)(pIretStack + 4), 4); + rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &eflags, (RTGCPTR)(pIretStack + 8), 4); + AssertRCReturn(rc, VERR_EM_INTERPRETER); + AssertReturn(eflags & X86_EFL_VM, VERR_EM_INTERPRETER); + + /* Deal with V86 above. */ + if (eflags & X86_EFL_VM) + return EMInterpretIretV86ForPatm(pVM, pVCpu, pRegFrame); + + cpl = CPUMRCGetGuestCPL(pVCpu, pRegFrame); + rpl = cs & X86_SEL_RPL; + + Log(("emInterpretIret: iret to CS:EIP=%04X:%08X eflags=%x\n", cs, eip, eflags)); + if (rpl != cpl) + { + rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &esp, (RTGCPTR)(pIretStack + 12), 4); + rc |= emRCStackRead(pVM, pVCpu, pRegFrame, &ss, (RTGCPTR)(pIretStack + 16), 4); + AssertRCReturn(rc, VERR_EM_INTERPRETER); + Log(("emInterpretIret: return to different privilege level (rpl=%d cpl=%d)\n", rpl, cpl)); + Log(("emInterpretIret: SS:ESP=%04X:08X\n", ss, esp)); + pRegFrame->ss.Sel = ss; + pRegFrame->esp = esp; + } + pRegFrame->cs.Sel = cs; + pRegFrame->eip = eip; + + /* Adjust CS & SS as required. */ + CPUMRCRecheckRawState(pVCpu, pRegFrame); + + /* Mask away all reserved bits */ + uMask = X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_TF | X86_EFL_IF | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT | X86_EFL_RF | X86_EFL_VM | X86_EFL_AC | X86_EFL_VIF | X86_EFL_VIP | X86_EFL_ID; + eflags &= uMask; + + CPUMRawSetEFlags(pVCpu, eflags); + Assert((pRegFrame->eflags.u32 & (X86_EFL_IF|X86_EFL_IOPL)) == X86_EFL_IF); + return VINF_SUCCESS; + } +#else + NOREF(pVM); NOREF(pVCpu); NOREF(pDis); NOREF(pRegFrame); NOREF(pvFault); NOREF(pcbSize); +#endif + return VERR_EM_INTERPRETER; +} + +#endif /* IN_RC */ @@ -1118,7 +1207,7 @@ VMMDECL(int) EMInterpretIretV86ForPatm(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegF * @param pRegFrame The register frame. * */ -VMMDECL(int) EMInterpretCpuId(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) +VMM_INT_DECL(int) EMInterpretCpuId(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) { Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); uint32_t iLeaf = pRegFrame->eax; @@ -1146,7 +1235,7 @@ VMMDECL(int) EMInterpretCpuId(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) * @param pRegFrame The register frame. * */ -VMMDECL(int) EMInterpretRdtsc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) +VMM_INT_DECL(int) EMInterpretRdtsc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) { Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); unsigned uCR4 = CPUMGetGuestCR4(pVCpu); @@ -1176,7 +1265,7 @@ VMMDECL(int) EMInterpretRdtsc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) * @param pCtx The CPU context. * */ -VMMDECL(int) EMInterpretRdtscp(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx) +VMM_INT_DECL(int) EMInterpretRdtscp(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx) { Assert(pCtx == CPUMQueryGuestCtxPtr(pVCpu)); uint32_t uCR4 = CPUMGetGuestCR4(pVCpu); @@ -1214,7 +1303,7 @@ VMMDECL(int) EMInterpretRdtscp(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx) * @param pRegFrame The register frame. * */ -VMMDECL(int) EMInterpretRdpmc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) +VMM_INT_DECL(int) EMInterpretRdpmc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) { Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); uint32_t uCR4 = CPUMGetGuestCR4(pVCpu); @@ -1241,7 +1330,7 @@ VMMDECL(int) EMInterpretRdpmc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) /** * MWAIT Emulation. */ -VMMDECL(VBOXSTRICTRC) EMInterpretMWait(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) +VMM_INT_DECL(VBOXSTRICTRC) EMInterpretMWait(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) { Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); uint32_t u32Dummy, u32ExtFeatures, cpl, u32MWaitFeatures; @@ -1280,7 +1369,7 @@ VMMDECL(VBOXSTRICTRC) EMInterpretMWait(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegF /** * MONITOR Emulation. */ -VMMDECL(int) EMInterpretMonitor(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) +VMM_INT_DECL(int) EMInterpretMonitor(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) { uint32_t u32Dummy, u32ExtFeatures, cpl; Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); @@ -1301,7 +1390,7 @@ VMMDECL(int) EMInterpretMonitor(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) if (!(u32ExtFeatures & X86_CPUID_FEATURE_ECX_MONITOR)) return VERR_EM_INTERPRETER; /* not supported */ - EMMonitorWaitPrepare(pVCpu, pRegFrame->rax, pRegFrame->rcx, pRegFrame->rdx); + EMMonitorWaitPrepare(pVCpu, pRegFrame->rax, pRegFrame->rcx, pRegFrame->rdx, NIL_RTGCPHYS); return VINF_SUCCESS; } @@ -1318,7 +1407,7 @@ VMMDECL(int) EMInterpretMonitor(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) * @param pAddrGC Operand address. * */ -VMMDECL(VBOXSTRICTRC) EMInterpretInvlpg(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pAddrGC) +VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInvlpg(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pAddrGC) { /** @todo is addr always a flat linear address or ds based * (in absence of segment override prefixes)???? @@ -1396,14 +1485,14 @@ static int emUpdateCRx(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t D if (pRegFrame->cs.Attr.n.u1Long) { AssertMsgFailed(("Illegal enabling of paging with CS.u1Long = 1!!\n")); - return VERR_EM_INTERPRETER; /* @todo generate #GP(0) */ + return VERR_EM_INTERPRETER; /** @todo generate #GP(0) */ } /* Illegal to switch to long mode before activating PAE first (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */ if (!(CPUMGetGuestCR4(pVCpu) & X86_CR4_PAE)) { AssertMsgFailed(("Illegal enabling of paging with PAE disabled!!\n")); - return VERR_EM_INTERPRETER; /* @todo generate #GP(0) */ + return VERR_EM_INTERPRETER; /** @todo generate #GP(0) */ } msrEFER |= MSR_K6_EFER_LMA; } @@ -1412,7 +1501,7 @@ static int emUpdateCRx(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t D && !(val & X86_CR0_PG)) { msrEFER &= ~MSR_K6_EFER_LMA; - /* @todo Do we need to cut off rip here? High dword of rip is undefined, so it shouldn't really matter. */ + /** @todo Do we need to cut off rip here? High dword of rip is undefined, so it shouldn't really matter. */ } CPUMSetGuestEFER(pVCpu, msrEFER); } @@ -1466,8 +1555,10 @@ static int emUpdateCRx(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t D VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3); } # endif - if ((val ^ oldval) & X86_CR4_VME) +# ifdef VBOX_WITH_RAW_MODE + if (((val ^ oldval) & X86_CR4_VME) && !HMIsEnabled(pVM)) VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS); +# endif rc2 = PGMChangeMode(pVCpu, CPUMGetGuestCR0(pVCpu), CPUMGetGuestCR4(pVCpu), CPUMGetGuestEFER(pVCpu)); return rc2 == VINF_SUCCESS ? rc : rc2; @@ -1495,7 +1586,7 @@ static int emUpdateCRx(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t D * @param SrcRegGen General purpose register index (USE_REG_E**)) * */ -VMMDECL(int) EMInterpretCRxWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint32_t SrcRegGen) +VMM_INT_DECL(int) EMInterpretCRxWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint32_t SrcRegGen) { uint64_t val; int rc; @@ -1526,7 +1617,7 @@ VMMDECL(int) EMInterpretCRxWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, * @param u16Data LMSW source data. * */ -VMMDECL(int) EMInterpretLMSW(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint16_t u16Data) +VMM_INT_DECL(int) EMInterpretLMSW(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint16_t u16Data) { Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); uint64_t OldCr0 = CPUMGetGuestCR0(pVCpu); @@ -1547,7 +1638,7 @@ VMMDECL(int) EMInterpretLMSW(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint * @param pVCpu Pointer to the VMCPU. * */ -VMMDECL(int) EMInterpretCLTS(PVM pVM, PVMCPU pVCpu) +VMM_INT_DECL(int) EMInterpretCLTS(PVM pVM, PVMCPU pVCpu) { NOREF(pVM); @@ -1558,6 +1649,127 @@ VMMDECL(int) EMInterpretCLTS(PVM pVM, PVMCPU pVCpu) } +#ifdef LOG_ENABLED +static const char *emMSRtoString(uint32_t uMsr) +{ + switch (uMsr) + { + case MSR_IA32_APICBASE: return "MSR_IA32_APICBASE"; + case MSR_IA32_CR_PAT: return "MSR_IA32_CR_PAT"; + case MSR_IA32_SYSENTER_CS: return "MSR_IA32_SYSENTER_CS"; + case MSR_IA32_SYSENTER_EIP: return "MSR_IA32_SYSENTER_EIP"; + case MSR_IA32_SYSENTER_ESP: return "MSR_IA32_SYSENTER_ESP"; + case MSR_K6_EFER: return "MSR_K6_EFER"; + case MSR_K8_SF_MASK: return "MSR_K8_SF_MASK"; + case MSR_K6_STAR: return "MSR_K6_STAR"; + case MSR_K8_LSTAR: return "MSR_K8_LSTAR"; + case MSR_K8_CSTAR: return "MSR_K8_CSTAR"; + case MSR_K8_FS_BASE: return "MSR_K8_FS_BASE"; + case MSR_K8_GS_BASE: return "MSR_K8_GS_BASE"; + case MSR_K8_KERNEL_GS_BASE: return "MSR_K8_KERNEL_GS_BASE"; + case MSR_K8_TSC_AUX: return "MSR_K8_TSC_AUX"; + case MSR_IA32_BIOS_SIGN_ID: return "Unsupported MSR_IA32_BIOS_SIGN_ID"; + case MSR_IA32_PLATFORM_ID: return "Unsupported MSR_IA32_PLATFORM_ID"; + case MSR_IA32_BIOS_UPDT_TRIG: return "Unsupported MSR_IA32_BIOS_UPDT_TRIG"; + case MSR_IA32_TSC: return "MSR_IA32_TSC"; + case MSR_IA32_MISC_ENABLE: return "MSR_IA32_MISC_ENABLE"; + case MSR_IA32_MTRR_CAP: return "MSR_IA32_MTRR_CAP"; + case MSR_IA32_MCG_CAP: return "Unsupported MSR_IA32_MCG_CAP"; + case MSR_IA32_MCG_STATUS: return "Unsupported MSR_IA32_MCG_STATUS"; + case MSR_IA32_MCG_CTRL: return "Unsupported MSR_IA32_MCG_CTRL"; + case MSR_IA32_MTRR_DEF_TYPE: return "MSR_IA32_MTRR_DEF_TYPE"; + case MSR_K7_EVNTSEL0: return "Unsupported MSR_K7_EVNTSEL0"; + case MSR_K7_EVNTSEL1: return "Unsupported MSR_K7_EVNTSEL1"; + case MSR_K7_EVNTSEL2: return "Unsupported MSR_K7_EVNTSEL2"; + case MSR_K7_EVNTSEL3: return "Unsupported MSR_K7_EVNTSEL3"; + case MSR_IA32_MC0_CTL: return "Unsupported MSR_IA32_MC0_CTL"; + case MSR_IA32_MC0_STATUS: return "Unsupported MSR_IA32_MC0_STATUS"; + case MSR_IA32_PERFEVTSEL0: return "Unsupported MSR_IA32_PERFEVTSEL0"; + case MSR_IA32_PERFEVTSEL1: return "Unsupported MSR_IA32_PERFEVTSEL1"; + case MSR_IA32_PERF_STATUS: return "MSR_IA32_PERF_STATUS"; + case MSR_IA32_PLATFORM_INFO: return "MSR_IA32_PLATFORM_INFO"; + case MSR_IA32_PERF_CTL: return "Unsupported MSR_IA32_PERF_CTL"; + case MSR_K7_PERFCTR0: return "Unsupported MSR_K7_PERFCTR0"; + case MSR_K7_PERFCTR1: return "Unsupported MSR_K7_PERFCTR1"; + case MSR_K7_PERFCTR2: return "Unsupported MSR_K7_PERFCTR2"; + case MSR_K7_PERFCTR3: return "Unsupported MSR_K7_PERFCTR3"; + case MSR_IA32_PMC0: return "Unsupported MSR_IA32_PMC0"; + case MSR_IA32_PMC1: return "Unsupported MSR_IA32_PMC1"; + case MSR_IA32_PMC2: return "Unsupported MSR_IA32_PMC2"; + case MSR_IA32_PMC3: return "Unsupported MSR_IA32_PMC3"; + } + return "Unknown MSR"; +} +#endif /* LOG_ENABLED */ + + +/** + * Interpret RDMSR + * + * @returns VBox status code. + * @param pVM Pointer to the VM. + * @param pVCpu Pointer to the VMCPU. + * @param pRegFrame The register frame. + */ +VMM_INT_DECL(int) EMInterpretRdmsr(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) +{ + NOREF(pVM); + + /* Get the current privilege level. */ + if (CPUMGetGuestCPL(pVCpu) != 0) + { + Log4(("EM: Refuse RDMSR: CPL != 0\n")); + return VERR_EM_INTERPRETER; /* supervisor only */ + } + + uint64_t uValue; + int rc = CPUMQueryGuestMsr(pVCpu, pRegFrame->ecx, &uValue); + if (RT_UNLIKELY(rc != VINF_SUCCESS)) + { + Assert(rc == VERR_CPUM_RAISE_GP_0); + Log4(("EM: Refuse RDMSR: rc=%Rrc\n", rc)); + return VERR_EM_INTERPRETER; + } + pRegFrame->rax = (uint32_t) uValue; + pRegFrame->rdx = (uint32_t)(uValue >> 32); + LogFlow(("EMInterpretRdmsr %s (%x) -> %RX64\n", emMSRtoString(pRegFrame->ecx), pRegFrame->ecx, uValue)); + return rc; +} + + +/** + * Interpret WRMSR + * + * @returns VBox status code. + * @param pVM Pointer to the VM. + * @param pVCpu Pointer to the VMCPU. + * @param pRegFrame The register frame. + */ +VMM_INT_DECL(int) EMInterpretWrmsr(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) +{ + Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); + + /* Check the current privilege level, this instruction is supervisor only. */ + if (CPUMGetGuestCPL(pVCpu) != 0) + { + Log4(("EM: Refuse WRMSR: CPL != 0\n")); + return VERR_EM_INTERPRETER; /** @todo raise \#GP(0) */ + } + + int rc = CPUMSetGuestMsr(pVCpu, pRegFrame->ecx, RT_MAKE_U64(pRegFrame->eax, pRegFrame->edx)); + if (rc != VINF_SUCCESS) + { + Assert(rc == VERR_CPUM_RAISE_GP_0); + Log4(("EM: Refuse WRMSR: rc=%d\n", rc)); + return VERR_EM_INTERPRETER; + } + LogFlow(("EMInterpretWrmsr %s (%x) val=%RX64\n", emMSRtoString(pRegFrame->ecx), pRegFrame->ecx, + RT_MAKE_U64(pRegFrame->eax, pRegFrame->edx))); + NOREF(pVM); + return rc; +} + + /** * Interpret CRx read. * @@ -1569,7 +1781,7 @@ VMMDECL(int) EMInterpretCLTS(PVM pVM, PVMCPU pVCpu) * @param SrcRegCRx CRx register index (DISUSE_REG_CR*) * */ -VMMDECL(int) EMInterpretCRxRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegCrx) +VMM_INT_DECL(int) EMInterpretCRxRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegCrx) { Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); uint64_t val64; @@ -1602,26 +1814,37 @@ VMMDECL(int) EMInterpretCRxRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, u * @param SrcRegGen General purpose register index (USE_REG_E**)) * */ -VMMDECL(int) EMInterpretDRxWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegDrx, uint32_t SrcRegGen) +VMM_INT_DECL(int) EMInterpretDRxWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegDrx, uint32_t SrcRegGen) { Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); - uint64_t val; + uint64_t uNewDrX; int rc; NOREF(pVM); if (CPUMIsGuestIn64BitCode(pVCpu)) - rc = DISFetchReg64(pRegFrame, SrcRegGen, &val); + rc = DISFetchReg64(pRegFrame, SrcRegGen, &uNewDrX); else { uint32_t val32; rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32); - val = val32; + uNewDrX = val32; } if (RT_SUCCESS(rc)) { + if (DestRegDrx == 6) + { + uNewDrX |= X86_DR6_RA1_MASK; + uNewDrX &= ~X86_DR6_RAZ_MASK; + } + else if (DestRegDrx == 7) + { + uNewDrX |= X86_DR7_RA1_MASK; + uNewDrX &= ~X86_DR7_RAZ_MASK; + } + /** @todo we don't fail if illegal bits are set/cleared for e.g. dr7 */ - rc = CPUMSetGuestDRx(pVCpu, DestRegDrx, val); + rc = CPUMSetGuestDRx(pVCpu, DestRegDrx, uNewDrX); if (RT_SUCCESS(rc)) return rc; AssertMsgFailed(("CPUMSetGuestDRx %d failed\n", DestRegDrx)); @@ -1641,7 +1864,7 @@ VMMDECL(int) EMInterpretDRxWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, * @param SrcRegDRx DRx register index (USE_REG_DR*) * */ -VMMDECL(int) EMInterpretDRxRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegDrx) +VMM_INT_DECL(int) EMInterpretDRxRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegDrx) { uint64_t val64; Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); @@ -2507,121 +2730,134 @@ static int emInterpretMov(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE if(RT_FAILURE(rc)) return VERR_EM_INTERPRETER; -#ifdef IN_RC - if (TRPMHasTrap(pVCpu)) + if (param1.type == DISQPV_TYPE_ADDRESS) { - if (TRPMGetErrorCode(pVCpu) & X86_TRAP_PF_RW) - { -#else - /** @todo Make this the default and don't rely on TRPM information. */ - if (param1.type == DISQPV_TYPE_ADDRESS) - { -#endif - RTGCPTR pDest; - uint64_t val64; + RTGCPTR pDest; + uint64_t val64; - switch(param1.type) - { - case DISQPV_TYPE_IMMEDIATE: - if(!(param1.flags & (DISQPV_FLAG_32|DISQPV_FLAG_64))) - return VERR_EM_INTERPRETER; - /* fallthru */ + switch(param1.type) + { + case DISQPV_TYPE_IMMEDIATE: + if(!(param1.flags & (DISQPV_FLAG_32|DISQPV_FLAG_64))) + return VERR_EM_INTERPRETER; + /* fallthru */ - case DISQPV_TYPE_ADDRESS: - pDest = (RTGCPTR)param1.val.val64; - pDest = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, pDest); - break; + case DISQPV_TYPE_ADDRESS: + pDest = (RTGCPTR)param1.val.val64; + pDest = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param1, pDest); + break; - default: - AssertFailed(); - return VERR_EM_INTERPRETER; - } + default: + AssertFailed(); + return VERR_EM_INTERPRETER; + } - switch(param2.type) - { - case DISQPV_TYPE_IMMEDIATE: /* register type is translated to this one too */ - val64 = param2.val.val64; - break; + switch(param2.type) + { + case DISQPV_TYPE_IMMEDIATE: /* register type is translated to this one too */ + val64 = param2.val.val64; + break; - default: - Log(("emInterpretMov: unexpected type=%d rip=%RGv\n", param2.type, (RTGCPTR)pRegFrame->rip)); - return VERR_EM_INTERPRETER; - } + default: + Log(("emInterpretMov: unexpected type=%d rip=%RGv\n", param2.type, (RTGCPTR)pRegFrame->rip)); + return VERR_EM_INTERPRETER; + } #ifdef LOG_ENABLED - if (pDis->uCpuMode == DISCPUMODE_64BIT) - LogFlow(("EMInterpretInstruction at %RGv: OP_MOV %RGv <- %RX64 (%d) &val64=%RHv\n", (RTGCPTR)pRegFrame->rip, pDest, val64, param2.size, &val64)); - else - LogFlow(("EMInterpretInstruction at %08RX64: OP_MOV %RGv <- %08X (%d) &val64=%RHv\n", pRegFrame->rip, pDest, (uint32_t)val64, param2.size, &val64)); + if (pDis->uCpuMode == DISCPUMODE_64BIT) + LogFlow(("EMInterpretInstruction at %RGv: OP_MOV %RGv <- %RX64 (%d) &val64=%RHv\n", (RTGCPTR)pRegFrame->rip, pDest, val64, param2.size, &val64)); + else + LogFlow(("EMInterpretInstruction at %08RX64: OP_MOV %RGv <- %08X (%d) &val64=%RHv\n", pRegFrame->rip, pDest, (uint32_t)val64, param2.size, &val64)); #endif - Assert(param2.size <= 8 && param2.size > 0); - EM_ASSERT_FAULT_RETURN(pDest == pvFault, VERR_EM_INTERPRETER); - rc = emRamWrite(pVM, pVCpu, pRegFrame, pDest, &val64, param2.size); - if (RT_FAILURE(rc)) - return VERR_EM_INTERPRETER; + Assert(param2.size <= 8 && param2.size > 0); + EM_ASSERT_FAULT_RETURN(pDest == pvFault, VERR_EM_INTERPRETER); + rc = emRamWrite(pVM, pVCpu, pRegFrame, pDest, &val64, param2.size); + if (RT_FAILURE(rc)) + return VERR_EM_INTERPRETER; - *pcbSize = param2.size; - } - else - { /* read fault */ - RTGCPTR pSrc; - uint64_t val64; + *pcbSize = param2.size; + } +#if defined(IN_RC) && defined(VBOX_WITH_RAW_RING1) + /* mov xx, cs instruction is dangerous in raw mode and replaced by an 'int3' by csam/patm. */ + else if ( param1.type == DISQPV_TYPE_REGISTER + && param2.type == DISQPV_TYPE_REGISTER) + { + AssertReturn((pDis->Param1.fUse & (DISUSE_REG_GEN8|DISUSE_REG_GEN16|DISUSE_REG_GEN32)), VERR_EM_INTERPRETER); + AssertReturn(pDis->Param2.fUse == DISUSE_REG_SEG, VERR_EM_INTERPRETER); + AssertReturn(pDis->Param2.Base.idxSegReg == DISSELREG_CS, VERR_EM_INTERPRETER); - /* Source */ - switch(param2.type) - { - case DISQPV_TYPE_IMMEDIATE: - if(!(param2.flags & (DISQPV_FLAG_32|DISQPV_FLAG_64))) - return VERR_EM_INTERPRETER; - /* fallthru */ + uint32_t u32Cpl = CPUMRCGetGuestCPL(pVCpu, pRegFrame); + uint32_t uValCS = (pRegFrame->cs.Sel & ~X86_SEL_RPL) | u32Cpl; - case DISQPV_TYPE_ADDRESS: - pSrc = (RTGCPTR)param2.val.val64; - pSrc = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param2, pSrc); - break; + Log(("EMInterpretInstruction: OP_MOV cs=%x->%x\n", pRegFrame->cs.Sel, uValCS)); + switch (param1.size) + { + case 1: rc = DISWriteReg8(pRegFrame, pDis->Param1.Base.idxGenReg, (uint8_t) uValCS); break; + case 2: rc = DISWriteReg16(pRegFrame, pDis->Param1.Base.idxGenReg, (uint16_t)uValCS); break; + case 4: rc = DISWriteReg32(pRegFrame, pDis->Param1.Base.idxGenReg, (uint32_t)uValCS); break; + default: + AssertFailed(); + return VERR_EM_INTERPRETER; + } + AssertRCReturn(rc, rc); + } +#endif + else + { /* read fault */ + RTGCPTR pSrc; + uint64_t val64; - default: + /* Source */ + switch(param2.type) + { + case DISQPV_TYPE_IMMEDIATE: + if(!(param2.flags & (DISQPV_FLAG_32|DISQPV_FLAG_64))) return VERR_EM_INTERPRETER; - } + /* fallthru */ - Assert(param1.size <= 8 && param1.size > 0); - EM_ASSERT_FAULT_RETURN(pSrc == pvFault, VERR_EM_INTERPRETER); - rc = emRamRead(pVM, pVCpu, pRegFrame, &val64, pSrc, param1.size); - if (RT_FAILURE(rc)) - return VERR_EM_INTERPRETER; + case DISQPV_TYPE_ADDRESS: + pSrc = (RTGCPTR)param2.val.val64; + pSrc = emConvertToFlatAddr(pVM, pRegFrame, pDis, &pDis->Param2, pSrc); + break; - /* Destination */ - switch(param1.type) - { - case DISQPV_TYPE_REGISTER: - switch(param1.size) - { - case 1: rc = DISWriteReg8(pRegFrame, pDis->Param1.Base.idxGenReg, (uint8_t) val64); break; - case 2: rc = DISWriteReg16(pRegFrame, pDis->Param1.Base.idxGenReg, (uint16_t)val64); break; - case 4: rc = DISWriteReg32(pRegFrame, pDis->Param1.Base.idxGenReg, (uint32_t)val64); break; - case 8: rc = DISWriteReg64(pRegFrame, pDis->Param1.Base.idxGenReg, val64); break; - default: - return VERR_EM_INTERPRETER; - } - if (RT_FAILURE(rc)) - return rc; - break; + default: + return VERR_EM_INTERPRETER; + } + + Assert(param1.size <= 8 && param1.size > 0); + EM_ASSERT_FAULT_RETURN(pSrc == pvFault, VERR_EM_INTERPRETER); + rc = emRamRead(pVM, pVCpu, pRegFrame, &val64, pSrc, param1.size); + if (RT_FAILURE(rc)) + return VERR_EM_INTERPRETER; + /* Destination */ + switch(param1.type) + { + case DISQPV_TYPE_REGISTER: + switch(param1.size) + { + case 1: rc = DISWriteReg8(pRegFrame, pDis->Param1.Base.idxGenReg, (uint8_t) val64); break; + case 2: rc = DISWriteReg16(pRegFrame, pDis->Param1.Base.idxGenReg, (uint16_t)val64); break; + case 4: rc = DISWriteReg32(pRegFrame, pDis->Param1.Base.idxGenReg, (uint32_t)val64); break; + case 8: rc = DISWriteReg64(pRegFrame, pDis->Param1.Base.idxGenReg, val64); break; default: return VERR_EM_INTERPRETER; } + if (RT_FAILURE(rc)) + return rc; + break; + + default: + return VERR_EM_INTERPRETER; + } #ifdef LOG_ENABLED - if (pDis->uCpuMode == DISCPUMODE_64BIT) - LogFlow(("EMInterpretInstruction: OP_MOV %RGv -> %RX64 (%d)\n", pSrc, val64, param1.size)); - else - LogFlow(("EMInterpretInstruction: OP_MOV %RGv -> %08X (%d)\n", pSrc, (uint32_t)val64, param1.size)); + if (pDis->uCpuMode == DISCPUMODE_64BIT) + LogFlow(("EMInterpretInstruction: OP_MOV %RGv -> %RX64 (%d)\n", pSrc, val64, param1.size)); + else + LogFlow(("EMInterpretInstruction: OP_MOV %RGv -> %08X (%d)\n", pSrc, (uint32_t)val64, param1.size)); #endif - } - return VINF_SUCCESS; -#ifdef IN_RC } - return VERR_EM_INTERPRETER; -#endif + return VINF_SUCCESS; } @@ -2871,7 +3107,6 @@ static int emInterpretCmpXchg(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTX */ static int emInterpretCmpXchg8b(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize) { - Assert(pDis->uCpuMode != DISCPUMODE_64BIT); /** @todo check */ DISQPVPARAMVAL param1; NOREF(pvFault); @@ -2925,7 +3160,7 @@ static int emInterpretCmpXchg8b(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMC } -#ifdef IN_RC /** @todo test+enable for HWACCM as well. */ +#ifdef IN_RC /** @todo test+enable for HM as well. */ /** * [LOCK] XADD emulation. */ @@ -3016,16 +3251,6 @@ static int emInterpretXAdd(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCOR /** - * IRET Emulation. - */ -static int emInterpretIret(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize) -{ - /* only allow direct calls to EMInterpretIret for now */ - NOREF(pVM); NOREF(pVCpu); NOREF(pDis); NOREF(pRegFrame); NOREF(pvFault); NOREF(pcbSize); - return VERR_EM_INTERPRETER; -} - -/** * WBINVD Emulation. */ static int emInterpretWbInvd(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize) @@ -3325,7 +3550,7 @@ static int emInterpretLIGdt(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCO static int emInterpretSti(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize) { NOREF(pcbSize); - PPATMGCSTATE pGCState = PATMQueryGCState(pVM); + PPATMGCSTATE pGCState = PATMGetGCState(pVM); if(!pGCState) { @@ -3389,139 +3614,6 @@ static VBOXSTRICTRC emInterpretMWait(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, P } -#ifdef LOG_ENABLED -static const char *emMSRtoString(uint32_t uMsr) -{ - switch (uMsr) - { - case MSR_IA32_APICBASE: - return "MSR_IA32_APICBASE"; - case MSR_IA32_CR_PAT: - return "MSR_IA32_CR_PAT"; - case MSR_IA32_SYSENTER_CS: - return "MSR_IA32_SYSENTER_CS"; - case MSR_IA32_SYSENTER_EIP: - return "MSR_IA32_SYSENTER_EIP"; - case MSR_IA32_SYSENTER_ESP: - return "MSR_IA32_SYSENTER_ESP"; - case MSR_K6_EFER: - return "MSR_K6_EFER"; - case MSR_K8_SF_MASK: - return "MSR_K8_SF_MASK"; - case MSR_K6_STAR: - return "MSR_K6_STAR"; - case MSR_K8_LSTAR: - return "MSR_K8_LSTAR"; - case MSR_K8_CSTAR: - return "MSR_K8_CSTAR"; - case MSR_K8_FS_BASE: - return "MSR_K8_FS_BASE"; - case MSR_K8_GS_BASE: - return "MSR_K8_GS_BASE"; - case MSR_K8_KERNEL_GS_BASE: - return "MSR_K8_KERNEL_GS_BASE"; - case MSR_K8_TSC_AUX: - return "MSR_K8_TSC_AUX"; - case MSR_IA32_BIOS_SIGN_ID: - return "Unsupported MSR_IA32_BIOS_SIGN_ID"; - case MSR_IA32_PLATFORM_ID: - return "Unsupported MSR_IA32_PLATFORM_ID"; - case MSR_IA32_BIOS_UPDT_TRIG: - return "Unsupported MSR_IA32_BIOS_UPDT_TRIG"; - case MSR_IA32_TSC: - return "MSR_IA32_TSC"; - case MSR_IA32_MISC_ENABLE: - return "MSR_IA32_MISC_ENABLE"; - case MSR_IA32_MTRR_CAP: - return "MSR_IA32_MTRR_CAP"; - case MSR_IA32_MCP_CAP: - return "Unsupported MSR_IA32_MCP_CAP"; - case MSR_IA32_MCP_STATUS: - return "Unsupported MSR_IA32_MCP_STATUS"; - case MSR_IA32_MCP_CTRL: - return "Unsupported MSR_IA32_MCP_CTRL"; - case MSR_IA32_MTRR_DEF_TYPE: - return "MSR_IA32_MTRR_DEF_TYPE"; - case MSR_K7_EVNTSEL0: - return "Unsupported MSR_K7_EVNTSEL0"; - case MSR_K7_EVNTSEL1: - return "Unsupported MSR_K7_EVNTSEL1"; - case MSR_K7_EVNTSEL2: - return "Unsupported MSR_K7_EVNTSEL2"; - case MSR_K7_EVNTSEL3: - return "Unsupported MSR_K7_EVNTSEL3"; - case MSR_IA32_MC0_CTL: - return "Unsupported MSR_IA32_MC0_CTL"; - case MSR_IA32_MC0_STATUS: - return "Unsupported MSR_IA32_MC0_STATUS"; - case MSR_IA32_PERFEVTSEL0: - return "Unsupported MSR_IA32_PERFEVTSEL0"; - case MSR_IA32_PERFEVTSEL1: - return "Unsupported MSR_IA32_PERFEVTSEL1"; - case MSR_IA32_PERF_STATUS: - return "MSR_IA32_PERF_STATUS"; - case MSR_IA32_PLATFORM_INFO: - return "MSR_IA32_PLATFORM_INFO"; - case MSR_IA32_PERF_CTL: - return "Unsupported MSR_IA32_PERF_CTL"; - case MSR_K7_PERFCTR0: - return "Unsupported MSR_K7_PERFCTR0"; - case MSR_K7_PERFCTR1: - return "Unsupported MSR_K7_PERFCTR1"; - case MSR_K7_PERFCTR2: - return "Unsupported MSR_K7_PERFCTR2"; - case MSR_K7_PERFCTR3: - return "Unsupported MSR_K7_PERFCTR3"; - case MSR_IA32_PMC0: - return "Unsupported MSR_IA32_PMC0"; - case MSR_IA32_PMC1: - return "Unsupported MSR_IA32_PMC1"; - case MSR_IA32_PMC2: - return "Unsupported MSR_IA32_PMC2"; - case MSR_IA32_PMC3: - return "Unsupported MSR_IA32_PMC3"; - } - return "Unknown MSR"; -} -#endif /* LOG_ENABLED */ - - -/** - * Interpret RDMSR - * - * @returns VBox status code. - * @param pVM Pointer to the VM. - * @param pVCpu Pointer to the VMCPU. - * @param pRegFrame The register frame. - */ -VMMDECL(int) EMInterpretRdmsr(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) -{ - /** @todo According to the Intel manuals, there's a REX version of RDMSR that is slightly different. - * That version clears the high dwords of both RDX & RAX */ - NOREF(pVM); - - /* Get the current privilege level. */ - if (CPUMGetGuestCPL(pVCpu) != 0) - { - Log4(("EM: Refuse RDMSR: CPL != 0\n")); - return VERR_EM_INTERPRETER; /* supervisor only */ - } - - uint64_t uValue; - int rc = CPUMQueryGuestMsr(pVCpu, pRegFrame->ecx, &uValue); - if (RT_UNLIKELY(rc != VINF_SUCCESS)) - { - Assert(rc == VERR_CPUM_RAISE_GP_0); - Log4(("EM: Refuse RDMSR: rc=%Rrc\n", rc)); - return VERR_EM_INTERPRETER; - } - pRegFrame->rax = (uint32_t) uValue; - pRegFrame->rdx = (uint32_t)(uValue >> 32); - LogFlow(("EMInterpretRdmsr %s (%x) -> %RX64\n", emMSRtoString(pRegFrame->ecx), pRegFrame->ecx, uValue)); - return rc; -} - - /** * RDMSR Emulation. */ @@ -3536,39 +3628,6 @@ static int emInterpretRdmsr(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCO /** - * Interpret WRMSR - * - * @returns VBox status code. - * @param pVM Pointer to the VM. - * @param pVCpu Pointer to the VMCPU. - * @param pRegFrame The register frame. - */ -VMMDECL(int) EMInterpretWrmsr(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) -{ - Assert(pRegFrame == CPUMGetGuestCtxCore(pVCpu)); - - /* Check the current privilege level, this instruction is supervisor only. */ - if (CPUMGetGuestCPL(pVCpu) != 0) - { - Log4(("EM: Refuse WRMSR: CPL != 0\n")); - return VERR_EM_INTERPRETER; /** @todo raise \#GP(0) */ - } - - int rc = CPUMSetGuestMsr(pVCpu, pRegFrame->ecx, RT_MAKE_U64(pRegFrame->eax, pRegFrame->edx)); - if (rc != VINF_SUCCESS) - { - Assert(rc == VERR_CPUM_RAISE_GP_0); - Log4(("EM: Refuse WRMSR: rc=%d\n", rc)); - return VERR_EM_INTERPRETER; - } - LogFlow(("EMInterpretWrmsr %s (%x) val=%RX64\n", emMSRtoString(pRegFrame->ecx), pRegFrame->ecx, - RT_MAKE_U64(pRegFrame->eax, pRegFrame->edx))); - NOREF(pVM); - return rc; -} - - -/** * WRMSR Emulation. */ static int emInterpretWrmsr(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize) @@ -3598,12 +3657,20 @@ DECLINLINE(VBOXSTRICTRC) emInterpretInstructionCPU(PVM pVM, PVMCPU pVCpu, PDISCP */ /* Get the current privilege level. */ uint32_t cpl = CPUMGetGuestCPL(pVCpu); - if ( cpl != 0 - && pDis->pCurInstr->uOpcode != OP_RDTSC) /* rdtsc requires emulation in ring 3 as well */ +#ifdef VBOX_WITH_RAW_RING1 + if ( !EMIsRawRing1Enabled(pVM) + || cpl > 1 + || pRegFrame->eflags.Bits.u2IOPL > cpl + ) +#endif { - Log(("WARNING: refusing instruction emulation for user-mode code!!\n")); - STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,FailedUserMode)); - return VERR_EM_INTERPRETER; + if ( cpl != 0 + && pDis->pCurInstr->uOpcode != OP_RDTSC) /* rdtsc requires emulation in ring 3 as well */ + { + Log(("WARNING: refusing instruction emulation for user-mode code!!\n")); + STAM_COUNTER_INC(&pVCpu->em.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,FailedUserMode)); + return VERR_EM_INTERPRETER; + } } } else @@ -3836,10 +3903,10 @@ DECLINLINE(VBOXSTRICTRC) emInterpretInstructionCPU(PVM pVM, PVMCPU pVCpu, PDISCP #ifdef IN_RC INTERPRET_CASE(OP_STI,Sti); INTERPRET_CASE(OP_XADD, XAdd); + INTERPRET_CASE(OP_IRET,Iret); #endif INTERPRET_CASE(OP_CMPXCHG8B, CmpXchg8b); INTERPRET_CASE(OP_HLT,Hlt); - INTERPRET_CASE(OP_IRET,Iret); INTERPRET_CASE(OP_WBINVD,WbInvd); #ifdef VBOX_WITH_STATISTICS # ifndef IN_RC |
