VirtualBox

source: vbox/trunk/src/VBox/VMM/PATM/VMMGC/PATMGC.cpp@ 21116

Last change on this file since 21116 was 18927, checked in by vboxsync, 16 years ago

Big step to separate VMM data structures for guest SMP. (pgm, em)

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