VirtualBox

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

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

DIS: Reducing the DISCPUMODE even more (200 bytes now) and making it have the same layout in all contexts. This is useful since it's used several places in the VM structure. Also a bunch of other cleanups.

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

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