PATMSSM.cpp revision c97989161fbe75bc14cea477a5443bbf474dd3ad
/* $Id$ */
/** @file
* PATMSSM - Dynamic Guest OS Patching Manager; Save and load state
*
* NOTE: CSAM assumes patch memory is never reused!!
*/
/*
* Copyright (C) 2006-2007 innotek GmbH
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License as published by the Free Software Foundation,
* in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
* distribution. VirtualBox OSE is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY of any kind.
*
* If you received this file as part of a commercial VirtualBox
* distribution, then only the terms of your commercial VirtualBox
* license agreement apply instead of the previous paragraph.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_PATM
#include "PATMInternal.h"
#include "PATMPatch.h"
#include "PATMA.h"
#include <VBox/disopcode.h>
#ifdef VBOX_STRICT
/**
* Callback function for RTAvlPVDoWithAll
*
* Counts the number of patches in the tree
*
* @returns VBox status code.
* @param pNode Current node
* @param pcPatches Pointer to patch counter (uint32_t)
*/
{
return VINF_SUCCESS;
}
/**
* Callback function for RTAvlU32DoWithAll
*
* Counts the number of patches in the tree
*
* @returns VBox status code.
* @param pNode Current node
* @param pcPatches Pointer to patch counter (uint32_t)
*/
{
return VINF_SUCCESS;
}
#endif /* VBOX_STRICT */
/**
* Callback function for RTAvloGCPtrDoWithAll
*
* Counts the number of patches in the tree
*
* @returns VBox status code.
* @param pNode Current node
* @param pcPatches Pointer to patch counter
*/
{
return VINF_SUCCESS;
}
/**
* Callback function for RTAvlU32DoWithAll
*
* Saves all patch to guest lookup records.
*
* @returns VBox status code.
* @param pNode Current node
* @param pVM1 VM Handle
*/
{
/* Save the lookup record. */
return VINF_SUCCESS;
}
/**
* Callback function for RTAvlPVDoWithAll
*
* Saves all patch to guest lookup records.
*
* @returns VBox status code.
* @param pNode Current node
* @param pVM1 VM Handle
*/
{
/* Save the lookup record. */
return VINF_SUCCESS;
}
/**
* Callback function for RTAvloGCPtrDoWithAll
*
* Saves the state of the patch that's being enumerated
*
* @returns VBox status code.
* @param pNode Current node
* @param pVM1 VM Handle
*/
{
int rc;
/*
* Reset HC pointers that need to be recalculated when loading the state
*/
AssertMsg(patch.patch.uState == PATCH_REFUSED || (patch.patch.pPatchBlockOffset || (patch.patch.flags & (PATMFL_SYSENTER_XP|PATMFL_INT3_REPLACEMENT))),
("State = %x pPrivInstrHC=%08x pPatchBlockHC=%08x flags=%x\n", patch.patch.uState, patch.patch.pPrivInstrHC, PATCHCODE_PTR_HC(&patch.patch), patch.patch.flags));
/* Save the patch record itself */
/*
* Reset HC pointers in fixup records and save them.
*/
#ifdef VBOX_STRICT
uint32_t nrFixupRecs = 0;
AssertMsg((int32_t)nrFixupRecs == pPatch->patch.nrFixups, ("Fixup inconsistency! counted %d vs %d\n", nrFixupRecs, pPatch->patch.nrFixups));
#endif
#ifdef VBOX_STRICT
uint32_t nrLookupRecords = 0;
#endif
return VINF_SUCCESS;
}
/**
* Execute state save operation.
*
* @returns VBox status code.
* @param pVM VM Handle.
* @param pSSM SSM operation handle.
*/
{
int rc;
/*
* Reset HC pointers that need to be recalculated when loading the state
*/
patmInfo.pGCStateHC = 0;
patmInfo.pvFaultMonitor = 0;
/*
* Count the number of patches in the tree (feeling lazy)
*/
RTAvloGCPtrDoWithAll(&pVM->patm.s.PatchLookupTreeHC->PatchTree, true, patmCountPatch, &patmInfo.savedstate.cPatches);
/*
* Save PATM structure
*/
/*
* Save patch memory contents
*/
/*
* Save GC state memory
*/
/*
* Save PATM stack page
*/
/*
* Save all patches
*/
rc = RTAvloGCPtrDoWithAll(&pVM->patm.s.PatchLookupTreeHC->PatchTree, true, patmSavePatchState, pVM);
/** @note patch statistics are not saved. */
return VINF_SUCCESS;
}
/**
* Execute state load operation.
*
* @returns VBox status code.
* @param pVM VM Handle.
* @param pSSM SSM operation handle.
* @param u32Version Data layout version.
*/
{
int rc;
if (u32Version != PATM_SSM_VERSION)
/*
* Restore PATM structure
*/
/** @todo this restriction could be removed as we relocate when loading the saved state,.. */
{
AssertMsgFailed(("GC state, stat or cpum ptrs don't match!!!\n"));
return VERR_SSM_INVALID_STATE;
}
/* Relative calls are made to the helper functions. Therefor their location must not change! */
{
AssertMsgFailed(("Helper function ptrs don't match!!!\n"));
return VERR_SSM_INVALID_STATE;
}
{
AssertMsgFailed(("Patch memory ptrs and/or sizes don't match!!!\n"));
return VERR_SSM_INVALID_STATE;
}
/* Lowest and highest patched instruction */
/* Sysenter handlers */
/** @note patch statistics are not restored. */
/*
* Restore patch memory contents
*/
/*
* Restore GC state memory
*/
{
AssertMsgFailed(("GC patch state ptrs don't match!!!\n"));
return VERR_SSM_INVALID_STATE;
}
/*
* Restore PATM stack page
*/
{
AssertMsgFailed(("GC patch stack ptrs don't match!!!\n"));
return VERR_SSM_INVALID_STATE;
}
/*
* Load all patches
*/
{
if (VBOX_FAILURE(rc))
{
AssertMsgFailed(("Out of memory!!!!\n"));
return VERR_NO_MEMORY;
}
/*
* Only restore the patch part of the tree record; not the internal data (except the key of course)
*/
{
{
/* We actually generated code for this patch. */
ret = RTAvloGCPtrInsert(&pVM->patm.s.PatchLookupTreeHC->PatchTreeByPatchAddr, &pPatchRec->CoreOffset);
AssertMsg(ret, ("Inserting patch %VGv offset %VGv failed!!\n", pPatchRec->patch.pPrivInstrGC, pPatchRec->CoreOffset.Key));
}
}
/* Set to zero as we don't need it anymore. */
/* The GC virtual ptr is fixed, but we must convert it manually again to HC. */
rc = PGMPhysGCPtr2HCPtr(pVM, pPatchRec->patch.pPrivInstrGC, (PRTHCPTR)&pPatchRec->patch.pPrivInstrHC);
/* Can fail due to page or page table not present. */
/*
* Restore fixup records and correct HC pointers in fixup records
*/
{
}
/* And all patch to guest lookup records */
Assert(pPatchRec->patch.nrPatch2GuestRecs || pPatchRec->patch.uState == PATCH_REFUSED || (pPatchRec->patch.flags & (PATMFL_SYSENTER_XP | PATMFL_IDTHANDLER | PATMFL_TRAPHANDLER | PATMFL_INT3_REPLACEMENT)));
{
for (uint32_t i=0;i<nrPatch2GuestRecs;i++)
{
patmr3AddP2GLookupRecord(pVM, &pPatchRec->patch, (uintptr_t)rec.Core.Key + pVM->patm.s.pPatchMemHC, rec.pOrgInstrGC, rec.enmType, rec.fDirty);
}
}
{
/* Insert the guest page lookup records (for detection self-modifying code) */
}
}
#ifdef VBOX_WITH_STATISTICS
/*
* Restore relevant old statistics
*/
#endif
return VINF_SUCCESS;
}