[23] | 1 | /* $Id: PATMAll.cpp 41965 2012-06-29 02:52:49Z vboxsync $ */
|
---|
[1] | 2 | /** @file
|
---|
| 3 | * PATM - The Patch Manager, all contexts.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[28800] | 7 | * Copyright (C) 2006-2007 Oracle Corporation
|
---|
[1] | 8 | *
|
---|
| 9 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
| 10 | * available from http://www.virtualbox.org. This file is free software;
|
---|
| 11 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
[5999] | 12 | * General Public License (GPL) as published by the Free Software
|
---|
| 13 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
| 14 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
| 15 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
[1] | 16 | */
|
---|
| 17 |
|
---|
| 18 | /*******************************************************************************
|
---|
| 19 | * Header Files *
|
---|
| 20 | *******************************************************************************/
|
---|
| 21 | #define LOG_GROUP LOG_GROUP_PATM
|
---|
[35346] | 22 | #include <VBox/vmm/patm.h>
|
---|
| 23 | #include <VBox/vmm/cpum.h>
|
---|
[1] | 24 | #include <VBox/dis.h>
|
---|
| 25 | #include <VBox/disopcode.h>
|
---|
[35346] | 26 | #include <VBox/vmm/em.h>
|
---|
[1] | 27 | #include <VBox/err.h>
|
---|
[35346] | 28 | #include <VBox/vmm/selm.h>
|
---|
| 29 | #include <VBox/vmm/mm.h>
|
---|
[1] | 30 | #include "PATMInternal.h"
|
---|
[35346] | 31 | #include <VBox/vmm/vm.h>
|
---|
| 32 | #include <VBox/vmm/vmm.h>
|
---|
[1] | 33 | #include "PATMA.h"
|
---|
| 34 |
|
---|
| 35 | #include <VBox/log.h>
|
---|
| 36 | #include <iprt/assert.h>
|
---|
| 37 |
|
---|
| 38 |
|
---|
| 39 | /**
|
---|
| 40 | * Load virtualized flags.
|
---|
| 41 | *
|
---|
| 42 | * This function is called from CPUMRawEnter(). It doesn't have to update the
|
---|
[33540] | 43 | * IF and IOPL eflags bits, the caller will enforce those to set and 0 respectively.
|
---|
[1] | 44 | *
|
---|
[41800] | 45 | * @param pVM Pointer to the VM.
|
---|
[1] | 46 | * @param pCtxCore The cpu context core.
|
---|
| 47 | * @see pg_raw
|
---|
| 48 | */
|
---|
[12989] | 49 | VMMDECL(void) PATMRawEnter(PVM pVM, PCPUMCTXCORE pCtxCore)
|
---|
[1] | 50 | {
|
---|
[26271] | 51 | bool fPatchCode = PATMIsPatchGCAddr(pVM, pCtxCore->eip);
|
---|
[1] | 52 |
|
---|
| 53 | /*
|
---|
| 54 | * Currently we don't bother to check whether PATM is enabled or not.
|
---|
| 55 | * For all cases where it isn't, IOPL will be safe and IF will be set.
|
---|
| 56 | */
|
---|
| 57 | register uint32_t efl = pCtxCore->eflags.u32;
|
---|
| 58 | CTXSUFF(pVM->patm.s.pGCState)->uVMFlags = efl & PATM_VIRTUAL_FLAGS_MASK;
|
---|
[13822] | 59 | AssertMsg((efl & X86_EFL_IF) || PATMShouldUseRawMode(pVM, (RTRCPTR)pCtxCore->eip), ("X86_EFL_IF is clear and PATM is disabled! (eip=%RRv eflags=%08x fPATM=%d pPATMGC=%RRv-%RRv\n", pCtxCore->eip, pCtxCore->eflags.u32, PATMIsEnabled(pVM), pVM->patm.s.pPatchMemGC, pVM->patm.s.pPatchMemGC + pVM->patm.s.cbPatchMem));
|
---|
[1] | 60 |
|
---|
[13822] | 61 | AssertReleaseMsg(CTXSUFF(pVM->patm.s.pGCState)->fPIF || fPatchCode, ("fPIF=%d eip=%RRv\n", CTXSUFF(pVM->patm.s.pGCState)->fPIF, pCtxCore->eip));
|
---|
[1] | 62 |
|
---|
| 63 | efl &= ~PATM_VIRTUAL_FLAGS_MASK;
|
---|
| 64 | efl |= X86_EFL_IF;
|
---|
| 65 | pCtxCore->eflags.u32 = efl;
|
---|
| 66 |
|
---|
| 67 | #ifdef IN_RING3
|
---|
| 68 | #ifdef PATM_EMULATE_SYSENTER
|
---|
| 69 | PCPUMCTX pCtx;
|
---|
| 70 |
|
---|
| 71 | /* Check if the sysenter handler has changed. */
|
---|
[13532] | 72 | pCtx = CPUMQueryGuestCtxPtr(pVM);
|
---|
| 73 | if ( pCtx->SysEnter.cs != 0
|
---|
[1] | 74 | && pCtx->SysEnter.eip != 0
|
---|
| 75 | )
|
---|
| 76 | {
|
---|
[9228] | 77 | if (pVM->patm.s.pfnSysEnterGC != (RTRCPTR)pCtx->SysEnter.eip)
|
---|
[1] | 78 | {
|
---|
| 79 | pVM->patm.s.pfnSysEnterPatchGC = 0;
|
---|
| 80 | pVM->patm.s.pfnSysEnterGC = 0;
|
---|
| 81 |
|
---|
[13822] | 82 | Log2(("PATMRawEnter: installing sysenter patch for %RRv\n", pCtx->SysEnter.eip));
|
---|
[1] | 83 | pVM->patm.s.pfnSysEnterPatchGC = PATMR3QueryPatchGCPtr(pVM, pCtx->SysEnter.eip);
|
---|
| 84 | if (pVM->patm.s.pfnSysEnterPatchGC == 0)
|
---|
| 85 | {
|
---|
| 86 | rc = PATMR3InstallPatch(pVM, pCtx->SysEnter.eip, PATMFL_SYSENTER | PATMFL_CODE32);
|
---|
| 87 | if (rc == VINF_SUCCESS)
|
---|
| 88 | {
|
---|
| 89 | pVM->patm.s.pfnSysEnterPatchGC = PATMR3QueryPatchGCPtr(pVM, pCtx->SysEnter.eip);
|
---|
[9228] | 90 | pVM->patm.s.pfnSysEnterGC = (RTRCPTR)pCtx->SysEnter.eip;
|
---|
[1] | 91 | Assert(pVM->patm.s.pfnSysEnterPatchGC);
|
---|
| 92 | }
|
---|
| 93 | }
|
---|
| 94 | else
|
---|
[9228] | 95 | pVM->patm.s.pfnSysEnterGC = (RTRCPTR)pCtx->SysEnter.eip;
|
---|
[1] | 96 | }
|
---|
| 97 | }
|
---|
| 98 | else
|
---|
| 99 | {
|
---|
| 100 | pVM->patm.s.pfnSysEnterPatchGC = 0;
|
---|
| 101 | pVM->patm.s.pfnSysEnterGC = 0;
|
---|
| 102 | }
|
---|
| 103 | #endif
|
---|
| 104 | #endif
|
---|
| 105 | }
|
---|
| 106 |
|
---|
| 107 |
|
---|
| 108 | /**
|
---|
| 109 | * Restores virtualized flags.
|
---|
| 110 | *
|
---|
| 111 | * This function is called from CPUMRawLeave(). It will update the eflags register.
|
---|
| 112 | *
|
---|
| 113 | ** @note Only here we are allowed to switch back to guest code (without a special reason such as a trap in patch code)!!
|
---|
| 114 | *
|
---|
[41800] | 115 | * @param pVM Pointer to the VM.
|
---|
[1] | 116 | * @param pCtxCore The cpu context core.
|
---|
| 117 | * @param rawRC Raw mode return code
|
---|
| 118 | * @see @ref pg_raw
|
---|
| 119 | */
|
---|
[12989] | 120 | VMMDECL(void) PATMRawLeave(PVM pVM, PCPUMCTXCORE pCtxCore, int rawRC)
|
---|
[1] | 121 | {
|
---|
[26271] | 122 | bool fPatchCode = PATMIsPatchGCAddr(pVM, pCtxCore->eip);
|
---|
[1] | 123 | /*
|
---|
| 124 | * We will only be called if PATMRawEnter was previously called.
|
---|
| 125 | */
|
---|
| 126 | register uint32_t efl = pCtxCore->eflags.u32;
|
---|
| 127 | efl = (efl & ~PATM_VIRTUAL_FLAGS_MASK) | (CTXSUFF(pVM->patm.s.pGCState)->uVMFlags & PATM_VIRTUAL_FLAGS_MASK);
|
---|
| 128 | pCtxCore->eflags.u32 = efl;
|
---|
| 129 | CTXSUFF(pVM->patm.s.pGCState)->uVMFlags = X86_EFL_IF;
|
---|
| 130 |
|
---|
[13822] | 131 | AssertReleaseMsg((efl & X86_EFL_IF) || fPatchCode || rawRC == VINF_PATM_PENDING_IRQ_AFTER_IRET || RT_FAILURE(rawRC), ("Inconsistent state at %RRv rc=%Rrc\n", pCtxCore->eip, rawRC));
|
---|
| 132 | AssertReleaseMsg(CTXSUFF(pVM->patm.s.pGCState)->fPIF || fPatchCode || RT_FAILURE(rawRC), ("fPIF=%d eip=%RRv rc=%Rrc\n", CTXSUFF(pVM->patm.s.pGCState)->fPIF, pCtxCore->eip, rawRC));
|
---|
[1] | 133 |
|
---|
| 134 | #ifdef IN_RING3
|
---|
| 135 | if ( (efl & X86_EFL_IF)
|
---|
| 136 | && fPatchCode
|
---|
| 137 | )
|
---|
| 138 | {
|
---|
[40280] | 139 | if ( rawRC < VINF_PATM_LEAVE_RC_FIRST
|
---|
| 140 | || rawRC > VINF_PATM_LEAVE_RC_LAST)
|
---|
[1] | 141 | {
|
---|
| 142 | /*
|
---|
| 143 | * Golden rules:
|
---|
| 144 | * - Don't interrupt special patch streams that replace special instructions
|
---|
| 145 | * - Don't break instruction fusing (sti, pop ss, mov ss)
|
---|
| 146 | * - Don't go back to an instruction that has been overwritten by a patch jump
|
---|
| 147 | * - Don't interrupt an idt handler on entry (1st instruction); technically incorrect
|
---|
| 148 | *
|
---|
| 149 | */
|
---|
| 150 | if (CTXSUFF(pVM->patm.s.pGCState)->fPIF == 1) /* consistent patch instruction state */
|
---|
| 151 | {
|
---|
| 152 | PATMTRANSSTATE enmState;
|
---|
[9228] | 153 | RTRCPTR pOrgInstrGC = PATMR3PatchToGCPtr(pVM, pCtxCore->eip, &enmState);
|
---|
[1] | 154 |
|
---|
| 155 | AssertRelease(pOrgInstrGC);
|
---|
| 156 |
|
---|
| 157 | Assert(enmState != PATMTRANS_OVERWRITTEN);
|
---|
| 158 | if (enmState == PATMTRANS_SAFE)
|
---|
| 159 | {
|
---|
| 160 | Assert(!PATMFindActivePatchByEntrypoint(pVM, pOrgInstrGC));
|
---|
[13822] | 161 | Log(("Switchback from %RRv to %RRv (Psp=%x)\n", pCtxCore->eip, pOrgInstrGC, CTXSUFF(pVM->patm.s.pGCState)->Psp));
|
---|
[1] | 162 | STAM_COUNTER_INC(&pVM->patm.s.StatSwitchBack);
|
---|
| 163 | pCtxCore->eip = pOrgInstrGC;
|
---|
| 164 | fPatchCode = false; /* to reset the stack ptr */
|
---|
| 165 |
|
---|
| 166 | CTXSUFF(pVM->patm.s.pGCState)->GCPtrInhibitInterrupts = 0; /* reset this pointer; safe otherwise the state would be PATMTRANS_INHIBITIRQ */
|
---|
| 167 | }
|
---|
| 168 | else
|
---|
| 169 | {
|
---|
[13822] | 170 | LogFlow(("Patch address %RRv can't be interrupted (state=%d)!\n", pCtxCore->eip, enmState));
|
---|
[1] | 171 | STAM_COUNTER_INC(&pVM->patm.s.StatSwitchBackFail);
|
---|
| 172 | }
|
---|
| 173 | }
|
---|
| 174 | else
|
---|
| 175 | {
|
---|
[13822] | 176 | LogFlow(("Patch address %RRv can't be interrupted (fPIF=%d)!\n", pCtxCore->eip, CTXSUFF(pVM->patm.s.pGCState)->fPIF));
|
---|
[1] | 177 | STAM_COUNTER_INC(&pVM->patm.s.StatSwitchBackFail);
|
---|
| 178 | }
|
---|
| 179 | }
|
---|
| 180 | }
|
---|
| 181 | #else /* !IN_RING3 */
|
---|
| 182 | AssertMsgFailed(("!IN_RING3"));
|
---|
| 183 | #endif /* !IN_RING3 */
|
---|
| 184 |
|
---|
| 185 | if (!fPatchCode)
|
---|
| 186 | {
|
---|
[9228] | 187 | if (CTXSUFF(pVM->patm.s.pGCState)->GCPtrInhibitInterrupts == (RTRCPTR)pCtxCore->eip)
|
---|
[1] | 188 | {
|
---|
[19141] | 189 | EMSetInhibitInterruptsPC(VMMGetCpu0(pVM), pCtxCore->eip);
|
---|
[1] | 190 | }
|
---|
| 191 | CTXSUFF(pVM->patm.s.pGCState)->GCPtrInhibitInterrupts = 0;
|
---|
| 192 |
|
---|
| 193 | /* Reset the stack pointer to the top of the stack. */
|
---|
| 194 | #ifdef DEBUG
|
---|
| 195 | if (CTXSUFF(pVM->patm.s.pGCState)->Psp != PATM_STACK_SIZE)
|
---|
| 196 | {
|
---|
| 197 | LogFlow(("PATMRawLeave: Reset PATM stack (Psp = %x)\n", CTXSUFF(pVM->patm.s.pGCState)->Psp));
|
---|
| 198 | }
|
---|
| 199 | #endif
|
---|
| 200 | CTXSUFF(pVM->patm.s.pGCState)->Psp = PATM_STACK_SIZE;
|
---|
| 201 | }
|
---|
| 202 | }
|
---|
| 203 |
|
---|
| 204 | /**
|
---|
| 205 | * Get the EFLAGS.
|
---|
| 206 | * This is a worker for CPUMRawGetEFlags().
|
---|
| 207 | *
|
---|
| 208 | * @returns The eflags.
|
---|
[41783] | 209 | * @param pVM Pointer to the VM.
|
---|
[1] | 210 | * @param pCtxCore The context core.
|
---|
| 211 | */
|
---|
[12989] | 212 | VMMDECL(uint32_t) PATMRawGetEFlags(PVM pVM, PCCPUMCTXCORE pCtxCore)
|
---|
[1] | 213 | {
|
---|
| 214 | uint32_t efl = pCtxCore->eflags.u32;
|
---|
| 215 | efl &= ~PATM_VIRTUAL_FLAGS_MASK;
|
---|
| 216 | efl |= pVM->patm.s.CTXSUFF(pGCState)->uVMFlags & PATM_VIRTUAL_FLAGS_MASK;
|
---|
| 217 | return efl;
|
---|
| 218 | }
|
---|
| 219 |
|
---|
| 220 | /**
|
---|
| 221 | * Updates the EFLAGS.
|
---|
| 222 | * This is a worker for CPUMRawSetEFlags().
|
---|
| 223 | *
|
---|
[41783] | 224 | * @param pVM Pointer to the VM.
|
---|
[1] | 225 | * @param pCtxCore The context core.
|
---|
| 226 | * @param efl The new EFLAGS value.
|
---|
| 227 | */
|
---|
[12989] | 228 | VMMDECL(void) PATMRawSetEFlags(PVM pVM, PCPUMCTXCORE pCtxCore, uint32_t efl)
|
---|
[1] | 229 | {
|
---|
| 230 | pVM->patm.s.CTXSUFF(pGCState)->uVMFlags = efl & PATM_VIRTUAL_FLAGS_MASK;
|
---|
| 231 | efl &= ~PATM_VIRTUAL_FLAGS_MASK;
|
---|
| 232 | efl |= X86_EFL_IF;
|
---|
| 233 | pCtxCore->eflags.u32 = efl;
|
---|
| 234 | }
|
---|
| 235 |
|
---|
| 236 | /**
|
---|
| 237 | * Check if we must use raw mode (patch code being executed)
|
---|
| 238 | *
|
---|
[41800] | 239 | * @param pVM Pointer to the VM.
|
---|
[1] | 240 | * @param pAddrGC Guest context address
|
---|
| 241 | */
|
---|
[12989] | 242 | VMMDECL(bool) PATMShouldUseRawMode(PVM pVM, RTRCPTR pAddrGC)
|
---|
[1] | 243 | {
|
---|
| 244 | return ( PATMIsEnabled(pVM)
|
---|
[9228] | 245 | && ((pAddrGC >= (RTRCPTR)pVM->patm.s.pPatchMemGC && pAddrGC < (RTRCPTR)((RTRCUINTPTR)pVM->patm.s.pPatchMemGC + pVM->patm.s.cbPatchMem)))) ? true : false;
|
---|
[1] | 246 | }
|
---|
| 247 |
|
---|
| 248 | /**
|
---|
| 249 | * Returns the guest context pointer and size of the GC context structure
|
---|
| 250 | *
|
---|
| 251 | * @returns VBox status code.
|
---|
[41801] | 252 | * @param pVM Pointer to the VM.
|
---|
[1] | 253 | */
|
---|
[12989] | 254 | VMMDECL(RCPTRTYPE(PPATMGCSTATE)) PATMQueryGCState(PVM pVM)
|
---|
[1] | 255 | {
|
---|
| 256 | return pVM->patm.s.pGCStateGC;
|
---|
| 257 | }
|
---|
| 258 |
|
---|
| 259 | /**
|
---|
| 260 | * Checks whether the GC address is part of our patch region
|
---|
| 261 | *
|
---|
| 262 | * @returns VBox status code.
|
---|
[41801] | 263 | * @param pVM Pointer to the VM.
|
---|
[1] | 264 | * @param pAddrGC Guest context address
|
---|
| 265 | */
|
---|
[26271] | 266 | VMMDECL(bool) PATMIsPatchGCAddr(PVM pVM, RTRCUINTPTR pAddrGC)
|
---|
[1] | 267 | {
|
---|
[26271] | 268 | return (PATMIsEnabled(pVM) && pAddrGC - (RTRCUINTPTR)pVM->patm.s.pPatchMemGC < pVM->patm.s.cbPatchMem) ? true : false;
|
---|
[1] | 269 | }
|
---|
| 270 |
|
---|
| 271 | /**
|
---|
| 272 | * Set parameters for pending MMIO patch operation
|
---|
| 273 | *
|
---|
| 274 | * @returns VBox status code.
|
---|
| 275 | * @param pDevIns Device instance.
|
---|
| 276 | * @param GCPhys MMIO physical address
|
---|
| 277 | * @param pCachedData GC pointer to cached data
|
---|
| 278 | */
|
---|
[12989] | 279 | VMMDECL(int) PATMSetMMIOPatchInfo(PVM pVM, RTGCPHYS GCPhys, RTRCPTR pCachedData)
|
---|
[1] | 280 | {
|
---|
| 281 | pVM->patm.s.mmio.GCPhys = GCPhys;
|
---|
[9228] | 282 | pVM->patm.s.mmio.pCachedData = (RTRCPTR)pCachedData;
|
---|
[1] | 283 |
|
---|
| 284 | return VINF_SUCCESS;
|
---|
| 285 | }
|
---|
| 286 |
|
---|
| 287 | /**
|
---|
| 288 | * Checks if the interrupt flag is enabled or not.
|
---|
| 289 | *
|
---|
| 290 | * @returns true if it's enabled.
|
---|
[33540] | 291 | * @returns false if it's disabled.
|
---|
[1] | 292 | *
|
---|
[41783] | 293 | * @param pVM Pointer to the VM.
|
---|
[1] | 294 | */
|
---|
[12989] | 295 | VMMDECL(bool) PATMAreInterruptsEnabled(PVM pVM)
|
---|
[1] | 296 | {
|
---|
[19259] | 297 | PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(VMMGetCpu(pVM));
|
---|
[1] | 298 |
|
---|
| 299 | return PATMAreInterruptsEnabledByCtxCore(pVM, CPUMCTX2CORE(pCtx));
|
---|
| 300 | }
|
---|
| 301 |
|
---|
| 302 | /**
|
---|
| 303 | * Checks if the interrupt flag is enabled or not.
|
---|
| 304 | *
|
---|
| 305 | * @returns true if it's enabled.
|
---|
[33540] | 306 | * @returns false if it's disabled.
|
---|
[1] | 307 | *
|
---|
[41783] | 308 | * @param pVM Pointer to the VM.
|
---|
[1] | 309 | * @param pCtxCore CPU context
|
---|
| 310 | */
|
---|
[12989] | 311 | VMMDECL(bool) PATMAreInterruptsEnabledByCtxCore(PVM pVM, PCPUMCTXCORE pCtxCore)
|
---|
[1] | 312 | {
|
---|
| 313 | if (PATMIsEnabled(pVM))
|
---|
| 314 | {
|
---|
[26271] | 315 | if (PATMIsPatchGCAddr(pVM, pCtxCore->eip))
|
---|
[1] | 316 | return false;
|
---|
| 317 | }
|
---|
| 318 | return !!(pCtxCore->eflags.u32 & X86_EFL_IF);
|
---|
| 319 | }
|
---|
| 320 |
|
---|
| 321 | /**
|
---|
| 322 | * Check if the instruction is patched as a duplicated function
|
---|
| 323 | *
|
---|
| 324 | * @returns patch record
|
---|
[41801] | 325 | * @param pVM Pointer to the VM.
|
---|
[1] | 326 | * @param pInstrGC Guest context point to the instruction
|
---|
| 327 | *
|
---|
| 328 | */
|
---|
[12989] | 329 | VMMDECL(PPATMPATCHREC) PATMQueryFunctionPatch(PVM pVM, RTRCPTR pInstrGC)
|
---|
[1] | 330 | {
|
---|
| 331 | PPATMPATCHREC pRec;
|
---|
| 332 |
|
---|
[9228] | 333 | AssertCompile(sizeof(AVLOU32KEY) == sizeof(pInstrGC));
|
---|
| 334 | pRec = (PPATMPATCHREC)RTAvloU32Get(&CTXSUFF(pVM->patm.s.PatchLookupTree)->PatchTree, (AVLOU32KEY)pInstrGC);
|
---|
[1] | 335 | if ( pRec
|
---|
| 336 | && (pRec->patch.uState == PATCH_ENABLED)
|
---|
| 337 | && (pRec->patch.flags & (PATMFL_DUPLICATE_FUNCTION|PATMFL_CALLABLE_AS_FUNCTION))
|
---|
| 338 | )
|
---|
| 339 | return pRec;
|
---|
| 340 | return 0;
|
---|
| 341 | }
|
---|
| 342 |
|
---|
| 343 | /**
|
---|
| 344 | * Checks if the int 3 was caused by a patched instruction
|
---|
| 345 | *
|
---|
| 346 | * @returns VBox status
|
---|
| 347 | *
|
---|
[41783] | 348 | * @param pVM Pointer to the VM.
|
---|
[1] | 349 | * @param pInstrGC Instruction pointer
|
---|
| 350 | * @param pOpcode Original instruction opcode (out, optional)
|
---|
| 351 | * @param pSize Original instruction size (out, optional)
|
---|
| 352 | */
|
---|
[12989] | 353 | VMMDECL(bool) PATMIsInt3Patch(PVM pVM, RTRCPTR pInstrGC, uint32_t *pOpcode, uint32_t *pSize)
|
---|
[1] | 354 | {
|
---|
| 355 | PPATMPATCHREC pRec;
|
---|
| 356 |
|
---|
[9228] | 357 | pRec = (PPATMPATCHREC)RTAvloU32Get(&CTXSUFF(pVM->patm.s.PatchLookupTree)->PatchTree, (AVLOU32KEY)pInstrGC);
|
---|
[1] | 358 | if ( pRec
|
---|
| 359 | && (pRec->patch.uState == PATCH_ENABLED)
|
---|
| 360 | && (pRec->patch.flags & (PATMFL_INT3_REPLACEMENT|PATMFL_INT3_REPLACEMENT_BLOCK))
|
---|
| 361 | )
|
---|
| 362 | {
|
---|
| 363 | if (pOpcode) *pOpcode = pRec->patch.opcode;
|
---|
| 364 | if (pSize) *pSize = pRec->patch.cbPrivInstr;
|
---|
| 365 | return true;
|
---|
| 366 | }
|
---|
| 367 | return false;
|
---|
| 368 | }
|
---|
| 369 |
|
---|
| 370 | /**
|
---|
| 371 | * Emulate sysenter, sysexit and syscall instructions
|
---|
| 372 | *
|
---|
| 373 | * @returns VBox status
|
---|
| 374 | *
|
---|
[41783] | 375 | * @param pVM Pointer to the VM.
|
---|
[1] | 376 | * @param pCtxCore The relevant core context.
|
---|
| 377 | * @param pCpu Disassembly context
|
---|
| 378 | */
|
---|
[12989] | 379 | VMMDECL(int) PATMSysCall(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
|
---|
[1] | 380 | {
|
---|
[18927] | 381 | PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(VMMGetCpu0(pVM));
|
---|
[1] | 382 |
|
---|
[41737] | 383 | if (pCpu->pCurInstr->uOpcode == OP_SYSENTER)
|
---|
[1] | 384 | {
|
---|
| 385 | if ( pCtx->SysEnter.cs == 0
|
---|
[1162] | 386 | || pRegFrame->eflags.Bits.u1VM
|
---|
[41906] | 387 | || (pRegFrame->cs.Sel & X86_SEL_RPL) != 3
|
---|
[1] | 388 | || pVM->patm.s.pfnSysEnterPatchGC == 0
|
---|
[26296] | 389 | || pVM->patm.s.pfnSysEnterGC != (RTRCPTR)(RTRCUINTPTR)pCtx->SysEnter.eip
|
---|
[1] | 390 | || !(PATMRawGetEFlags(pVM, pRegFrame) & X86_EFL_IF))
|
---|
| 391 | goto end;
|
---|
| 392 |
|
---|
[13822] | 393 | Log2(("PATMSysCall: sysenter from %RRv to %RRv\n", pRegFrame->eip, pVM->patm.s.pfnSysEnterPatchGC));
|
---|
[1] | 394 | /** @todo the base and limit are forced to 0 & 4G-1 resp. We assume the selector is wide open here. */
|
---|
| 395 | /** @note The Intel manual suggests that the OS is responsible for this. */
|
---|
[41906] | 396 | pRegFrame->cs.Sel = (pCtx->SysEnter.cs & ~X86_SEL_RPL) | 1;
|
---|
[1] | 397 | pRegFrame->eip = /** @todo ugly conversion! */(uint32_t)pVM->patm.s.pfnSysEnterPatchGC;
|
---|
[41906] | 398 | pRegFrame->ss.Sel = pRegFrame->cs.Sel + 8; /* SysEnter.cs + 8 */
|
---|
[1] | 399 | pRegFrame->esp = pCtx->SysEnter.esp;
|
---|
[41906] | 400 | pRegFrame->eflags.u32 &= ~(X86_EFL_VM | X86_EFL_RF);
|
---|
[1] | 401 | pRegFrame->eflags.u32 |= X86_EFL_IF;
|
---|
| 402 |
|
---|
| 403 | /* Turn off interrupts. */
|
---|
| 404 | pVM->patm.s.CTXSUFF(pGCState)->uVMFlags &= ~X86_EFL_IF;
|
---|
| 405 |
|
---|
| 406 | STAM_COUNTER_INC(&pVM->patm.s.StatSysEnter);
|
---|
| 407 |
|
---|
| 408 | return VINF_SUCCESS;
|
---|
| 409 | }
|
---|
[41737] | 410 | if (pCpu->pCurInstr->uOpcode == OP_SYSEXIT)
|
---|
[1] | 411 | {
|
---|
| 412 | if ( pCtx->SysEnter.cs == 0
|
---|
[41906] | 413 | || (pRegFrame->cs.Sel & X86_SEL_RPL) != 1
|
---|
[1162] | 414 | || pRegFrame->eflags.Bits.u1VM
|
---|
[1] | 415 | || !(PATMRawGetEFlags(pVM, pRegFrame) & X86_EFL_IF))
|
---|
| 416 | goto end;
|
---|
| 417 |
|
---|
[13822] | 418 | Log2(("PATMSysCall: sysexit from %RRv to %RRv\n", pRegFrame->eip, pRegFrame->edx));
|
---|
[1] | 419 |
|
---|
[41906] | 420 | pRegFrame->cs.Sel = ((pCtx->SysEnter.cs + 16) & ~X86_SEL_RPL) | 3;
|
---|
[1] | 421 | pRegFrame->eip = pRegFrame->edx;
|
---|
[41906] | 422 | pRegFrame->ss.Sel = pRegFrame->cs.Sel + 8; /* SysEnter.cs + 24 */
|
---|
[1] | 423 | pRegFrame->esp = pRegFrame->ecx;
|
---|
| 424 |
|
---|
| 425 | STAM_COUNTER_INC(&pVM->patm.s.StatSysExit);
|
---|
| 426 |
|
---|
| 427 | return VINF_SUCCESS;
|
---|
| 428 | }
|
---|
[41737] | 429 | if (pCpu->pCurInstr->uOpcode == OP_SYSCALL)
|
---|
[1] | 430 | {
|
---|
| 431 | /** @todo implement syscall */
|
---|
| 432 | }
|
---|
| 433 | else
|
---|
[41737] | 434 | if (pCpu->pCurInstr->uOpcode == OP_SYSRET)
|
---|
[1] | 435 | {
|
---|
| 436 | /** @todo implement sysret */
|
---|
| 437 | }
|
---|
| 438 |
|
---|
| 439 | end:
|
---|
| 440 | return VINF_EM_RAW_RING_SWITCH;
|
---|
| 441 | }
|
---|
| 442 |
|
---|
| 443 | /**
|
---|
| 444 | * Adds branch pair to the lookup cache of the particular branch instruction
|
---|
| 445 | *
|
---|
| 446 | * @returns VBox status
|
---|
[41801] | 447 | * @param pVM Pointer to the VM.
|
---|
[1] | 448 | * @param pJumpTableGC Pointer to branch instruction lookup cache
|
---|
| 449 | * @param pBranchTarget Original branch target
|
---|
| 450 | * @param pRelBranchPatch Relative duplicated function address
|
---|
| 451 | */
|
---|
[12989] | 452 | VMMDECL(int) PATMAddBranchToLookupCache(PVM pVM, RTRCPTR pJumpTableGC, RTRCPTR pBranchTarget, RTRCUINTPTR pRelBranchPatch)
|
---|
[1] | 453 | {
|
---|
| 454 | PPATCHJUMPTABLE pJumpTable;
|
---|
| 455 |
|
---|
[13822] | 456 | Log(("PATMAddBranchToLookupCache: Adding (%RRv->%RRv (%RRv)) to table %RRv\n", pBranchTarget, pRelBranchPatch + pVM->patm.s.pPatchMemGC, pRelBranchPatch, pJumpTableGC));
|
---|
[1] | 457 |
|
---|
[26271] | 458 | AssertReturn(PATMIsPatchGCAddr(pVM, (RTRCUINTPTR)pJumpTableGC), VERR_INVALID_PARAMETER);
|
---|
[1] | 459 |
|
---|
[13832] | 460 | #ifdef IN_RC
|
---|
[1] | 461 | pJumpTable = (PPATCHJUMPTABLE) pJumpTableGC;
|
---|
| 462 | #else
|
---|
| 463 | pJumpTable = (PPATCHJUMPTABLE) (pJumpTableGC - pVM->patm.s.pPatchMemGC + pVM->patm.s.pPatchMemHC);
|
---|
| 464 | #endif
|
---|
| 465 | Log(("Nr addresses = %d, insert pos = %d\n", pJumpTable->cAddresses, pJumpTable->ulInsertPos));
|
---|
| 466 | if (pJumpTable->cAddresses < pJumpTable->nrSlots)
|
---|
| 467 | {
|
---|
| 468 | uint32_t i;
|
---|
| 469 |
|
---|
| 470 | for (i=0;i<pJumpTable->nrSlots;i++)
|
---|
| 471 | {
|
---|
| 472 | if (pJumpTable->Slot[i].pInstrGC == 0)
|
---|
| 473 | {
|
---|
| 474 | pJumpTable->Slot[i].pInstrGC = pBranchTarget;
|
---|
| 475 | /* Relative address - eases relocation */
|
---|
| 476 | pJumpTable->Slot[i].pRelPatchGC = pRelBranchPatch;
|
---|
| 477 | pJumpTable->cAddresses++;
|
---|
| 478 | break;
|
---|
| 479 | }
|
---|
| 480 | }
|
---|
| 481 | AssertReturn(i < pJumpTable->nrSlots, VERR_INTERNAL_ERROR);
|
---|
| 482 | #ifdef VBOX_WITH_STATISTICS
|
---|
| 483 | STAM_COUNTER_INC(&pVM->patm.s.StatFunctionLookupInsert);
|
---|
| 484 | if (pVM->patm.s.StatU32FunctionMaxSlotsUsed < i)
|
---|
| 485 | pVM->patm.s.StatU32FunctionMaxSlotsUsed = i + 1;
|
---|
| 486 | #endif
|
---|
| 487 | }
|
---|
| 488 | else
|
---|
| 489 | {
|
---|
| 490 | /* Replace an old entry. */
|
---|
| 491 | /** @todo replacement strategy isn't really bright. change to something better if required. */
|
---|
| 492 | Assert(pJumpTable->ulInsertPos < pJumpTable->nrSlots);
|
---|
| 493 | Assert((pJumpTable->nrSlots & 1) == 0);
|
---|
| 494 |
|
---|
| 495 | pJumpTable->ulInsertPos &= (pJumpTable->nrSlots-1);
|
---|
| 496 | pJumpTable->Slot[pJumpTable->ulInsertPos].pInstrGC = pBranchTarget;
|
---|
| 497 | /* Relative address - eases relocation */
|
---|
| 498 | pJumpTable->Slot[pJumpTable->ulInsertPos].pRelPatchGC = pRelBranchPatch;
|
---|
| 499 |
|
---|
| 500 | pJumpTable->ulInsertPos = (pJumpTable->ulInsertPos+1) & (pJumpTable->nrSlots-1);
|
---|
| 501 |
|
---|
| 502 | STAM_COUNTER_INC(&pVM->patm.s.StatFunctionLookupReplace);
|
---|
| 503 | }
|
---|
| 504 |
|
---|
| 505 | return VINF_SUCCESS;
|
---|
| 506 | }
|
---|
| 507 |
|
---|
[1134] | 508 |
|
---|
[9344] | 509 | #if defined(VBOX_WITH_STATISTICS) || defined(LOG_ENABLED)
|
---|
[1] | 510 | /**
|
---|
| 511 | * Return the name of the patched instruction
|
---|
| 512 | *
|
---|
| 513 | * @returns instruction name
|
---|
| 514 | *
|
---|
| 515 | * @param opcode DIS instruction opcode
|
---|
| 516 | * @param fPatchFlags Patch flags
|
---|
| 517 | */
|
---|
[12989] | 518 | VMMDECL(const char *) patmGetInstructionString(uint32_t opcode, uint32_t fPatchFlags)
|
---|
[1] | 519 | {
|
---|
[2333] | 520 | const char *pszInstr = NULL;
|
---|
[1] | 521 |
|
---|
| 522 | switch (opcode)
|
---|
| 523 | {
|
---|
| 524 | case OP_CLI:
|
---|
| 525 | pszInstr = "cli";
|
---|
| 526 | break;
|
---|
| 527 | case OP_PUSHF:
|
---|
| 528 | pszInstr = "pushf";
|
---|
| 529 | break;
|
---|
| 530 | case OP_POPF:
|
---|
| 531 | pszInstr = "popf";
|
---|
| 532 | break;
|
---|
| 533 | case OP_STR:
|
---|
| 534 | pszInstr = "str";
|
---|
| 535 | break;
|
---|
| 536 | case OP_LSL:
|
---|
| 537 | pszInstr = "lsl";
|
---|
| 538 | break;
|
---|
| 539 | case OP_LAR:
|
---|
| 540 | pszInstr = "lar";
|
---|
| 541 | break;
|
---|
| 542 | case OP_SGDT:
|
---|
| 543 | pszInstr = "sgdt";
|
---|
| 544 | break;
|
---|
| 545 | case OP_SLDT:
|
---|
| 546 | pszInstr = "sldt";
|
---|
| 547 | break;
|
---|
| 548 | case OP_SIDT:
|
---|
| 549 | pszInstr = "sidt";
|
---|
| 550 | break;
|
---|
| 551 | case OP_SMSW:
|
---|
| 552 | pszInstr = "smsw";
|
---|
| 553 | break;
|
---|
| 554 | case OP_VERW:
|
---|
| 555 | pszInstr = "verw";
|
---|
| 556 | break;
|
---|
| 557 | case OP_VERR:
|
---|
| 558 | pszInstr = "verr";
|
---|
| 559 | break;
|
---|
| 560 | case OP_CPUID:
|
---|
| 561 | pszInstr = "cpuid";
|
---|
| 562 | break;
|
---|
| 563 | case OP_JMP:
|
---|
| 564 | pszInstr = "jmp";
|
---|
| 565 | break;
|
---|
| 566 | case OP_JO:
|
---|
| 567 | pszInstr = "jo";
|
---|
| 568 | break;
|
---|
| 569 | case OP_JNO:
|
---|
| 570 | pszInstr = "jno";
|
---|
| 571 | break;
|
---|
| 572 | case OP_JC:
|
---|
| 573 | pszInstr = "jc";
|
---|
| 574 | break;
|
---|
| 575 | case OP_JNC:
|
---|
| 576 | pszInstr = "jnc";
|
---|
| 577 | break;
|
---|
| 578 | case OP_JE:
|
---|
| 579 | pszInstr = "je";
|
---|
| 580 | break;
|
---|
| 581 | case OP_JNE:
|
---|
| 582 | pszInstr = "jne";
|
---|
| 583 | break;
|
---|
| 584 | case OP_JBE:
|
---|
| 585 | pszInstr = "jbe";
|
---|
| 586 | break;
|
---|
| 587 | case OP_JNBE:
|
---|
| 588 | pszInstr = "jnbe";
|
---|
| 589 | break;
|
---|
| 590 | case OP_JS:
|
---|
| 591 | pszInstr = "js";
|
---|
| 592 | break;
|
---|
| 593 | case OP_JNS:
|
---|
| 594 | pszInstr = "jns";
|
---|
| 595 | break;
|
---|
| 596 | case OP_JP:
|
---|
| 597 | pszInstr = "jp";
|
---|
| 598 | break;
|
---|
| 599 | case OP_JNP:
|
---|
| 600 | pszInstr = "jnp";
|
---|
| 601 | break;
|
---|
| 602 | case OP_JL:
|
---|
| 603 | pszInstr = "jl";
|
---|
| 604 | break;
|
---|
| 605 | case OP_JNL:
|
---|
| 606 | pszInstr = "jnl";
|
---|
| 607 | break;
|
---|
| 608 | case OP_JLE:
|
---|
| 609 | pszInstr = "jle";
|
---|
| 610 | break;
|
---|
| 611 | case OP_JNLE:
|
---|
| 612 | pszInstr = "jnle";
|
---|
| 613 | break;
|
---|
| 614 | case OP_JECXZ:
|
---|
| 615 | pszInstr = "jecxz";
|
---|
| 616 | break;
|
---|
| 617 | case OP_LOOP:
|
---|
| 618 | pszInstr = "loop";
|
---|
| 619 | break;
|
---|
| 620 | case OP_LOOPNE:
|
---|
| 621 | pszInstr = "loopne";
|
---|
| 622 | break;
|
---|
| 623 | case OP_LOOPE:
|
---|
| 624 | pszInstr = "loope";
|
---|
| 625 | break;
|
---|
| 626 | case OP_MOV:
|
---|
| 627 | if (fPatchFlags & PATMFL_IDTHANDLER)
|
---|
| 628 | {
|
---|
| 629 | pszInstr = "mov (Int/Trap Handler)";
|
---|
| 630 | }
|
---|
| 631 | break;
|
---|
| 632 | case OP_SYSENTER:
|
---|
| 633 | pszInstr = "sysenter";
|
---|
| 634 | break;
|
---|
| 635 | case OP_PUSH:
|
---|
| 636 | pszInstr = "push (cs)";
|
---|
| 637 | break;
|
---|
| 638 | case OP_CALL:
|
---|
| 639 | pszInstr = "call";
|
---|
| 640 | break;
|
---|
| 641 | case OP_IRET:
|
---|
| 642 | pszInstr = "iret";
|
---|
| 643 | break;
|
---|
| 644 | }
|
---|
| 645 | return pszInstr;
|
---|
| 646 | }
|
---|
[9344] | 647 | #endif
|
---|