EMAll.cpp revision 6d9de847ae1685acb4967293c198a3448b1a797e
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync * EM - Execution Monitor(/Manager) - All contexts
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync * Copyright (C) 2006-2007 innotek GmbH
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync * available from http://www.virtualbox.org. This file is free software;
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync * you can redistribute it and/or modify it under the terms of the GNU
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync * General Public License as published by the Free Software Foundation,
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync/*******************************************************************************
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync* Header Files *
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync*******************************************************************************/
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync/*******************************************************************************
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync* Structures and Typedefs *
7af218a7441de38fc9e814919db04bae3e917664vboxsync*******************************************************************************/
172ae196da38208e5f1e3485715a89f2d53c6880vboxsynctypedef DECLCALLBACK(uint32_t) PFN_EMULATE_PARAM2_UINT32(uint32_t *pu32Param1, uint32_t val2);
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsynctypedef DECLCALLBACK(uint32_t) PFN_EMULATE_PARAM2(uint32_t *pu32Param1, size_t val2);
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsynctypedef DECLCALLBACK(uint32_t) PFN_EMULATE_PARAM3(uint32_t *pu32Param1, uint32_t val2, size_t val3);
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync/*******************************************************************************
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync* Internal Functions *
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync*******************************************************************************/
172ae196da38208e5f1e3485715a89f2d53c6880vboxsyncDECLINLINE(int) emInterpretInstructionCPU(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize);
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * Get the current execution manager status.
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * @returns Current status.
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * Read callback for disassembly function; supports reading bytes that cross a page boundary
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * @returns VBox status code.
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * @param pSrc GC source pointer
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * @param pDest HC destination pointer
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * @param size Number of bytes to read
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * @param dwUserdata Callback specific user data (pCpu)
172ae196da38208e5f1e3485715a89f2d53c6880vboxsyncDECLCALLBACK(int32_t) EMReadBytes(RTHCUINTPTR pSrc, uint8_t *pDest, uint32_t size, RTHCUINTPTR dwUserdata)
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync if (VBOX_SUCCESS(PATMR3QueryOpcode(pVM, (RTGCPTR)pSrc + i, &opcode)))
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync#endif /* IN_RING0 */
172ae196da38208e5f1e3485715a89f2d53c6880vboxsyncDECLINLINE(int) emDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync return DISCoreOneEx(InstrGC, pCpu->mode, EMReadBytes, pVM, pCpu, pOpsize);
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsyncDECLINLINE(int) emDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
7af218a7441de38fc9e814919db04bae3e917664vboxsync * Disassembles one instruction.
7af218a7441de38fc9e814919db04bae3e917664vboxsync * @param pVM The VM handle.
7af218a7441de38fc9e814919db04bae3e917664vboxsync * @param pCtxCore The context core (used for both the mode and instruction).
7af218a7441de38fc9e814919db04bae3e917664vboxsync * @param pCpu Where to return the parsed instruction info.
7af218a7441de38fc9e814919db04bae3e917664vboxsync * @param pcbInstr Where to return the instruction size. (optional)
7af218a7441de38fc9e814919db04bae3e917664vboxsyncEMDECL(int) EMInterpretDisasOne(PVM pVM, PCCPUMCTXCORE pCtxCore, PDISCPUSTATE pCpu, unsigned *pcbInstr)
7af218a7441de38fc9e814919db04bae3e917664vboxsync int rc = SELMValidateAndConvertCSAddr(pVM, pCtxCore->eflags, pCtxCore->ss, pCtxCore->cs, (PCPUMSELREGHID)&pCtxCore->csHid, (RTGCPTR)pCtxCore->eip, &GCPtrInstr);
7af218a7441de38fc9e814919db04bae3e917664vboxsync Log(("EMInterpretDisasOne: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Vrc !!\n",
7af218a7441de38fc9e814919db04bae3e917664vboxsync pCtxCore->cs, pCtxCore->eip, pCtxCore->ss & X86_SEL_RPL, rc));
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync return EMInterpretDisasOneEx(pVM, (RTGCUINTPTR)GCPtrInstr, pCtxCore, pCpu, pcbInstr);
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * Disassembles one instruction.
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * This is used by internally by the interpreter and by trap/access handlers.
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @param pVM The VM handle.
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @param GCPtrInstr The flat address of the instruction.
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @param pCtxCore The context core (used to determin the cpu mode).
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @param pCpu Where to return the parsed instruction info.
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @param pcbInstr Where to return the instruction size. (optional)
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsyncEMDECL(int) EMInterpretDisasOneEx(PVM pVM, RTGCUINTPTR GCPtrInstr, PCCPUMCTXCORE pCtxCore, PDISCPUSTATE pCpu, unsigned *pcbInstr)
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync int rc = DISCoreOneEx(GCPtrInstr, SELMIsSelector32Bit(pVM, pCtxCore->eflags, pCtxCore->cs, (PCPUMSELREGHID)&pCtxCore->csHid) ? CPUMODE_32BIT : CPUMODE_16BIT,
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync AssertMsgFailed(("DISCoreOne failed to GCPtrInstr=%VGv rc=%Vrc\n", GCPtrInstr, rc));
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * Interprets the current instruction.
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @returns VBox status code.
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @retval VINF_* Scheduling instructions.
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @retval VERR_EM_INTERPRETER Something we can't cope with.
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @retval VERR_* Fatal errors.
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @param pVM The VM handle.
7af218a7441de38fc9e814919db04bae3e917664vboxsync * @param pRegFrame The register frame.
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * Updates the EIP if an instruction was executed successfully.
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @param pvFault The fault address (CR2).
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @param pcbSize Size of the write (if applicable).
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @remark Invalid opcode exceptions have a higher priority than GP (see Intel
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * Architecture System Developers Manual, Vol 3, 5.5) so we don't need
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * to worry about e.g. invalid modrm combinations (!)
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsyncEMDECL(int) EMInterpretInstruction(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &pbCode);
7af218a7441de38fc9e814919db04bae3e917664vboxsync Cpu.mode = SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) ? CPUMODE_32BIT : CPUMODE_16BIT;
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync rc = emDisCoreOne(pVM, &Cpu, (RTGCUINTPTR)pbCode, &cbOp);
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync rc = EMInterpretInstructionCPU(pVM, &Cpu, pRegFrame, pvFault, pcbSize);
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync pRegFrame->eip += cbOp; /* Move on to the next instruction. */
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * Interprets the current instruction using the supplied DISCPUSTATE structure.
7af218a7441de38fc9e814919db04bae3e917664vboxsync * EIP is *NOT* updated!
7af218a7441de38fc9e814919db04bae3e917664vboxsync * @returns VBox status code.
7af218a7441de38fc9e814919db04bae3e917664vboxsync * @retval VINF_* Scheduling instructions. When these are returned, it
7af218a7441de38fc9e814919db04bae3e917664vboxsync * starts to get a bit tricky to know whether code was
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * executed or not... We'll address this when it becomes a problem.
7af218a7441de38fc9e814919db04bae3e917664vboxsync * @retval VERR_EM_INTERPRETER Something we can't cope with.
7af218a7441de38fc9e814919db04bae3e917664vboxsync * @retval VERR_* Fatal errors.
7af218a7441de38fc9e814919db04bae3e917664vboxsync * @param pVM The VM handle.
7af218a7441de38fc9e814919db04bae3e917664vboxsync * @param pCpu The disassembler cpu state for the instruction to be interpreted.
7af218a7441de38fc9e814919db04bae3e917664vboxsync * @param pRegFrame The register frame. EIP is *NOT* changed!
7af218a7441de38fc9e814919db04bae3e917664vboxsync * @param pvFault The fault address (CR2).
7af218a7441de38fc9e814919db04bae3e917664vboxsync * @param pcbSize Size of the write (if applicable).
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @remark Invalid opcode exceptions have a higher priority than GP (see Intel
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * Architecture System Developers Manual, Vol 3, 5.5) so we don't need
7af218a7441de38fc9e814919db04bae3e917664vboxsync * to worry about e.g. invalid modrm combinations (!)
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * @todo At this time we do NOT check if the instruction overwrites vital information.
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * Make sure this can't happen!! (will add some assertions/checks later)
172ae196da38208e5f1e3485715a89f2d53c6880vboxsyncEMDECL(int) EMInterpretInstructionCPU(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync STAM_PROFILE_START(&CTXMID(pVM->em.s.CTXSUFF(pStats)->Stat,Emulate), a);
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync int rc = emInterpretInstructionCPU(pVM, pCpu, pRegFrame, pvFault, pcbSize);
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync STAM_PROFILE_STOP(&CTXMID(pVM->em.s.CTXSUFF(pStats)->Stat,Emulate), a);
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,InterpretSucceeded));
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,InterpretFailed));
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * Interpret a port I/O instruction.
20593760b116c90f3e439552763eef632a3bbb17vboxsync * @returns VBox status code suitable for scheduling.
20593760b116c90f3e439552763eef632a3bbb17vboxsync * @param pVM The VM handle.
20593760b116c90f3e439552763eef632a3bbb17vboxsync * @param pCtxCore The context core. This will be updated on successful return.
20593760b116c90f3e439552763eef632a3bbb17vboxsync * @param pCpu The instruction to interpret.
20593760b116c90f3e439552763eef632a3bbb17vboxsync * @param cbOp The size of the instruction.
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * @remark This may raise exceptions.
20593760b116c90f3e439552763eef632a3bbb17vboxsyncEMDECL(int) EMInterpretPortIO(PVM pVM, PCPUMCTXCORE pCtxCore, PDISCPUSTATE pCpu, uint32_t cbOp)
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * Hand it on to IOM.
172ae196da38208e5f1e3485715a89f2d53c6880vboxsyncDECLINLINE(int) emRamRead(PVM pVM, void *pDest, RTGCPTR GCSrc, uint32_t cb)
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * The page pool cache may end up here in some cases because it
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * flushed one of the shadow mappings used by the trapping
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * instruction and it either flushed the TLB or the CPU reused it.
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync return PGMPhysReadGCPtrSafe(pVM, pDest, GCSrc, cb);
172ae196da38208e5f1e3485715a89f2d53c6880vboxsyncDECLINLINE(int) emRamWrite(PVM pVM, RTGCPTR GCDest, void *pSrc, uint32_t cb)
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync * The page pool cache may end up here in some cases because it
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync * flushed one of the shadow mappings used by the trapping
db55f7b1060a6a72704b5369a8e776c59e5e4f64vboxsync * instruction and it either flushed the TLB or the CPU reused it.
db55f7b1060a6a72704b5369a8e776c59e5e4f64vboxsync * We want to play safe here, verifying that we've got write
db55f7b1060a6a72704b5369a8e776c59e5e4f64vboxsync * access doesn't cost us much (see PGMPhysGCPtr2GCPhys()).
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync PGMPhysWrite(pVM, GCPhys + ((RTGCUINTPTR)GCDest & PAGE_OFFSET_MASK), pSrc, cb);
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync return PGMPhysWriteGCPtrSafe(pVM, GCDest, pSrc, cb);
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync/* Convert sel:addr to a flat GC address */
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsyncstatic RTGCPTR emConvertToFlatAddr(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, POP_PARAMETER pParam, RTGCPTR pvAddr)
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync rc = DISFetchRegSegEx(pRegFrame, prefix_seg, &sel, &pSelHidReg);
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync return SELMToFlat(pVM, pRegFrame->eflags, sel, pSelHidReg, pvAddr);
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync * XCHG instruction emulation.
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsyncstatic int emInterpretXchg(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync /* Source to make DISQueryParamVal read the register value - ugly hack */
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, ¶m1, PARAM_SOURCE);
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, ¶m2, PARAM_SOURCE);
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync AssertReturn(pCpu->param1.size == pCpu->param2.size, VERR_EM_INTERPRETER);
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync case PARMTYPE_IMMEDIATE: /* register type is translated to this one too */
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync /* Safety check (in theory it could cross a page boundary and fault there though) */
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync AssertReturn(pParam1 == pvFault, VERR_EM_INTERPRETER);
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
72a6fe3989272cb2d409b50caca25e1edbca9398vboxsync AssertMsgFailed(("MMGCRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync pParam2 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param2, pParam2);
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync /* Safety check (in theory it could cross a page boundary and fault there though) */
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync AssertReturn(pParam2 == pvFault, VERR_EM_INTERPRETER);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = emRamRead(pVM, &valpar2, pParam2, param2.size);
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync AssertMsgFailed(("MMGCRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync /* Write value of parameter 2 to parameter 1 (reg or memory address) */
de6e321f351aa489a6a62bed474390a0056e8093vboxsync Assert(param1.type == PARMTYPE_IMMEDIATE); /* register actually */
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync rc = DISWriteReg8(pRegFrame, pCpu->param1.base.reg_gen8, (uint8_t)valpar2); break;
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync case 2: rc = DISWriteReg16(pRegFrame, pCpu->param1.base.reg_gen32, (uint16_t)valpar2); break;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync case 4: rc = DISWriteReg32(pRegFrame, pCpu->param1.base.reg_gen32, valpar2); break;
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync rc = emRamWrite(pVM, pParam1, &valpar2, param1.size);
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync /* Write value of parameter 1 to parameter 2 (reg or memory address) */
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync Assert(param2.type == PARMTYPE_IMMEDIATE); /* register actually */
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync rc = DISWriteReg8(pRegFrame, pCpu->param2.base.reg_gen8, (uint8_t)valpar1); break;
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync case 2: rc = DISWriteReg16(pRegFrame, pCpu->param2.base.reg_gen32, (uint16_t)valpar1); break;
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync case 4: rc = DISWriteReg32(pRegFrame, pCpu->param2.base.reg_gen32, valpar1); break;
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync rc = emRamWrite(pVM, pParam2, &valpar1, param2.size);
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync * INC and DEC emulation.
172ae196da38208e5f1e3485715a89f2d53c6880vboxsyncstatic int emInterpretIncDec(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, ¶m1, PARAM_DEST);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* Safety check (in theory it could cross a page boundary and fault there though) */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync AssertReturn(pParam1 == pvFault, VERR_EM_INTERPRETER);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* Write result back */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* Update guest's eflags and finish. */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync | (eflags & (X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* All done! */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * POP Emulation.
bbb4c0bfd5ea55e99591d8811771257a437053eevboxsyncstatic int emInterpretPop(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
bbb4c0bfd5ea55e99591d8811771257a437053eevboxsync int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, ¶m1, PARAM_DEST);
bbb4c0bfd5ea55e99591d8811771257a437053eevboxsync /* Read stack value first */
bbb4c0bfd5ea55e99591d8811771257a437053eevboxsync if (SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->ss, &pRegFrame->ssHid) == false)
bbb4c0bfd5ea55e99591d8811771257a437053eevboxsync return VERR_EM_INTERPRETER; /* No legacy 16 bits stuff here, please. */
bbb4c0bfd5ea55e99591d8811771257a437053eevboxsync /* Convert address; don't bother checking limits etc, as we only read here */
bbb4c0bfd5ea55e99591d8811771257a437053eevboxsync pStackVal = SELMToFlat(pVM, pRegFrame->eflags, pRegFrame->ss, &pRegFrame->ssHid, (RTGCPTR)pRegFrame->esp);
bbb4c0bfd5ea55e99591d8811771257a437053eevboxsync rc = emRamRead(pVM, &valpar1, pStackVal, param1.size);
bbb4c0bfd5ea55e99591d8811771257a437053eevboxsync AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
bbb4c0bfd5ea55e99591d8811771257a437053eevboxsync /* pop [esp+xx] uses esp after the actual pop! */
bbb4c0bfd5ea55e99591d8811771257a437053eevboxsync && (pCpu->param1.flags & (USE_REG_GEN16|USE_REG_GEN32))
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync pParam1 = (RTGCPTR)((RTGCUINTPTR)pParam1 + param1.size);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* Safety check (in theory it could cross a page boundary and fault there though) */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync AssertMsgReturn(pParam1 == pvFault || (RTGCPTR)pRegFrame->esp == pvFault, ("%VGv != %VGv ss:esp=%04X:%VGv\n", pParam1, pvFault, pRegFrame->ss, pRegFrame->esp), VERR_EM_INTERPRETER);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync AssertMsgFailed(("emRamWrite %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* Update ESP as the last step */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* All done! */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * XOR/OR/AND Emulation.
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsyncstatic int emInterpretOrXorAnd(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, ¶m1, PARAM_DEST);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, ¶m2, PARAM_SOURCE);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync const char *pszInstr;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync AssertMsgFailed(("%s at %VGv parameter mismatch %d vs %d!!\n", pszInstr, pRegFrame->eip, pCpu->param1.size, pCpu->param2.size)); /* should never happen! */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* The destination is always a virtual address */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* Safety check (in theory it could cross a page boundary and fault there though) */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync AssertMsgReturn(pParam1 == pvFault, ("eip=%VGv, pParam1=%VGv pvFault=%VGv\n", pRegFrame->eip, pParam1, pvFault), VERR_EM_INTERPRETER);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* Register or immediate data */
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* Data read, emulate instruction. */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync uint32_t eflags = pfnEmulate(&valpar1, valpar2, param2.size);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* Update guest's eflags and finish. */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* And write it back */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* All done! */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * ADD, ADC & SUB Emulation.
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsyncstatic int emInterpretAddSub(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, ¶m1, PARAM_DEST);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, ¶m2, PARAM_SOURCE);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync const char *pszInstr;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync AssertMsgFailed(("%s at %VGv parameter mismatch %d vs %d!!\n", pszInstr, pRegFrame->eip, pCpu->param1.size, pCpu->param2.size)); /* should never happen! */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* Or %Ev, Ib -> just a hack to save some space; the data width of the 1st parameter determines the real width */
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync /* The destination is always a virtual address */
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync /* Safety check (in theory it could cross a page boundary and fault there though) */
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync AssertReturn(pParam1 == pvFault, VERR_EM_INTERPRETER);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync /* Register or immediate data */
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync /* Data read, emulate instruction. */
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync uint32_t eflags = pfnEmulate(&valpar1, valpar2, param2.size);
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync /* Update guest's eflags and finish. */
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* And write it back */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync rc = emRamWrite(pVM, pParam1, &valpar1, param1.size);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* All done! */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync * ADC Emulation.
a1df400bbe9d64aad400442e56eb637019300a5evboxsyncstatic int emInterpretAdc(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync return emInterpretAddSub(pVM, pCpu, pRegFrame, pvFault, pcbSize, EMEmulateAdcWithCarrySet);
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync return emInterpretAddSub(pVM, pCpu, pRegFrame, pvFault, pcbSize, EMEmulateAdd);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync * BTR/C/S Emulation.
a1df400bbe9d64aad400442e56eb637019300a5evboxsyncstatic int emInterpretBitTest(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize,
a1df400bbe9d64aad400442e56eb637019300a5evboxsync int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, ¶m1, PARAM_DEST);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, ¶m2, PARAM_SOURCE);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync const char *pszInstr;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* The destination is always a virtual address */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* Register or immediate data */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync case PARMTYPE_IMMEDIATE: /* both immediate data and register (ugly) */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync Log2(("emInterpret%s: pvFault=%VGv pParam1=%VGv val2=%x\n", pszInstr, pvFault, pParam1, valpar2));
a1df400bbe9d64aad400442e56eb637019300a5evboxsync pParam1 = (RTGCPTR)((RTGCUINTPTR)pParam1 + valpar2/8);
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync /* Safety check. */
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync AssertMsgReturn((RTGCPTR)((RTGCUINTPTR)pParam1 & ~3) == pvFault, ("pParam1=%VGv pvFault=%VGv\n", pParam1, pvFault), VERR_EM_INTERPRETER);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync AssertMsgFailed(("emRamRead %VGv size=%d failed with %Vrc\n", pParam1, param1.size, rc));
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* Data read, emulate bit test instruction. */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync Log2(("emInterpretBtx: val=%x CF=%d\n", valpar1, !!(eflags & X86_EFL_CF)));
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* Update guest's eflags and finish. */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
a1df400bbe9d64aad400442e56eb637019300a5evboxsync | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* And write it back */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* All done! */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync * MOV emulation.
a1df400bbe9d64aad400442e56eb637019300a5evboxsyncstatic int emInterpretMov(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
a1df400bbe9d64aad400442e56eb637019300a5evboxsync int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, ¶m1, PARAM_DEST);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, ¶m2, PARAM_SOURCE);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /** @todo Make this the default and don't rely on TRPM information. */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* fallthru */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync pDest = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pDest);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync case PARMTYPE_IMMEDIATE: /* register type is translated to this one too */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync Log(("emInterpretMov: unexpected type=%d eip=%VGv\n", param2.type, pRegFrame->eip));
a1df400bbe9d64aad400442e56eb637019300a5evboxsync LogFlow(("EMInterpretInstruction at %08x: OP_MOV %08X <- %08X (%d) &val32=%08x\n", pRegFrame->eip, pDest, val32, param2.size, &val32));
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* Safety check (in theory it could cross a page boundary and fault there though) */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync AssertMsgReturn(pDest == pvFault, ("eip=%VGv pDest=%VGv pvFault=%VGv\n", pRegFrame->eip, pDest, pvFault), VERR_EM_INTERPRETER);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync { /* read fault */
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync /* Source */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* fallthru */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync pSrc = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param2, pSrc);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* Safety check (in theory it could cross a page boundary and fault there though) */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync AssertReturn(pSrc == pvFault, VERR_EM_INTERPRETER);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* Destination */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync case 1: rc = DISWriteReg8(pRegFrame, pCpu->param1.base.reg_gen8, (uint8_t)val32); break;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync case 2: rc = DISWriteReg16(pRegFrame, pCpu->param1.base.reg_gen16, (uint16_t)val32); break;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync case 4: rc = DISWriteReg32(pRegFrame, pCpu->param1.base.reg_gen32, val32); break;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync LogFlow(("EMInterpretInstruction: OP_MOV %08X -> %08X (%d)\n", pSrc, val32, param1.size));
a1df400bbe9d64aad400442e56eb637019300a5evboxsyncstatic int emInterpretCmpXchg(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
a1df400bbe9d64aad400442e56eb637019300a5evboxsync /* Source to make DISQueryParamVal read the register value - ugly hack */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, ¶m1, PARAM_SOURCE);
a1df400bbe9d64aad400442e56eb637019300a5evboxsync rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param2, ¶m2, PARAM_SOURCE);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync AssertReturn(pCpu->param1.size == pCpu->param2.size, VERR_EM_INTERPRETER);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync pParam1 = emConvertToFlatAddr(pVM, pRegFrame, pCpu, &pCpu->param1, pParam1);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* Safety check (in theory it could cross a page boundary and fault there though) */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync AssertMsgReturn(pParam1 == pvFault, ("eip=%VGv pParam1=%VGv pvFault=%VGv\n", pRegFrame->eip, pParam1, pvFault), VERR_EM_INTERPRETER);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync LogFlow(("CmpXchg %VGv=%08x eax=%08x %08x\n", pParam1, valpar1, pRegFrame->eax, valpar));
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync eflags = EMGCEmulateLockCmpXchg(pParam1, &pRegFrame->eax, valpar, pCpu->param2.size);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync eflags = EMGCEmulateCmpXchg(pParam1, &pRegFrame->eax, valpar, pCpu->param2.size);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync rc = emRamRead(pVM, &valpar1, pParam1, param1.size);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync LogFlow(("CmpXchg %VGv=%08x eax=%08x %08x ZF=%d\n", pParam1, valpar1, pRegFrame->eax, valpar, !!(eflags & X86_EFL_ZF)));
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync /* Update guest's eflags and finish. */
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync * Interpret IRET (currently only to V86 code)
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync * @returns VBox status code.
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync * @param pVM The VM handle.
044af0d1e6474076366759db86f101778c5f20ccvboxsync * @param pRegFrame The register frame.
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsyncEMDECL(int) EMInterpretIret(PVM pVM, PCPUMCTXCORE pRegFrame)
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync RTGCUINTPTR pIretStack = (RTGCUINTPTR)pRegFrame->esp;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync RTGCUINTPTR eip, cs, esp, ss, eflags, ds, es, fs, gs, uMask;
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync rc = emRamRead(pVM, &eip, (RTGCPTR)pIretStack , 4);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync rc |= emRamRead(pVM, &cs, (RTGCPTR)(pIretStack + 4), 4);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync rc |= emRamRead(pVM, &eflags, (RTGCPTR)(pIretStack + 8), 4);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync AssertReturn(eflags & X86_EFL_VM, VERR_EM_INTERPRETER);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync rc |= emRamRead(pVM, &esp, (RTGCPTR)(pIretStack + 12), 4);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync rc |= emRamRead(pVM, &ss, (RTGCPTR)(pIretStack + 16), 4);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync rc |= emRamRead(pVM, &es, (RTGCPTR)(pIretStack + 20), 4);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync rc |= emRamRead(pVM, &ds, (RTGCPTR)(pIretStack + 24), 4);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync rc |= emRamRead(pVM, &fs, (RTGCPTR)(pIretStack + 28), 4);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync rc |= emRamRead(pVM, &gs, (RTGCPTR)(pIretStack + 32), 4);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* Mask away all reserved bits */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync 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;
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync Assert((pRegFrame->eflags.u32 & (X86_EFL_IF|X86_EFL_IOPL)) == X86_EFL_IF);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * IRET Emulation.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsyncstatic int emInterpretIret(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* only allow direct calls to EMInterpretIret for now */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * INVLPG Emulation.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * Interpret INVLPG
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync * @returns VBox status code.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @param pVM The VM handle.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @param pRegFrame The register frame.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @param pAddrGC Operand address
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsyncEMDECL(int) EMInterpretInvlpg(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pAddrGC)
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /** @todo is addr always a flat linear address or ds based
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * (in absence of segment override prefixes)????
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync // Note: we could also use PGMFlushPage here, but it currently doesn't always use invlpg!!!!!!!!!!
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync Log(("PGMInvalidatePage %VGv returned %VGv (%d)\n", pAddrGC, rc, rc));
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /** @todo r=bird: we shouldn't ignore returns codes like this... I'm 99% sure the error is fatal. */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsyncstatic int emInterpretInvlPg(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, ¶m1, PARAM_SOURCE);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /** @todo is addr always a flat linear address or ds based
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * (in absence of segment override prefixes)????
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync // Note: we could also use PGMFlushPage here, but it currently doesn't always use invlpg!!!!!!!!!!
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /** @todo r=bird: we shouldn't ignore returns codes like this... I'm 99% sure the error is fatal. */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * CPUID Emulation.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * Interpret CPUID given the parameters in the CPU context
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @returns VBox status code.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @param pVM The VM handle.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @param pRegFrame The register frame.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsyncEMDECL(int) EMInterpretCpuId(PVM pVM, PCPUMCTXCORE pRegFrame)
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync CPUMGetGuestCpuId(pVM, pRegFrame->eax, &pRegFrame->eax, &pRegFrame->ebx, &pRegFrame->ecx, &pRegFrame->edx);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsyncstatic int emInterpretCpuId(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync Log(("Emulate: CPUID %x -> %08x %08x %08x %08x\n", iLeaf, pRegFrame->eax, pRegFrame->ebx, pRegFrame->ecx, pRegFrame->edx));
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * MOV CRx Emulation.
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync * Interpret CRx read
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @returns VBox status code.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @param pVM The VM handle.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @param pRegFrame The register frame.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @param DestRegGen General purpose register index (USE_REG_E**))
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @param SrcRegCRx CRx register index (USE_REG_CR*)
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsyncEMDECL(int) EMInterpretCRxRead(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegCrx)
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync AssertMsgRCReturn(rc, ("CPUMGetGuestCRx %d failed\n", SrcRegCrx), VERR_EM_INTERPRETER);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync LogFlow(("MOV_CR: gen32=%d CR=%d val=%08x\n", DestRegGen, SrcRegCrx, val32));
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * Interpret LMSW
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @returns VBox status code.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @param pVM The VM handle.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @param u16Data LMSW source data.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsyncEMDECL(int) EMInterpretLMSW(PVM pVM, uint16_t u16Data)
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* don't use this path to go into protected mode! */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* Only PE, MP, EM and TS can be changed; note that PE can't be cleared by this instruction. */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync uint32_t NewCr0 = ( OldCr0 & ~( X86_CR0_MP | X86_CR0_EM | X86_CR0_TS))
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync | (u16Data & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS));
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync /* Need to change the hyper CR0? Doing it the lazy way then. */
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync if ( (OldCr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP | X86_CR0_AM | X86_CR0_WP))
8b4a8db7768e94d025f1216ecfcd50d727fa2b7cvboxsync != (NewCr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP | X86_CR0_AM | X86_CR0_WP)))
return VINF_SUCCESS;
#ifdef IN_GC
static int emInterpretClts(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
EMDECL(int) EMInterpretCRxWrite(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint32_t SrcRegGen)
switch (DestRegCrx)
case USE_REG_CR0:
#ifndef IN_RING3
return VERR_EM_INTERPRETER;
rc = CPUMSetGuestCR0(pVM, val32); AssertRC(rc); /** @todo CPUSetGuestCR0 stuff should be void, this is silly. */
# ifdef IN_GC
case USE_REG_CR2:
return VINF_SUCCESS;
case USE_REG_CR3:
return VINF_SUCCESS;
case USE_REG_CR4:
#ifndef IN_RING3
if ( (oldval & (X86_CR4_OSFSXR|X86_CR4_OSXMMEEXCPT|X86_CR4_PCE|X86_CR4_MCE|X86_CR4_PAE|X86_CR4_DE|X86_CR4_TSD|X86_CR4_PVI|X86_CR4_VME))
!= (val32 & (X86_CR4_OSFSXR|X86_CR4_OSXMMEEXCPT|X86_CR4_PCE|X86_CR4_MCE|X86_CR4_PAE|X86_CR4_DE|X86_CR4_TSD|X86_CR4_PVI|X86_CR4_VME)))
AssertFailed();
return VERR_EM_INTERPRETER;
static int emInterpretMovCRx(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
return EMInterpretCRxWrite(pVM, pRegFrame, pCpu->param1.base.reg_ctrl, pCpu->param2.base.reg_gen32);
return VERR_EM_INTERPRETER;
EMDECL(int) EMInterpretDRxWrite(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegDrx, uint32_t SrcRegGen)
return rc;
return VERR_EM_INTERPRETER;
EMDECL(int) EMInterpretDRxRead(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegDrx)
return VINF_SUCCESS;
return VERR_EM_INTERPRETER;
static int emInterpretMovDRx(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
return rc;
static int emInterpretLLdt(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
return VERR_EM_INTERPRETER;
case PARMTYPE_ADDRESS:
case PARMTYPE_IMMEDIATE:
return VERR_EM_INTERPRETER;
return VERR_EM_INTERPRETER;
if (sel == 0)
return VINF_SUCCESS;
return VERR_EM_INTERPRETER;
#ifdef IN_GC
* @remark the instruction following sti is guaranteed to be executed before any interrupts are dispatched
static int emInterpretSti(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
if(!pGCState)
return VERR_EM_INTERPRETER;
Assert(pvFault == SELMToFlat(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip));
return VINF_SUCCESS;
static int emInterpretHlt(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
return VINF_EM_HALT;
return VINF_SUCCESS;
static int emInterpretRdtsc(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
static int emInterpretMonitor(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
if (cpl != 0)
return VINF_SUCCESS;
static int emInterpretMWait(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
if (cpl != 0)
return VINF_EM_HALT;
DECLINLINE(int) emInterpretInstructionCPU(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
*pcbSize = 0;
if ( cpl != 0
return VERR_EM_INTERPRETER;
#ifdef IN_GC
return VERR_EM_INTERPRETER;
int rc;
case opcode:\
return rc
case opcode:\
return rc
case opcode:\
return rc
case opcode: STAM_COUNTER_INC(&pVM->em.s.CTXSUFF(pStats)->CTXMID(Stat,Failed##Instr)); return VERR_EM_INTERPRETER;
#ifdef IN_GC
#ifdef VBOX_WITH_STATISTICS
#ifndef IN_GC
return VERR_EM_INTERPRETER;
AssertFailed();
return VERR_INTERNAL_ERROR;