PATMRC.cpp revision d7097a142464c500766b2cb3d564986e0a072799
4c221b0da1816acf2ca302b10092df059484468dvboxsync * PATM - Dynamic Guest OS Patching Manager - Raw-mode Context.
4c221b0da1816acf2ca302b10092df059484468dvboxsync * Copyright (C) 2006-2012 Oracle Corporation
4c221b0da1816acf2ca302b10092df059484468dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
4c221b0da1816acf2ca302b10092df059484468dvboxsync * available from http://www.virtualbox.org. This file is free software;
4c221b0da1816acf2ca302b10092df059484468dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
4c221b0da1816acf2ca302b10092df059484468dvboxsync * General Public License (GPL) as published by the Free Software
4c221b0da1816acf2ca302b10092df059484468dvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
4c221b0da1816acf2ca302b10092df059484468dvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
4c221b0da1816acf2ca302b10092df059484468dvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
4c221b0da1816acf2ca302b10092df059484468dvboxsync/*******************************************************************************
4c221b0da1816acf2ca302b10092df059484468dvboxsync* Header Files *
4c221b0da1816acf2ca302b10092df059484468dvboxsync*******************************************************************************/
4c221b0da1816acf2ca302b10092df059484468dvboxsync * \#PF Virtual Handler callback for Guest access a page monitored by PATM
4c221b0da1816acf2ca302b10092df059484468dvboxsync * @returns VBox status code (appropriate for trap handling and GC return).
4c221b0da1816acf2ca302b10092df059484468dvboxsync * @param pVM VM Handle.
4c221b0da1816acf2ca302b10092df059484468dvboxsync * @param uErrorCode CPU Error code.
4c221b0da1816acf2ca302b10092df059484468dvboxsync * @param pRegFrame Trap register frame.
4c221b0da1816acf2ca302b10092df059484468dvboxsync * @param pvFault The fault address (cr2).
4c221b0da1816acf2ca302b10092df059484468dvboxsync * @param pvRange The base address of the handled virtual range.
4c221b0da1816acf2ca302b10092df059484468dvboxsync * @param offRange The offset of the access into this range.
4c221b0da1816acf2ca302b10092df059484468dvboxsync * (If it's a EIP range this is the EIP, if not it's pvFault.)
4c221b0da1816acf2ca302b10092df059484468dvboxsyncVMMRCDECL(int) PATMGCMonitorPage(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
return VINF_PATM_CHECK_PATCH_PAGE;
VMMRCDECL(int) PATMGCHandleWriteToPatchPage(PVM pVM, PCPUMCTXCORE pRegFrame, RTRCPTR GCPtr, uint32_t cbWrite)
return VERR_PATCH_NOT_FOUND;
pPatchPage = (PPATMPATCHPAGE)RTAvloU32Get(CTXSUFF(&pVM->patm.s.PatchLookupTree)->PatchTreeByPage, (AVLOU32KEY)pWritePageStart);
if ( !pPatchPage
pPatchPage = (PPATMPATCHPAGE)RTAvloU32Get(CTXSUFF(&pVM->patm.s.PatchLookupTree)->PatchTreeByPage, (AVLOU32KEY)pWritePageEnd);
#ifdef LOG_ENABLED
if (pPatchPage)
Log(("PATMGCHandleWriteToPatchPage: Found page %RRv for write to %RRv %d bytes (page low:high %RRv:%RRv\n", pPatchPage->Core.Key, GCPtr, cbWrite, pPatchPage->pLowestAddrGC, pPatchPage->pHighestAddrGC));
if (pPatchPage)
return VINF_SUCCESS;
return VINF_EM_RAW_EMULATE_INSTR;
return VERR_PATCH_NOT_FOUND;
int rc;
AssertReturn(!pRegFrame->eflags.Bits.u1VM && (pRegFrame->ss & X86_SEL_RPL) == 1, VERR_ACCESS_DENIED);
LogFlow(("PATMRC: Pending action %x at %x\n", CTXSUFF(pVM->patm.s.pGCState)->uPendingAction, pRegFrame->eip));
AssertMsg(!pRegFrame->edi || PATMIsPatchGCAddr(pVM, pRegFrame->edi), ("edx = %x\n", pRegFrame->edi));
if (pRec)
return VINF_SUCCESS;
AssertFailed();
return VINF_SUCCESS;
/* Check first before trying to generate a function/trampoline patch. */
return VINF_SUCCESS;
return VINF_PATM_DUPLICATE_FUNCTION;
Assert(pVM->patm.s.CTXSUFF(pGCState)->Restore.uFlags == (PATM_RESTORE_EAX|PATM_RESTORE_ECX|PATM_RESTORE_EDI));
return VINF_SUCCESS;
Assert(pVM->patm.s.CTXSUFF(pGCState)->Restore.uFlags == (PATM_RESTORE_EAX|PATM_RESTORE_ECX|PATM_RESTORE_EDI));
return VINF_PATM_PENDING_IRQ_AFTER_IRET;
case PATM_ACTION_DO_V86_IRET:
return rc;
#ifdef DEBUG
case PATM_ACTION_LOG_CLI:
Log(("PATMRC: CLI at %x (current IF=%d iopl=%d)\n", pRegFrame->eip, !!(pVM->patm.s.CTXSUFF(pGCState)->uVMFlags & X86_EFL_IF), X86_EFL_GET_IOPL(pVM->patm.s.CTXSUFF(pGCState)->uVMFlags) ));
return VINF_SUCCESS;
case PATM_ACTION_LOG_STI:
Log(("PATMRC: STI at %x (current IF=%d iopl=%d)\n", pRegFrame->eip, !!(pVM->patm.s.CTXSUFF(pGCState)->uVMFlags & X86_EFL_IF), X86_EFL_GET_IOPL(pVM->patm.s.CTXSUFF(pGCState)->uVMFlags) ));
return VINF_SUCCESS;
case PATM_ACTION_LOG_POPF_IF1:
Log(("PATMRC: POPF setting IF at %x (current IF=%d iopl=%d)\n", pRegFrame->eip, !!(pVM->patm.s.CTXSUFF(pGCState)->uVMFlags & X86_EFL_IF), X86_EFL_GET_IOPL(pVM->patm.s.CTXSUFF(pGCState)->uVMFlags)));
return VINF_SUCCESS;
case PATM_ACTION_LOG_POPF_IF0:
Log(("PATMRC: POPF at %x (current IF=%d iopl=%d)\n", pRegFrame->eip, !!(pVM->patm.s.CTXSUFF(pGCState)->uVMFlags & X86_EFL_IF), X86_EFL_GET_IOPL(pVM->patm.s.CTXSUFF(pGCState)->uVMFlags)));
return VINF_SUCCESS;
case PATM_ACTION_LOG_PUSHF:
Log(("PATMRC: PUSHF at %x (current IF=%d iopl=%d)\n", pRegFrame->eip, !!(pVM->patm.s.CTXSUFF(pGCState)->uVMFlags & X86_EFL_IF), X86_EFL_GET_IOPL(pVM->patm.s.CTXSUFF(pGCState)->uVMFlags) ));
return VINF_SUCCESS;
case PATM_ACTION_LOG_IF1:
return VINF_SUCCESS;
case PATM_ACTION_LOG_IRET:
Log(("PATMRC: IRET->VM stack frame: return address %04X:%x eflags=%08x ss:esp=%04X:%x\n", selCS, eip, uEFlags, selSS, esp));
Log(("PATMRC: IRET->VM stack frame: DS=%04X ES=%04X FS=%04X GS=%04X\n", selDS, selES, selFS, selGS));
Log(("PATMRC: IRET stack frame: return address %04X:%x eflags=%08x ss:esp=%04X:%x\n", selCS, eip, uEFlags, selSS, esp));
Log(("PATMRC: IRET from %x (IF->1) current eflags=%x\n", pRegFrame->eip, pVM->patm.s.CTXSUFF(pGCState)->uVMFlags));
return VINF_SUCCESS;
Log(("PATMRC: GATE->VM stack frame: return address %04X:%x eflags=%08x ss:esp=%04X:%x\n", selCS, eip, uEFlags, selSS, esp));
Log(("PATMRC: GATE->VM stack frame: DS=%04X ES=%04X FS=%04X GS=%04X\n", selDS, selES, selFS, selGS));
Log(("PATMRC: GATE stack frame: return address %04X:%x eflags=%08x ss:esp=%04X:%x\n", selCS, eip, uEFlags, selSS, esp));
return VINF_SUCCESS;
case PATM_ACTION_LOG_RET:
Log(("PATMRC: RET from %x to %x ESP=%x iopl=%d\n", pRegFrame->eip, pRegFrame->edx, pRegFrame->ebx, X86_EFL_GET_IOPL(pVM->patm.s.CTXSUFF(pGCState)->uVMFlags)));
return VINF_SUCCESS;
case PATM_ACTION_LOG_CALL:
Log(("PATMRC: CALL to %RRv return addr %RRv ESP=%x iopl=%d\n", pVM->patm.s.CTXSUFF(pGCState)->GCCallPatchTargetAddr, pVM->patm.s.CTXSUFF(pGCState)->GCCallReturnAddr, pRegFrame->edx, X86_EFL_GET_IOPL(pVM->patm.s.CTXSUFF(pGCState)->uVMFlags)));
return VINF_SUCCESS;
AssertFailed();
AssertFailed();
AssertMsgFailed(("Unexpected OP_ILLUD2 in patch code at %x (pending action %x)!!!!\n", pRegFrame->eip, CTXSUFF(pVM->patm.s.pGCState)->uPendingAction));
return VINF_EM_RAW_EMULATE_INSTR;
int rc;
AssertReturn(!pRegFrame->eflags.Bits.u1VM && (pRegFrame->ss & X86_SEL_RPL) == 1, VERR_ACCESS_DENIED);
return VINF_PATM_PATCH_INT3;
pRec = (PPATMPATCHREC)RTAvloU32Get(&CTXSUFF(pVM->patm.s.PatchLookupTree)->PatchTree, (AVLOU32KEY)(pRegFrame->eip - 1)); /* eip is pointing to the instruction *after* 'int 3' already */
/* This is a special cli block that was turned into an int 3 patch. We jump to the generated code manually. */
return VINF_SUCCESS;
Log(("PATMHandleInt3PatchTrap found int3 for %s at %x\n", patmGetInstructionString(pRec->patch.opcode, 0), pRegFrame->eip));
case OP_CPUID:
case OP_IRET:
case OP_STR:
case OP_SGDT:
case OP_SLDT:
case OP_SIDT:
case OP_LSL:
case OP_LAR:
case OP_SMSW:
case OP_VERW:
case OP_VERR:
return VINF_EM_RAW_EMULATE_INSTR;
AssertFailed();
return VINF_EM_RAW_EMULATE_INSTR;
#ifdef VBOX_WITH_IEM
return VINF_EM_RAW_EMULATE_INSTR;
return VINF_EM_RAW_EMULATE_INSTR;
return rc;
return VERR_PATCH_NOT_FOUND;