VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMRC/PATMRC.cpp@ 40442

Last change on this file since 40442 was 40442, checked in by vboxsync, 13 years ago

IEM integration in progress - doing some EM refactoring to ease this process.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 23.0 KB
Line 
1/* $Id: PATMRC.cpp 40442 2012-03-13 11:40:27Z vboxsync $ */
2/** @file
3 * PATM - Dynamic Guest OS Patching Manager - Guest Context
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
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
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.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_PATM
23#include <VBox/vmm/cpum.h>
24#include <VBox/vmm/stam.h>
25#include <VBox/vmm/patm.h>
26#include <VBox/vmm/pgm.h>
27#include <VBox/vmm/mm.h>
28#include <VBox/sup.h>
29#include <VBox/vmm/mm.h>
30#include <VBox/param.h>
31#include <iprt/avl.h>
32#include "PATMInternal.h"
33#include "PATMA.h"
34#include <VBox/vmm/vm.h>
35#include <VBox/dbg.h>
36#include <VBox/dis.h>
37#include <VBox/disopcode.h>
38#include <VBox/vmm/em.h>
39#include <VBox/err.h>
40#include <VBox/vmm/selm.h>
41#include <VBox/log.h>
42#include <iprt/assert.h>
43#include <iprt/asm.h>
44#include <iprt/string.h>
45
46
47/**
48 * \#PF Virtual Handler callback for Guest access a page monitored by PATM
49 *
50 * @returns VBox status code (appropriate for trap handling and GC return).
51 * @param pVM VM Handle.
52 * @param uErrorCode CPU Error code.
53 * @param pRegFrame Trap register frame.
54 * @param pvFault The fault address (cr2).
55 * @param pvRange The base address of the handled virtual range.
56 * @param offRange The offset of the access into this range.
57 * (If it's a EIP range this is the EIP, if not it's pvFault.)
58 */
59VMMRCDECL(int) PATMGCMonitorPage(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
60{
61 NOREF(uErrorCode); NOREF(pRegFrame); NOREF(pvFault); NOREF(pvRange); NOREF(offRange);
62 pVM->patm.s.pvFaultMonitor = (RTRCPTR)(RTRCUINTPTR)pvFault;
63 return VINF_PATM_CHECK_PATCH_PAGE;
64}
65
66
67/**
68 * Checks if the write is located on a page with was patched before.
69 * (if so, then we are not allowed to turn on r/w)
70 *
71 * @returns VBox status
72 * @param pVM The VM to operate on.
73 * @param pRegFrame CPU context
74 * @param GCPtr GC pointer to write address
75 * @param cbWrite Nr of bytes to write
76 *
77 */
78VMMRCDECL(int) PATMGCHandleWriteToPatchPage(PVM pVM, PCPUMCTXCORE pRegFrame, RTRCPTR GCPtr, uint32_t cbWrite)
79{
80 RTGCUINTPTR pWritePageStart, pWritePageEnd;
81 PPATMPATCHPAGE pPatchPage;
82
83 /* Quick boundary check */
84 if ( PAGE_ADDRESS(GCPtr) < PAGE_ADDRESS(pVM->patm.s.pPatchedInstrGCLowest)
85 || PAGE_ADDRESS(GCPtr) > PAGE_ADDRESS(pVM->patm.s.pPatchedInstrGCHighest)
86 )
87 return VERR_PATCH_NOT_FOUND;
88
89 STAM_PROFILE_ADV_START(&pVM->patm.s.StatPatchWriteDetect, a);
90
91 pWritePageStart = (RTRCUINTPTR)GCPtr & PAGE_BASE_GC_MASK;
92 pWritePageEnd = ((RTRCUINTPTR)GCPtr + cbWrite - 1) & PAGE_BASE_GC_MASK;
93
94 pPatchPage = (PPATMPATCHPAGE)RTAvloU32Get(CTXSUFF(&pVM->patm.s.PatchLookupTree)->PatchTreeByPage, (AVLOU32KEY)pWritePageStart);
95 if ( !pPatchPage
96 && pWritePageStart != pWritePageEnd
97 )
98 {
99 pPatchPage = (PPATMPATCHPAGE)RTAvloU32Get(CTXSUFF(&pVM->patm.s.PatchLookupTree)->PatchTreeByPage, (AVLOU32KEY)pWritePageEnd);
100 }
101
102#ifdef LOG_ENABLED
103 if (pPatchPage)
104 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));
105#endif
106
107 if (pPatchPage)
108 {
109 if ( pPatchPage->pLowestAddrGC > (RTRCPTR)((RTRCUINTPTR)GCPtr + cbWrite - 1)
110 || pPatchPage->pHighestAddrGC < (RTRCPTR)GCPtr)
111 {
112 /* This part of the page was not patched; try to emulate the instruction. */
113 uint32_t cb;
114
115 LogFlow(("PATMHandleWriteToPatchPage: Interpret %x accessing %RRv\n", pRegFrame->eip, GCPtr));
116 int rc = EMInterpretInstruction(pVM, VMMGetCpu0(pVM), pRegFrame, (RTGCPTR)(RTRCUINTPTR)GCPtr, &cb);
117 if (rc == VINF_SUCCESS)
118 {
119 STAM_COUNTER_INC(&pVM->patm.s.StatPatchWriteInterpreted);
120 STAM_PROFILE_ADV_STOP(&pVM->patm.s.StatPatchWriteDetect, a);
121 return VINF_SUCCESS;
122 }
123 STAM_COUNTER_INC(&pVM->patm.s.StatPatchWriteInterpretedFailed);
124 }
125 R3PTRTYPE(PPATCHINFO) *paPatch = (R3PTRTYPE(PPATCHINFO) *)MMHyperR3ToRC(pVM, pPatchPage->aPatch);
126
127 /* Increase the invalid write counter for each patch that's registered for that page. */
128 for (uint32_t i=0;i<pPatchPage->cCount;i++)
129 {
130 PPATCHINFO pPatch = (PPATCHINFO)MMHyperR3ToRC(pVM, paPatch[i]);
131
132 pPatch->cInvalidWrites++;
133 }
134
135 STAM_PROFILE_ADV_STOP(&pVM->patm.s.StatPatchWriteDetect, a);
136 return VINF_EM_RAW_EMULATE_INSTR;
137 }
138
139 STAM_PROFILE_ADV_STOP(&pVM->patm.s.StatPatchWriteDetect, a);
140 return VERR_PATCH_NOT_FOUND;
141}
142
143
144/**
145 * Checks if the illegal instruction was caused by a patched instruction
146 *
147 * @returns VBox status
148 *
149 * @param pVM The VM handle.
150 * @param pCtxCore The relevant core context.
151 */
152VMMDECL(int) PATMGCHandleIllegalInstrTrap(PVM pVM, PCPUMCTXCORE pRegFrame)
153{
154 PPATMPATCHREC pRec;
155 int rc;
156
157 /* Very important check -> otherwise we have a security leak. */
158 AssertReturn(!pRegFrame->eflags.Bits.u1VM && (pRegFrame->ss & X86_SEL_RPL) == 1, VERR_ACCESS_DENIED);
159 Assert(PATMIsPatchGCAddr(pVM, pRegFrame->eip));
160
161 /* OP_ILLUD2 in PATM generated code? */
162 if (CTXSUFF(pVM->patm.s.pGCState)->uPendingAction)
163 {
164 LogFlow(("PATMGC: Pending action %x at %x\n", CTXSUFF(pVM->patm.s.pGCState)->uPendingAction, pRegFrame->eip));
165
166 /* Private PATM interface (@todo hack due to lack of anything generic). */
167 /* Parameters:
168 * eax = Pending action (currently PATM_ACTION_LOOKUP_ADDRESS)
169 * ecx = PATM_ACTION_MAGIC
170 */
171 if ( (pRegFrame->eax & CTXSUFF(pVM->patm.s.pGCState)->uPendingAction)
172 && pRegFrame->ecx == PATM_ACTION_MAGIC
173 )
174 {
175 CTXSUFF(pVM->patm.s.pGCState)->uPendingAction = 0;
176
177 switch (pRegFrame->eax)
178 {
179 case PATM_ACTION_LOOKUP_ADDRESS:
180 {
181 /* Parameters:
182 * edx = GC address to find
183 * edi = PATCHJUMPTABLE ptr
184 */
185 AssertMsg(!pRegFrame->edi || PATMIsPatchGCAddr(pVM, pRegFrame->edi), ("edx = %x\n", pRegFrame->edi));
186
187 Log(("PATMGC: lookup %x jump table=%x\n", pRegFrame->edx, pRegFrame->edi));
188
189 pRec = PATMQueryFunctionPatch(pVM, (RTRCPTR)(pRegFrame->edx));
190 if (pRec)
191 {
192 if (pRec->patch.uState == PATCH_ENABLED)
193 {
194 RTGCUINTPTR pRelAddr = pRec->patch.pPatchBlockOffset; /* make it relative */
195 rc = PATMAddBranchToLookupCache(pVM, (RTRCPTR)pRegFrame->edi, (RTRCPTR)pRegFrame->edx, pRelAddr);
196 if (rc == VINF_SUCCESS)
197 {
198 Log(("Patch block %RRv called as function\n", pRec->patch.pPrivInstrGC));
199 pRec->patch.flags |= PATMFL_CODE_REFERENCED;
200
201 pRegFrame->eip += PATM_ILLEGAL_INSTR_SIZE;
202 pRegFrame->eax = pRelAddr;
203 STAM_COUNTER_INC(&pVM->patm.s.StatFunctionFound);
204 return VINF_SUCCESS;
205 }
206 AssertFailed();
207 }
208 else
209 {
210 pRegFrame->eip += PATM_ILLEGAL_INSTR_SIZE;
211 pRegFrame->eax = 0; /* make it fault */
212 STAM_COUNTER_INC(&pVM->patm.s.StatFunctionNotFound);
213 return VINF_SUCCESS;
214 }
215 }
216 else
217 {
218 /* Check first before trying to generate a function/trampoline patch. */
219 if (pVM->patm.s.fOutOfMemory)
220 {
221 pRegFrame->eip += PATM_ILLEGAL_INSTR_SIZE;
222 pRegFrame->eax = 0; /* make it fault */
223 STAM_COUNTER_INC(&pVM->patm.s.StatFunctionNotFound);
224 return VINF_SUCCESS;
225 }
226 STAM_COUNTER_INC(&pVM->patm.s.StatFunctionNotFound);
227 return VINF_PATM_DUPLICATE_FUNCTION;
228 }
229 }
230
231 case PATM_ACTION_DISPATCH_PENDING_IRQ:
232 /* Parameters:
233 * edi = GC address to jump to
234 */
235 Log(("PATMGC: Dispatch pending interrupt; eip=%x->%x\n", pRegFrame->eip, pRegFrame->edi));
236
237 /* Change EIP to the guest address the patch would normally jump to after setting IF. */
238 pRegFrame->eip = pRegFrame->edi;
239
240 Assert(pVM->patm.s.CTXSUFF(pGCState)->Restore.uFlags == (PATM_RESTORE_EAX|PATM_RESTORE_ECX|PATM_RESTORE_EDI));
241 Assert(pVM->patm.s.CTXSUFF(pGCState)->fPIF == 0);
242
243 pRegFrame->eax = pVM->patm.s.CTXSUFF(pGCState)->Restore.uEAX;
244 pRegFrame->ecx = pVM->patm.s.CTXSUFF(pGCState)->Restore.uECX;
245 pRegFrame->edi = pVM->patm.s.CTXSUFF(pGCState)->Restore.uEDI;
246
247 pVM->patm.s.CTXSUFF(pGCState)->Restore.uFlags = 0;
248
249 /* We are no longer executing PATM code; set PIF again. */
250 pVM->patm.s.CTXSUFF(pGCState)->fPIF = 1;
251
252 STAM_COUNTER_INC(&pVM->patm.s.StatCheckPendingIRQ);
253
254 /* The caller will call trpmGCExitTrap, which will dispatch pending interrupts for us. */
255 return VINF_SUCCESS;
256
257 case PATM_ACTION_PENDING_IRQ_AFTER_IRET:
258 /* Parameters:
259 * edi = GC address to jump to
260 */
261 Log(("PATMGC: Dispatch pending interrupt (iret); eip=%x->%x\n", pRegFrame->eip, pRegFrame->edi));
262 Assert(pVM->patm.s.CTXSUFF(pGCState)->Restore.uFlags == (PATM_RESTORE_EAX|PATM_RESTORE_ECX|PATM_RESTORE_EDI));
263 Assert(pVM->patm.s.CTXSUFF(pGCState)->fPIF == 0);
264
265 /* Change EIP to the guest address of the iret. */
266 pRegFrame->eip = pRegFrame->edi;
267
268 pRegFrame->eax = pVM->patm.s.CTXSUFF(pGCState)->Restore.uEAX;
269 pRegFrame->ecx = pVM->patm.s.CTXSUFF(pGCState)->Restore.uECX;
270 pRegFrame->edi = pVM->patm.s.CTXSUFF(pGCState)->Restore.uEDI;
271 pVM->patm.s.CTXSUFF(pGCState)->Restore.uFlags = 0;
272
273 /* We are no longer executing PATM code; set PIF again. */
274 pVM->patm.s.CTXSUFF(pGCState)->fPIF = 1;
275
276 return VINF_PATM_PENDING_IRQ_AFTER_IRET;
277
278 case PATM_ACTION_DO_V86_IRET:
279 {
280 Log(("PATMGC: Do iret to V86 code; eip=%x\n", pRegFrame->eip));
281 Assert(pVM->patm.s.CTXSUFF(pGCState)->Restore.uFlags == (PATM_RESTORE_EAX|PATM_RESTORE_ECX));
282 Assert(pVM->patm.s.CTXSUFF(pGCState)->fPIF == 0);
283
284 pRegFrame->eax = pVM->patm.s.CTXSUFF(pGCState)->Restore.uEAX;
285 pRegFrame->ecx = pVM->patm.s.CTXSUFF(pGCState)->Restore.uECX;
286 pVM->patm.s.CTXSUFF(pGCState)->Restore.uFlags = 0;
287
288 rc = EMInterpretIret(pVM, VMMGetCpu0(pVM), pRegFrame);
289 if (RT_SUCCESS(rc))
290 {
291 STAM_COUNTER_INC(&pVM->patm.s.StatEmulIret);
292
293 /* We are no longer executing PATM code; set PIF again. */
294 pVM->patm.s.CTXSUFF(pGCState)->fPIF = 1;
295 PGMRZDynMapReleaseAutoSet(VMMGetCpu0(pVM));
296 CPUMGCCallV86Code(pRegFrame);
297 /* does not return */
298 }
299 else
300 STAM_COUNTER_INC(&pVM->patm.s.StatEmulIretFailed);
301 return rc;
302 }
303
304#ifdef DEBUG
305 case PATM_ACTION_LOG_CLI:
306 Log(("PATMGC: 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) ));
307 pRegFrame->eip += PATM_ILLEGAL_INSTR_SIZE;
308 return VINF_SUCCESS;
309
310 case PATM_ACTION_LOG_STI:
311 Log(("PATMGC: 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) ));
312 pRegFrame->eip += PATM_ILLEGAL_INSTR_SIZE;
313 return VINF_SUCCESS;
314
315 case PATM_ACTION_LOG_POPF_IF1:
316 Log(("PATMGC: 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)));
317 pRegFrame->eip += PATM_ILLEGAL_INSTR_SIZE;
318 return VINF_SUCCESS;
319
320 case PATM_ACTION_LOG_POPF_IF0:
321 Log(("PATMGC: 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)));
322 pRegFrame->eip += PATM_ILLEGAL_INSTR_SIZE;
323 return VINF_SUCCESS;
324
325 case PATM_ACTION_LOG_PUSHF:
326 Log(("PATMGC: 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) ));
327 pRegFrame->eip += PATM_ILLEGAL_INSTR_SIZE;
328 return VINF_SUCCESS;
329
330 case PATM_ACTION_LOG_IF1:
331 Log(("PATMGC: IF=1 escape from %x\n", pRegFrame->eip));
332 pRegFrame->eip += PATM_ILLEGAL_INSTR_SIZE;
333 return VINF_SUCCESS;
334
335 case PATM_ACTION_LOG_IRET:
336 {
337 char *pIretFrame = (char *)pRegFrame->edx;
338 uint32_t eip, selCS, uEFlags;
339
340 rc = MMGCRamRead(pVM, &eip, pIretFrame, 4);
341 rc |= MMGCRamRead(pVM, &selCS, pIretFrame + 4, 4);
342 rc |= MMGCRamRead(pVM, &uEFlags, pIretFrame + 8, 4);
343 if (rc == VINF_SUCCESS)
344 {
345 if ( (uEFlags & X86_EFL_VM)
346 || (selCS & X86_SEL_RPL) == 3)
347 {
348 uint32_t selSS, esp;
349
350 rc |= MMGCRamRead(pVM, &esp, pIretFrame + 12, 4);
351 rc |= MMGCRamRead(pVM, &selSS, pIretFrame + 16, 4);
352
353 if (uEFlags & X86_EFL_VM)
354 {
355 uint32_t selDS, selES, selFS, selGS;
356 rc = MMGCRamRead(pVM, &selES, pIretFrame + 20, 4);
357 rc |= MMGCRamRead(pVM, &selDS, pIretFrame + 24, 4);
358 rc |= MMGCRamRead(pVM, &selFS, pIretFrame + 28, 4);
359 rc |= MMGCRamRead(pVM, &selGS, pIretFrame + 32, 4);
360 if (rc == VINF_SUCCESS)
361 {
362 Log(("PATMGC: IRET->VM stack frame: return address %04X:%x eflags=%08x ss:esp=%04X:%x\n", selCS, eip, uEFlags, selSS, esp));
363 Log(("PATMGC: IRET->VM stack frame: DS=%04X ES=%04X FS=%04X GS=%04X\n", selDS, selES, selFS, selGS));
364 }
365 }
366 else
367 Log(("PATMGC: IRET stack frame: return address %04X:%x eflags=%08x ss:esp=%04X:%x\n", selCS, eip, uEFlags, selSS, esp));
368 }
369 else
370 Log(("PATMGC: IRET stack frame: return address %04X:%x eflags=%08x\n", selCS, eip, uEFlags));
371 }
372 Log(("PATMGC: IRET from %x (IF->1) current eflags=%x\n", pRegFrame->eip, pVM->patm.s.CTXSUFF(pGCState)->uVMFlags));
373 pRegFrame->eip += PATM_ILLEGAL_INSTR_SIZE;
374 return VINF_SUCCESS;
375 }
376
377 case PATM_ACTION_LOG_GATE_ENTRY:
378 {
379 char *pIretFrame = (char *)pRegFrame->edx;
380 uint32_t eip, selCS, uEFlags;
381
382 rc = MMGCRamRead(pVM, &eip, pIretFrame, 4);
383 rc |= MMGCRamRead(pVM, &selCS, pIretFrame + 4, 4);
384 rc |= MMGCRamRead(pVM, &uEFlags, pIretFrame + 8, 4);
385 if (rc == VINF_SUCCESS)
386 {
387 if ( (uEFlags & X86_EFL_VM)
388 || (selCS & X86_SEL_RPL) == 3)
389 {
390 uint32_t selSS, esp;
391
392 rc |= MMGCRamRead(pVM, &esp, pIretFrame + 12, 4);
393 rc |= MMGCRamRead(pVM, &selSS, pIretFrame + 16, 4);
394
395 if (uEFlags & X86_EFL_VM)
396 {
397 uint32_t selDS, selES, selFS, selGS;
398 rc = MMGCRamRead(pVM, &selES, pIretFrame + 20, 4);
399 rc |= MMGCRamRead(pVM, &selDS, pIretFrame + 24, 4);
400 rc |= MMGCRamRead(pVM, &selFS, pIretFrame + 28, 4);
401 rc |= MMGCRamRead(pVM, &selGS, pIretFrame + 32, 4);
402 if (rc == VINF_SUCCESS)
403 {
404 Log(("PATMGC: GATE->VM stack frame: return address %04X:%x eflags=%08x ss:esp=%04X:%x\n", selCS, eip, uEFlags, selSS, esp));
405 Log(("PATMGC: GATE->VM stack frame: DS=%04X ES=%04X FS=%04X GS=%04X\n", selDS, selES, selFS, selGS));
406 }
407 }
408 else
409 Log(("PATMGC: GATE stack frame: return address %04X:%x eflags=%08x ss:esp=%04X:%x\n", selCS, eip, uEFlags, selSS, esp));
410 }
411 else
412 Log(("PATMGC: GATE stack frame: return address %04X:%x eflags=%08x\n", selCS, eip, uEFlags));
413 }
414 pRegFrame->eip += PATM_ILLEGAL_INSTR_SIZE;
415 return VINF_SUCCESS;
416 }
417
418 case PATM_ACTION_LOG_RET:
419 Log(("PATMGC: 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)));
420 pRegFrame->eip += PATM_ILLEGAL_INSTR_SIZE;
421 return VINF_SUCCESS;
422
423 case PATM_ACTION_LOG_CALL:
424 Log(("PATMGC: 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)));
425 pRegFrame->eip += PATM_ILLEGAL_INSTR_SIZE;
426 return VINF_SUCCESS;
427#endif
428 default:
429 AssertFailed();
430 break;
431 }
432 }
433 else
434 AssertFailed();
435 CTXSUFF(pVM->patm.s.pGCState)->uPendingAction = 0;
436 }
437 AssertMsgFailed(("Unexpected OP_ILLUD2 in patch code at %x (pending action %x)!!!!\n", pRegFrame->eip, CTXSUFF(pVM->patm.s.pGCState)->uPendingAction));
438 return VINF_EM_RAW_EMULATE_INSTR;
439}
440
441/**
442 * Checks if the int 3 was caused by a patched instruction
443 *
444 * @returns VBox status
445 *
446 * @param pVM The VM handle.
447 * @param pCtxCore The relevant core context.
448 */
449VMMDECL(int) PATMHandleInt3PatchTrap(PVM pVM, PCPUMCTXCORE pRegFrame)
450{
451 PPATMPATCHREC pRec;
452 int rc;
453
454 AssertReturn(!pRegFrame->eflags.Bits.u1VM && (pRegFrame->ss & X86_SEL_RPL) == 1, VERR_ACCESS_DENIED);
455
456 /* Int 3 in PATM generated code? (most common case) */
457 if (PATMIsPatchGCAddr(pVM, pRegFrame->eip))
458 {
459 /* @note hardcoded assumption about it being a single byte int 3 instruction. */
460 pRegFrame->eip--;
461 return VINF_PATM_PATCH_INT3;
462 }
463
464 /** @todo could use simple caching here to speed things up. */
465 pRec = (PPATMPATCHREC)RTAvloU32Get(&CTXSUFF(pVM->patm.s.PatchLookupTree)->PatchTree, (AVLOU32KEY)(pRegFrame->eip - 1)); /* eip is pointing to the instruction *after* 'int 3' already */
466 if (pRec && pRec->patch.uState == PATCH_ENABLED)
467 {
468 if (pRec->patch.flags & PATMFL_INT3_REPLACEMENT_BLOCK)
469 {
470 Assert(pRec->patch.opcode == OP_CLI);
471 /* This is a special cli block that was turned into an int 3 patch. We jump to the generated code manually. */
472 pRegFrame->eip = (uint32_t)PATCHCODE_PTR_GC(&pRec->patch);
473 STAM_COUNTER_INC(&pVM->patm.s.StatInt3BlockRun);
474 return VINF_SUCCESS;
475 }
476 else
477 if (pRec->patch.flags & PATMFL_INT3_REPLACEMENT)
478 {
479 uint32_t cbOp;
480 DISCPUSTATE cpu;
481
482 /* eip is pointing to the instruction *after* 'int 3' already */
483 pRegFrame->eip = pRegFrame->eip - 1;
484
485 PATM_STAT_RUN_INC(&pRec->patch);
486
487 Log(("PATMHandleInt3PatchTrap found int3 for %s at %x\n", patmGetInstructionString(pRec->patch.opcode, 0), pRegFrame->eip));
488
489 switch(pRec->patch.opcode)
490 {
491 case OP_CPUID:
492 case OP_IRET:
493 break;
494
495 case OP_STR:
496 case OP_SGDT:
497 case OP_SLDT:
498 case OP_SIDT:
499 case OP_LSL:
500 case OP_LAR:
501 case OP_SMSW:
502 case OP_VERW:
503 case OP_VERR:
504 default:
505 PATM_STAT_FAULT_INC(&pRec->patch);
506 pRec->patch.cTraps++;
507 return VINF_EM_RAW_EMULATE_INSTR;
508 }
509
510 cpu.mode = SELMGetCpuModeFromSelector(pVM, pRegFrame->eflags, pRegFrame->cs, 0);
511 if(cpu.mode != CPUMODE_32BIT)
512 {
513 AssertFailed();
514 return VINF_EM_RAW_EMULATE_INSTR;
515 }
516 rc = DISCoreOne(&cpu, (uintptr_t)&pRec->patch.aPrivInstr[0], &cbOp);
517 if (RT_FAILURE(rc))
518 {
519 Log(("DISCoreOne failed with %Rrc\n", rc));
520 PATM_STAT_FAULT_INC(&pRec->patch);
521 pRec->patch.cTraps++;
522 return VINF_EM_RAW_EMULATE_INSTR;
523 }
524
525 rc = EMInterpretInstructionCpuUpdtPC(pVM, VMMGetCpu0(pVM), &cpu, pRegFrame, 0 /* not relevant here */,
526 EMCODETYPE_SUPERVISOR);
527 if (rc != VINF_SUCCESS)
528 {
529 Log(("EMInterpretInstructionCPU failed with %Rrc\n", rc));
530 PATM_STAT_FAULT_INC(&pRec->patch);
531 pRec->patch.cTraps++;
532 return VINF_EM_RAW_EMULATE_INSTR;
533 }
534 return VINF_SUCCESS;
535 }
536 }
537 return VERR_PATCH_NOT_FOUND;
538}
539
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette