VirtualBox

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

Last change on this file since 22621 was 22480, checked in by vboxsync, 15 years ago

SSM,VMM,Devices,Main,VBoxBFE: Live snapshot/migration SSM API adjustments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 43.2 KB
Line 
1/* $Id: PATMSSM.cpp 22480 2009-08-26 17:14:13Z 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 uVersion Data layout version.
302 * @param uPhase The data phase.
303 */
304DECLCALLBACK(int) patmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPhase)
305{
306 PATM patmInfo;
307 int rc;
308
309 if ( uVersion != PATM_SSM_VERSION
310 && uVersion != PATM_SSM_VERSION_FIXUP_HACK
311 && uVersion != PATM_SSM_VERSION_VER16
312#ifdef PATM_WITH_NEW_SSM
313 && uVersion != PATM_SSM_VERSION_GETPUTMEM)
314#else
315 )
316#endif
317 {
318 AssertMsgFailed(("patmR3Load: Invalid version uVersion=%d!\n", uVersion));
319 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
320 }
321
322 pVM->patm.s.savedstate.pSSM = pSSM;
323
324 /*
325 * Restore PATM structure
326 */
327#ifdef PATM_WITH_NEW_SSM
328 if (uVersion == PATM_SSM_VERSION_GETPUTMEM)
329 {
330#endif
331 rc = SSMR3GetMem(pSSM, &patmInfo, sizeof(patmInfo));
332 AssertRCReturn(rc, rc);
333#ifdef PATM_WITH_NEW_SSM
334 }
335 else
336 {
337 memset(&patmInfo, 0, sizeof(patmInfo));
338
339 AssertCompile(sizeof(patmInfo.pGCStateGC) == sizeof(RTRCPTR));
340 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pGCStateGC);
341 AssertRCReturn(rc, rc);
342
343 AssertCompile(sizeof(patmInfo.pCPUMCtxGC) == sizeof(RTRCPTR));
344 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pCPUMCtxGC);
345 AssertRCReturn(rc, rc);
346
347 AssertCompile(sizeof(patmInfo.pStatsGC) == sizeof(RTRCPTR));
348 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pStatsGC);
349 AssertRCReturn(rc, rc);
350
351 AssertCompile(sizeof(patmInfo.pfnHelperCallGC) == sizeof(RTRCPTR));
352 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pfnHelperCallGC);
353 AssertRCReturn(rc, rc);
354
355 AssertCompile(sizeof(patmInfo.pfnHelperRetGC) == sizeof(RTRCPTR));
356 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pfnHelperRetGC);
357 AssertRCReturn(rc, rc);
358
359 AssertCompile(sizeof(patmInfo.pfnHelperJumpGC) == sizeof(RTRCPTR));
360 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pfnHelperJumpGC);
361 AssertRCReturn(rc, rc);
362
363 AssertCompile(sizeof(patmInfo.pfnHelperIretGC) == sizeof(RTRCPTR));
364 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pfnHelperIretGC);
365 AssertRCReturn(rc, rc);
366
367 AssertCompile(sizeof(patmInfo.pPatchMemGC) == sizeof(RTRCPTR));
368 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pPatchMemGC);
369 AssertRCReturn(rc, rc);
370
371 AssertCompile(sizeof(patmInfo.cbPatchMem) == sizeof(uint32_t));
372 rc = SSMR3GetU32(pSSM, &patmInfo.cbPatchMem);
373 AssertRCReturn(rc, rc);
374
375 AssertCompile(sizeof(patmInfo.offPatchMem) == sizeof(uint32_t));
376 rc = SSMR3GetU32(pSSM, &patmInfo.offPatchMem);
377 AssertRCReturn(rc, rc);
378
379 AssertCompile(sizeof(patmInfo.deltaReloc) == sizeof(int32_t));
380 rc = SSMR3GetS32(pSSM, &patmInfo.deltaReloc);
381 AssertRCReturn(rc, rc);
382
383 AssertCompile(sizeof(patmInfo.uCurrentPatchIdx) == sizeof(uint32_t));
384 rc = SSMR3GetS32(pSSM, &patmInfo.uCurrentPatchIdx);
385 AssertRCReturn(rc, rc);
386
387 AssertCompile(sizeof(patmInfo.pPatchedInstrGCLowest) == sizeof(RTRCPTR));
388 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pPatchedInstrGCLowest);
389 AssertRCReturn(rc, rc);
390
391 AssertCompile(sizeof(patmInfo.pPatchedInstrGCHighest) == sizeof(RTRCPTR));
392 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pPatchedInstrGCHighest);
393 AssertRCReturn(rc, rc);
394
395 AssertCompile(sizeof(patmInfo.pfnSysEnterGC) == sizeof(RTRCPTR));
396 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pfnSysEnterGC);
397 AssertRCReturn(rc, rc);
398
399 AssertCompile(sizeof(patmInfo.pfnSysEnterPatchGC) == sizeof(RTRCPTR));
400 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pfnSysEnterPatchGC);
401 AssertRCReturn(rc, rc);
402
403 AssertCompile(sizeof(patmInfo.uSysEnterPatchIdx) == sizeof(uint32_t));
404 rc = SSMR3GetU32(pSSM, &patmInfo.uSysEnterPatchIdx);
405 AssertRCReturn(rc, rc);
406
407 AssertCompile(sizeof(patmInfo.ulCallDepth) == sizeof(uint32_t));
408 rc = SSMR3GetU32(pSSM, &patmInfo.ulCallDepth);
409 AssertRCReturn(rc, rc);
410
411 AssertCompile(sizeof(patmInfo.pGCStackGC) == sizeof(RTRCPTR));
412 rc = SSMR3GetRCPtr(pSSM, &patmInfo.pGCStackGC);
413 AssertRCReturn(rc, rc);
414
415 AssertCompile(sizeof(patmInfo.cPageRecords) == sizeof(uint32_t));
416 rc = SSMR3GetU32(pSSM, &patmInfo.cPageRecords);
417 AssertRCReturn(rc, rc);
418
419 AssertCompile(sizeof(patmInfo.fOutOfMemory) == sizeof(bool));
420 rc = SSMR3GetBool(pSSM, &patmInfo.fOutOfMemory);
421 AssertRCReturn(rc, rc);
422
423 AssertCompile(sizeof(patmInfo.savedstate.cPatches) == sizeof(uint32_t));
424 rc = SSMR3GetU32(pSSM, &patmInfo.savedstate.cPatches);
425 AssertRCReturn(rc, rc);
426
427 }
428#endif
429
430 /* Relative calls are made to the helper functions. Therefor their relative location must not change! */
431 /* Note: we reuse the saved global helpers and assume they are identical, which is kind of dangerous. */
432 if ( (pVM->patm.s.pfnHelperCallGC - pVM->patm.s.pPatchMemGC) != (patmInfo.pfnHelperCallGC - patmInfo.pPatchMemGC)
433 || (pVM->patm.s.pfnHelperRetGC - pVM->patm.s.pPatchMemGC) != (patmInfo.pfnHelperRetGC - patmInfo.pPatchMemGC)
434 || (pVM->patm.s.pfnHelperJumpGC - pVM->patm.s.pPatchMemGC) != (patmInfo.pfnHelperJumpGC - patmInfo.pPatchMemGC)
435 || (pVM->patm.s.pfnHelperIretGC - pVM->patm.s.pPatchMemGC) != (patmInfo.pfnHelperIretGC - patmInfo.pPatchMemGC))
436 {
437 AssertMsgFailed(("Helper function ptrs don't match!!!\n"));
438 return VERR_SSM_INVALID_STATE;
439 }
440
441 if (pVM->patm.s.cbPatchMem != patmInfo.cbPatchMem)
442 {
443 AssertMsgFailed(("Patch memory ptrs and/or sizes don't match!!!\n"));
444 return VERR_SSM_INVALID_STATE;
445 }
446 pVM->patm.s.offPatchMem = patmInfo.offPatchMem;
447 pVM->patm.s.deltaReloc = patmInfo.deltaReloc;
448 pVM->patm.s.uCurrentPatchIdx = patmInfo.uCurrentPatchIdx;
449 pVM->patm.s.fOutOfMemory = patmInfo.fOutOfMemory;
450
451 /* Lowest and highest patched instruction */
452 pVM->patm.s.pPatchedInstrGCLowest = patmInfo.pPatchedInstrGCLowest;
453 pVM->patm.s.pPatchedInstrGCHighest = patmInfo.pPatchedInstrGCHighest;
454
455 /* Sysenter handlers */
456 pVM->patm.s.pfnSysEnterGC = patmInfo.pfnSysEnterGC;
457 pVM->patm.s.pfnSysEnterPatchGC = patmInfo.pfnSysEnterPatchGC;
458 pVM->patm.s.uSysEnterPatchIdx = patmInfo.uSysEnterPatchIdx;
459
460 Assert(patmInfo.ulCallDepth == 0 && pVM->patm.s.ulCallDepth == 0);
461
462 Log(("pPatchMemGC %RRv vs old %RRv\n", pVM->patm.s.pPatchMemGC, patmInfo.pPatchMemGC));
463 Log(("pGCStateGC %RRv vs old %RRv\n", pVM->patm.s.pGCStateGC, patmInfo.pGCStateGC));
464 Log(("pGCStackGC %RRv vs old %RRv\n", pVM->patm.s.pGCStackGC, patmInfo.pGCStackGC));
465 Log(("pCPUMCtxGC %RRv vs old %RRv\n", pVM->patm.s.pCPUMCtxGC, patmInfo.pCPUMCtxGC));
466
467
468 /** @note patch statistics are not restored. */
469
470 /*
471 * Restore patch memory contents
472 */
473 Log(("Restore patch memory: new %RRv old %RRv\n", pVM->patm.s.pPatchMemGC, patmInfo.pPatchMemGC));
474 rc = SSMR3GetMem(pSSM, pVM->patm.s.pPatchMemHC, pVM->patm.s.cbPatchMem);
475 AssertRCReturn(rc, rc);
476
477 /*
478 * Restore GC state memory
479 */
480#ifdef PATM_WITH_NEW_SSM
481 if (uVersion == PATM_SSM_VERSION_GETPUTMEM)
482 {
483#endif
484 rc = SSMR3GetMem(pSSM, pVM->patm.s.pGCStateHC, sizeof(PATMGCSTATE));
485 AssertRCReturn(rc, rc);
486#ifdef PATM_WITH_NEW_SSM
487 }
488 else
489 {
490 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->uVMFlags) == sizeof(uint32_t));
491 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->uVMFlags);
492 AssertRCReturn(rc, rc);
493
494 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->uPendingAction) == sizeof(uint32_t));
495 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->uPendingAction);
496 AssertRCReturn(rc, rc);
497
498 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->uPatchCalls) == sizeof(uint32_t));
499 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->uPatchCalls);
500 AssertRCReturn(rc, rc);
501
502 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->uScratch) == sizeof(uint32_t));
503 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->uScratch);
504 AssertRCReturn(rc, rc);
505
506 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->uIretEFlags) == sizeof(uint32_t));
507 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->uIretEFlags);
508 AssertRCReturn(rc, rc);
509
510 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->uIretCS) == sizeof(uint32_t));
511 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->uIretCS);
512 AssertRCReturn(rc, rc);
513
514 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->uIretEIP) == sizeof(uint32_t));
515 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->uIretEIP);
516 AssertRCReturn(rc, rc);
517
518 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->Psp) == sizeof(uint32_t));
519 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->Psp);
520 AssertRCReturn(rc, rc);
521
522 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->fPIF) == sizeof(uint32_t));
523 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->fPIF);
524 AssertRCReturn(rc, rc);
525
526 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->GCPtrInhibitInterrupts) == sizeof(RTRCPTR));
527 rc = SSMR3GetRCPtr(pSSM, &pVM->patm.s.pGCStateHC->GCPtrInhibitInterrupts);
528 AssertRCReturn(rc, rc);
529
530 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->GCCallPatchTargetAddr) == sizeof(RTRCPTR));
531 rc = SSMR3GetRCPtr(pSSM, &pVM->patm.s.pGCStateHC->GCCallPatchTargetAddr);
532 AssertRCReturn(rc, rc);
533
534 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->GCCallReturnAddr) == sizeof(RTRCPTR));
535 rc = SSMR3GetRCPtr(pSSM, &pVM->patm.s.pGCStateHC->GCCallReturnAddr);
536 AssertRCReturn(rc, rc);
537
538 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->Restore.uEAX) == sizeof(uint32_t));
539 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->Restore.uEAX);
540 AssertRCReturn(rc, rc);
541
542 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->Restore.uECX) == sizeof(uint32_t));
543 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->Restore.uECX);
544 AssertRCReturn(rc, rc);
545
546 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->Restore.uEDI) == sizeof(uint32_t));
547 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->Restore.uEDI);
548 AssertRCReturn(rc, rc);
549
550 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->Restore.eFlags) == sizeof(uint32_t));
551 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->Restore.eFlags);
552 AssertRCReturn(rc, rc);
553
554 AssertCompile(sizeof(pVM->patm.s.pGCStateHC->Restore.uFlags) == sizeof(uint32_t));
555 rc = SSMR3GetU32(pSSM, &pVM->patm.s.pGCStateHC->Restore.uFlags);
556 AssertRCReturn(rc, rc);
557 }
558#endif
559
560 /*
561 * Restore PATM stack page
562 */
563 rc = SSMR3GetMem(pSSM, pVM->patm.s.pGCStackHC, PATM_STACK_TOTAL_SIZE);
564 AssertRCReturn(rc, rc);
565
566 /*
567 * Load all patches
568 */
569 for (uint32_t i=0;i<patmInfo.savedstate.cPatches;i++)
570 {
571 PATMPATCHREC patch, *pPatchRec;
572
573 rc = SSMR3GetMem(pSSM, &patch, sizeof(patch));
574 AssertRCReturn(rc, rc);
575
576 Assert(!(patch.patch.flags & PATMFL_GLOBAL_FUNCTIONS));
577
578 rc = MMHyperAlloc(pVM, sizeof(PATMPATCHREC), 0, MM_TAG_PATM_PATCH, (void **)&pPatchRec);
579 if (RT_FAILURE(rc))
580 {
581 AssertMsgFailed(("Out of memory!!!!\n"));
582 return VERR_NO_MEMORY;
583 }
584 /*
585 * Only restore the patch part of the tree record; not the internal data (except the key of course)
586 */
587 pPatchRec->patch = patch.patch;
588 pPatchRec->Core.Key = patch.Core.Key;
589 pPatchRec->CoreOffset.Key = patch.CoreOffset.Key;
590
591 Log(("Restoring patch %RRv -> %RRv\n", pPatchRec->patch.pPrivInstrGC, patmInfo.pPatchMemGC + pPatchRec->patch.pPatchBlockOffset));
592 bool ret = RTAvloU32Insert(&pVM->patm.s.PatchLookupTreeHC->PatchTree, &pPatchRec->Core);
593 Assert(ret);
594 if (pPatchRec->patch.uState != PATCH_REFUSED)
595 {
596 if (pPatchRec->patch.pPatchBlockOffset)
597 {
598 /* We actually generated code for this patch. */
599 ret = RTAvloU32Insert(&pVM->patm.s.PatchLookupTreeHC->PatchTreeByPatchAddr, &pPatchRec->CoreOffset);
600 AssertMsg(ret, ("Inserting patch %RRv offset %08RX32 failed!!\n", pPatchRec->patch.pPrivInstrGC, pPatchRec->CoreOffset.Key));
601 }
602 }
603 /* Set to zero as we don't need it anymore. */
604 pPatchRec->patch.pTempInfo = 0;
605
606 pPatchRec->patch.pPrivInstrHC = 0;
607 /* The GC virtual ptr is fixed, but we must convert it manually again to HC. */
608 int rc2 = rc = PGMPhysGCPtr2R3Ptr(VMMGetCpu0(pVM), pPatchRec->patch.pPrivInstrGC, (PRTR3PTR)&pPatchRec->patch.pPrivInstrHC);
609 /* Can fail due to page or page table not present. */
610
611 /*
612 * Restore fixup records and correct HC pointers in fixup records
613 */
614 pPatchRec->patch.FixupTree = 0;
615 pPatchRec->patch.nrFixups = 0; /* increased by patmPatchAddReloc32 */
616 for (int i=0;i<patch.patch.nrFixups;i++)
617 {
618 RELOCREC rec;
619 int32_t offset;
620 RTRCPTR *pFixup;
621
622 rc = SSMR3GetMem(pSSM, &rec, sizeof(rec));
623 AssertRCReturn(rc, rc);
624
625 /* rec.pRelocPos now contains the relative position inside the hypervisor area. */
626 offset = (int32_t)(int64_t)rec.pRelocPos;
627 /* Convert to HC pointer again. */
628 PATM_ADD_PTR(rec.pRelocPos, pVM->patm.s.pPatchMemHC);
629 pFixup = (RTRCPTR *)rec.pRelocPos;
630
631 if (pPatchRec->patch.uState != PATCH_REFUSED)
632 {
633 if ( rec.uType == FIXUP_REL_JMPTOPATCH
634 && (pPatchRec->patch.flags & PATMFL_PATCHED_GUEST_CODE))
635 {
636 Assert(pPatchRec->patch.cbPatchJump == SIZEOF_NEARJUMP32 || pPatchRec->patch.cbPatchJump == SIZEOF_NEAR_COND_JUMP32);
637 unsigned offset = (pPatchRec->patch.cbPatchJump == SIZEOF_NEARJUMP32) ? 1 : 2;
638
639 /** @todo This will fail & crash in patmCorrectFixup if the page isn't present
640 * when we restore. Happens with my XP image here
641 * (pPrivInstrGC=0x8069e051). */
642 AssertLogRelMsg(pPatchRec->patch.pPrivInstrHC, ("%RRv rc=%Rrc uState=%u\n", pPatchRec->patch.pPrivInstrGC, rc2, pPatchRec->patch.uState));
643 rec.pRelocPos = pPatchRec->patch.pPrivInstrHC + offset;
644 pFixup = (RTRCPTR *)rec.pRelocPos;
645 }
646
647 patmCorrectFixup(pVM, uVersion, patmInfo, &pPatchRec->patch, &rec, offset, pFixup);
648 }
649
650 rc = patmPatchAddReloc32(pVM, &pPatchRec->patch, rec.pRelocPos, rec.uType, rec.pSource, rec.pDest);
651 AssertRCReturn(rc, rc);
652 }
653
654 /* And all patch to guest lookup records */
655 Assert(pPatchRec->patch.nrPatch2GuestRecs || pPatchRec->patch.uState == PATCH_REFUSED || (pPatchRec->patch.flags & (PATMFL_SYSENTER_XP | PATMFL_IDTHANDLER | PATMFL_TRAPHANDLER | PATMFL_INT3_REPLACEMENT)));
656
657 pPatchRec->patch.Patch2GuestAddrTree = 0;
658 pPatchRec->patch.Guest2PatchAddrTree = 0;
659 if (pPatchRec->patch.nrPatch2GuestRecs)
660 {
661 RECPATCHTOGUEST rec;
662 uint32_t nrPatch2GuestRecs = pPatchRec->patch.nrPatch2GuestRecs;
663
664 pPatchRec->patch.nrPatch2GuestRecs = 0; /* incremented by patmr3AddP2GLookupRecord */
665 for (uint32_t i=0;i<nrPatch2GuestRecs;i++)
666 {
667 rc = SSMR3GetMem(pSSM, &rec, sizeof(rec));
668 AssertRCReturn(rc, rc);
669
670 patmr3AddP2GLookupRecord(pVM, &pPatchRec->patch, (uintptr_t)rec.Core.Key + pVM->patm.s.pPatchMemHC, rec.pOrgInstrGC, rec.enmType, rec.fDirty);
671 }
672 Assert(pPatchRec->patch.Patch2GuestAddrTree);
673 }
674
675 if (pPatchRec->patch.flags & PATMFL_CODE_MONITORED)
676 {
677 /* Insert the guest page lookup records (for detection self-modifying code) */
678 rc = patmInsertPatchPages(pVM, &pPatchRec->patch);
679 AssertRCReturn(rc, rc);
680 }
681
682#if 0 /* can fail def LOG_ENABLED */
683 if ( pPatchRec->patch.uState != PATCH_REFUSED
684 && !(pPatchRec->patch.flags & PATMFL_INT3_REPLACEMENT))
685 {
686 pPatchRec->patch.pTempInfo = (PPATCHINFOTEMP)MMR3HeapAllocZ(pVM, MM_TAG_PATM_PATCH, sizeof(PATCHINFOTEMP));
687 Log(("Patch code ----------------------------------------------------------\n"));
688 patmr3DisasmCodeStream(pVM, PATCHCODE_PTR_GC(&pPatchRec->patch), PATCHCODE_PTR_GC(&pPatchRec->patch), patmr3DisasmCallback, &pPatchRec->patch);
689 Log(("Patch code ends -----------------------------------------------------\n"));
690 MMR3HeapFree(pPatchRec->patch.pTempInfo);
691 pPatchRec->patch.pTempInfo = NULL;
692 }
693#endif
694
695 }
696
697 /*
698 * Correct absolute fixups in the global patch. (helper functions)
699 * Bit of a mess. Uses the new patch record, but restored patch functions.
700 */
701 PRELOCREC pRec = 0;
702 AVLPVKEY key = 0;
703
704 Log(("Correct fixups in global helper functions\n"));
705 while (true)
706 {
707 int32_t offset;
708 RTRCPTR *pFixup;
709
710 /* Get the record that's closest from above */
711 pRec = (PRELOCREC)RTAvlPVGetBestFit(&pVM->patm.s.pGlobalPatchRec->patch.FixupTree, key, true);
712 if (pRec == 0)
713 break;
714
715 key = (AVLPVKEY)(pRec->pRelocPos + 1); /* search for the next record during the next round. */
716
717 /* rec.pRelocPos now contains the relative position inside the hypervisor area. */
718 offset = (int32_t)(pRec->pRelocPos - pVM->patm.s.pPatchMemHC);
719 pFixup = (RTRCPTR *)pRec->pRelocPos;
720
721 /* Correct fixups that refer to PATM structures in the hypervisor region (their addresses might have changed). */
722 patmCorrectFixup(pVM, uVersion, patmInfo, &pVM->patm.s.pGlobalPatchRec->patch, pRec, offset, pFixup);
723 }
724
725#ifdef VBOX_WITH_STATISTICS
726 /*
727 * Restore relevant old statistics
728 */
729 pVM->patm.s.StatDisabled = patmInfo.StatDisabled;
730 pVM->patm.s.StatUnusable = patmInfo.StatUnusable;
731 pVM->patm.s.StatEnabled = patmInfo.StatEnabled;
732 pVM->patm.s.StatInstalled = patmInfo.StatInstalled;
733#endif
734
735 return VINF_SUCCESS;
736}
737
738/**
739 * Correct fixups to predefined hypervisor PATM regions. (their addresses might have changed)
740 *
741 * @returns VBox status code.
742 * @param pVM VM Handle.
743 * @param ulSSMVersion SSM version
744 * @param patmInfo Saved PATM structure
745 * @param pPatch Patch record
746 * @param pRec Relocation record
747 * @param offset Offset of referenced data/code
748 * @param pFixup Fixup address
749 */
750static void patmCorrectFixup(PVM pVM, unsigned ulSSMVersion, PATM &patmInfo, PPATCHINFO pPatch, PRELOCREC pRec, int32_t offset, RTRCPTR *pFixup)
751{
752 int32_t delta = pVM->patm.s.pPatchMemGC - patmInfo.pPatchMemGC;
753
754 switch (pRec->uType)
755 {
756 case FIXUP_ABSOLUTE:
757 {
758 if (pRec->pSource && !PATMIsPatchGCAddr(pVM, pRec->pSource))
759 break;
760
761 if ( *pFixup >= patmInfo.pGCStateGC
762 && *pFixup < patmInfo.pGCStateGC + sizeof(PATMGCSTATE))
763 {
764 LogFlow(("Changing absolute GCState at %RRv from %RRv to %RRv\n", patmInfo.pPatchMemGC + offset, *pFixup, (*pFixup - patmInfo.pGCStateGC) + pVM->patm.s.pGCStateGC));
765 *pFixup = (*pFixup - patmInfo.pGCStateGC) + pVM->patm.s.pGCStateGC;
766 }
767 else
768 if ( *pFixup >= patmInfo.pCPUMCtxGC
769 && *pFixup < patmInfo.pCPUMCtxGC + sizeof(CPUMCTX))
770 {
771 LogFlow(("Changing absolute CPUMCTX at %RRv from %RRv to %RRv\n", patmInfo.pPatchMemGC + offset, *pFixup, (*pFixup - patmInfo.pCPUMCtxGC) + pVM->patm.s.pCPUMCtxGC));
772
773 /* The CPUMCTX structure has completely changed, so correct the offsets too. */
774 if (ulSSMVersion == PATM_SSM_VERSION_VER16)
775 {
776 unsigned uCPUMOffset = *pFixup - patmInfo.pCPUMCtxGC;
777
778 /* ''case RT_OFFSETOF()'' does not work as gcc refuses to use & as a constant expression.
779 * Defining RT_OFFSETOF as __builtin_offsetof for gcc would make this possible. But this
780 * function is not available in older gcc versions, at least not in gcc-3.3 */
781 if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr0))
782 {
783 LogFlow(("Changing dr[0] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[0])));
784 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[0]);
785 }
786 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr1))
787 {
788 LogFlow(("Changing dr[1] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[1])));
789 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[1]);
790 }
791 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr2))
792 {
793 LogFlow(("Changing dr[2] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[2])));
794 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[2]);
795 }
796 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr3))
797 {
798 LogFlow(("Changing dr[3] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[3])));
799 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[3]);
800 }
801 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr4))
802 {
803 LogFlow(("Changing dr[4] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[4])));
804 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[4]);
805 }
806 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr5))
807 {
808 LogFlow(("Changing dr[5] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[5])));
809 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[5]);
810 }
811 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr6))
812 {
813 LogFlow(("Changing dr[6] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[6])));
814 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[6]);
815 }
816 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, dr7))
817 {
818 LogFlow(("Changing dr[7] offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, dr[7])));
819 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, dr[7]);
820 }
821 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, cr0))
822 {
823 LogFlow(("Changing cr0 offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, cr0)));
824 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, cr0);
825 }
826 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, cr2))
827 {
828 LogFlow(("Changing cr2 offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, cr2)));
829 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, cr2);
830 }
831 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, cr3))
832 {
833 LogFlow(("Changing cr3 offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, cr3)));
834 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, cr3);
835 }
836 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, cr4))
837 {
838 LogFlow(("Changing cr4 offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, cr4)));
839 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, cr4);
840 }
841 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, tr))
842 {
843 LogFlow(("Changing tr offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, tr)));
844 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, tr);
845 }
846 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, ldtr))
847 {
848 LogFlow(("Changing ldtr offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, ldtr)));
849 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, ldtr);
850 }
851 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, gdtr.pGdt))
852 {
853 LogFlow(("Changing pGdt offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, gdtr.pGdt)));
854 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, gdtr.pGdt);
855 }
856 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, gdtr.cbGdt))
857 {
858 LogFlow(("Changing cbGdt offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, gdtr.cbGdt)));
859 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, gdtr.cbGdt);
860 }
861 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, idtr.pIdt))
862 {
863 LogFlow(("Changing pIdt offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, idtr.pIdt)));
864 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, idtr.pIdt);
865 }
866 else if (uCPUMOffset == (unsigned)RT_OFFSETOF(CPUMCTX_VER1_6, idtr.cbIdt))
867 {
868 LogFlow(("Changing cbIdt offset from %x to %x\n", uCPUMOffset, RT_OFFSETOF(CPUMCTX, idtr.cbIdt)));
869 *pFixup = pVM->patm.s.pCPUMCtxGC + RT_OFFSETOF(CPUMCTX, idtr.cbIdt);
870 }
871 else
872 AssertMsgFailed(("Unexpected CPUMCTX offset %x\n", uCPUMOffset));
873 }
874 else
875 *pFixup = (*pFixup - patmInfo.pCPUMCtxGC) + pVM->patm.s.pCPUMCtxGC;
876 }
877 else
878 if ( *pFixup >= patmInfo.pStatsGC
879 && *pFixup < patmInfo.pStatsGC + PATM_STAT_MEMSIZE)
880 {
881 LogFlow(("Changing absolute Stats at %RRv from %RRv to %RRv\n", patmInfo.pPatchMemGC + offset, *pFixup, (*pFixup - patmInfo.pStatsGC) + pVM->patm.s.pStatsGC));
882 *pFixup = (*pFixup - patmInfo.pStatsGC) + pVM->patm.s.pStatsGC;
883 }
884 else
885 if ( *pFixup >= patmInfo.pGCStackGC
886 && *pFixup < patmInfo.pGCStackGC + PATM_STACK_TOTAL_SIZE)
887 {
888 LogFlow(("Changing absolute Stack at %RRv from %RRv to %RRv\n", patmInfo.pPatchMemGC + offset, *pFixup, (*pFixup - patmInfo.pGCStackGC) + pVM->patm.s.pGCStackGC));
889 *pFixup = (*pFixup - patmInfo.pGCStackGC) + pVM->patm.s.pGCStackGC;
890 }
891 else
892 if ( *pFixup >= patmInfo.pPatchMemGC
893 && *pFixup < patmInfo.pPatchMemGC + patmInfo.cbPatchMem)
894 {
895 LogFlow(("Changing absolute PatchMem at %RRv from %RRv to %RRv\n", patmInfo.pPatchMemGC + offset, *pFixup, (*pFixup - patmInfo.pPatchMemGC) + pVM->patm.s.pPatchMemGC));
896 *pFixup = (*pFixup - patmInfo.pPatchMemGC) + pVM->patm.s.pPatchMemGC;
897 }
898 else
899 if ( ulSSMVersion <= PATM_SSM_VERSION_FIXUP_HACK
900 && *pFixup >= pVM->pVMRC
901 && *pFixup < pVM->pVMRC + 32)
902 {
903 LogFlow(("Changing fLocalForcedActions fixup from %x to %x\n", *pFixup, pVM->pVMRC + RT_OFFSETOF(VM, aCpus[0].fLocalForcedActions)));
904 *pFixup = pVM->pVMRC + RT_OFFSETOF(VM, aCpus[0].fLocalForcedActions);
905 }
906 else
907 if ( ulSSMVersion <= PATM_SSM_VERSION_FIXUP_HACK
908 && *pFixup >= pVM->pVMRC
909 && *pFixup < pVM->pVMRC + 8192)
910 {
911 static int cCpuidFixup = 0;
912#ifdef LOG_ENABLED
913 RTRCPTR oldFixup = *pFixup;
914#endif
915 /* very dirty assumptions about the cpuid patch and cpuid ordering. */
916 switch(cCpuidFixup & 3)
917 {
918 case 0:
919 *pFixup = CPUMR3GetGuestCpuIdDefRCPtr(pVM);
920 break;
921 case 1:
922 *pFixup = CPUMR3GetGuestCpuIdStdRCPtr(pVM);
923 break;
924 case 2:
925 *pFixup = CPUMR3GetGuestCpuIdExtRCPtr(pVM);
926 break;
927 case 3:
928 *pFixup = CPUMR3GetGuestCpuIdCentaurRCPtr(pVM);
929 break;
930 }
931 LogFlow(("Changing cpuid fixup %d from %x to %x\n", cCpuidFixup, oldFixup, *pFixup));
932 cCpuidFixup++;
933 }
934 else
935 if (ulSSMVersion >= PATM_SSM_VERSION)
936 {
937#ifdef LOG_ENABLED
938 RTRCPTR oldFixup = *pFixup;
939#endif
940 /* Core.Key abused to store the type of fixup */
941 switch ((uintptr_t)pRec->Core.Key)
942 {
943 case PATM_FIXUP_CPU_FF_ACTION:
944 *pFixup = pVM->pVMRC + RT_OFFSETOF(VM, aCpus[0].fLocalForcedActions);
945 LogFlow(("Changing cpu ff action fixup from %x to %x\n", oldFixup, *pFixup));
946 break;
947 case PATM_FIXUP_CPUID_DEFAULT:
948 *pFixup = CPUMR3GetGuestCpuIdDefRCPtr(pVM);
949 LogFlow(("Changing cpuid def fixup from %x to %x\n", oldFixup, *pFixup));
950 break;
951 case PATM_FIXUP_CPUID_STANDARD:
952 *pFixup = CPUMR3GetGuestCpuIdStdRCPtr(pVM);
953 LogFlow(("Changing cpuid std fixup from %x to %x\n", oldFixup, *pFixup));
954 break;
955 case PATM_FIXUP_CPUID_EXTENDED:
956 *pFixup = CPUMR3GetGuestCpuIdExtRCPtr(pVM);
957 LogFlow(("Changing cpuid ext fixup from %x to %x\n", oldFixup, *pFixup));
958 break;
959 case PATM_FIXUP_CPUID_CENTAUR:
960 *pFixup = CPUMR3GetGuestCpuIdCentaurRCPtr(pVM);
961 LogFlow(("Changing cpuid centaur fixup from %x to %x\n", oldFixup, *pFixup));
962 break;
963 default:
964 AssertMsgFailed(("Unexpected fixup value %x\n", *pFixup));
965 break;
966 }
967 }
968
969#ifdef RT_OS_WINDOWS
970 AssertCompile(RT_OFFSETOF(VM, fGlobalForcedActions) < 32);
971#endif
972 break;
973 }
974
975 case FIXUP_REL_JMPTOPATCH:
976 {
977 RTRCPTR pTarget = (RTRCPTR)((RTRCINTPTR)pRec->pDest + delta);
978
979 if ( pPatch->uState == PATCH_ENABLED
980 && (pPatch->flags & PATMFL_PATCHED_GUEST_CODE))
981 {
982 uint8_t oldJump[SIZEOF_NEAR_COND_JUMP32];
983 uint8_t temp[SIZEOF_NEAR_COND_JUMP32];
984 RTRCPTR pJumpOffGC;
985 RTRCINTPTR displ = (RTRCINTPTR)pTarget - (RTRCINTPTR)pRec->pSource;
986 RTRCINTPTR displOld= (RTRCINTPTR)pRec->pDest - (RTRCINTPTR)pRec->pSource;
987
988 Log(("Relative fixup (g2p) %08X -> %08X at %08X (source=%08x, target=%08x)\n", *(int32_t*)pRec->pRelocPos, displ, pRec->pRelocPos, pRec->pSource, pRec->pDest));
989
990 Assert(pRec->pSource - pPatch->cbPatchJump == pPatch->pPrivInstrGC);
991#ifdef PATM_RESOLVE_CONFLICTS_WITH_JUMP_PATCHES
992 if (pPatch->cbPatchJump == SIZEOF_NEAR_COND_JUMP32)
993 {
994 Assert(pPatch->flags & PATMFL_JUMP_CONFLICT);
995
996 pJumpOffGC = pPatch->pPrivInstrGC + 2; //two byte opcode
997 oldJump[0] = pPatch->aPrivInstr[0];
998 oldJump[1] = pPatch->aPrivInstr[1];
999 *(RTRCUINTPTR *)&oldJump[2] = displOld;
1000 }
1001 else
1002#endif
1003 if (pPatch->cbPatchJump == SIZEOF_NEARJUMP32)
1004 {
1005 pJumpOffGC = pPatch->pPrivInstrGC + 1; //one byte opcode
1006 oldJump[0] = 0xE9;
1007 *(RTRCUINTPTR *)&oldJump[1] = displOld;
1008 }
1009 else
1010 {
1011 AssertMsgFailed(("Invalid patch jump size %d\n", pPatch->cbPatchJump));
1012 break;
1013 }
1014 Assert(pPatch->cbPatchJump <= sizeof(temp));
1015
1016 /*
1017 * Read old patch jump and compare it to the one we previously installed
1018 */
1019 int rc = PGMPhysSimpleReadGCPtr(VMMGetCpu0(pVM), temp, pPatch->pPrivInstrGC, pPatch->cbPatchJump);
1020 Assert(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
1021
1022 if (rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT)
1023 {
1024 RTRCPTR pPage = pPatch->pPrivInstrGC & PAGE_BASE_GC_MASK;
1025
1026 rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_ALL, pPage, pPage + (PAGE_SIZE - 1) /* inclusive! */, 0, patmVirtPageHandler, "PATMGCMonitorPage", 0, "PATMMonitorPatchJump");
1027 Assert(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT);
1028 }
1029 else
1030 if (memcmp(temp, oldJump, pPatch->cbPatchJump))
1031 {
1032 Log(("PATM: Patch jump was overwritten -> disabling patch!!\n"));
1033 /*
1034 * Disable patch; this is not a good solution
1035 */
1036 /* @todo hopefully it was completely overwritten (if the read was successful)!!!! */
1037 pPatch->uState = PATCH_DISABLED;
1038 }
1039 else
1040 if (RT_SUCCESS(rc))
1041 {
1042 rc = PGMPhysSimpleDirtyWriteGCPtr(VMMGetCpu0(pVM), pJumpOffGC, &displ, sizeof(displ));
1043 AssertRC(rc);
1044 }
1045 else
1046 {
1047 AssertMsgFailed(("Unexpected error %d from MMR3PhysReadGCVirt\n", rc));
1048 }
1049 }
1050 else
1051 {
1052 Log(("Skip the guest jump to patch code for this disabled patch %08X - %08X\n", pPatch->pPrivInstrHC, pRec->pRelocPos));
1053 }
1054
1055 pRec->pDest = pTarget;
1056 break;
1057 }
1058
1059 case FIXUP_REL_JMPTOGUEST:
1060 {
1061 RTRCPTR pSource = (RTRCPTR)((RTRCINTPTR)pRec->pSource + delta);
1062 RTRCINTPTR displ = (RTRCINTPTR)pRec->pDest - (RTRCINTPTR)pSource;
1063
1064 Assert(!(pPatch->flags & PATMFL_GLOBAL_FUNCTIONS));
1065 Log(("Relative fixup (p2g) %08X -> %08X at %08X (source=%08x, target=%08x)\n", *(int32_t*)pRec->pRelocPos, displ, pRec->pRelocPos, pRec->pSource, pRec->pDest));
1066 *(RTRCUINTPTR *)pRec->pRelocPos = displ;
1067 pRec->pSource = pSource;
1068 break;
1069
1070 }
1071}
1072}
1073
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