VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PATMPatch.cpp@ 56085

Last change on this file since 56085 was 54764, checked in by vboxsync, 10 years ago

Added an infix 'ASMFIX' to the PATMA.h fixup types used in the patch template code in PATMA.asm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 58.0 KB
Line 
1/* $Id: PATMPatch.cpp 54764 2015-03-15 03:25:11Z vboxsync $ */
2/** @file
3 * PATMPatch - Dynamic Guest OS Instruction patches
4 *
5 * NOTE: CSAM assumes patch memory is never reused!!
6 */
7
8/*
9 * Copyright (C) 2006-2015 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#define LOG_GROUP LOG_GROUP_PATM
24#include <VBox/vmm/patm.h>
25#include <VBox/vmm/pdmapi.h>
26#include <VBox/vmm/pgm.h>
27#include <VBox/vmm/cpum.h>
28#include <VBox/vmm/mm.h>
29#include <VBox/vmm/em.h>
30#include <VBox/vmm/trpm.h>
31#include <VBox/vmm/csam.h>
32#include "PATMInternal.h"
33#include <VBox/vmm/vm.h>
34#include <VBox/param.h>
35
36#include <VBox/err.h>
37#include <VBox/log.h>
38#include <VBox/dis.h>
39#include <VBox/disopcode.h>
40
41#include <iprt/assert.h>
42#include <iprt/asm.h>
43#include <iprt/string.h>
44
45#include "PATMA.h"
46#include "PATMPatch.h"
47
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52/**
53 * Internal structure for passing more information about call fixups to
54 * patmPatchGenCode.
55 */
56typedef struct
57{
58 RTRCPTR pTargetGC;
59 RTRCPTR pCurInstrGC;
60 RTRCPTR pNextInstrGC;
61 RTRCPTR pReturnGC;
62} PATMCALLINFO, *PPATMCALLINFO;
63
64
65/*******************************************************************************
66* Defined Constants And Macros *
67*******************************************************************************/
68/** Value to use when not sure about the patch size. */
69#define PATCHGEN_DEF_SIZE 256
70
71#define PATCHGEN_PROLOG_NODEF(pVM, pPatch, a_cbMaxEmit) \
72 do { \
73 cbGivenPatchSize = (a_cbMaxEmit) + 16U /*jmp++*/; \
74 if (RT_LIKELY((pPatch)->pPatchBlockOffset + pPatch->uCurPatchOffset + cbGivenPatchSize < pVM->patm.s.cbPatchMem)) \
75 pPB = PATCHCODE_PTR_HC(pPatch) + pPatch->uCurPatchOffset; \
76 else \
77 { \
78 pVM->patm.s.fOutOfMemory = true; \
79 AssertMsgFailed(("offPatch=%#x + offEmit=%#x + a_cbMaxEmit=%#x + jmp --> cbTotalWithFudge=%#x >= cbPatchMem=%#x", \
80 (pPatch)->pPatchBlockOffset, pPatch->uCurPatchOffset, a_cbMaxEmit, \
81 (pPatch)->pPatchBlockOffset + pPatch->uCurPatchOffset + cbGivenPatchSize, pVM->patm.s.cbPatchMem)); \
82 return VERR_NO_MEMORY; \
83 } \
84 } while (0)
85
86#define PATCHGEN_PROLOG(pVM, pPatch, a_cbMaxEmit) \
87 uint8_t *pPB; \
88 uint32_t cbGivenPatchSize; \
89 PATCHGEN_PROLOG_NODEF(pVM, pPatch, a_cbMaxEmit)
90
91#define PATCHGEN_EPILOG(pPatch, a_cbActual) \
92 do { \
93 AssertMsg((a_cbActual) <= cbGivenPatchSize, ("a_cbActual=%#x cbGivenPatchSize=%#x\n", a_cbActual, cbGivenPatchSize)); \
94 Assert((a_cbActual) <= 640); \
95 pPatch->uCurPatchOffset += (a_cbActual); \
96 } while (0)
97
98
99
100
101int patmPatchAddReloc32(PVM pVM, PPATCHINFO pPatch, uint8_t *pRelocHC, uint32_t uType,
102 RTRCPTR pSource /*= 0*/, RTRCPTR pDest /*= 0*/)
103{
104 PRELOCREC pRec;
105
106 Assert( uType == FIXUP_ABSOLUTE
107 || ( ( uType == FIXUP_ABSOLUTE_IN_PATCH_ASM_TMPL
108 || uType == FIXUP_CONSTANT_IN_PATCH_ASM_TMPL
109 || uType == FIXUP_REL_HELPER_IN_PATCH_ASM_TMPL)
110 && pSource == pDest
111 && PATM_IS_ASMFIX(pSource))
112 || ((uType == FIXUP_REL_JMPTOPATCH || uType == FIXUP_REL_JMPTOGUEST) && pSource && pDest));
113
114 LogFlow(("patmPatchAddReloc32 type=%d pRelocGC=%RRv source=%RRv dest=%RRv\n", uType, pRelocHC - pVM->patm.s.pPatchMemGC + pVM->patm.s.pPatchMemGC , pSource, pDest));
115
116 pRec = (PRELOCREC)MMR3HeapAllocZ(pVM, MM_TAG_PATM_PATCH, sizeof(*pRec));
117 Assert(pRec);
118 pRec->Core.Key = (AVLPVKEY)pRelocHC;
119 pRec->pRelocPos = pRelocHC; /* @todo redundant. */
120 pRec->pSource = pSource;
121 pRec->pDest = pDest;
122 pRec->uType = uType;
123
124 bool ret = RTAvlPVInsert(&pPatch->FixupTree, &pRec->Core);
125 Assert(ret); NOREF(ret);
126 pPatch->nrFixups++;
127
128 return VINF_SUCCESS;
129}
130
131int patmPatchAddJump(PVM pVM, PPATCHINFO pPatch, uint8_t *pJumpHC, uint32_t offset, RTRCPTR pTargetGC, uint32_t opcode)
132{
133 PJUMPREC pRec;
134
135 pRec = (PJUMPREC)MMR3HeapAllocZ(pVM, MM_TAG_PATM_PATCH, sizeof(*pRec));
136 Assert(pRec);
137
138 pRec->Core.Key = (AVLPVKEY)pJumpHC;
139 pRec->pJumpHC = pJumpHC; /* @todo redundant. */
140 pRec->offDispl = offset;
141 pRec->pTargetGC = pTargetGC;
142 pRec->opcode = opcode;
143
144 bool ret = RTAvlPVInsert(&pPatch->JumpTree, &pRec->Core);
145 Assert(ret); NOREF(ret);
146 pPatch->nrJumpRecs++;
147
148 return VINF_SUCCESS;
149}
150
151static uint32_t patmPatchGenCode(PVM pVM, PPATCHINFO pPatch, uint8_t *pPB, PCPATCHASMRECORD pAsmRecord,
152 RCPTRTYPE(uint8_t *) pReturnAddrGC, bool fGenJump,
153 PPATMCALLINFO pCallInfo = 0)
154{
155 Assert(fGenJump == false || pReturnAddrGC);
156 Assert(fGenJump == false || pAsmRecord->offJump);
157 Assert(pAsmRecord);
158 Assert(pAsmRecord->cbFunction > sizeof(pAsmRecord->aRelocs[0].uType) * pAsmRecord->cRelocs);
159
160 // Copy the code block
161 memcpy(pPB, pAsmRecord->pbFunction, pAsmRecord->cbFunction);
162
163 // Process all fixups
164 uint32_t i, j;
165 for (j = 0, i = 0; i < pAsmRecord->cRelocs; i++)
166 {
167 for (; j < pAsmRecord->cbFunction; j++)
168 {
169 if (*(uint32_t*)&pPB[j] == pAsmRecord->aRelocs[i].uType)
170 {
171 RCPTRTYPE(uint32_t *) dest;
172
173#ifdef VBOX_STRICT
174 if (pAsmRecord->aRelocs[i].uType == PATM_ASMFIX_FIXUP)
175 Assert(pAsmRecord->aRelocs[i].uInfo != 0);
176 else
177 Assert(pAsmRecord->aRelocs[i].uInfo == 0);
178#endif
179
180 /*
181 * BE VERY CAREFUL WITH THESE FIXUPS. TAKE INTO ACCOUNT THAT PROBLEMS MAY ARISE WHEN RESTORING
182 * A SAVED STATE WITH A DIFFERENT HYPERVISOR LAYOUT.
183 */
184 uint32_t uRelocType = FIXUP_ABSOLUTE_IN_PATCH_ASM_TMPL;
185 switch (pAsmRecord->aRelocs[i].uType)
186 {
187 /*
188 * PATMGCSTATE member fixups.
189 */
190 case PATM_ASMFIX_VMFLAGS:
191 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, uVMFlags);
192 break;
193 case PATM_ASMFIX_PENDINGACTION:
194 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, uPendingAction);
195 break;
196 case PATM_ASMFIX_STACKPTR:
197 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, Psp);
198 break;
199 case PATM_ASMFIX_INTERRUPTFLAG:
200 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, fPIF);
201 break;
202 case PATM_ASMFIX_INHIBITIRQADDR:
203 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, GCPtrInhibitInterrupts);
204 break;
205 case PATM_ASMFIX_TEMP_EAX:
206 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, Restore.uEAX);
207 break;
208 case PATM_ASMFIX_TEMP_ECX:
209 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, Restore.uECX);
210 break;
211 case PATM_ASMFIX_TEMP_EDI:
212 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, Restore.uEDI);
213 break;
214 case PATM_ASMFIX_TEMP_EFLAGS:
215 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, Restore.eFlags);
216 break;
217 case PATM_ASMFIX_TEMP_RESTORE_FLAGS:
218 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, Restore.uFlags);
219 break;
220 case PATM_ASMFIX_CALL_PATCH_TARGET_ADDR:
221 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, GCCallPatchTargetAddr);
222 break;
223 case PATM_ASMFIX_CALL_RETURN_ADDR:
224 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, GCCallReturnAddr);
225 break;
226#ifdef VBOX_WITH_STATISTICS
227 case PATM_ASMFIX_ALLPATCHCALLS:
228 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, uPatchCalls);
229 break;
230 case PATM_ASMFIX_IRETEFLAGS:
231 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, uIretEFlags);
232 break;
233 case PATM_ASMFIX_IRETCS:
234 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, uIretCS);
235 break;
236 case PATM_ASMFIX_IRETEIP:
237 dest = pVM->patm.s.pGCStateGC + RT_OFFSETOF(PATMGCSTATE, uIretEIP);
238 break;
239#endif
240
241
242 case PATM_ASMFIX_FIXUP:
243 /* Offset in aRelocs[i].uInfo is from the base of the function. */
244 dest = (RTGCUINTPTR32)pVM->patm.s.pPatchMemGC + pAsmRecord->aRelocs[i].uInfo
245 + (RTGCUINTPTR32)(pPB - pVM->patm.s.pPatchMemHC);
246 break;
247
248#ifdef VBOX_WITH_STATISTICS
249 case PATM_ASMFIX_PERPATCHCALLS:
250 dest = patmPatchQueryStatAddress(pVM, pPatch);
251 break;
252#endif
253
254 /* The first part of our PATM stack is used to store offsets of patch return addresses; the 2nd
255 * part to store the original return addresses.
256 */
257 case PATM_ASMFIX_STACKBASE:
258 dest = pVM->patm.s.pGCStackGC;
259 break;
260
261 case PATM_ASMFIX_STACKBASE_GUEST:
262 dest = pVM->patm.s.pGCStackGC + PATM_STACK_SIZE;
263 break;
264
265 case PATM_ASMFIX_RETURNADDR: /* absolute guest address; no fixup required */
266 Assert(pCallInfo && pAsmRecord->aRelocs[i].uType >= PATM_ASMFIX_NO_FIXUP);
267 dest = pCallInfo->pReturnGC;
268 break;
269
270 case PATM_ASMFIX_PATCHNEXTBLOCK: /* relative address of instruction following this block */
271 Assert(pCallInfo && pAsmRecord->aRelocs[i].uType >= PATM_ASMFIX_NO_FIXUP);
272
273 /** @note hardcoded assumption that we must return to the instruction following this block */
274 dest = (uintptr_t)pPB - (uintptr_t)pVM->patm.s.pPatchMemHC + pAsmRecord->cbFunction;
275 break;
276
277 case PATM_ASMFIX_CALLTARGET: /* relative to patch address; no fixup required */
278 Assert(pCallInfo && pAsmRecord->aRelocs[i].uType >= PATM_ASMFIX_NO_FIXUP);
279
280 /* Address must be filled in later. (see patmr3SetBranchTargets) */
281 patmPatchAddJump(pVM, pPatch, &pPB[j-1], 1, pCallInfo->pTargetGC, OP_CALL);
282 dest = PATM_ILLEGAL_DESTINATION;
283 break;
284
285 case PATM_ASMFIX_PATCHBASE: /* Patch GC base address */
286 dest = pVM->patm.s.pPatchMemGC;
287 break;
288
289 case PATM_ASMFIX_NEXTINSTRADDR:
290 Assert(pCallInfo);
291 /* pNextInstrGC can be 0 if several instructions, that inhibit irqs, follow each other */
292 dest = pCallInfo->pNextInstrGC;
293 break;
294
295 case PATM_ASMFIX_CURINSTRADDR:
296 Assert(pCallInfo);
297 dest = pCallInfo->pCurInstrGC;
298 break;
299
300 /* Relative address of global patm lookup and call function. */
301 case PATM_ASMFIX_LOOKUP_AND_CALL_FUNCTION:
302 {
303 RTRCPTR pInstrAfterCall = pVM->patm.s.pPatchMemGC
304 + (RTGCUINTPTR32)(&pPB[j] + sizeof(RTRCPTR) - pVM->patm.s.pPatchMemHC);
305 Assert(pVM->patm.s.pfnHelperCallGC);
306 Assert(sizeof(uint32_t) == sizeof(RTRCPTR));
307
308 /* Relative value is target minus address of instruction after the actual call instruction. */
309 dest = pVM->patm.s.pfnHelperCallGC - pInstrAfterCall;
310 break;
311 }
312
313 case PATM_ASMFIX_RETURN_FUNCTION:
314 {
315 RTRCPTR pInstrAfterCall = pVM->patm.s.pPatchMemGC
316 + (RTGCUINTPTR32)(&pPB[j] + sizeof(RTRCPTR) - pVM->patm.s.pPatchMemHC);
317 Assert(pVM->patm.s.pfnHelperRetGC);
318 Assert(sizeof(uint32_t) == sizeof(RTRCPTR));
319
320 /* Relative value is target minus address of instruction after the actual call instruction. */
321 dest = pVM->patm.s.pfnHelperRetGC - pInstrAfterCall;
322 break;
323 }
324
325 case PATM_ASMFIX_IRET_FUNCTION:
326 {
327 RTRCPTR pInstrAfterCall = pVM->patm.s.pPatchMemGC
328 + (RTGCUINTPTR32)(&pPB[j] + sizeof(RTRCPTR) - pVM->patm.s.pPatchMemHC);
329 Assert(pVM->patm.s.pfnHelperIretGC);
330 Assert(sizeof(uint32_t) == sizeof(RTRCPTR));
331
332 /* Relative value is target minus address of instruction after the actual call instruction. */
333 dest = pVM->patm.s.pfnHelperIretGC - pInstrAfterCall;
334 break;
335 }
336
337 case PATM_ASMFIX_LOOKUP_AND_JUMP_FUNCTION:
338 {
339 RTRCPTR pInstrAfterCall = pVM->patm.s.pPatchMemGC
340 + (RTGCUINTPTR32)(&pPB[j] + sizeof(RTRCPTR) - pVM->patm.s.pPatchMemHC);
341 Assert(pVM->patm.s.pfnHelperJumpGC);
342 Assert(sizeof(uint32_t) == sizeof(RTRCPTR));
343
344 /* Relative value is target minus address of instruction after the actual call instruction. */
345 dest = pVM->patm.s.pfnHelperJumpGC - pInstrAfterCall;
346 break;
347 }
348
349 case PATM_ASMFIX_CPUID_STD_MAX: /* saved state only */
350 dest = CPUMR3GetGuestCpuIdPatmStdMax(pVM);
351 break;
352 case PATM_ASMFIX_CPUID_EXT_MAX: /* saved state only */
353 dest = CPUMR3GetGuestCpuIdPatmExtMax(pVM);
354 break;
355 case PATM_ASMFIX_CPUID_CENTAUR_MAX: /* saved state only */
356 dest = CPUMR3GetGuestCpuIdPatmCentaurMax(pVM);
357 break;
358
359 /*
360 * The following fixups needs to be recalculated when loading saved state
361 * Note! Earlier saved state versions had different hacks for detecting some of these.
362 */
363 case PATM_ASMFIX_VM_FORCEDACTIONS:
364 dest = pVM->pVMRC + RT_OFFSETOF(VM, aCpus[0].fLocalForcedActions);
365 break;
366
367 case PATM_ASMFIX_CPUID_DEF_PTR: /* saved state only */
368 dest = CPUMR3GetGuestCpuIdPatmDefRCPtr(pVM);
369 break;
370 case PATM_ASMFIX_CPUID_STD_PTR: /* saved state only */
371 dest = CPUMR3GetGuestCpuIdPatmStdRCPtr(pVM);
372 break;
373 case PATM_ASMFIX_CPUID_EXT_PTR: /* saved state only */
374 dest = CPUMR3GetGuestCpuIdPatmExtRCPtr(pVM);
375 break;
376 case PATM_ASMFIX_CPUID_CENTAUR_PTR: /* saved state only */
377 dest = CPUMR3GetGuestCpuIdPatmCentaurRCPtr(pVM);
378 break;
379
380 /*
381 * The following fixups are constants and helper code calls that only
382 * needs to be corrected when loading saved state.
383 */
384 case PATM_ASMFIX_HELPER_CPUM_CPUID:
385 {
386 int rc = PDMR3LdrGetSymbolRC(pVM, NULL, "CPUMPatchHlpCpuId", &dest);
387 AssertReleaseRCBreakStmt(rc, dest = PATM_ILLEGAL_DESTINATION);
388 uRelocType = FIXUP_REL_HELPER_IN_PATCH_ASM_TMPL;
389 break;
390 }
391
392 /*
393 * Unknown fixup.
394 */
395 case PATM_ASMFIX_REUSE_LATER_0:
396 case PATM_ASMFIX_REUSE_LATER_1:
397 case PATM_ASMFIX_REUSE_LATER_2:
398 case PATM_ASMFIX_REUSE_LATER_3:
399 default:
400 AssertReleaseMsgFailed(("Unknown fixup: %#x\n", pAsmRecord->aRelocs[i].uType));
401 dest = PATM_ILLEGAL_DESTINATION;
402 break;
403 }
404
405 if (uRelocType == FIXUP_REL_HELPER_IN_PATCH_ASM_TMPL)
406 {
407 RTRCUINTPTR RCPtrAfter = pVM->patm.s.pPatchMemGC
408 + (RTRCUINTPTR)(&pPB[j + sizeof(RTRCPTR)] - pVM->patm.s.pPatchMemHC);
409 dest -= RCPtrAfter;
410 }
411
412 *(PRTRCPTR)&pPB[j] = dest;
413
414 if (pAsmRecord->aRelocs[i].uType < PATM_ASMFIX_NO_FIXUP)
415 {
416 patmPatchAddReloc32(pVM, pPatch, &pPB[j], uRelocType,
417 pAsmRecord->aRelocs[i].uType /*pSources*/, pAsmRecord->aRelocs[i].uType /*pDest*/);
418 }
419 break;
420 }
421 }
422 Assert(j < pAsmRecord->cbFunction);
423 }
424 Assert(pAsmRecord->aRelocs[i].uInfo == 0xffffffff);
425
426 /* Add the jump back to guest code (if required) */
427 if (fGenJump)
428 {
429 int32_t displ = pReturnAddrGC - (PATCHCODE_PTR_GC(pPatch) + pPatch->uCurPatchOffset + pAsmRecord->offJump - 1 + SIZEOF_NEARJUMP32);
430
431 /* Add lookup record for patch to guest address translation */
432 Assert(pPB[pAsmRecord->offJump - 1] == 0xE9);
433 patmR3AddP2GLookupRecord(pVM, pPatch, &pPB[pAsmRecord->offJump - 1], pReturnAddrGC, PATM_LOOKUP_PATCH2GUEST);
434
435 *(uint32_t *)&pPB[pAsmRecord->offJump] = displ;
436 patmPatchAddReloc32(pVM, pPatch, &pPB[pAsmRecord->offJump], FIXUP_REL_JMPTOGUEST,
437 PATCHCODE_PTR_GC(pPatch) + pPatch->uCurPatchOffset + pAsmRecord->offJump - 1 + SIZEOF_NEARJUMP32,
438 pReturnAddrGC);
439 }
440
441 // Calculate the right size of this patch block
442 if ((fGenJump && pAsmRecord->offJump) || (!fGenJump && !pAsmRecord->offJump))
443 return pAsmRecord->cbFunction;
444 // if a jump instruction is present and we don't want one, then subtract SIZEOF_NEARJUMP32
445 return pAsmRecord->cbFunction - SIZEOF_NEARJUMP32;
446}
447
448/* Read bytes and check for overwritten instructions. */
449static int patmPatchReadBytes(PVM pVM, uint8_t *pDest, RTRCPTR pSrc, uint32_t cb)
450{
451 int rc = PGMPhysSimpleReadGCPtr(&pVM->aCpus[0], pDest, pSrc, cb);
452 AssertRCReturn(rc, rc);
453 /*
454 * Could be patched already; make sure this is checked!
455 */
456 for (uint32_t i=0;i<cb;i++)
457 {
458 uint8_t temp;
459
460 int rc2 = PATMR3QueryOpcode(pVM, pSrc+i, &temp);
461 if (RT_SUCCESS(rc2))
462 {
463 pDest[i] = temp;
464 }
465 else
466 break; /* no more */
467 }
468 return VINF_SUCCESS;
469}
470
471int patmPatchGenDuplicate(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pCurInstrGC)
472{
473 uint32_t const cbInstrShutUpGcc = pCpu->cbInstr;
474 PATCHGEN_PROLOG(pVM, pPatch, cbInstrShutUpGcc);
475
476 int rc = patmPatchReadBytes(pVM, pPB, pCurInstrGC, cbInstrShutUpGcc);
477 AssertRC(rc);
478 PATCHGEN_EPILOG(pPatch, cbInstrShutUpGcc);
479 return rc;
480}
481
482int patmPatchGenIret(PVM pVM, PPATCHINFO pPatch, RTRCPTR pCurInstrGC, bool fSizeOverride)
483{
484 uint32_t size;
485 PATMCALLINFO callInfo;
486 PCPATCHASMRECORD pPatchAsmRec = EMIsRawRing1Enabled(pVM) ? &g_patmIretRing1Record : &g_patmIretRecord;
487
488 PATCHGEN_PROLOG(pVM, pPatch, pPatchAsmRec->cbFunction);
489
490 AssertMsg(fSizeOverride == false, ("operand size override!!\n"));
491 callInfo.pCurInstrGC = pCurInstrGC;
492
493 size = patmPatchGenCode(pVM, pPatch, pPB, pPatchAsmRec, 0, false, &callInfo);
494
495 PATCHGEN_EPILOG(pPatch, size);
496 return VINF_SUCCESS;
497}
498
499int patmPatchGenCli(PVM pVM, PPATCHINFO pPatch)
500{
501 uint32_t size;
502 PATCHGEN_PROLOG(pVM, pPatch, g_patmCliRecord.cbFunction);
503
504 size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmCliRecord, 0, false);
505
506 PATCHGEN_EPILOG(pPatch, size);
507 return VINF_SUCCESS;
508}
509
510/*
511 * Generate an STI patch
512 */
513int patmPatchGenSti(PVM pVM, PPATCHINFO pPatch, RTRCPTR pCurInstrGC, RTRCPTR pNextInstrGC)
514{
515 PATMCALLINFO callInfo;
516 uint32_t size;
517
518 Log(("patmPatchGenSti at %RRv; next %RRv\n", pCurInstrGC, pNextInstrGC));
519 PATCHGEN_PROLOG(pVM, pPatch, g_patmStiRecord.cbFunction);
520 callInfo.pNextInstrGC = pNextInstrGC;
521 size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmStiRecord, 0, false, &callInfo);
522 PATCHGEN_EPILOG(pPatch, size);
523
524 return VINF_SUCCESS;
525}
526
527
528int patmPatchGenPopf(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t *) pReturnAddrGC, bool fSizeOverride, bool fGenJumpBack)
529{
530 uint32_t size;
531 PATMCALLINFO callInfo;
532 PCPATCHASMRECORD pPatchAsmRec;
533 if (fSizeOverride == true)
534 pPatchAsmRec = fGenJumpBack ? &g_patmPopf16Record : &g_patmPopf16Record_NoExit;
535 else
536 pPatchAsmRec = fGenJumpBack ? &g_patmPopf32Record : &g_patmPopf32Record_NoExit;
537
538 PATCHGEN_PROLOG(pVM, pPatch, pPatchAsmRec->cbFunction);
539
540 callInfo.pNextInstrGC = pReturnAddrGC;
541
542 Log(("patmPatchGenPopf at %RRv\n", pReturnAddrGC));
543
544 /* Note: keep IOPL in mind when changing any of this!! (see comments in PATMA.asm, PATMPopf32Replacement) */
545 if (fSizeOverride == true)
546 Log(("operand size override!!\n"));
547 size = patmPatchGenCode(pVM, pPatch, pPB, pPatchAsmRec, pReturnAddrGC, fGenJumpBack, &callInfo);
548
549 PATCHGEN_EPILOG(pPatch, size);
550 STAM_COUNTER_INC(&pVM->patm.s.StatGenPopf);
551 return VINF_SUCCESS;
552}
553
554int patmPatchGenPushf(PVM pVM, PPATCHINFO pPatch, bool fSizeOverride)
555{
556 uint32_t size;
557 PCPATCHASMRECORD pPatchAsmRec = fSizeOverride == true ? &g_patmPushf16Record : &g_patmPushf32Record;
558 PATCHGEN_PROLOG(pVM, pPatch, pPatchAsmRec->cbFunction);
559
560 size = patmPatchGenCode(pVM, pPatch, pPB, pPatchAsmRec, 0, false);
561
562 PATCHGEN_EPILOG(pPatch, size);
563 return VINF_SUCCESS;
564}
565
566int patmPatchGenPushCS(PVM pVM, PPATCHINFO pPatch)
567{
568 uint32_t size;
569 PATCHGEN_PROLOG(pVM, pPatch, g_patmPushCSRecord.cbFunction);
570 size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmPushCSRecord, 0, false);
571 PATCHGEN_EPILOG(pPatch, size);
572 return VINF_SUCCESS;
573}
574
575int patmPatchGenLoop(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t *) pTargetGC, uint32_t opcode, bool fSizeOverride)
576{
577 uint32_t size = 0;
578 PCPATCHASMRECORD pPatchAsmRec;
579 switch (opcode)
580 {
581 case OP_LOOP:
582 pPatchAsmRec = &g_patmLoopRecord;
583 break;
584 case OP_LOOPNE:
585 pPatchAsmRec = &g_patmLoopNZRecord;
586 break;
587 case OP_LOOPE:
588 pPatchAsmRec = &g_patmLoopZRecord;
589 break;
590 case OP_JECXZ:
591 pPatchAsmRec = &g_patmJEcxRecord;
592 break;
593 default:
594 AssertMsgFailed(("PatchGenLoop: invalid opcode %d\n", opcode));
595 return VERR_INVALID_PARAMETER;
596 }
597 Assert(pPatchAsmRec->offSizeOverride && pPatchAsmRec->offRelJump);
598
599 PATCHGEN_PROLOG(pVM, pPatch, pPatchAsmRec->cbFunction);
600 Log(("PatchGenLoop %d jump %d to %08x offrel=%d\n", opcode, pPatch->nrJumpRecs, pTargetGC, pPatchAsmRec->offRelJump));
601
602 // Generate the patch code
603 size = patmPatchGenCode(pVM, pPatch, pPB, pPatchAsmRec, 0, false);
604
605 if (fSizeOverride)
606 {
607 pPB[pPatchAsmRec->offSizeOverride] = 0x66; // ecx -> cx or vice versa
608 }
609
610 *(RTRCPTR *)&pPB[pPatchAsmRec->offRelJump] = 0xDEADBEEF;
611
612 patmPatchAddJump(pVM, pPatch, &pPB[pPatchAsmRec->offRelJump - 1], 1, pTargetGC, opcode);
613
614 PATCHGEN_EPILOG(pPatch, size);
615 return VINF_SUCCESS;
616}
617
618int patmPatchGenRelJump(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t *) pTargetGC, uint32_t opcode, bool fSizeOverride)
619{
620 uint32_t offset = 0;
621 PATCHGEN_PROLOG(pVM, pPatch, PATCHGEN_DEF_SIZE);
622
623 // internal relative jumps from patch code to patch code; no relocation record required
624
625 Assert(PATMIsPatchGCAddr(pVM, pTargetGC) == false);
626
627 switch (opcode)
628 {
629 case OP_JO:
630 pPB[1] = 0x80;
631 break;
632 case OP_JNO:
633 pPB[1] = 0x81;
634 break;
635 case OP_JC:
636 pPB[1] = 0x82;
637 break;
638 case OP_JNC:
639 pPB[1] = 0x83;
640 break;
641 case OP_JE:
642 pPB[1] = 0x84;
643 break;
644 case OP_JNE:
645 pPB[1] = 0x85;
646 break;
647 case OP_JBE:
648 pPB[1] = 0x86;
649 break;
650 case OP_JNBE:
651 pPB[1] = 0x87;
652 break;
653 case OP_JS:
654 pPB[1] = 0x88;
655 break;
656 case OP_JNS:
657 pPB[1] = 0x89;
658 break;
659 case OP_JP:
660 pPB[1] = 0x8A;
661 break;
662 case OP_JNP:
663 pPB[1] = 0x8B;
664 break;
665 case OP_JL:
666 pPB[1] = 0x8C;
667 break;
668 case OP_JNL:
669 pPB[1] = 0x8D;
670 break;
671 case OP_JLE:
672 pPB[1] = 0x8E;
673 break;
674 case OP_JNLE:
675 pPB[1] = 0x8F;
676 break;
677
678 case OP_JMP:
679 /* If interrupted here, then jump to the target instruction. Used by PATM.cpp for jumping to known instructions. */
680 /* Add lookup record for patch to guest address translation */
681 patmR3AddP2GLookupRecord(pVM, pPatch, pPB, pTargetGC, PATM_LOOKUP_PATCH2GUEST);
682
683 pPB[0] = 0xE9;
684 break;
685
686 case OP_JECXZ:
687 case OP_LOOP:
688 case OP_LOOPNE:
689 case OP_LOOPE:
690 return patmPatchGenLoop(pVM, pPatch, pTargetGC, opcode, fSizeOverride);
691
692 default:
693 AssertMsg(0, ("Invalid jump opcode %d\n", opcode));
694 return VERR_PATCHING_REFUSED;
695 }
696 if (opcode != OP_JMP)
697 {
698 pPB[0] = 0xF;
699 offset += 2;
700 }
701 else offset++;
702
703 *(RTRCPTR *)&pPB[offset] = 0xDEADBEEF;
704
705 patmPatchAddJump(pVM, pPatch, pPB, offset, pTargetGC, opcode);
706
707 offset += sizeof(RTRCPTR);
708
709 PATCHGEN_EPILOG(pPatch, offset);
710 return VINF_SUCCESS;
711}
712
713/*
714 * Rewrite call to dynamic or currently unknown function (on-demand patching of function)
715 */
716int patmPatchGenCall(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu, RTRCPTR pCurInstrGC, RTRCPTR pTargetGC, bool fIndirect)
717{
718 PATMCALLINFO callInfo;
719 uint32_t offset;
720 uint32_t i, size;
721 int rc;
722
723 /** @note Don't check for IF=1 here. The ret instruction will do this. */
724 /** @note It's dangerous to do this for 'normal' patches. the jump target might be inside the generated patch jump. (seen this!) */
725
726 /* 1: Clear PATM interrupt flag on entry. */
727 rc = patmPatchGenClearPIF(pVM, pPatch, pCurInstrGC);
728 if (rc == VERR_NO_MEMORY)
729 return rc;
730 AssertRCReturn(rc, rc);
731
732 PATCHGEN_PROLOG(pVM, pPatch, PATCHGEN_DEF_SIZE);
733 /* 2: We must push the target address onto the stack before appending the indirect call code. */
734
735 if (fIndirect)
736 {
737 Log(("patmPatchGenIndirectCall\n"));
738 Assert(pCpu->Param1.cb == 4);
739 Assert(OP_PARM_VTYPE(pCpu->pCurInstr->fParam1) != OP_PARM_J);
740
741 /* We push it onto the stack here, so the guest's context isn't ruined when this happens to cause
742 * a page fault. The assembly code restores the stack afterwards.
743 */
744 offset = 0;
745 /* include prefix byte to make sure we don't use the incorrect selector register. */
746 if (pCpu->fPrefix & DISPREFIX_SEG)
747 pPB[offset++] = DISQuerySegPrefixByte(pCpu);
748 pPB[offset++] = 0xFF; // push r/m32
749 pPB[offset++] = MAKE_MODRM(pCpu->ModRM.Bits.Mod, 6 /* group 5 */, pCpu->ModRM.Bits.Rm);
750 i = 2; /* standard offset of modrm bytes */
751 if (pCpu->fPrefix & DISPREFIX_OPSIZE)
752 i++; //skip operand prefix
753 if (pCpu->fPrefix & DISPREFIX_SEG)
754 i++; //skip segment prefix
755
756 rc = patmPatchReadBytes(pVM, &pPB[offset], (RTRCPTR)((RTGCUINTPTR32)pCurInstrGC + i), pCpu->cbInstr - i);
757 AssertRCReturn(rc, rc);
758 offset += (pCpu->cbInstr - i);
759 }
760 else
761 {
762 AssertMsg(PATMIsPatchGCAddr(pVM, pTargetGC) == false, ("Target is already a patch address (%RRv)?!?\n", pTargetGC));
763 Assert(pTargetGC);
764 Assert(OP_PARM_VTYPE(pCpu->pCurInstr->fParam1) == OP_PARM_J);
765
766 /** @todo wasting memory as the complex search is overkill and we need only one lookup slot... */
767
768 /* Relative call to patch code (patch to patch -> no fixup). */
769 Log(("PatchGenCall from %RRv (next=%RRv) to %RRv\n", pCurInstrGC, pCurInstrGC + pCpu->cbInstr, pTargetGC));
770
771 /* We push it onto the stack here, so the guest's context isn't ruined when this happens to cause
772 * a page fault. The assembly code restores the stack afterwards.
773 */
774 offset = 0;
775 pPB[offset++] = 0x68; // push %Iv
776 *(RTRCPTR *)&pPB[offset] = pTargetGC;
777 offset += sizeof(RTRCPTR);
778 }
779
780 /* align this block properly to make sure the jump table will not be misaligned. */
781 size = (RTHCUINTPTR)&pPB[offset] & 3;
782 if (size)
783 size = 4 - size;
784
785 for (i=0;i<size;i++)
786 {
787 pPB[offset++] = 0x90; /* nop */
788 }
789 PATCHGEN_EPILOG(pPatch, offset);
790
791 /* 3: Generate code to lookup address in our local cache; call hypervisor PATM code if it can't be located. */
792 PCPATCHASMRECORD pPatchAsmRec = fIndirect ? &g_patmCallIndirectRecord : &g_patmCallRecord;
793 PATCHGEN_PROLOG_NODEF(pVM, pPatch, pPatchAsmRec->cbFunction);
794 callInfo.pReturnGC = pCurInstrGC + pCpu->cbInstr;
795 callInfo.pTargetGC = (fIndirect) ? 0xDEADBEEF : pTargetGC;
796 size = patmPatchGenCode(pVM, pPatch, pPB, pPatchAsmRec, 0, false, &callInfo);
797 PATCHGEN_EPILOG(pPatch, size);
798
799 /* Need to set PATM_ASMFIX_INTERRUPTFLAG after the patched ret returns here. */
800 rc = patmPatchGenSetPIF(pVM, pPatch, pCurInstrGC);
801 if (rc == VERR_NO_MEMORY)
802 return rc;
803 AssertRCReturn(rc, rc);
804
805 STAM_COUNTER_INC(&pVM->patm.s.StatGenCall);
806 return VINF_SUCCESS;
807}
808
809/**
810 * Generate indirect jump to unknown destination
811 *
812 * @returns VBox status code.
813 * @param pVM Pointer to the VM.
814 * @param pPatch Patch record
815 * @param pCpu Disassembly state
816 * @param pCurInstrGC Current instruction address
817 */
818int patmPatchGenJump(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu, RTRCPTR pCurInstrGC)
819{
820 PATMCALLINFO callInfo;
821 uint32_t offset;
822 uint32_t i, size;
823 int rc;
824
825 /* 1: Clear PATM interrupt flag on entry. */
826 rc = patmPatchGenClearPIF(pVM, pPatch, pCurInstrGC);
827 if (rc == VERR_NO_MEMORY)
828 return rc;
829 AssertRCReturn(rc, rc);
830
831 PATCHGEN_PROLOG(pVM, pPatch, PATCHGEN_DEF_SIZE);
832 /* 2: We must push the target address onto the stack before appending the indirect call code. */
833
834 Log(("patmPatchGenIndirectJump\n"));
835 Assert(pCpu->Param1.cb == 4);
836 Assert(OP_PARM_VTYPE(pCpu->pCurInstr->fParam1) != OP_PARM_J);
837
838 /* We push it onto the stack here, so the guest's context isn't ruined when this happens to cause
839 * a page fault. The assembly code restores the stack afterwards.
840 */
841 offset = 0;
842 /* include prefix byte to make sure we don't use the incorrect selector register. */
843 if (pCpu->fPrefix & DISPREFIX_SEG)
844 pPB[offset++] = DISQuerySegPrefixByte(pCpu);
845
846 pPB[offset++] = 0xFF; // push r/m32
847 pPB[offset++] = MAKE_MODRM(pCpu->ModRM.Bits.Mod, 6 /* group 5 */, pCpu->ModRM.Bits.Rm);
848 i = 2; /* standard offset of modrm bytes */
849 if (pCpu->fPrefix & DISPREFIX_OPSIZE)
850 i++; //skip operand prefix
851 if (pCpu->fPrefix & DISPREFIX_SEG)
852 i++; //skip segment prefix
853
854 rc = patmPatchReadBytes(pVM, &pPB[offset], (RTRCPTR)((RTGCUINTPTR32)pCurInstrGC + i), pCpu->cbInstr - i);
855 AssertRCReturn(rc, rc);
856 offset += (pCpu->cbInstr - i);
857
858 /* align this block properly to make sure the jump table will not be misaligned. */
859 size = (RTHCUINTPTR)&pPB[offset] & 3;
860 if (size)
861 size = 4 - size;
862
863 for (i=0;i<size;i++)
864 {
865 pPB[offset++] = 0x90; /* nop */
866 }
867 PATCHGEN_EPILOG(pPatch, offset);
868
869 /* 3: Generate code to lookup address in our local cache; call hypervisor PATM code if it can't be located. */
870 PATCHGEN_PROLOG_NODEF(pVM, pPatch, g_patmJumpIndirectRecord.cbFunction);
871 callInfo.pReturnGC = pCurInstrGC + pCpu->cbInstr;
872 callInfo.pTargetGC = 0xDEADBEEF;
873 size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmJumpIndirectRecord, 0, false, &callInfo);
874 PATCHGEN_EPILOG(pPatch, size);
875
876 STAM_COUNTER_INC(&pVM->patm.s.StatGenJump);
877 return VINF_SUCCESS;
878}
879
880/**
881 * Generate return instruction
882 *
883 * @returns VBox status code.
884 * @param pVM Pointer to the VM.
885 * @param pPatch Patch structure
886 * @param pCpu Disassembly struct
887 * @param pCurInstrGC Current instruction pointer
888 *
889 */
890int patmPatchGenRet(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pCurInstrGC)
891{
892 RTRCPTR pPatchRetInstrGC;
893
894 /* Remember start of this patch for below. */
895 pPatchRetInstrGC = PATCHCODE_PTR_GC(pPatch) + pPatch->uCurPatchOffset;
896
897 Log(("patmPatchGenRet %RRv\n", pCurInstrGC));
898
899 /** @note optimization: multiple identical ret instruction in a single patch can share a single patched ret. */
900 if ( pPatch->pTempInfo->pPatchRetInstrGC
901 && pPatch->pTempInfo->uPatchRetParam1 == (uint32_t)pCpu->Param1.uValue) /* nr of bytes popped off the stack should be identical of course! */
902 {
903 Assert(pCpu->pCurInstr->uOpcode == OP_RETN);
904 STAM_COUNTER_INC(&pVM->patm.s.StatGenRetReused);
905
906 return patmPatchGenPatchJump(pVM, pPatch, pCurInstrGC, pPatch->pTempInfo->pPatchRetInstrGC);
907 }
908
909 /* Jump back to the original instruction if IF is set again. */
910 Assert(!patmFindActivePatchByEntrypoint(pVM, pCurInstrGC));
911 int rc = patmPatchGenCheckIF(pVM, pPatch, pCurInstrGC);
912 AssertRCReturn(rc, rc);
913
914 /* align this block properly to make sure the jump table will not be misaligned. */
915 PATCHGEN_PROLOG(pVM, pPatch, 4);
916 uint32_t size = (RTHCUINTPTR)pPB & 3;
917 if (size)
918 size = 4 - size;
919
920 for (uint32_t i = 0; i < size; i++)
921 pPB[i] = 0x90; /* nop */
922 PATCHGEN_EPILOG(pPatch, size);
923
924 PATCHGEN_PROLOG_NODEF(pVM, pPatch, g_patmRetRecord.cbFunction);
925 size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmRetRecord, 0, false);
926 PATCHGEN_EPILOG(pPatch, size);
927
928 STAM_COUNTER_INC(&pVM->patm.s.StatGenRet);
929 /* Duplicate the ret or ret n instruction; it will use the PATM return address */
930 rc = patmPatchGenDuplicate(pVM, pPatch, pCpu, pCurInstrGC);
931
932 if (rc == VINF_SUCCESS)
933 {
934 pPatch->pTempInfo->pPatchRetInstrGC = pPatchRetInstrGC;
935 pPatch->pTempInfo->uPatchRetParam1 = pCpu->Param1.uValue;
936 }
937 return rc;
938}
939
940/**
941 * Generate all global patm functions
942 *
943 * @returns VBox status code.
944 * @param pVM Pointer to the VM.
945 * @param pPatch Patch structure
946 *
947 */
948int patmPatchGenGlobalFunctions(PVM pVM, PPATCHINFO pPatch)
949{
950 pVM->patm.s.pfnHelperCallGC = PATCHCODE_PTR_GC(pPatch) + pPatch->uCurPatchOffset;
951 PATCHGEN_PROLOG(pVM, pPatch, g_patmLookupAndCallRecord.cbFunction);
952 uint32_t size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmLookupAndCallRecord, 0, false);
953 PATCHGEN_EPILOG(pPatch, size);
954
955 /* Round to next 8 byte boundary. */
956 pPatch->uCurPatchOffset = RT_ALIGN_32(pPatch->uCurPatchOffset, 8);
957
958 pVM->patm.s.pfnHelperRetGC = PATCHCODE_PTR_GC(pPatch) + pPatch->uCurPatchOffset;
959 PATCHGEN_PROLOG_NODEF(pVM, pPatch, g_patmRetFunctionRecord.cbFunction);
960 size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmRetFunctionRecord, 0, false);
961 PATCHGEN_EPILOG(pPatch, size);
962
963 /* Round to next 8 byte boundary. */
964 pPatch->uCurPatchOffset = RT_ALIGN_32(pPatch->uCurPatchOffset, 8);
965
966 pVM->patm.s.pfnHelperJumpGC = PATCHCODE_PTR_GC(pPatch) + pPatch->uCurPatchOffset;
967 PATCHGEN_PROLOG_NODEF(pVM, pPatch, g_patmLookupAndJumpRecord.cbFunction);
968 size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmLookupAndJumpRecord, 0, false);
969 PATCHGEN_EPILOG(pPatch, size);
970
971 /* Round to next 8 byte boundary. */
972 pPatch->uCurPatchOffset = RT_ALIGN_32(pPatch->uCurPatchOffset, 8);
973
974 pVM->patm.s.pfnHelperIretGC = PATCHCODE_PTR_GC(pPatch) + pPatch->uCurPatchOffset;
975 PATCHGEN_PROLOG_NODEF(pVM, pPatch, g_patmIretFunctionRecord.cbFunction);
976 size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmIretFunctionRecord, 0, false);
977 PATCHGEN_EPILOG(pPatch, size);
978
979 Log(("pfnHelperCallGC %RRv\n", pVM->patm.s.pfnHelperCallGC));
980 Log(("pfnHelperRetGC %RRv\n", pVM->patm.s.pfnHelperRetGC));
981 Log(("pfnHelperJumpGC %RRv\n", pVM->patm.s.pfnHelperJumpGC));
982 Log(("pfnHelperIretGC %RRv\n", pVM->patm.s.pfnHelperIretGC));
983
984 return VINF_SUCCESS;
985}
986
987/**
988 * Generate illegal instruction (int 3)
989 *
990 * @returns VBox status code.
991 * @param pVM Pointer to the VM.
992 * @param pPatch Patch structure
993 *
994 */
995int patmPatchGenIllegalInstr(PVM pVM, PPATCHINFO pPatch)
996{
997 PATCHGEN_PROLOG(pVM, pPatch, 1);
998
999 pPB[0] = 0xCC;
1000
1001 PATCHGEN_EPILOG(pPatch, 1);
1002 return VINF_SUCCESS;
1003}
1004
1005/**
1006 * Check virtual IF flag and jump back to original guest code if set
1007 *
1008 * @returns VBox status code.
1009 * @param pVM Pointer to the VM.
1010 * @param pPatch Patch structure
1011 * @param pCurInstrGC Guest context pointer to the current instruction
1012 *
1013 */
1014int patmPatchGenCheckIF(PVM pVM, PPATCHINFO pPatch, RTRCPTR pCurInstrGC)
1015{
1016 uint32_t size;
1017
1018 PATCHGEN_PROLOG(pVM, pPatch, g_patmCheckIFRecord.cbFunction);
1019
1020 /* Add lookup record for patch to guest address translation */
1021 patmR3AddP2GLookupRecord(pVM, pPatch, pPB, pCurInstrGC, PATM_LOOKUP_PATCH2GUEST);
1022
1023 /* Generate code to check for IF=1 before executing the call to the duplicated function. */
1024 size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmCheckIFRecord, pCurInstrGC, true);
1025
1026 PATCHGEN_EPILOG(pPatch, size);
1027 return VINF_SUCCESS;
1028}
1029
1030/**
1031 * Set PATM interrupt flag
1032 *
1033 * @returns VBox status code.
1034 * @param pVM Pointer to the VM.
1035 * @param pPatch Patch structure
1036 * @param pInstrGC Corresponding guest instruction
1037 *
1038 */
1039int patmPatchGenSetPIF(PVM pVM, PPATCHINFO pPatch, RTRCPTR pInstrGC)
1040{
1041 PATCHGEN_PROLOG(pVM, pPatch, g_patmSetPIFRecord.cbFunction);
1042
1043 /* Add lookup record for patch to guest address translation */
1044 patmR3AddP2GLookupRecord(pVM, pPatch, pPB, pInstrGC, PATM_LOOKUP_PATCH2GUEST);
1045
1046 uint32_t size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmSetPIFRecord, 0, false);
1047 PATCHGEN_EPILOG(pPatch, size);
1048 return VINF_SUCCESS;
1049}
1050
1051/**
1052 * Clear PATM interrupt flag
1053 *
1054 * @returns VBox status code.
1055 * @param pVM Pointer to the VM.
1056 * @param pPatch Patch structure
1057 * @param pInstrGC Corresponding guest instruction
1058 *
1059 */
1060int patmPatchGenClearPIF(PVM pVM, PPATCHINFO pPatch, RTRCPTR pInstrGC)
1061{
1062 PATCHGEN_PROLOG(pVM, pPatch, g_patmSetPIFRecord.cbFunction);
1063
1064 /* Add lookup record for patch to guest address translation */
1065 patmR3AddP2GLookupRecord(pVM, pPatch, pPB, pInstrGC, PATM_LOOKUP_PATCH2GUEST);
1066
1067 uint32_t size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmClearPIFRecord, 0, false);
1068 PATCHGEN_EPILOG(pPatch, size);
1069 return VINF_SUCCESS;
1070}
1071
1072
1073/**
1074 * Clear PATM inhibit irq flag
1075 *
1076 * @returns VBox status code.
1077 * @param pVM Pointer to the VM.
1078 * @param pPatch Patch structure
1079 * @param pNextInstrGC Next guest instruction
1080 */
1081int patmPatchGenClearInhibitIRQ(PVM pVM, PPATCHINFO pPatch, RTRCPTR pNextInstrGC)
1082{
1083 PATMCALLINFO callInfo;
1084 PCPATCHASMRECORD pPatchAsmRec = pPatch->flags & PATMFL_DUPLICATE_FUNCTION
1085 ? &g_patmClearInhibitIRQContIF0Record : &g_patmClearInhibitIRQFaultIF0Record;
1086 PATCHGEN_PROLOG(pVM, pPatch, pPatchAsmRec->cbFunction);
1087
1088 Assert((pPatch->flags & (PATMFL_GENERATE_JUMPTOGUEST|PATMFL_DUPLICATE_FUNCTION)) != (PATMFL_GENERATE_JUMPTOGUEST|PATMFL_DUPLICATE_FUNCTION));
1089
1090 /* Add lookup record for patch to guest address translation */
1091 patmR3AddP2GLookupRecord(pVM, pPatch, pPB, pNextInstrGC, PATM_LOOKUP_PATCH2GUEST);
1092
1093 callInfo.pNextInstrGC = pNextInstrGC;
1094
1095 uint32_t size = patmPatchGenCode(pVM, pPatch, pPB, pPatchAsmRec, 0, false, &callInfo);
1096
1097 PATCHGEN_EPILOG(pPatch, size);
1098 return VINF_SUCCESS;
1099}
1100
1101/**
1102 * Generate an interrupt handler entrypoint
1103 *
1104 * @returns VBox status code.
1105 * @param pVM Pointer to the VM.
1106 * @param pPatch Patch record
1107 * @param pIntHandlerGC IDT handler address
1108 *
1109 ** @todo must check if virtual IF is already cleared on entry!!!!!!!!!!!!!!!!!!!!!!!
1110 */
1111int patmPatchGenIntEntry(PVM pVM, PPATCHINFO pPatch, RTRCPTR pIntHandlerGC)
1112{
1113 int rc = VINF_SUCCESS;
1114
1115 if (!EMIsRawRing1Enabled(pVM)) /* direct passthru of interrupts is not allowed in the ring-1 support case as we can't
1116 deal with the ring-1/2 ambiguity in the patm asm code and we don't need it either as
1117 TRPMForwardTrap takes care of the details. */
1118 {
1119 uint32_t size;
1120 PCPATCHASMRECORD pPatchAsmRec = pPatch->flags & PATMFL_INTHANDLER_WITH_ERRORCODE
1121 ? &g_patmIntEntryRecordErrorCode : &g_patmIntEntryRecord;
1122 PATCHGEN_PROLOG(pVM, pPatch, pPatchAsmRec->cbFunction);
1123
1124 /* Add lookup record for patch to guest address translation */
1125 patmR3AddP2GLookupRecord(pVM, pPatch, pPB, pIntHandlerGC, PATM_LOOKUP_PATCH2GUEST);
1126
1127 /* Generate entrypoint for the interrupt handler (correcting CS in the interrupt stack frame) */
1128 size = patmPatchGenCode(pVM, pPatch, pPB, pPatchAsmRec, 0, false);
1129
1130 PATCHGEN_EPILOG(pPatch, size);
1131 }
1132
1133 // Interrupt gates set IF to 0
1134 rc = patmPatchGenCli(pVM, pPatch);
1135 AssertRCReturn(rc, rc);
1136
1137 return rc;
1138}
1139
1140/**
1141 * Generate a trap handler entrypoint
1142 *
1143 * @returns VBox status code.
1144 * @param pVM Pointer to the VM.
1145 * @param pPatch Patch record
1146 * @param pTrapHandlerGC IDT handler address
1147 */
1148int patmPatchGenTrapEntry(PVM pVM, PPATCHINFO pPatch, RTRCPTR pTrapHandlerGC)
1149{
1150 uint32_t size;
1151 PCPATCHASMRECORD pPatchAsmRec = (pPatch->flags & PATMFL_TRAPHANDLER_WITH_ERRORCODE)
1152 ? &g_patmTrapEntryRecordErrorCode : &g_patmTrapEntryRecord;
1153
1154 Assert(!EMIsRawRing1Enabled(pVM));
1155
1156 PATCHGEN_PROLOG(pVM, pPatch, pPatchAsmRec->cbFunction);
1157
1158 /* Add lookup record for patch to guest address translation */
1159 patmR3AddP2GLookupRecord(pVM, pPatch, pPB, pTrapHandlerGC, PATM_LOOKUP_PATCH2GUEST);
1160
1161 /* Generate entrypoint for the trap handler (correcting CS in the interrupt stack frame) */
1162 size = patmPatchGenCode(pVM, pPatch, pPB, pPatchAsmRec, pTrapHandlerGC, true);
1163 PATCHGEN_EPILOG(pPatch, size);
1164
1165 return VINF_SUCCESS;
1166}
1167
1168#ifdef VBOX_WITH_STATISTICS
1169int patmPatchGenStats(PVM pVM, PPATCHINFO pPatch, RTRCPTR pInstrGC)
1170{
1171 uint32_t size;
1172
1173 PATCHGEN_PROLOG(pVM, pPatch, g_patmStatsRecord.cbFunction);
1174
1175 /* Add lookup record for stats code -> guest handler. */
1176 patmR3AddP2GLookupRecord(pVM, pPatch, pPB, pInstrGC, PATM_LOOKUP_PATCH2GUEST);
1177
1178 /* Generate code to keep calling statistics for this patch */
1179 size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmStatsRecord, pInstrGC, false);
1180 PATCHGEN_EPILOG(pPatch, size);
1181
1182 return VINF_SUCCESS;
1183}
1184#endif
1185
1186/**
1187 * Debug register moves to or from general purpose registers
1188 * mov GPR, DRx
1189 * mov DRx, GPR
1190 *
1191 * @todo: if we ever want to support hardware debug registers natively, then
1192 * this will need to be changed!
1193 */
1194int patmPatchGenMovDebug(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu)
1195{
1196 int rc = VINF_SUCCESS;
1197 unsigned reg, mod, rm, dbgreg;
1198 uint32_t offset;
1199
1200 PATCHGEN_PROLOG(pVM, pPatch, PATCHGEN_DEF_SIZE);
1201
1202 mod = 0; //effective address (only)
1203 rm = 5; //disp32
1204 if (pCpu->pCurInstr->fParam1 == OP_PARM_Dd)
1205 {
1206 Assert(0); // You not come here. Illegal!
1207
1208 // mov DRx, GPR
1209 pPB[0] = 0x89; //mov disp32, GPR
1210 Assert(pCpu->Param1.fUse & DISUSE_REG_DBG);
1211 Assert(pCpu->Param2.fUse & DISUSE_REG_GEN32);
1212
1213 dbgreg = pCpu->Param1.Base.idxDbgReg;
1214 reg = pCpu->Param2.Base.idxGenReg;
1215 }
1216 else
1217 {
1218 // mov GPR, DRx
1219 Assert(pCpu->Param1.fUse & DISUSE_REG_GEN32);
1220 Assert(pCpu->Param2.fUse & DISUSE_REG_DBG);
1221
1222 pPB[0] = 0x8B; // mov GPR, disp32
1223 reg = pCpu->Param1.Base.idxGenReg;
1224 dbgreg = pCpu->Param2.Base.idxDbgReg;
1225 }
1226
1227 pPB[1] = MAKE_MODRM(mod, reg, rm);
1228
1229 AssertReturn(dbgreg <= DISDREG_DR7, VERR_INVALID_PARAMETER);
1230 offset = RT_OFFSETOF(CPUMCTX, dr[dbgreg]);
1231
1232 *(RTRCPTR *)&pPB[2] = pVM->patm.s.pCPUMCtxGC + offset;
1233 patmPatchAddReloc32(pVM, pPatch, &pPB[2], FIXUP_ABSOLUTE);
1234
1235 PATCHGEN_EPILOG(pPatch, 2 + sizeof(RTRCPTR));
1236 return rc;
1237}
1238
1239/*
1240 * Control register moves to or from general purpose registers
1241 * mov GPR, CRx
1242 * mov CRx, GPR
1243 */
1244int patmPatchGenMovControl(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu)
1245{
1246 int rc = VINF_SUCCESS;
1247 int reg, mod, rm, ctrlreg;
1248 uint32_t offset;
1249
1250 PATCHGEN_PROLOG(pVM, pPatch, PATCHGEN_DEF_SIZE);
1251
1252 mod = 0; //effective address (only)
1253 rm = 5; //disp32
1254 if (pCpu->pCurInstr->fParam1 == OP_PARM_Cd)
1255 {
1256 Assert(0); // You not come here. Illegal!
1257
1258 // mov CRx, GPR
1259 pPB[0] = 0x89; //mov disp32, GPR
1260 ctrlreg = pCpu->Param1.Base.idxCtrlReg;
1261 reg = pCpu->Param2.Base.idxGenReg;
1262 Assert(pCpu->Param1.fUse & DISUSE_REG_CR);
1263 Assert(pCpu->Param2.fUse & DISUSE_REG_GEN32);
1264 }
1265 else
1266 {
1267 // mov GPR, CRx
1268 Assert(pCpu->Param1.fUse & DISUSE_REG_GEN32);
1269 Assert(pCpu->Param2.fUse & DISUSE_REG_CR);
1270
1271 pPB[0] = 0x8B; // mov GPR, disp32
1272 reg = pCpu->Param1.Base.idxGenReg;
1273 ctrlreg = pCpu->Param2.Base.idxCtrlReg;
1274 }
1275
1276 pPB[1] = MAKE_MODRM(mod, reg, rm);
1277
1278 /// @todo: make this an array in the context structure
1279 switch (ctrlreg)
1280 {
1281 case DISCREG_CR0:
1282 offset = RT_OFFSETOF(CPUMCTX, cr0);
1283 break;
1284 case DISCREG_CR2:
1285 offset = RT_OFFSETOF(CPUMCTX, cr2);
1286 break;
1287 case DISCREG_CR3:
1288 offset = RT_OFFSETOF(CPUMCTX, cr3);
1289 break;
1290 case DISCREG_CR4:
1291 offset = RT_OFFSETOF(CPUMCTX, cr4);
1292 break;
1293 default: /* Shut up compiler warning. */
1294 AssertFailed();
1295 offset = 0;
1296 break;
1297 }
1298 *(RTRCPTR *)&pPB[2] = pVM->patm.s.pCPUMCtxGC + offset;
1299 patmPatchAddReloc32(pVM, pPatch, &pPB[2], FIXUP_ABSOLUTE);
1300
1301 PATCHGEN_EPILOG(pPatch, 2 + sizeof(RTRCPTR));
1302 return rc;
1303}
1304
1305/*
1306 * mov GPR, SS
1307 */
1308int patmPatchGenMovFromSS(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu, RTRCPTR pCurInstrGC)
1309{
1310 uint32_t size, offset;
1311
1312 Log(("patmPatchGenMovFromSS %RRv\n", pCurInstrGC));
1313
1314 Assert(pPatch->flags & PATMFL_CODE32);
1315
1316 PATCHGEN_PROLOG(pVM, pPatch, g_patmClearPIFRecord.cbFunction + 2 + g_patmMovFromSSRecord.cbFunction + 2 + g_patmSetPIFRecord.cbFunction);
1317 size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmClearPIFRecord, 0, false);
1318 PATCHGEN_EPILOG(pPatch, size);
1319
1320 /* push ss */
1321 PATCHGEN_PROLOG_NODEF(pVM, pPatch, 2);
1322 offset = 0;
1323 if (pCpu->fPrefix & DISPREFIX_OPSIZE)
1324 pPB[offset++] = 0x66; /* size override -> 16 bits push */
1325 pPB[offset++] = 0x16;
1326 PATCHGEN_EPILOG(pPatch, offset);
1327
1328 /* checks and corrects RPL of pushed ss*/
1329 PATCHGEN_PROLOG_NODEF(pVM, pPatch, g_patmMovFromSSRecord.cbFunction);
1330 size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmMovFromSSRecord, 0, false);
1331 PATCHGEN_EPILOG(pPatch, size);
1332
1333 /* pop general purpose register */
1334 PATCHGEN_PROLOG_NODEF(pVM, pPatch, 2);
1335 offset = 0;
1336 if (pCpu->fPrefix & DISPREFIX_OPSIZE)
1337 pPB[offset++] = 0x66; /* size override -> 16 bits pop */
1338 pPB[offset++] = 0x58 + pCpu->Param1.Base.idxGenReg;
1339 PATCHGEN_EPILOG(pPatch, offset);
1340
1341
1342 PATCHGEN_PROLOG_NODEF(pVM, pPatch, g_patmSetPIFRecord.cbFunction);
1343 size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmSetPIFRecord, 0, false);
1344 PATCHGEN_EPILOG(pPatch, size);
1345
1346 return VINF_SUCCESS;
1347}
1348
1349
1350/**
1351 * Generate an sldt or str patch instruction
1352 *
1353 * @returns VBox status code.
1354 * @param pVM Pointer to the VM.
1355 * @param pPatch Patch record
1356 * @param pCpu Disassembly state
1357 * @param pCurInstrGC Guest instruction address
1358 */
1359int patmPatchGenSldtStr(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu, RTRCPTR pCurInstrGC)
1360{
1361 // sldt %Ew
1362 int rc = VINF_SUCCESS;
1363 uint32_t offset = 0;
1364 uint32_t i;
1365
1366 /** @todo segment prefix (untested) */
1367 Assert(pCpu->fPrefix == DISPREFIX_NONE || pCpu->fPrefix == DISPREFIX_OPSIZE);
1368
1369 PATCHGEN_PROLOG(pVM, pPatch, PATCHGEN_DEF_SIZE);
1370
1371 if (pCpu->Param1.fUse == DISUSE_REG_GEN32 || pCpu->Param1.fUse == DISUSE_REG_GEN16)
1372 {
1373 /* Register operand */
1374 // 8B 15 [32 bits addr] mov edx, CPUMCTX.tr/ldtr
1375
1376 if (pCpu->fPrefix == DISPREFIX_OPSIZE)
1377 pPB[offset++] = 0x66;
1378
1379 pPB[offset++] = 0x8B; // mov destreg, CPUMCTX.tr/ldtr
1380 /* Modify REG part according to destination of original instruction */
1381 pPB[offset++] = MAKE_MODRM(0, pCpu->Param1.Base.idxGenReg, 5);
1382 if (pCpu->pCurInstr->uOpcode == OP_STR)
1383 {
1384 *(RTRCPTR *)&pPB[offset] = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, tr);
1385 }
1386 else
1387 {
1388 *(RTRCPTR *)&pPB[offset] = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, ldtr);
1389 }
1390 patmPatchAddReloc32(pVM, pPatch, &pPB[offset], FIXUP_ABSOLUTE);
1391 offset += sizeof(RTRCPTR);
1392 }
1393 else
1394 {
1395 /* Memory operand */
1396 //50 push eax
1397 //52 push edx
1398 //8D 15 48 7C 42 00 lea edx, dword ptr [dest]
1399 //66 A1 48 7C 42 00 mov ax, CPUMCTX.tr/ldtr
1400 //66 89 02 mov word ptr [edx],ax
1401 //5A pop edx
1402 //58 pop eax
1403
1404 pPB[offset++] = 0x50; // push eax
1405 pPB[offset++] = 0x52; // push edx
1406
1407 if (pCpu->fPrefix == DISPREFIX_SEG)
1408 {
1409 pPB[offset++] = DISQuerySegPrefixByte(pCpu);
1410 }
1411 pPB[offset++] = 0x8D; // lea edx, dword ptr [dest]
1412 // duplicate and modify modrm byte and additional bytes if present (e.g. direct address)
1413 pPB[offset++] = MAKE_MODRM(pCpu->ModRM.Bits.Mod, DISGREG_EDX , pCpu->ModRM.Bits.Rm);
1414
1415 i = 3; /* standard offset of modrm bytes */
1416 if (pCpu->fPrefix == DISPREFIX_OPSIZE)
1417 i++; //skip operand prefix
1418 if (pCpu->fPrefix == DISPREFIX_SEG)
1419 i++; //skip segment prefix
1420
1421 rc = patmPatchReadBytes(pVM, &pPB[offset], (RTRCPTR)((RTGCUINTPTR32)pCurInstrGC + i), pCpu->cbInstr - i);
1422 AssertRCReturn(rc, rc);
1423 offset += (pCpu->cbInstr - i);
1424
1425 pPB[offset++] = 0x66; // mov ax, CPUMCTX.tr/ldtr
1426 pPB[offset++] = 0xA1;
1427 if (pCpu->pCurInstr->uOpcode == OP_STR)
1428 {
1429 *(RTRCPTR *)&pPB[offset] = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, tr);
1430 }
1431 else
1432 {
1433 *(RTRCPTR *)&pPB[offset] = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, ldtr);
1434 }
1435 patmPatchAddReloc32(pVM, pPatch, &pPB[offset], FIXUP_ABSOLUTE);
1436 offset += sizeof(RTRCPTR);
1437
1438 pPB[offset++] = 0x66; // mov word ptr [edx],ax
1439 pPB[offset++] = 0x89;
1440 pPB[offset++] = 0x02;
1441
1442 pPB[offset++] = 0x5A; // pop edx
1443 pPB[offset++] = 0x58; // pop eax
1444 }
1445
1446 PATCHGEN_EPILOG(pPatch, offset);
1447
1448 return rc;
1449}
1450
1451/**
1452 * Generate an sgdt or sidt patch instruction
1453 *
1454 * @returns VBox status code.
1455 * @param pVM Pointer to the VM.
1456 * @param pPatch Patch record
1457 * @param pCpu Disassembly state
1458 * @param pCurInstrGC Guest instruction address
1459 */
1460int patmPatchGenSxDT(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu, RTRCPTR pCurInstrGC)
1461{
1462 int rc = VINF_SUCCESS;
1463 uint32_t offset = 0, offset_base, offset_limit;
1464 uint32_t i;
1465
1466 /* @todo segment prefix (untested) */
1467 Assert(pCpu->fPrefix == DISPREFIX_NONE);
1468
1469 // sgdt %Ms
1470 // sidt %Ms
1471
1472 switch (pCpu->pCurInstr->uOpcode)
1473 {
1474 case OP_SGDT:
1475 offset_base = RT_OFFSETOF(CPUMCTX, gdtr.pGdt);
1476 offset_limit = RT_OFFSETOF(CPUMCTX, gdtr.cbGdt);
1477 break;
1478
1479 case OP_SIDT:
1480 offset_base = RT_OFFSETOF(CPUMCTX, idtr.pIdt);
1481 offset_limit = RT_OFFSETOF(CPUMCTX, idtr.cbIdt);
1482 break;
1483
1484 default:
1485 return VERR_INVALID_PARAMETER;
1486 }
1487
1488//50 push eax
1489//52 push edx
1490//8D 15 48 7C 42 00 lea edx, dword ptr [dest]
1491//66 A1 48 7C 42 00 mov ax, CPUMCTX.gdtr.limit
1492//66 89 02 mov word ptr [edx],ax
1493//A1 48 7C 42 00 mov eax, CPUMCTX.gdtr.base
1494//89 42 02 mov dword ptr [edx+2],eax
1495//5A pop edx
1496//58 pop eax
1497
1498 PATCHGEN_PROLOG(pVM, pPatch, PATCHGEN_DEF_SIZE);
1499 pPB[offset++] = 0x50; // push eax
1500 pPB[offset++] = 0x52; // push edx
1501
1502 if (pCpu->fPrefix == DISPREFIX_SEG)
1503 {
1504 pPB[offset++] = DISQuerySegPrefixByte(pCpu);
1505 }
1506 pPB[offset++] = 0x8D; // lea edx, dword ptr [dest]
1507 // duplicate and modify modrm byte and additional bytes if present (e.g. direct address)
1508 pPB[offset++] = MAKE_MODRM(pCpu->ModRM.Bits.Mod, DISGREG_EDX , pCpu->ModRM.Bits.Rm);
1509
1510 i = 3; /* standard offset of modrm bytes */
1511 if (pCpu->fPrefix == DISPREFIX_OPSIZE)
1512 i++; //skip operand prefix
1513 if (pCpu->fPrefix == DISPREFIX_SEG)
1514 i++; //skip segment prefix
1515 rc = patmPatchReadBytes(pVM, &pPB[offset], (RTRCPTR)((RTGCUINTPTR32)pCurInstrGC + i), pCpu->cbInstr - i);
1516 AssertRCReturn(rc, rc);
1517 offset += (pCpu->cbInstr - i);
1518
1519 pPB[offset++] = 0x66; // mov ax, CPUMCTX.gdtr.limit
1520 pPB[offset++] = 0xA1;
1521 *(RTRCPTR *)&pPB[offset] = pVM->patm.s.pCPUMCtxGC + offset_limit;
1522 patmPatchAddReloc32(pVM, pPatch, &pPB[offset], FIXUP_ABSOLUTE);
1523 offset += sizeof(RTRCPTR);
1524
1525 pPB[offset++] = 0x66; // mov word ptr [edx],ax
1526 pPB[offset++] = 0x89;
1527 pPB[offset++] = 0x02;
1528
1529 pPB[offset++] = 0xA1; // mov eax, CPUMCTX.gdtr.base
1530 *(RTRCPTR *)&pPB[offset] = pVM->patm.s.pCPUMCtxGC + offset_base;
1531 patmPatchAddReloc32(pVM, pPatch, &pPB[offset], FIXUP_ABSOLUTE);
1532 offset += sizeof(RTRCPTR);
1533
1534 pPB[offset++] = 0x89; // mov dword ptr [edx+2],eax
1535 pPB[offset++] = 0x42;
1536 pPB[offset++] = 0x02;
1537
1538 pPB[offset++] = 0x5A; // pop edx
1539 pPB[offset++] = 0x58; // pop eax
1540
1541 PATCHGEN_EPILOG(pPatch, offset);
1542
1543 return rc;
1544}
1545
1546/**
1547 * Generate a cpuid patch instruction
1548 *
1549 * @returns VBox status code.
1550 * @param pVM Pointer to the VM.
1551 * @param pPatch Patch record
1552 * @param pCurInstrGC Guest instruction address
1553 */
1554int patmPatchGenCpuid(PVM pVM, PPATCHINFO pPatch, RTRCPTR pCurInstrGC)
1555{
1556 uint32_t size;
1557 PATCHGEN_PROLOG(pVM, pPatch, g_patmCpuidRecord.cbFunction);
1558
1559 size = patmPatchGenCode(pVM, pPatch, pPB, &g_patmCpuidRecord, 0, false);
1560
1561 PATCHGEN_EPILOG(pPatch, size);
1562 NOREF(pCurInstrGC);
1563 return VINF_SUCCESS;
1564}
1565
1566/**
1567 * Generate the jump from guest to patch code
1568 *
1569 * @returns VBox status code.
1570 * @param pVM Pointer to the VM.
1571 * @param pPatch Patch record
1572 * @param pTargetGC Guest target jump
1573 * @param fClearInhibitIRQs Clear inhibit irq flag
1574 */
1575int patmPatchGenJumpToGuest(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t *) pReturnAddrGC, bool fClearInhibitIRQs)
1576{
1577 int rc = VINF_SUCCESS;
1578 uint32_t size;
1579
1580 if (fClearInhibitIRQs)
1581 {
1582 rc = patmPatchGenClearInhibitIRQ(pVM, pPatch, pReturnAddrGC);
1583 if (rc == VERR_NO_MEMORY)
1584 return rc;
1585 AssertRCReturn(rc, rc);
1586 }
1587
1588 PATCHGEN_PROLOG(pVM, pPatch, PATMJumpToGuest_IF1Record.cbFunction);
1589
1590 /* Add lookup record for patch to guest address translation */
1591 patmR3AddP2GLookupRecord(pVM, pPatch, pPB, pReturnAddrGC, PATM_LOOKUP_PATCH2GUEST);
1592
1593 /* Generate code to jump to guest code if IF=1, else fault. */
1594 size = patmPatchGenCode(pVM, pPatch, pPB, &PATMJumpToGuest_IF1Record, pReturnAddrGC, true);
1595 PATCHGEN_EPILOG(pPatch, size);
1596
1597 return rc;
1598}
1599
1600/*
1601 * Relative jump from patch code to patch code (no fixup required)
1602 */
1603int patmPatchGenPatchJump(PVM pVM, PPATCHINFO pPatch, RTRCPTR pCurInstrGC, RCPTRTYPE(uint8_t *) pPatchAddrGC, bool fAddLookupRecord)
1604{
1605 int32_t displ;
1606 int rc = VINF_SUCCESS;
1607
1608 Assert(PATMIsPatchGCAddr(pVM, pPatchAddrGC));
1609 PATCHGEN_PROLOG(pVM, pPatch, SIZEOF_NEARJUMP32);
1610
1611 if (fAddLookupRecord)
1612 {
1613 /* Add lookup record for patch to guest address translation */
1614 patmR3AddP2GLookupRecord(pVM, pPatch, pPB, pCurInstrGC, PATM_LOOKUP_PATCH2GUEST);
1615 }
1616
1617 pPB[0] = 0xE9; //JMP
1618
1619 displ = pPatchAddrGC - (PATCHCODE_PTR_GC(pPatch) + pPatch->uCurPatchOffset + SIZEOF_NEARJUMP32);
1620
1621 *(uint32_t *)&pPB[1] = displ;
1622
1623 PATCHGEN_EPILOG(pPatch, SIZEOF_NEARJUMP32);
1624
1625 return rc;
1626}
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