VirtualBox

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

Last change on this file since 28 was 23, checked in by vboxsync, 18 years ago

string.h & stdio.h + header cleanups.

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