VirtualBox

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

Last change on this file since 56072 was 56045, checked in by vboxsync, 9 years ago

PATMRC.cpp: docs

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