VirtualBox

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

最後變更 在這個檔案從54714是 54714,由 vboxsync 提交於 10 年 前

PATM,CPUM: CPUID patch update.

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

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