VirtualBox

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

Last change on this file since 5458 was 4190, checked in by vboxsync, 17 years ago

SSMAFTER_DEBUG_IT hack.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 15.2 KB
Line 
1/* $Id: PATMSSM.cpp 4190 2007-08-16 22:48:51Z 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 innotek GmbH
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 as published by the Free Software Foundation,
15 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
16 * distribution. VirtualBox OSE is distributed in the hope that it will
17 * 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/patm.h>
25#include <VBox/stam.h>
26#include <VBox/pgm.h>
27#include <VBox/cpum.h>
28#include <VBox/iom.h>
29#include <VBox/sup.h>
30#include <VBox/mm.h>
31#include <VBox/ssm.h>
32#include <VBox/pdm.h>
33#include <VBox/trpm.h>
34#include <VBox/param.h>
35#include <iprt/avl.h>
36#include "PATMInternal.h"
37#include "PATMPatch.h"
38#include "PATMA.h"
39#include <VBox/vm.h>
40#include <VBox/csam.h>
41
42#include <VBox/dbg.h>
43#include <VBox/err.h>
44#include <VBox/log.h>
45#include <iprt/assert.h>
46#include <iprt/asm.h>
47#include <iprt/string.h>
48#include <VBox/dis.h>
49#include <VBox/disopcode.h>
50
51#define PATM_SUBTRACT_PTR(a, b) *(uintptr_t *)&(a) = (uintptr_t)(a) - (uintptr_t)(b)
52#define PATM_ADD_PTR(a, b) *(uintptr_t *)&(a) = (uintptr_t)(a) + (uintptr_t)(b)
53
54#ifdef VBOX_STRICT
55/**
56 * Callback function for RTAvlPVDoWithAll
57 *
58 * Counts the number of patches in the tree
59 *
60 * @returns VBox status code.
61 * @param pNode Current node
62 * @param pcPatches Pointer to patch counter (uint32_t)
63 */
64static DECLCALLBACK(int) patmCountLeafPV(PAVLPVNODECORE pNode, void *pcPatches)
65{
66 *(uint32_t *)pcPatches = *(uint32_t *)pcPatches + 1;
67 return VINF_SUCCESS;
68}
69
70/**
71 * Callback function for RTAvlU32DoWithAll
72 *
73 * Counts the number of patches in the tree
74 *
75 * @returns VBox status code.
76 * @param pNode Current node
77 * @param pcPatches Pointer to patch counter (uint32_t)
78 */
79static DECLCALLBACK(int) patmCountLeaf(PAVLU32NODECORE pNode, void *pcPatches)
80{
81 *(uint32_t *)pcPatches = *(uint32_t *)pcPatches + 1;
82 return VINF_SUCCESS;
83}
84#endif /* VBOX_STRICT */
85
86/**
87 * Callback function for RTAvloGCPtrDoWithAll
88 *
89 * Counts the number of patches in the tree
90 *
91 * @returns VBox status code.
92 * @param pNode Current node
93 * @param pcPatches Pointer to patch counter
94 */
95static DECLCALLBACK(int) patmCountPatch(PAVLOGCPTRNODECORE pNode, void *pcPatches)
96{
97 *(uint32_t *)pcPatches = *(uint32_t *)pcPatches + 1;
98 return VINF_SUCCESS;
99}
100
101/**
102 * Callback function for RTAvlU32DoWithAll
103 *
104 * Saves all patch to guest lookup records.
105 *
106 * @returns VBox status code.
107 * @param pNode Current node
108 * @param pVM1 VM Handle
109 */
110static DECLCALLBACK(int) patmSaveP2GLookupRecords(PAVLU32NODECORE pNode, void *pVM1)
111{
112 PVM pVM = (PVM)pVM1;
113 PSSMHANDLE pSSM = pVM->patm.s.savedstate.pSSM;
114 PRECPATCHTOGUEST pPatchToGuestRec = (PRECPATCHTOGUEST)pNode;
115
116 /* Save the lookup record. */
117 int rc = SSMR3PutMem(pSSM, pPatchToGuestRec, sizeof(RECPATCHTOGUEST));
118 AssertRCReturn(rc, rc);
119
120 return VINF_SUCCESS;
121}
122
123/**
124 * Callback function for RTAvlPVDoWithAll
125 *
126 * Saves all patch to guest lookup records.
127 *
128 * @returns VBox status code.
129 * @param pNode Current node
130 * @param pVM1 VM Handle
131 */
132static DECLCALLBACK(int) patmSaveFixupRecords(PAVLPVNODECORE pNode, void *pVM1)
133{
134 PVM pVM = (PVM)pVM1;
135 PSSMHANDLE pSSM = pVM->patm.s.savedstate.pSSM;
136 RELOCREC rec = *(PRELOCREC)pNode;
137
138 Assert(rec.pRelocPos);
139 PATM_SUBTRACT_PTR(rec.pRelocPos, pVM->patm.s.pPatchMemHC);
140
141 /* Save the lookup record. */
142 int rc = SSMR3PutMem(pSSM, &rec, sizeof(rec));
143 AssertRCReturn(rc, rc);
144
145 return VINF_SUCCESS;
146}
147
148
149/**
150 * Callback function for RTAvloGCPtrDoWithAll
151 *
152 * Saves the state of the patch that's being enumerated
153 *
154 * @returns VBox status code.
155 * @param pNode Current node
156 * @param pVM1 VM Handle
157 */
158static DECLCALLBACK(int) patmSavePatchState(PAVLOGCPTRNODECORE pNode, void *pVM1)
159{
160 PVM pVM = (PVM)pVM1;
161 PPATMPATCHREC pPatch = (PPATMPATCHREC)pNode;
162 PATMPATCHREC patch = *pPatch;
163 PSSMHANDLE pSSM = pVM->patm.s.savedstate.pSSM;
164 int rc;
165
166 Assert(!(pPatch->patch.flags & PATMFL_GLOBAL_FUNCTIONS));
167
168 /*
169 * Reset HC pointers that need to be recalculated when loading the state
170 */
171 AssertMsg(patch.patch.uState == PATCH_REFUSED || (patch.patch.pPatchBlockOffset || (patch.patch.flags & (PATMFL_SYSENTER_XP|PATMFL_INT3_REPLACEMENT))),
172 ("State = %x pPrivInstrHC=%08x pPatchBlockHC=%08x flags=%x\n", patch.patch.uState, patch.patch.pPrivInstrHC, PATCHCODE_PTR_HC(&patch.patch), patch.patch.flags));
173 Assert(pPatch->patch.JumpTree == 0);
174 Assert(!pPatch->patch.pTempInfo || pPatch->patch.pTempInfo->DisasmJumpTree == 0);
175 Assert(!pPatch->patch.pTempInfo || pPatch->patch.pTempInfo->IllegalInstrTree == 0);
176
177 memset(&patch.patch.cacheRec, 0, sizeof(patch.patch.cacheRec));
178
179 /* Save the patch record itself */
180 rc = SSMR3PutMem(pSSM, &patch, sizeof(patch));
181 AssertRCReturn(rc, rc);
182
183 /*
184 * Reset HC pointers in fixup records and save them.
185 */
186#ifdef VBOX_STRICT
187 uint32_t nrFixupRecs = 0;
188 RTAvlPVDoWithAll(&pPatch->patch.FixupTree, true, patmCountLeafPV, &nrFixupRecs);
189 AssertMsg((int32_t)nrFixupRecs == pPatch->patch.nrFixups, ("Fixup inconsistency! counted %d vs %d\n", nrFixupRecs, pPatch->patch.nrFixups));
190#endif
191 RTAvlPVDoWithAll(&pPatch->patch.FixupTree, true, patmSaveFixupRecords, pVM);
192
193#ifdef VBOX_STRICT
194 uint32_t nrLookupRecords = 0;
195 RTAvlU32DoWithAll(&pPatch->patch.Patch2GuestAddrTree, true, patmCountLeaf, &nrLookupRecords);
196 Assert(nrLookupRecords == pPatch->patch.nrPatch2GuestRecs);
197#endif
198
199 RTAvlU32DoWithAll(&pPatch->patch.Patch2GuestAddrTree, true, patmSaveP2GLookupRecords, pVM);
200 return VINF_SUCCESS;
201}
202
203/**
204 * Execute state save operation.
205 *
206 * @returns VBox status code.
207 * @param pVM VM Handle.
208 * @param pSSM SSM operation handle.
209 */
210DECLCALLBACK(int) patmr3Save(PVM pVM, PSSMHANDLE pSSM)
211{
212 PATM patmInfo = pVM->patm.s;
213 int rc;
214
215 pVM->patm.s.savedstate.pSSM = pSSM;
216
217 /*
218 * Reset HC pointers that need to be recalculated when loading the state
219 */
220 patmInfo.pPatchMemHC = NULL;
221 patmInfo.pGCStateHC = 0;
222 patmInfo.pvFaultMonitor = 0;
223
224 Assert(patmInfo.ulCallDepth == 0);
225
226 /*
227 * Count the number of patches in the tree (feeling lazy)
228 */
229 patmInfo.savedstate.cPatches = 0;
230 RTAvloGCPtrDoWithAll(&pVM->patm.s.PatchLookupTreeHC->PatchTree, true, patmCountPatch, &patmInfo.savedstate.cPatches);
231
232 /*
233 * Save PATM structure
234 */
235 rc = SSMR3PutMem(pSSM, &patmInfo, sizeof(patmInfo));
236 AssertRCReturn(rc, rc);
237
238 /*
239 * Save patch memory contents
240 */
241 rc = SSMR3PutMem(pSSM, pVM->patm.s.pPatchMemHC, pVM->patm.s.cbPatchMem);
242 AssertRCReturn(rc, rc);
243
244 /*
245 * Save GC state memory
246 */
247 rc = SSMR3PutMem(pSSM, pVM->patm.s.pGCStateHC, sizeof(PATMGCSTATE));
248 AssertRCReturn(rc, rc);
249
250 /*
251 * Save PATM stack page
252 */
253 rc = SSMR3PutMem(pSSM, pVM->patm.s.pGCStackHC, PATM_STACK_TOTAL_SIZE);
254 AssertRCReturn(rc, rc);
255
256 /*
257 * Save all patches
258 */
259 rc = RTAvloGCPtrDoWithAll(&pVM->patm.s.PatchLookupTreeHC->PatchTree, true, patmSavePatchState, pVM);
260 AssertRCReturn(rc, rc);
261
262 /** @note patch statistics are not saved. */
263
264 return VINF_SUCCESS;
265}
266
267/**
268 * Execute state load operation.
269 *
270 * @returns VBox status code.
271 * @param pVM VM Handle.
272 * @param pSSM SSM operation handle.
273 * @param u32Version Data layout version.
274 */
275DECLCALLBACK(int) patmr3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
276{
277 PATM patmInfo;
278 int rc;
279
280 if (u32Version != PATM_SSM_VERSION)
281 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
282
283 pVM->patm.s.savedstate.pSSM = pSSM;
284
285 /*
286 * Restore PATM structure
287 */
288 rc = SSMR3GetMem(pSSM, &patmInfo, sizeof(patmInfo));
289 AssertRCReturn(rc, rc);
290
291 /** @todo this restriction could be removed as we relocate when loading the saved state,.. */
292 if ( pVM->patm.s.pGCStateGC != patmInfo.pGCStateGC
293 || pVM->patm.s.pCPUMCtxGC != patmInfo.pCPUMCtxGC
294 || pVM->patm.s.pStatsGC != patmInfo.pStatsGC)
295 {
296 if (SSMR3HandleGetAfter(pSSM) == SSMAFTER_DEBUG_IT) /* hack for x86 / amd64 mix. */
297 return VINF_SUCCESS;
298 AssertMsgFailed(("GC state, stat or cpum ptrs don't match!!!\n"));
299 return VERR_SSM_INVALID_STATE;
300 }
301
302 /* Relative calls are made to the helper functions. Therefor their location must not change! */
303 if ( pVM->patm.s.pfnHelperCallGC != patmInfo.pfnHelperCallGC
304 || pVM->patm.s.pfnHelperRetGC != patmInfo.pfnHelperRetGC
305 || pVM->patm.s.pfnHelperJumpGC != patmInfo.pfnHelperJumpGC
306 || pVM->patm.s.pfnHelperIretGC != patmInfo.pfnHelperIretGC)
307 {
308 AssertMsgFailed(("Helper function ptrs don't match!!!\n"));
309 return VERR_SSM_INVALID_STATE;
310 }
311
312 if ( pVM->patm.s.pPatchMemGC != patmInfo.pPatchMemGC
313 || pVM->patm.s.cbPatchMem != patmInfo.cbPatchMem)
314 {
315 AssertMsgFailed(("Patch memory ptrs and/or sizes don't match!!!\n"));
316 return VERR_SSM_INVALID_STATE;
317 }
318 pVM->patm.s.offPatchMem = patmInfo.offPatchMem;
319 pVM->patm.s.deltaReloc = patmInfo.deltaReloc;
320 pVM->patm.s.uCurrentPatchIdx = patmInfo.uCurrentPatchIdx;
321
322 /* Lowest and highest patched instruction */
323 pVM->patm.s.pPatchedInstrGCLowest = patmInfo.pPatchedInstrGCLowest;
324 pVM->patm.s.pPatchedInstrGCHighest = patmInfo.pPatchedInstrGCHighest;
325
326 /* Sysenter handlers */
327 pVM->patm.s.pfnSysEnterGC = patmInfo.pfnSysEnterGC;
328 pVM->patm.s.pfnSysEnterPatchGC = patmInfo.pfnSysEnterPatchGC;
329 pVM->patm.s.uSysEnterPatchIdx = patmInfo.uSysEnterPatchIdx;
330
331 Assert(patmInfo.ulCallDepth == 0 && pVM->patm.s.ulCallDepth == 0);
332
333 /** @note patch statistics are not restored. */
334
335 /*
336 * Restore patch memory contents
337 */
338 rc = SSMR3GetMem(pSSM, pVM->patm.s.pPatchMemHC, pVM->patm.s.cbPatchMem);
339 AssertRCReturn(rc, rc);
340
341 /*
342 * Restore GC state memory
343 */
344 if (pVM->patm.s.pGCStateGC != patmInfo.pGCStateGC)
345 {
346 AssertMsgFailed(("GC patch state ptrs don't match!!!\n"));
347 return VERR_SSM_INVALID_STATE;
348 }
349 rc = SSMR3GetMem(pSSM, pVM->patm.s.pGCStateHC, sizeof(PATMGCSTATE));
350 AssertRCReturn(rc, rc);
351
352 /*
353 * Restore PATM stack page
354 */
355 if (pVM->patm.s.pGCStackGC != patmInfo.pGCStackGC)
356 {
357 AssertMsgFailed(("GC patch stack ptrs don't match!!!\n"));
358 return VERR_SSM_INVALID_STATE;
359 }
360 rc = SSMR3GetMem(pSSM, pVM->patm.s.pGCStackHC, PATM_STACK_TOTAL_SIZE);
361 AssertRCReturn(rc, rc);
362
363 /*
364 * Load all patches
365 */
366 for (uint32_t i=0;i<patmInfo.savedstate.cPatches;i++)
367 {
368 PATMPATCHREC patch, *pPatchRec;
369
370 rc = SSMR3GetMem(pSSM, &patch, sizeof(patch));
371 AssertRCReturn(rc, rc);
372
373 Assert(!(patch.patch.flags & PATMFL_GLOBAL_FUNCTIONS));
374
375 rc = MMHyperAlloc(pVM, sizeof(PATMPATCHREC), 0, MM_TAG_PATM_PATCH, (void **)&pPatchRec);
376 if (VBOX_FAILURE(rc))
377 {
378 AssertMsgFailed(("Out of memory!!!!\n"));
379 return VERR_NO_MEMORY;
380 }
381 /*
382 * Only restore the patch part of the tree record; not the internal data (except the key of course)
383 */
384 pPatchRec->patch = patch.patch;
385 pPatchRec->Core.Key = patch.Core.Key;
386 pPatchRec->CoreOffset.Key = patch.CoreOffset.Key;
387
388 bool ret = RTAvloGCPtrInsert(&pVM->patm.s.PatchLookupTreeHC->PatchTree, &pPatchRec->Core);
389 Assert(ret);
390 if (pPatchRec->patch.uState != PATCH_REFUSED)
391 {
392 if (pPatchRec->patch.pPatchBlockOffset)
393 {
394 /* We actually generated code for this patch. */
395 ret = RTAvloGCPtrInsert(&pVM->patm.s.PatchLookupTreeHC->PatchTreeByPatchAddr, &pPatchRec->CoreOffset);
396 AssertMsg(ret, ("Inserting patch %VGv offset %VGv failed!!\n", pPatchRec->patch.pPrivInstrGC, pPatchRec->CoreOffset.Key));
397 }
398 }
399 /* Set to zero as we don't need it anymore. */
400 pPatchRec->patch.pTempInfo = 0;
401
402 pPatchRec->patch.pPrivInstrHC = 0;
403 /* The GC virtual ptr is fixed, but we must convert it manually again to HC. */
404 rc = PGMPhysGCPtr2HCPtr(pVM, pPatchRec->patch.pPrivInstrGC, (PRTHCPTR)&pPatchRec->patch.pPrivInstrHC);
405 /* Can fail due to page or page table not present. */
406
407 /*
408 * Restore fixup records and correct HC pointers in fixup records
409 */
410 pPatchRec->patch.FixupTree = 0;
411 pPatchRec->patch.nrFixups = 0; /* increased by patmPatchAddReloc32 */
412 for (int i=0;i<patch.patch.nrFixups;i++)
413 {
414 RELOCREC rec;
415
416 rc = SSMR3GetMem(pSSM, &rec, sizeof(rec));
417 AssertRCReturn(rc, rc);
418 PATM_ADD_PTR(rec.pRelocPos, pVM->patm.s.pPatchMemHC);
419
420 rc = patmPatchAddReloc32(pVM, &pPatchRec->patch, rec.pRelocPos, rec.uType, rec.pSource, rec.pDest);
421 AssertRCReturn(rc, rc);
422 }
423
424 /* And all patch to guest lookup records */
425 Assert(pPatchRec->patch.nrPatch2GuestRecs || pPatchRec->patch.uState == PATCH_REFUSED || (pPatchRec->patch.flags & (PATMFL_SYSENTER_XP | PATMFL_IDTHANDLER | PATMFL_TRAPHANDLER | PATMFL_INT3_REPLACEMENT)));
426
427 pPatchRec->patch.Patch2GuestAddrTree = 0;
428 pPatchRec->patch.Guest2PatchAddrTree = 0;
429 if (pPatchRec->patch.nrPatch2GuestRecs)
430 {
431 RECPATCHTOGUEST rec;
432 uint32_t nrPatch2GuestRecs = pPatchRec->patch.nrPatch2GuestRecs;
433
434 pPatchRec->patch.nrPatch2GuestRecs = 0; /* incremented by patmr3AddP2GLookupRecord */
435 for (uint32_t i=0;i<nrPatch2GuestRecs;i++)
436 {
437 rc = SSMR3GetMem(pSSM, &rec, sizeof(rec));
438 AssertRCReturn(rc, rc);
439
440 patmr3AddP2GLookupRecord(pVM, &pPatchRec->patch, (uintptr_t)rec.Core.Key + pVM->patm.s.pPatchMemHC, rec.pOrgInstrGC, rec.enmType, rec.fDirty);
441 }
442 Assert(pPatchRec->patch.Patch2GuestAddrTree);
443 }
444
445 if (pPatchRec->patch.flags & PATMFL_CODE_MONITORED)
446 {
447 /* Insert the guest page lookup records (for detection self-modifying code) */
448 rc = patmInsertPatchPages(pVM, &pPatchRec->patch);
449 AssertRCReturn(rc, rc);
450 }
451 }
452
453#ifdef VBOX_WITH_STATISTICS
454 /*
455 * Restore relevant old statistics
456 */
457 pVM->patm.s.StatDisabled = patmInfo.StatDisabled;
458 pVM->patm.s.StatUnusable = patmInfo.StatUnusable;
459 pVM->patm.s.StatEnabled = patmInfo.StatEnabled;
460 pVM->patm.s.StatInstalled = patmInfo.StatInstalled;
461#endif
462 return VINF_SUCCESS;
463}
464
465
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