VirtualBox

source: vbox/trunk/src/VBox/VMM/PATM/PATMSSM.cpp@ 22015

Last change on this file since 22015 was 19144, checked in by vboxsync, 16 years ago

Compile fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 43.1 KB
Line 
1/* $Id: PATMSSM.cpp 19144 2009-04-23 14:05:09Z vboxsync $ */
2/** @file
3 * PATMSSM - Dynamic Guest OS Patching Manager; Save and load state
4 *
5 * NOTE: CSAM assumes patch memory is never reused!!
6 */
7
8/*
9 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#define LOG_GROUP LOG_GROUP_PATM
28#include <VBox/patm.h>
29#include <VBox/hwaccm.h>
30#include <VBox/stam.h>
31#include <VBox/pgm.h>
32#include <VBox/cpum.h>
33#include <VBox/iom.h>
34#include <VBox/sup.h>
35#include <VBox/mm.h>
36#include <VBox/ssm.h>
37#include <VBox/pdm.h>
38#include <VBox/trpm.h>
39#include <VBox/param.h>
40#include <iprt/avl.h>
41#include "PATMInternal.h"
42#include "PATMPatch.h"
43#include "PATMA.h"
44#include <VBox/vm.h>
45#include <VBox/csam.h>
46
47#include <VBox/dbg.h>
48#include <VBox/err.h>
49#include <VBox/log.h>
50#include <iprt/assert.h>
51#include <iprt/asm.h>
52#include <iprt/string.h>
53#include <VBox/dis.h>
54#include <VBox/disopcode.h>
55
56#define PATM_SUBTRACT_PTR(a, b) *(uintptr_t *)&(a) = (uintptr_t)(a) - (uintptr_t)(b)
57#define PATM_ADD_PTR(a, b) *(uintptr_t *)&(a) = (uintptr_t)(a) + (uintptr_t)(b)
58
59static void patmCorrectFixup(PVM pVM, unsigned ulSSMVersion, PATM &patmInfo, PPATCHINFO pPatch, PRELOCREC pRec, int32_t offset, RTRCPTR *pFixup);
60
61#ifdef VBOX_STRICT
62/**
63 * Callback function for RTAvlPVDoWithAll
64 *
65 * Counts the number of patches in the tree
66 *
67 * @returns VBox status code.
68 * @param pNode Current node
69 * @param pcPatches Pointer to patch counter (uint32_t)
70 */
71static DECLCALLBACK(int) patmCountLeafPV(PAVLPVNODECORE pNode, void *pcPatches)
72{
73 *(uint32_t *)pcPatches = *(uint32_t *)pcPatches + 1;
74 return VINF_SUCCESS;
75}
76
77/**
78 * Callback function for RTAvlU32DoWithAll
79 *
80 * Counts the number of patches in the tree
81 *
82 * @returns VBox status code.
83 * @param pNode Current node
84 * @param pcPatches Pointer to patch counter (uint32_t)
85 */
86static DECLCALLBACK(int) patmCountLeaf(PAVLU32NODECORE pNode, void *pcPatches)
87{
88 *(uint32_t *)pcPatches = *(uint32_t *)pcPatches + 1;
89 return VINF_SUCCESS;
90}
91#endif /* VBOX_STRICT */
92
93/**
94 * Callback function for RTAvloU32DoWithAll
95 *
96 * Counts the number of patches in the tree
97 *
98 * @returns VBox status code.
99 * @param pNode Current node
100 * @param pcPatches Pointer to patch counter
101 */
102static DECLCALLBACK(int) patmCountPatch(PAVLOU32NODECORE pNode, void *pcPatches)
103{
104 *(uint32_t *)pcPatches = *(uint32_t *)pcPatches + 1;
105 return VINF_SUCCESS;
106}
107
108/**
109 * Callback function for RTAvlU32DoWithAll
110 *
111 * Saves all patch to guest lookup records.
112 *
113 * @returns VBox status code.
114 * @param pNode Current node
115 * @param pVM1 VM Handle
116 */
117static DECLCALLBACK(int) patmSaveP2GLookupRecords(PAVLU32NODECORE pNode, void *pVM1)
118{
119 PVM pVM = (PVM)pVM1;
120 PSSMHANDLE pSSM = pVM->patm.s.savedstate.pSSM;
121 PRECPATCHTOGUEST pPatchToGuestRec = (PRECPATCHTOGUEST)pNode;
122
123 /* Save the lookup record. */
124 int rc = SSMR3PutMem(pSSM, pPatchToGuestRec, sizeof(RECPATCHTOGUEST));
125 AssertRCReturn(rc, rc);
126
127 return VINF_SUCCESS;
128}
129
130/**
131 * Callback function for RTAvlPVDoWithAll
132 *
133 * Saves all patch to guest lookup records.
134 *
135 * @returns VBox status code.
136 * @param pNode Current node
137 * @param pVM1 VM Handle
138 */
139static DECLCALLBACK(int) patmSaveFixupRecords(PAVLPVNODECORE pNode, void *pVM1)
140{
141 PVM pVM = (PVM)pVM1;
142 PSSMHANDLE pSSM = pVM->patm.s.savedstate.pSSM;
143 RELOCREC rec = *(PRELOCREC)pNode;
144 RTRCPTR *pFixup = (RTRCPTR *)rec.pRelocPos;
145
146 Assert(rec.pRelocPos);
147 /* Convert pointer to an offset into patch memory. */
148 PATM_SUBTRACT_PTR(rec.pRelocPos, pVM->patm.s.pPatchMemHC);
149
150 if (rec.uType == FIXUP_ABSOLUTE)
151 {
152 /* Core.Key abused to store the fixup type. */
153 if (*pFixup == pVM->pVMRC + RT_OFFSETOF(VM, aCpus[0].fLocalForcedActions))
154 rec.Core.Key = (AVLPVKEY)PATM_FIXUP_CPU_FF_ACTION;
155 else
156 if (*pFixup == CPUMR3GetGuestCpuIdDefRCPtr(pVM))
157 rec.Core.Key = (AVLPVKEY)PATM_FIXUP_CPUID_DEFAULT;
158 else
159 if (*pFixup == CPUMR3GetGuestCpuIdStdRCPtr(pVM))
160 rec.Core.Key = (AVLPVKEY)PATM_FIXUP_CPUID_STANDARD;
161 else
162 if (*pFixup == CPUMR3GetGuestCpuIdExtRCPtr(pVM))
163 rec.Core.Key = (AVLPVKEY)PATM_FIXUP_CPUID_EXTENDED;
164 else
165 if (*pFixup == CPUMR3GetGuestCpuIdCentaurRCPtr(pVM))
166 rec.Core.Key = (AVLPVKEY)PATM_FIXUP_CPUID_CENTAUR;
167 }
168
169 /* Save the lookup record. */
170 int rc = SSMR3PutMem(pSSM, &rec, sizeof(rec));
171 AssertRCReturn(rc, rc);
172
173 return VINF_SUCCESS;
174}
175
176
177/**
178 * Callback function for RTAvloU32DoWithAll
179 *
180 * Saves the state of the patch that's being enumerated
181 *
182 * @returns VBox status code.
183 * @param pNode Current node
184 * @param pVM1 VM Handle
185 */
186static DECLCALLBACK(int) patmSavePatchState(PAVLOU32NODECORE pNode, void *pVM1)
187{
188 PVM pVM = (PVM)pVM1;
189 PPATMPATCHREC pPatch = (PPATMPATCHREC)pNode;
190 PATMPATCHREC patch = *pPatch;
191 PSSMHANDLE pSSM = pVM->patm.s.savedstate.pSSM;
192 int rc;
193
194 Assert(!(pPatch->patch.flags & PATMFL_GLOBAL_FUNCTIONS));
195
196 /*
197 * Reset HC pointers that need to be recalculated when loading the state
198 */
199 AssertMsg(patch.patch.uState == PATCH_REFUSED || (patch.patch.pPatchBlockOffset || (patch.patch.flags & (PATMFL_SYSENTER_XP|PATMFL_INT3_REPLACEMENT))),
200 ("State = %x pPrivInstrHC=%08x pPatchBlockHC=%08x flags=%x\n", patch.patch.uState, patch.patch.pPrivInstrHC, PATCHCODE_PTR_HC(&patch.patch), patch.patch.flags));
201 Assert(pPatch->patch.JumpTree == 0);
202 Assert(!pPatch->patch.pTempInfo || pPatch->patch.pTempInfo->DisasmJumpTree == 0);
203 Assert(!pPatch->patch.pTempInfo || pPatch->patch.pTempInfo->IllegalInstrTree == 0);
204
205 memset(&patch.patch.cacheRec, 0, sizeof(patch.patch.cacheRec));
206
207 /* Save the patch record itself */
208 rc = SSMR3PutMem(pSSM, &patch, sizeof(patch));
209 AssertRCReturn(rc, rc);
210
211 /*
212 * Reset HC pointers in fixup records and save them.
213 */
214#ifdef VBOX_STRICT
215 uint32_t nrFixupRecs = 0;
216 RTAvlPVDoWithAll(&pPatch->patch.FixupTree, true, patmCountLeafPV, &nrFixupRecs);
217 AssertMsg((int32_t)nrFixupRecs == pPatch->patch.nrFixups, ("Fixup inconsistency! counted %d vs %d\n", nrFixupRecs, pPatch->patch.nrFixups));
218#endif
219 RTAvlPVDoWithAll(&pPatch->patch.FixupTree, true, patmSaveFixupRecords, pVM);
220
221#ifdef VBOX_STRICT
222 uint32_t nrLookupRecords = 0;
223 RTAvlU32DoWithAll(&pPatch->patch.Patch2GuestAddrTree, true, patmCountLeaf, &nrLookupRecords);
224 Assert(nrLookupRecords == pPatch->patch.nrPatch2GuestRecs);
225#endif
226
227 RTAvlU32DoWithAll(&pPatch->patch.Patch2GuestAddrTree, true, patmSaveP2GLookupRecords, pVM);
228 return VINF_SUCCESS;
229}
230
231/**
232 * Execute state save operation.
233 *
234 * @returns VBox status code.
235 * @param pVM VM Handle.
236 * @param pSSM SSM operation handle.
237 */
238DECLCALLBACK(int) patmr3Save(PVM pVM, PSSMHANDLE pSSM)
239{
240 PATM patmInfo = pVM->patm.s;
241 int rc;
242
243 pVM->patm.s.savedstate.pSSM = pSSM;
244
245 /*
246 * Reset HC pointers that need to be recalculated when loading the state
247 */
248 patmInfo.pPatchMemHC = NULL;
249 patmInfo.pGCStateHC = 0;
250 patmInfo.pvFaultMonitor = 0;
251
252 Assert(patmInfo.ulCallDepth == 0);
253
254 /*
255 * Count the number of patches in the tree (feeling lazy)
256 */
257 patmInfo.savedstate.cPatches = 0;
258 RTAvloU32DoWithAll(&pVM->patm.s.PatchLookupTreeHC->PatchTree, true, patmCountPatch, &patmInfo.savedstate.cPatches);
259
260 /*
261 * Save PATM structure
262 */
263 rc = SSMR3PutMem(pSSM, &patmInfo, sizeof(patmInfo));
264 AssertRCReturn(rc, rc);
265
266 /*
267 * Save patch memory contents
268 */
269 rc = SSMR3PutMem(pSSM, pVM->patm.s.pPatchMemHC, pVM->patm.s.cbPatchMem);
270 AssertRCReturn(rc, rc);
271
272 /*
273 * Save GC state memory
274 */
275 rc = SSMR3PutMem(pSSM, pVM->patm.s.pGCStateHC, sizeof(PATMGCSTATE));
276 AssertRCReturn(rc, rc);
277
278 /*
279 * Save PATM stack page
280 */
281 rc = SSMR3PutMem(pSSM, pVM->patm.s.pGCStackHC, PATM_STACK_TOTAL_SIZE);
282 AssertRCReturn(rc, rc);
283
284 /*
285 * Save all patches
286 */
287 rc = RTAvloU32DoWithAll(&pVM->patm.s.PatchLookupTreeHC->PatchTree, true, patmSavePatchState, pVM);
288 AssertRCReturn(rc, rc);
289
290 /** @note patch statistics are not saved. */
291
292 return VINF_SUCCESS;
293}
294
295/**
296 * Execute state load operation.
297 *
298 * @returns VBox status code.
299 * @param pVM VM Handle.
300 * @param pSSM SSM operation handle.
301 * @param u32Version Data layout version.
302 */
303DECLCALLBACK(int) patmr3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
304{
305 PATM patmInfo;
306 int rc;
307
308 if ( u32Version != PATM_SSM_VERSION
309 && u32Version != PATM_SSM_VERSION_FIXUP_HACK
310 && u32Version != PATM_SSM_VERSION_VER16
311#ifdef PATM_WITH_NEW_SSM
312 && u32Version != PATM_SSM_VERSION_GETPUTMEM)
313#else
314 )
315#endif
316 {
317 AssertMsgFailed(("patmR3Load: Invalid version u32Version=%d!\n", u32Version));
318 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
319 }
320
321 pVM->patm.s.savedstate.pSSM = pSSM;
322
323 /*
324 * Restore PATM structure
325 */
326#ifdef PATM_WITH_NEW_SSM
327 if (u32Version == PATM_SSM_VERSION_GETPUTMEM)
328 {
329#endif
330 rc = SSMR3GetMem(pSSM, &patmInfo, sizeof(patmInfo));
331 AssertRCReturn(rc, rc);
332#ifdef PATM_WITH_NEW_SSM
333 }
334 else
335 {
336 memset(&patmInfo, 0, sizeof(patmInfo));
337
338 AssertCompile(sizeof(patmInfo.pGCStateGC) == sizeof(RTRCPTR));
339 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pGCStateGC);
340 AssertRCReturn(rc, rc);
341
342 AssertCompile(sizeof(patmInfo.pCPUMCtxGC) == sizeof(RTRCPTR));
343 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pCPUMCtxGC);
344 AssertRCReturn(rc, rc);
345
346 AssertCompile(sizeof(patmInfo.pStatsGC) == sizeof(RTRCPTR));
347 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pStatsGC);
348 AssertRCReturn(rc, rc);
349
350 AssertCompile(sizeof(patmInfo.pfnHelperCallGC) == sizeof(RTRCPTR));
351 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pfnHelperCallGC);
352 AssertRCReturn(rc, rc);
353
354 AssertCompile(sizeof(patmInfo.pfnHelperRetGC) == sizeof(RTRCPTR));
355 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pfnHelperRetGC);
356 AssertRCReturn(rc, rc);
357
358 AssertCompile(sizeof(patmInfo.pfnHelperJumpGC) == sizeof(RTRCPTR));
359 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pfnHelperJumpGC);
360 AssertRCReturn(rc, rc);
361
362 AssertCompile(sizeof(patmInfo.pfnHelperIretGC) == sizeof(RTRCPTR));
363 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pfnHelperIretGC);
364 AssertRCReturn(rc, rc);
365
366 AssertCompile(sizeof(patmInfo.pPatchMemGC) == sizeof(RTRCPTR));
367 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pPatchMemGC);
368 AssertRCReturn(rc, rc);
369
370 AssertCompile(sizeof(patmInfo.cbPatchMem) == sizeof(uint32_t));
371 rc = SSMR3GetU32(pSSM, &patmInfo.cbPatchMem);
372 AssertRCReturn(rc, rc);
373
374 AssertCompile(sizeof(patmInfo.offPatchMem) == sizeof(uint32_t));
375 rc = SSMR3GetU32(pSSM, &patmInfo.offPatchMem);
376 AssertRCReturn(rc, rc);
377
378 AssertCompile(sizeof(patmInfo.deltaReloc) == sizeof(int32_t));
379 rc = SSMR3GetS32(pSSM, &patmInfo.deltaReloc);
380 AssertRCReturn(rc, rc);
381
382 AssertCompile(sizeof(patmInfo.uCurrentPatchIdx) == sizeof(uint32_t));
383 rc = SSMR3GetS32(pSSM, &patmInfo.uCurrentPatchIdx);
384 AssertRCReturn(rc, rc);
385
386 AssertCompile(sizeof(patmInfo.pPatchedInstrGCLowest) == sizeof(RTRCPTR));
387 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pPatchedInstrGCLowest);
388 AssertRCReturn(rc, rc);
389
390 AssertCompile(sizeof(patmInfo.pPatchedInstrGCHighest) == sizeof(RTRCPTR));
391 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pPatchedInstrGCHighest);
392 AssertRCReturn(rc, rc);
393
394 AssertCompile(sizeof(patmInfo.pfnSysEnterGC) == sizeof(RTRCPTR));
395 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pfnSysEnterGC);
396 AssertRCReturn(rc, rc);
397
398 AssertCompile(sizeof(patmInfo.pfnSysEnterPatchGC) == sizeof(RTRCPTR));
399 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pfnSysEnterPatchGC);
400 AssertRCReturn(rc, rc);
401
402 AssertCompile(sizeof(patmInfo.uSysEnterPatchIdx) == sizeof(uint32_t));
403 rc = SSMR3GetU32(pSSM, &patmInfo.uSysEnterPatchIdx);
404 AssertRCReturn(rc, rc);
405
406 AssertCompile(sizeof(patmInfo.ulCallDepth) == sizeof(uint32_t));
407 rc = SSMR3GetU32(pSSM, &patmInfo.ulCallDepth);
408 AssertRCReturn(rc, rc);
409
410 AssertCompile(sizeof(patmInfo.pGCStackGC) == sizeof(RTRCPTR));
411 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pGCStackGC);
412 AssertRCReturn(rc, rc);
413
414 AssertCompile(sizeof(patmInfo.cPageRecords) == sizeof(uint32_t));
415 rc = SSMR3GetU32(pSSM, &patmInfo.cPageRecords);
416 AssertRCReturn(rc, rc);
417
418 AssertCompile(sizeof(patmInfo.fOutOfMemory) == sizeof(bool));
419 rc = SSMR3GetBool(pSSM, &patmInfo.fOutOfMemory);
420 AssertRCReturn(rc, rc);
421
422 AssertCompile(sizeof(patmInfo.savedstate.cPatches) == sizeof(uint32_t));
423 rc = SSMR3GetU32(pSSM, &patmInfo.savedstate.cPatches);
424 AssertRCReturn(rc, rc);
425
426 }
427#endif
428
429 /* Relative calls are made to the helper functions. Therefor their relative location must not change! */
430 /* Note: we reuse the saved global helpers and assume they are identical, which is kind of dangerous. */
431 if ( (pVM->patm.s.pfnHelperCallGC - pVM->patm.s.pPatchMemGC) != (patmInfo.pfnHelperCallGC - patmInfo.pPatchMemGC)
432 || (pVM->patm.s.pfnHelperRetGC - pVM->patm.s.pPatchMemGC) != (patmInfo.pfnHelperRetGC - patmInfo.pPatchMemGC)
433 || (pVM->patm.s.pfnHelperJumpGC - pVM->patm.s.pPatchMemGC) != (patmInfo.pfnHelperJumpGC - patmInfo.pPatchMemGC)
434 || (pVM->patm.s.pfnHelperIretGC - pVM->patm.s.pPatchMemGC) != (patmInfo.pfnHelperIretGC - patmInfo.pPatchMemGC))
435 {
436 AssertMsgFailed(("Helper function ptrs don't match!!!\n"));
437 return VERR_SSM_INVALID_STATE;
438 }
439
440 if (pVM->patm.s.cbPatchMem != patmInfo.cbPatchMem)
441 {
442 AssertMsgFailed(("Patch memory ptrs and/or sizes don't match!!!\n"));
443 return VERR_SSM_INVALID_STATE;
444 }
445 pVM->patm.s.offPatchMem = patmInfo.offPatchMem;
446 pVM->patm.s.deltaReloc = patmInfo.deltaReloc;
447 pVM->patm.s.uCurrentPatchIdx = patmInfo.uCurrentPatchIdx;
448 pVM->patm.s.fOutOfMemory = patmInfo.fOutOfMemory;
449
450 /* Lowest and highest patched instruction */
451 pVM->patm.s.pPatchedInstrGCLowest = patmInfo.pPatchedInstrGCLowest;
452 pVM->patm.s.pPatchedInstrGCHighest = patmInfo.pPatchedInstrGCHighest;
453
454 /* Sysenter handlers */
455 pVM->patm.s.pfnSysEnterGC = patmInfo.pfnSysEnterGC;
456 pVM->patm.s.pfnSysEnterPatchGC = patmInfo.pfnSysEnterPatchGC;
457 pVM->patm.s.uSysEnterPatchIdx = patmInfo.uSysEnterPatchIdx;
458
459 Assert(patmInfo.ulCallDepth == 0 && pVM->patm.s.ulCallDepth == 0);
460
461 Log(("pPatchMemGC %RRv vs old %RRv\n", pVM->patm.s.pPatchMemGC, patmInfo.pPatchMemGC));
462 Log(("pGCStateGC %RRv vs old %RRv\n", pVM->patm.s.pGCStateGC, patmInfo.pGCStateGC));
463 Log(("pGCStackGC %RRv vs old %RRv\n", pVM->patm.s.pGCStackGC, patmInfo.pGCStackGC));
464 Log(("pCPUMCtxGC %RRv vs old %RRv\n", pVM->patm.s.pCPUMCtxGC, patmInfo.pCPUMCtxGC));
465
466
467 /** @note patch statistics are not restored. */
468
469 /*
470 * Restore patch memory contents
471 */
472 Log(("Restore patch memory: new %RRv old %RRv\n", pVM->patm.s.pPatchMemGC, patmInfo.pPatchMemGC));
473 rc = SSMR3GetMem(pSSM, pVM->patm.s.pPatchMemHC, pVM->patm.s.cbPatchMem);
474 AssertRCReturn(rc, rc);
475
476 /*
477 * Restore GC state memory
478 */
479#ifdef PATM_WITH_NEW_SSM
480 if (u32Version == PATM_SSM_VERSION_GETPUTMEM)
481 {
482#endif
483 rc = SSMR3GetMem(pSSM, pVM->patm.s.pGCStateHC, sizeof(PATMGCSTATE));
484 AssertRCReturn(rc, rc);
485#ifdef PATM_WITH_NEW_SSM
486 }
487 else
488 {
489 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->uVMFlags) == sizeof(uint32_t));
490 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->uVMFlags);
491 AssertRCReturn(rc, rc);
492
493 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->uPendingAction) == sizeof(uint32_t));
494 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->uPendingAction);
495 AssertRCReturn(rc, rc);
496
497 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->uPatchCalls) == sizeof(uint32_t));
498 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->uPatchCalls);
499 AssertRCReturn(rc, rc);
500
501 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->uScratch) == sizeof(uint32_t));
502 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->uScratch);
503 AssertRCReturn(rc, rc);
504
505 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->uIretEFlags) == sizeof(uint32_t));
506 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->uIretEFlags);
507 AssertRCReturn(rc, rc);
508
509 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->uIretCS) == sizeof(uint32_t));
510 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->uIretCS);
511 AssertRCReturn(rc, rc);
512
513 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->uIretEIP) == sizeof(uint32_t));
514 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->uIretEIP);
515 AssertRCReturn(rc, rc);
516
517 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->Psp) == sizeof(uint32_t));
518 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->Psp);
519 AssertRCReturn(rc, rc);
520
521 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->fPIF) == sizeof(uint32_t));
522 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->fPIF);
523 AssertRCReturn(rc, rc);
524
525 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->GCPtrInhibitInterrupts) == sizeof(RTRCPTR));
526 rc = SSMR3GetRCPtr(pSSM, &pVM->patm.s.pGCStateHC->GCPtrInhibitInterrupts);
527 AssertRCReturn(rc, rc);
528
529 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->GCCallPatchTargetAddr) == sizeof(RTRCPTR));
530 rc = SSMR3GetRCPtr(pSSM, &pVM->patm.s.pGCStateHC->GCCallPatchTargetAddr);
531 AssertRCReturn(rc, rc);
532
533 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->GCCallReturnAddr) == sizeof(RTRCPTR));
534 rc = SSMR3GetRCPtr(pSSM, &pVM->patm.s.pGCStateHC->GCCallReturnAddr);
535 AssertRCReturn(rc, rc);
536
537 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->Restore.uEAX) == sizeof(uint32_t));
538 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->Restore.uEAX);
539 AssertRCReturn(rc, rc);
540
541 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->Restore.uECX) == sizeof(uint32_t));
542 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->Restore.uECX);
543 AssertRCReturn(rc, rc);
544
545 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->Restore.uEDI) == sizeof(uint32_t));
546 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->Restore.uEDI);
547 AssertRCReturn(rc, rc);
548
549 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->Restore.eFlags) == sizeof(uint32_t));
550 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->Restore.eFlags);
551 AssertRCReturn(rc, rc);
552
553 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->Restore.uFlags) == sizeof(uint32_t));
554 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->Restore.uFlags);
555 AssertRCReturn(rc, rc);
556 }
557#endif
558
559 /*
560 * Restore PATM stack page
561 */
562 rc = SSMR3GetMem(pSSM, pVM->patm.s.pGCStackHC, PATM_STACK_TOTAL_SIZE);
563 AssertRCReturn(rc, rc);
564
565 /*
566 * Load all patches
567 */
568 for (uint32_t i=0;i<patmInfo.savedstate.cPatches;i++)
569 {
570 PATMPATCHREC patch, *pPatchRec;
571
572 rc = SSMR3GetMem(pSSM, &patch, sizeof(patch));
573 AssertRCReturn(rc, rc);
574
575 Assert(!(patch.patch.flags & PATMFL_GLOBAL_FUNCTIONS));
576
577 rc = MMHyperAlloc(pVM, sizeof(PATMPATCHREC), 0, MM_TAG_PATM_PATCH, (void **)&pPatchRec);
578 if (RT_FAILURE(rc))
579 {
580 AssertMsgFailed(("Out of memory!!!!\n"));
581 return VERR_NO_MEMORY;
582 }
583 /*
584 * Only restore the patch part of the tree record; not the internal data (except the key of course)
585 */
586 pPatchRec->patch = patch.patch;
587 pPatchRec->Core.Key = patch.Core.Key;
588 pPatchRec->CoreOffset.Key = patch.CoreOffset.Key;
589
590 Log(("Restoring patch %RRv -> %RRv\n", pPatchRec->patch.pPrivInstrGC, patmInfo.pPatchMemGC + pPatchRec->patch.pPatchBlockOffset));
591 bool ret = RTAvloU32Insert(&pVM->patm.s.PatchLookupTreeHC->PatchTree, &pPatchRec->Core);
592 Assert(ret);
593 if (pPatchRec->patch.uState != PATCH_REFUSED)
594 {
595 if (pPatchRec->patch.pPatchBlockOffset)
596 {
597 /* We actually generated code for this patch. */
598 ret = RTAvloU32Insert(&pVM->patm.s.PatchLookupTreeHC->PatchTreeByPatchAddr, &pPatchRec->CoreOffset);
599 AssertMsg(ret, ("Inserting patch %RRv offset %08RX32 failed!!\n", pPatchRec->patch.pPrivInstrGC, pPatchRec->CoreOffset.Key));
600 }
601 }
602 /* Set to zero as we don't need it anymore. */
603 pPatchRec->patch.pTempInfo = 0;
604
605 pPatchRec->patch.pPrivInstrHC = 0;
606 /* The GC virtual ptr is fixed, but we must convert it manually again to HC. */
607 int rc2 = rc = PGMPhysGCPtr2R3Ptr(VMMGetCpu0(pVM), pPatchRec->patch.pPrivInstrGC, (PRTR3PTR)&pPatchRec->patch.pPrivInstrHC);
608 /* Can fail due to page or page table not present. */
609
610 /*
611 * Restore fixup records and correct HC pointers in fixup records
612 */
613 pPatchRec->patch.FixupTree = 0;
614 pPatchRec->patch.nrFixups = 0; /* increased by patmPatchAddReloc32 */
615 for (int i=0;i<patch.patch.nrFixups;i++)
616 {
617 RELOCREC rec;
618 int32_t offset;
619 RTRCPTR *pFixup;
620
621 rc = SSMR3GetMem(pSSM, &rec, sizeof(rec));
622 AssertRCReturn(rc, rc);
623
624 /* rec.pRelocPos now contains the relative position inside the hypervisor area. */
625 offset = (int32_t)(int64_t)rec.pRelocPos;
626 /* Convert to HC pointer again. */
627 PATM_ADD_PTR(rec.pRelocPos, pVM->patm.s.pPatchMemHC);
628 pFixup = (RTRCPTR *)rec.pRelocPos;
629
630 if (pPatchRec->patch.uState != PATCH_REFUSED)
631 {
632 if ( rec.uType == FIXUP_REL_JMPTOPATCH
633 && (pPatchRec->patch.flags & PATMFL_PATCHED_GUEST_CODE))
634 {
635 Assert(pPatchRec->patch.cbPatchJump == SIZEOF_NEARJUMP32 || pPatchRec->patch.cbPatchJump == SIZEOF_NEAR_COND_JUMP32);
636 unsigned offset = (pPatchRec->patch.cbPatchJump == SIZEOF_NEARJUMP32) ? 1 : 2;
637
638 /** @todo This will fail & crash in patmCorrectFixup if the page isn't present
639 * when we restore. Happens with my XP image here
640 * (pPrivInstrGC=0x8069e051). */
641 AssertLogRelMsg(pPatchRec->patch.pPrivInstrHC, ("%RRv rc=%Rrc uState=%u\n", pPatchRec->patch.pPrivInstrGC, rc2, pPatchRec->patch.uState));
642 rec.pRelocPos = pPatchRec->patch.pPrivInstrHC + offset;
643 pFixup = (RTRCPTR *)rec.pRelocPos;
644 }
645
646 patmCorrectFixup(pVM, u32Version, patmInfo, &pPatchRec->patch, &rec, offset, pFixup);
647 }
648
649 rc = patmPatchAddReloc32(pVM, &pPatchRec->patch, rec.pRelocPos, rec.uType, rec.pSource, rec.pDest);
650 AssertRCReturn(rc, rc);
651 }
652
653 /* And all patch to guest lookup records */
654 Assert(pPatchRec->patch.nrPatch2GuestRecs || pPatchRec->patch.uState == PATCH_REFUSED || (pPatchRec->patch.flags & (PATMFL_SYSENTER_XP | PATMFL_IDTHANDLER | PATMFL_TRAPHANDLER | PATMFL_INT3_REPLACEMENT)));
655
656 pPatchRec->patch.Patch2GuestAddrTree = 0;
657 pPatchRec->patch.Guest2PatchAddrTree = 0;
658 if (pPatchRec->patch.nrPatch2GuestRecs)
659 {
660 RECPATCHTOGUEST rec;
661 uint32_t nrPatch2GuestRecs = pPatchRec->patch.nrPatch2GuestRecs;
662
663 pPatchRec->patch.nrPatch2GuestRecs = 0; /* incremented by patmr3AddP2GLookupRecord */
664 for (uint32_t i=0;i<nrPatch2GuestRecs;i++)
665 {
666 rc = SSMR3GetMem(pSSM, &rec, sizeof(rec));
667 AssertRCReturn(rc, rc);
668
669 patmr3AddP2GLookupRecord(pVM, &pPatchRec->patch, (uintptr_t)rec.Core.Key + pVM->patm.s.pPatchMemHC, rec.pOrgInstrGC, rec.enmType, rec.fDirty);
670 }
671 Assert(pPatchRec->patch.Patch2GuestAddrTree);
672 }
673
674 if (pPatchRec->patch.flags & PATMFL_CODE_MONITORED)
675 {
676 /* Insert the guest page lookup records (for detection self-modifying code) */
677 rc = patmInsertPatchPages(pVM, &pPatchRec->patch);
678 AssertRCReturn(rc, rc);
679 }
680
681#if 0 /* can fail def LOG_ENABLED */
682 if ( pPatchRec->patch.uState != PATCH_REFUSED
683 && !(pPatchRec->patch.flags & PATMFL_INT3_REPLACEMENT))
684 {
685 pPatchRec->patch.pTempInfo = (PPATCHINFOTEMP)MMR3HeapAllocZ(pVM, MM_TAG_PATM_PATCH, sizeof(PATCHINFOTEMP));
686 Log(("Patch code ----------------------------------------------------------\n"));
687 patmr3DisasmCodeStream(pVM, PATCHCODE_PTR_GC(&pPatchRec->patch), PATCHCODE_PTR_GC(&pPatchRec->patch), patmr3DisasmCallback, &pPatchRec->patch);
688 Log(("Patch code ends -----------------------------------------------------\n"));
689 MMR3HeapFree(pPatchRec->patch.pTempInfo);
690 pPatchRec->patch.pTempInfo = NULL;
691 }
692#endif
693
694 }
695
696 /*
697 * Correct absolute fixups in the global patch. (helper functions)
698 * Bit of a mess. Uses the new patch record, but restored patch functions.
699 */
700 PRELOCREC pRec = 0;
701 AVLPVKEY key = 0;
702
703 Log(("Correct fixups in global helper functions\n"));
704 while (true)
705 {
706 int32_t offset;
707 RTRCPTR *pFixup;
708
709 /* Get the record that's closest from above */
710 pRec = (PRELOCREC)RTAvlPVGetBestFit(&pVM->patm.s.pGlobalPatchRec->patch.FixupTree, key, true);
711 if (pRec == 0)
712 break;
713
714 key = (AVLPVKEY)(pRec->pRelocPos + 1); /* search for the next record during the next round. */
715
716 /* rec.pRelocPos now contains the relative position inside the hypervisor area. */
717 offset = (int32_t)(pRec->pRelocPos - pVM->patm.s.pPatchMemHC);
718 pFixup = (RTRCPTR *)pRec->pRelocPos;
719
720 /* Correct fixups that refer to PATM structures in the hypervisor region (their addresses might have changed). */
721 patmCorrectFixup(pVM, u32Version, patmInfo, &pVM->patm.s.pGlobalPatchRec->patch, pRec, offset, pFixup);
722 }
723
724#ifdef VBOX_WITH_STATISTICS
725 /*
726 * Restore relevant old statistics
727 */
728 pVM->patm.s.StatDisabled = patmInfo.StatDisabled;
729 pVM->patm.s.StatUnusable = patmInfo.StatUnusable;
730 pVM->patm.s.StatEnabled = patmInfo.StatEnabled;
731 pVM->patm.s.StatInstalled = patmInfo.StatInstalled;
732#endif
733
734 return VINF_SUCCESS;
735}
736
737/**
738 * Correct fixups to predefined hypervisor PATM regions. (their addresses might have changed)
739 *
740 * @returns VBox status code.
741 * @param pVM VM Handle.
742 * @param ulSSMVersion SSM version
743 * @param patmInfo Saved PATM structure
744 * @param pPatch Patch record
745 * @param pRec Relocation record
746 * @param offset Offset of referenced data/code
747 * @param pFixup Fixup address
748 */
749static void patmCorrectFixup(PVM pVM, unsigned ulSSMVersion, PATM &patmInfo, PPATCHINFO pPatch, PRELOCREC pRec, int32_t offset, RTRCPTR *pFixup)
750{
751 int32_t delta = pVM->patm.s.pPatchMemGC - patmInfo.pPatchMemGC;
752
753 switch (pRec->uType)
754 {
755 case FIXUP_ABSOLUTE:
756 {
757 if (pRec->pSource && !PATMIsPatchGCAddr(pVM, pRec->pSource))
758 break;
759
760 if ( *pFixup >= patmInfo.pGCStateGC
761 && *pFixup < patmInfo.pGCStateGC + sizeof(PATMGCSTATE))
762 {
763 LogFlow(("Changing absolute GCState at %RRv from %RRv to %RRv\n", patmInfo.pPatchMemGC + offset, *pFixup, (*pFixup - patmInfo.pGCStateGC) + pVM->patm.s.pGCStateGC));
764 *pFixup = (*pFixup - patmInfo.pGCStateGC) + pVM->patm.s.pGCStateGC;
765 }
766 else
767 if ( *pFixup >= patmInfo.pCPUMCtxGC
768 && *pFixup < patmInfo.pCPUMCtxGC + sizeof(CPUMCTX))
769 {
770 LogFlow(("Changing absolute CPUMCTX at %RRv from %RRv to %RRv\n", patmInfo.pPatchMemGC + offset, *pFixup, (*pFixup - patmInfo.pCPUMCtxGC) + pVM->patm.s.pCPUMCtxGC));
771
772 /* The CPUMCTX structure has completely changed, so correct the offsets too. */
773 if (ulSSMVersion == PATM_SSM_VERSION_VER16)
774 {
775 unsigned uCPUMOffset = *pFixup - patmInfo.pCPUMCtxGC;
776
777 /* ''case RT_OFFSETOF()'' does not work as gcc refuses to use & as a constant expression.
778 * Defining RT_OFFSETOF as __builtin_offsetof for gcc would make this possible. But this
779 * function is not available in older gcc versions, at least not in gcc-3.3 */
780 if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr0))
781 {
782 LogFlow(("Changing dr[0] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[0])));
783 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[0]);
784 }
785 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr1))
786 {
787 LogFlow(("Changing dr[1] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[1])));
788 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[1]);
789 }
790 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr2))
791 {
792 LogFlow(("Changing dr[2] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[2])));
793 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[2]);
794 }
795 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr3))
796 {
797 LogFlow(("Changing dr[3] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[3])));
798 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[3]);
799 }
800 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr4))
801 {
802 LogFlow(("Changing dr[4] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[4])));
803 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[4]);
804 }
805 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr5))
806 {
807 LogFlow(("Changing dr[5] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[5])));
808 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[5]);
809 }
810 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr6))
811 {
812 LogFlow(("Changing dr[6] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[6])));
813 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[6]);
814 }
815 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr7))
816 {
817 LogFlow(("Changing dr[7] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[7])));
818 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[7]);
819 }
820 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, cr0))
821 {
822 LogFlow(("Changing cr0 offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, cr0)));
823 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, cr0);
824 }
825 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, cr2))
826 {
827 LogFlow(("Changing cr2 offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, cr2)));
828 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, cr2);
829 }
830 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, cr3))
831 {
832 LogFlow(("Changing cr3 offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, cr3)));
833 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, cr3);
834 }
835 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, cr4))
836 {
837 LogFlow(("Changing cr4 offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, cr4)));
838 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, cr4);
839 }
840 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, tr))
841 {
842 LogFlow(("Changing tr offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, tr)));
843 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, tr);
844 }
845 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, ldtr))
846 {
847 LogFlow(("Changing ldtr offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, ldtr)));
848 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, ldtr);
849 }
850 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, gdtr.pGdt))
851 {
852 LogFlow(("Changing pGdt offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, gdtr.pGdt)));
853 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, gdtr.pGdt);
854 }
855 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, gdtr.cbGdt))
856 {
857 LogFlow(("Changing cbGdt offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, gdtr.cbGdt)));
858 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, gdtr.cbGdt);
859 }
860 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, idtr.pIdt))
861 {
862 LogFlow(("Changing pIdt offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, idtr.pIdt)));
863 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, idtr.pIdt);
864 }
865 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, idtr.cbIdt))
866 {
867 LogFlow(("Changing cbIdt offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, idtr.cbIdt)));
868 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, idtr.cbIdt);
869 }
870 else
871 AssertMsgFailed(("Unexpected CPUMCTX offset %x\n", uCPUMOffset));
872 }
873 else
874 *pFixup = (*pFixup - patmInfo.pCPUMCtxGC) + pVM->patm.s.pCPUMCtxGC;
875 }
876 else
877 if ( *pFixup >= patmInfo.pStatsGC
878 && *pFixup < patmInfo.pStatsGC + PATM_STAT_MEMSIZE)
879 {
880 LogFlow(("Changing absolute Stats at %RRv from %RRv to %RRv\n", patmInfo.pPatchMemGC + offset, *pFixup, (*pFixup - patmInfo.pStatsGC) + pVM->patm.s.pStatsGC));
881 *pFixup = (*pFixup - patmInfo.pStatsGC) + pVM->patm.s.pStatsGC;
882 }
883 else
884 if ( *pFixup >= patmInfo.pGCStackGC
885 && *pFixup < patmInfo.pGCStackGC + PATM_STACK_TOTAL_SIZE)
886 {
887 LogFlow(("Changing absolute Stack at %RRv from %RRv to %RRv\n", patmInfo.pPatchMemGC + offset, *pFixup, (*pFixup - patmInfo.pGCStackGC) + pVM->patm.s.pGCStackGC));
888 *pFixup = (*pFixup - patmInfo.pGCStackGC) + pVM->patm.s.pGCStackGC;
889 }
890 else
891 if ( *pFixup >= patmInfo.pPatchMemGC
892 && *pFixup < patmInfo.pPatchMemGC + patmInfo.cbPatchMem)
893 {
894 LogFlow(("Changing absolute PatchMem at %RRv from %RRv to %RRv\n", patmInfo.pPatchMemGC + offset, *pFixup, (*pFixup - patmInfo.pPatchMemGC) + pVM->patm.s.pPatchMemGC));
895 *pFixup = (*pFixup - patmInfo.pPatchMemGC) + pVM->patm.s.pPatchMemGC;
896 }
897 else
898 if ( ulSSMVersion <= PATM_SSM_VERSION_FIXUP_HACK
899 && *pFixup >= pVM->pVMRC
900 && *pFixup < pVM->pVMRC + 32)
901 {
902 LogFlow(("Changing fLocalForcedActions fixup from %x to %x\n", *pFixup, pVM->pVMRC + RT_OFFSETOF(VM, aCpus[0].fLocalForcedActions)));
903 *pFixup = pVM->pVMRC + RT_OFFSETOF(VM, aCpus[0].fLocalForcedActions);
904 }
905 else
906 if ( ulSSMVersion <= PATM_SSM_VERSION_FIXUP_HACK
907 && *pFixup >= pVM->pVMRC
908 && *pFixup < pVM->pVMRC + 8192)
909 {
910 static int cCpuidFixup = 0;
911#ifdef LOG_ENABLED
912 RTRCPTR oldFixup = *pFixup;
913#endif
914 /* very dirty assumptions about the cpuid patch and cpuid ordering. */
915 switch(cCpuidFixup & 3)
916 {
917 case 0:
918 *pFixup = CPUMR3GetGuestCpuIdDefRCPtr(pVM);
919 break;
920 case 1:
921 *pFixup = CPUMR3GetGuestCpuIdStdRCPtr(pVM);
922 break;
923 case 2:
924 *pFixup = CPUMR3GetGuestCpuIdExtRCPtr(pVM);
925 break;
926 case 3:
927 *pFixup = CPUMR3GetGuestCpuIdCentaurRCPtr(pVM);
928 break;
929 }
930 LogFlow(("Changing cpuid fixup %d from %x to %x\n", cCpuidFixup, oldFixup, *pFixup));
931 cCpuidFixup++;
932 }
933 else
934 if (ulSSMVersion >= PATM_SSM_VERSION)
935 {
936#ifdef LOG_ENABLED
937 RTRCPTR oldFixup = *pFixup;
938#endif
939 /* Core.Key abused to store the type of fixup */
940 switch ((uintptr_t)pRec->Core.Key)
941 {
942 case PATM_FIXUP_CPU_FF_ACTION:
943 *pFixup = pVM->pVMRC + RT_OFFSETOF(VM, aCpus[0].fLocalForcedActions);
944 LogFlow(("Changing cpu ff action fixup from %x to %x\n", oldFixup, *pFixup));
945 break;
946 case PATM_FIXUP_CPUID_DEFAULT:
947 *pFixup = CPUMR3GetGuestCpuIdDefRCPtr(pVM);
948 LogFlow(("Changing cpuid def fixup from %x to %x\n", oldFixup, *pFixup));
949 break;
950 case PATM_FIXUP_CPUID_STANDARD:
951 *pFixup = CPUMR3GetGuestCpuIdStdRCPtr(pVM);
952 LogFlow(("Changing cpuid std fixup from %x to %x\n", oldFixup, *pFixup));
953 break;
954 case PATM_FIXUP_CPUID_EXTENDED:
955 *pFixup = CPUMR3GetGuestCpuIdExtRCPtr(pVM);
956 LogFlow(("Changing cpuid ext fixup from %x to %x\n", oldFixup, *pFixup));
957 break;
958 case PATM_FIXUP_CPUID_CENTAUR:
959 *pFixup = CPUMR3GetGuestCpuIdCentaurRCPtr(pVM);
960 LogFlow(("Changing cpuid centaur fixup from %x to %x\n", oldFixup, *pFixup));
961 break;
962 default:
963 AssertMsgFailed(("Unexpected fixup value %x\n", *pFixup));
964 break;
965 }
966 }
967
968#ifdef RT_OS_WINDOWS
969 AssertCompile(RT_OFFSETOF(VM, fGlobalForcedActions) < 32);
970#endif
971 break;
972 }
973
974 case FIXUP_REL_JMPTOPATCH:
975 {
976 RTRCPTR pTarget = (RTRCPTR)((RTRCINTPTR)pRec->pDest + delta);
977
978 if ( pPatch->uState == PATCH_ENABLED
979 && (pPatch->flags & PATMFL_PATCHED_GUEST_CODE))
980 {
981 uint8_t oldJump[SIZEOF_NEAR_COND_JUMP32];
982 uint8_t temp[SIZEOF_NEAR_COND_JUMP32];
983 RTRCPTR pJumpOffGC;
984 RTRCINTPTR displ = (RTRCINTPTR)pTarget - (RTRCINTPTR)pRec->pSource;
985 RTRCINTPTR displOld= (RTRCINTPTR)pRec->pDest - (RTRCINTPTR)pRec->pSource;
986
987 Log(("Relative fixup (g2p) %08X -> %08X at %08X (source=%08x, target=%08x)\n", *(int32_t*)pRec->pRelocPos, displ, pRec->pRelocPos, pRec->pSource, pRec->pDest));
988
989 Assert(pRec->pSource - pPatch->cbPatchJump == pPatch->pPrivInstrGC);
990#ifdef PATM_RESOLVE_CONFLICTS_WITH_JUMP_PATCHES
991 if (pPatch->cbPatchJump == SIZEOF_NEAR_COND_JUMP32)
992 {
993 Assert(pPatch->flags & PATMFL_JUMP_CONFLICT);
994
995 pJumpOffGC = pPatch->pPrivInstrGC + 2; //two byte opcode
996 oldJump[0] = pPatch->aPrivInstr[0];
997 oldJump[1] = pPatch->aPrivInstr[1];
998 *(RTRCUINTPTR *)&oldJump[2] = displOld;
999 }
1000 else
1001#endif
1002 if (pPatch->cbPatchJump == SIZEOF_NEARJUMP32)
1003 {
1004 pJumpOffGC = pPatch->pPrivInstrGC + 1; //one byte opcode
1005 oldJump[0] = 0xE9;
1006 *(RTRCUINTPTR *)&oldJump[1] = displOld;
1007 }
1008 else
1009 {
1010 AssertMsgFailed(("Invalid patch jump size %d\n", pPatch->cbPatchJump));
1011 break;
1012 }
1013 Assert(pPatch->cbPatchJump <= sizeof(temp));
1014
1015 /*
1016 * Read old patch jump and compare it to the one we previously installed
1017 */
1018 int rc = PGMPhysSimpleReadGCPtr(VMMGetCpu0(pVM), temp, pPatch->pPrivInstrGC, pPatch->cbPatchJump);
1019 Assert(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
1020
1021 if (rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT)
1022 {
1023 RTRCPTR pPage = pPatch->pPrivInstrGC & PAGE_BASE_GC_MASK;
1024
1025 rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_ALL, pPage, pPage + (PAGE_SIZE - 1) /* inclusive! */, 0, patmVirtPageHandler, "PATMGCMonitorPage", 0, "PATMMonitorPatchJump");
1026 Assert(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT);
1027 }
1028 else
1029 if (memcmp(temp, oldJump, pPatch->cbPatchJump))
1030 {
1031 Log(("PATM: Patch jump was overwritten -> disabling patch!!\n"));
1032 /*
1033 * Disable patch; this is not a good solution
1034 */
1035 /* @todo hopefully it was completely overwritten (if the read was successful)!!!! */
1036 pPatch->uState = PATCH_DISABLED;
1037 }
1038 else
1039 if (RT_SUCCESS(rc))
1040 {
1041 rc = PGMPhysSimpleDirtyWriteGCPtr(VMMGetCpu0(pVM), pJumpOffGC, &displ, sizeof(displ));
1042 AssertRC(rc);
1043 }
1044 else
1045 {
1046 AssertMsgFailed(("Unexpected error %d from MMR3PhysReadGCVirt\n", rc));
1047 }
1048 }
1049 else
1050 {
1051 Log(("Skip the guest jump to patch code for this disabled patch %08X - %08X\n", pPatch->pPrivInstrHC, pRec->pRelocPos));
1052 }
1053
1054 pRec->pDest = pTarget;
1055 break;
1056 }
1057
1058 case FIXUP_REL_JMPTOGUEST:
1059 {
1060 RTRCPTR pSource = (RTRCPTR)((RTRCINTPTR)pRec->pSource + delta);
1061 RTRCINTPTR displ = (RTRCINTPTR)pRec->pDest - (RTRCINTPTR)pSource;
1062
1063 Assert(!(pPatch->flags & PATMFL_GLOBAL_FUNCTIONS));
1064 Log(("Relative fixup (p2g) %08X -> %08X at %08X (source=%08x, target=%08x)\n", *(int32_t*)pRec->pRelocPos, displ, pRec->pRelocPos, pRec->pSource, pRec->pDest));
1065 *(RTRCUINTPTR *)pRec->pRelocPos = displ;
1066 pRec->pSource = pSource;
1067 break;
1068
1069 }
1070}
1071}
1072
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