VirtualBox

Changeset 36669 in vbox


Ignore:
Timestamp:
Apr 14, 2011 12:21:43 PM (14 years ago)
Author:
vboxsync
Message:

PATM: Record trampoline patches in the target to update the displacement on a patch refresh. (see xTracker #5593 for further information)

Location:
trunk/src/VBox/VMM
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR3/PATM.cpp

    r35696 r36669  
    5555//#define PATM_DISABLE_ALL
    5656
     57/**
     58 * Refresh trampoline patch state.
     59 */
     60typedef struct PATMREFRESHPATCH
     61{
     62    /** Pointer to the VM structure. */
     63    PVM        pVM;
     64    /** The trampoline patch record. */
     65    PPATCHINFO pPatchTrampoline;
     66    /** The new patch we want to jump to. */
     67    PPATCHINFO pPatchRec;
     68} PATMREFRESHPATCH, *PPATMREFRESHPATCH;
     69
     70
    5771/*******************************************************************************
    5872*   Internal Functions                                                         *
     
    11521166    uint32_t PatchOffset = pPatchInstrHC - pVM->patm.s.pPatchMemHC;  /* Offset in memory reserved for PATM. */
    11531167
     1168    LogFlowFunc(("pVM=%#p pPatch=%#p pPatchInstrHC=%#p pInstrGC=%#x enmType=%d fDirty=%RTbool\n",
     1169                 pVM, pPatch, pPatchInstrHC, pInstrGC, enmType, fDirty));
     1170
    11541171    if (enmType == PATM_LOOKUP_PATCH2GUEST)
    11551172    {
     
    32583275    uint32_t    orgOffsetPatchMem = ~0;
    32593276    int         rc = VERR_PATCHING_REFUSED;
     3277    PPATCHINFO  pPatchToJmp = NULL; /**< Patch the trampoline jumps to. */
     3278    PTRAMPREC   pTrampRec = NULL; /**< Trampoline record used to find the patch. */
     3279    bool        fInserted = false;
    32603280
    32613281    Log(("patmCreateTrampoline %RRv\n", pInstrGC));
     
    32763296            if (pPatchPage->aPatch[i])
    32773297            {
    3278                 PPATCHINFO pPatch2 = pPatchPage->aPatch[i];
    3279 
    3280                 if (    (pPatch2->flags & PATMFL_DUPLICATE_FUNCTION)
    3281                     &&  pPatch2->uState == PATCH_ENABLED)
     3298                pPatchToJmp = pPatchPage->aPatch[i];
     3299
     3300                if (    (pPatchToJmp->flags & PATMFL_DUPLICATE_FUNCTION)
     3301                    &&  pPatchToJmp->uState == PATCH_ENABLED)
    32823302                {
    3283                     pPatchTargetGC = patmGuestGCPtrToPatchGCPtr(pVM, pPatch2, pInstrGC);
     3303                    pPatchTargetGC = patmGuestGCPtrToPatchGCPtr(pVM, pPatchToJmp, pInstrGC);
    32843304                    if (pPatchTargetGC)
    32853305                    {
    32863306                        uint32_t         offsetPatch      = pPatchTargetGC - pVM->patm.s.pPatchMemGC;
    3287                         PRECPATCHTOGUEST pPatchToGuestRec = (PRECPATCHTOGUEST)RTAvlU32GetBestFit(&pPatch2->Patch2GuestAddrTree, offsetPatch, false);
     3307                        PRECPATCHTOGUEST pPatchToGuestRec = (PRECPATCHTOGUEST)RTAvlU32GetBestFit(&pPatchToJmp->Patch2GuestAddrTree, offsetPatch, false);
    32883308                        Assert(pPatchToGuestRec);
    32893309
    32903310                        pPatchToGuestRec->fJumpTarget = true;
    3291                         Assert(pPatchTargetGC != pPatch2->pPrivInstrGC);
    3292                         Log(("patmCreateTrampoline: generating jump to code inside patch at %RRv\n", pPatch2->pPrivInstrGC));
    3293                         pPatch2->flags |= PATMFL_EXTERNAL_JUMP_INSIDE;
     3311                        Assert(pPatchTargetGC != pPatchToJmp->pPrivInstrGC);
     3312                        Log(("patmCreateTrampoline: generating jump to code inside patch at %RRv (patch target %RRv)\n", pPatchToJmp->pPrivInstrGC, pPatchTargetGC));
    32943313                        break;
    32953314                    }
     
    32983317        }
    32993318    }
    3300     AssertReturn(pPatchPage && pPatchTargetGC, VERR_PATCHING_REFUSED);
     3319    AssertReturn(pPatchPage && pPatchTargetGC && pPatchToJmp, VERR_PATCHING_REFUSED);
     3320
     3321    /*
     3322     * Only record the trampoline patch if this is the first patch to the target
     3323     * or we recorded other patches already.
     3324     * The goal is to refuse refreshing function duplicates if the guest
     3325     * modifies code after a saved state was loaded because it is not possible
     3326     * to save the relation between trampoline and target without changing the
     3327     * saved satte version.
     3328     */
     3329    if (   !(pPatchToJmp->flags & PATMFL_EXTERNAL_JUMP_INSIDE)
     3330        || pPatchToJmp->pTrampolinePatchesHead)
     3331    {
     3332        pPatchToJmp->flags |= PATMFL_EXTERNAL_JUMP_INSIDE;
     3333        pTrampRec = (PTRAMPREC)MMR3HeapAllocZ(pVM, MM_TAG_PATM_PATCH, sizeof(*pTrampRec));
     3334        if (!pTrampRec)
     3335            return VERR_NO_MEMORY; /* or better return VERR_PATCHING_REFUSED to let the VM continue? */
     3336
     3337        pTrampRec->pPatchTrampoline = pPatchRec;
     3338    }
    33013339
    33023340    pPatch->nrPatch2GuestRecs = 0;
     
    33243362    LogFlow(("Insert %RRv patch offset %RRv\n", pPatchRec->patch.pPrivInstrGC, pPatch->pPatchBlockOffset));
    33253363    pPatchRec->CoreOffset.Key = pPatch->pPatchBlockOffset;
    3326     rc = RTAvloU32Insert(&pVM->patm.s.PatchLookupTreeHC->PatchTreeByPatchAddr, &pPatchRec->CoreOffset);
    3327     AssertMsg(rc, ("RTAvloU32Insert failed for %x\n", pPatchRec->CoreOffset.Key));
    3328     if (!rc)
     3364    fInserted = RTAvloU32Insert(&pVM->patm.s.PatchLookupTreeHC->PatchTreeByPatchAddr, &pPatchRec->CoreOffset);
     3365    AssertMsg(fInserted, ("RTAvloU32Insert failed for %x\n", pPatchRec->CoreOffset.Key));
     3366    if (!fInserted)
    33293367    {
    33303368        rc = VERR_PATCHING_REFUSED;
     
    33473385    /* We allow this patch to be called as a function. */
    33483386    pPatch->flags |= PATMFL_CALLABLE_AS_FUNCTION;
     3387
     3388    if (pTrampRec)
     3389    {
     3390        pTrampRec->pNext = pPatchToJmp->pTrampolinePatchesHead;
     3391        pPatchToJmp->pTrampolinePatchesHead = pTrampRec;
     3392    }
    33493393    STAM_COUNTER_INC(&pVM->patm.s.StatInstalledTrampoline);
    33503394    return VINF_SUCCESS;
     
    33703414    Assert(orgOffsetPatchMem != (uint32_t)~0);
    33713415    pVM->patm.s.offPatchMem = orgOffsetPatchMem;
     3416
     3417    if (pTrampRec)
     3418        MMR3HeapFree(pTrampRec);
    33723419
    33733420    return rc;
     
    41624209    pPatchRec->patch.flags   = flags;
    41634210    pPatchRec->patch.uOpMode = (flags & PATMFL_CODE32) ? CPUMODE_32BIT : CPUMODE_16BIT;
     4211    pPatchRec->patch.pTrampolinePatchesHead = NULL;
    41644212
    41654213    pPatchRec->patch.pInstrGCLowest  = pInstrGC;
     
    54255473
    54265474/**
     5475 * RTAvlU32DoWithAll() worker.
     5476 * Checks whether the current trampoline instruction is the jump to the target patch
     5477 * and updates the displacement to jump to the new target.
     5478 *
     5479 * @returns VBox status code.
     5480 * @retval  VERR_ALREADY_EXISTS if the jump was found.
     5481 * @param   pNode    The current patch to guest record to check.
     5482 * @param   pvUser   The refresh state.
     5483 */
     5484static int patmR3PatchRefreshFindTrampolinePatch(PAVLU32NODECORE pNode, void *pvUser)
     5485{
     5486    PRECPATCHTOGUEST  pPatch2GuestRec = (PRECPATCHTOGUEST)pNode;
     5487    PPATMREFRESHPATCH pRefreshPatchState = (PPATMREFRESHPATCH)pvUser;
     5488    PVM               pVM = pRefreshPatchState->pVM;
     5489
     5490    uint8_t *pPatchInstr = (uint8_t *)(pVM->patm.s.pPatchMemHC + pPatch2GuestRec->Core.Key);
     5491
     5492    /*
     5493     * Check if the patch instruction starts with a jump.
     5494     * ASSUMES that there is no other patch to guest record that starts
     5495     * with a jump.
     5496     */
     5497    if (*pPatchInstr == 0xE9)
     5498    {
     5499        /* Jump found, update the displacement. */
     5500        RTRCPTR pPatchTargetGC = patmGuestGCPtrToPatchGCPtr(pVM, pRefreshPatchState->pPatchRec,
     5501                                                            pRefreshPatchState->pPatchTrampoline->pPrivInstrGC);
     5502        int32_t displ =  pPatchTargetGC - (pVM->patm.s.pPatchMemGC + pPatch2GuestRec->Core.Key + SIZEOF_NEARJUMP32);
     5503
     5504        LogFlow(("Updating trampoline patch new patch target %RRv, new displacment %d (old was %d)\n",
     5505                 pPatchTargetGC, displ, *(uint32_t *)&pPatchInstr[1]));
     5506
     5507        *(uint32_t *)&pPatchInstr[1] = displ;
     5508        return VERR_ALREADY_EXISTS; /** @todo better return code */
     5509    }
     5510
     5511    return VINF_SUCCESS;
     5512}
     5513
     5514/**
    54275515 * Attempt to refresh the patch by recompiling its entire code block
    54285516 *
     
    54365524    int         rc;
    54375525    RTRCPTR     pInstrGC = pPatchRec->patch.pPrivInstrGC;
     5526    PTRAMPREC   pTrampolinePatchesHead = NULL;
    54385527
    54395528    Log(("patmR3RefreshPatch: attempt to refresh patch at %RRv\n", pInstrGC));
     
    54435532    if (pPatch->flags & PATMFL_EXTERNAL_JUMP_INSIDE)
    54445533    {
    5445         Log(("patmR3RefreshPatch: refused because external jumps to this patch exist\n"));
    5446         return VERR_PATCHING_REFUSED;
     5534        if (!pPatch->pTrampolinePatchesHead)
     5535        {
     5536            /*
     5537             * It is sometimes possible that there are trampoline patches to this patch
     5538             * but they are not recorded (after a saved state load for example).
     5539             * Refuse to refresh those patches.
     5540             * Can hurt performance in theory if the patched code is modified by the guest
     5541             * and is executed often. However most of the time states are saved after the guest
     5542             * code was modified and is not updated anymore afterwards so this shouldn't be a
     5543             * big problem.
     5544             */
     5545            Log(("patmR3RefreshPatch: refused because external jumps to this patch exist but the jumps are not recorded\n"));
     5546            return VERR_PATCHING_REFUSED;
     5547        }
     5548        Log(("patmR3RefreshPatch: external jumps to this patch exist, updating\n"));
     5549        pTrampolinePatchesHead = pPatch->pTrampolinePatchesHead;
    54475550    }
    54485551
     
    55185621        /* Used by another patch, so don't remove it! */
    55195622        pNewPatchRec->patch.flags |= PATMFL_CODE_REFERENCED;
     5623
     5624        if (pTrampolinePatchesHead)
     5625        {
     5626            /* Update all trampoline patches to jump to the new patch. */
     5627            PTRAMPREC pTrampRec = NULL;
     5628            PATMREFRESHPATCH RefreshPatch;
     5629
     5630            RefreshPatch.pVM = pVM;
     5631            RefreshPatch.pPatchRec = &pNewPatchRec->patch;
     5632
     5633            pTrampRec = pTrampolinePatchesHead;
     5634
     5635            while (pTrampRec)
     5636            {
     5637                PPATCHINFO pPatchTrampoline = &pTrampRec->pPatchTrampoline->patch;
     5638
     5639                RefreshPatch.pPatchTrampoline = pPatchTrampoline;
     5640                /*
     5641                 * We have to find the right patch2guest record because there might be others
     5642                 * for statistics.
     5643                 */
     5644                rc = RTAvlU32DoWithAll(&pPatchTrampoline->Patch2GuestAddrTree, true,
     5645                                       patmR3PatchRefreshFindTrampolinePatch, &RefreshPatch);
     5646                Assert(rc == VERR_ALREADY_EXISTS);
     5647                rc = VINF_SUCCESS;
     5648                pTrampRec = pTrampRec->pNext;
     5649            }
     5650            pNewPatchRec->patch.pTrampolinePatchesHead = pTrampolinePatchesHead;
     5651            pNewPatchRec->patch.flags                 |= PATMFL_EXTERNAL_JUMP_INSIDE;
     5652            /* Clear the list of trampoline patches for the old patch (safety precaution). */
     5653            pPatchRec->patch.pTrampolinePatchesHead = NULL;
     5654        }
    55205655    }
    55215656
  • trunk/src/VBox/VMM/VMMR3/PATMSSM.cpp

    r35348 r36669  
    4242#include <VBox/dis.h>
    4343#include <VBox/disopcode.h>
     44
     45/**
     46 * Patch information - SSM version.
     47 *
     48 * the difference is the missing pTrampolinePatchesHead member
     49 * to avoid changing the saved state version for now (will come later).
     50 */
     51typedef struct _PATCHINFOSSM
     52{
     53    uint32_t              uState;
     54    uint32_t              uOldState;
     55    DISCPUMODE            uOpMode;
     56
     57    /* GC pointer of privileged instruction */
     58    RCPTRTYPE(uint8_t *)  pPrivInstrGC;
     59    R3PTRTYPE(uint8_t *)  unusedHC;                             /* todo Can't remove due to structure size dependencies in saved states. */
     60    uint8_t               aPrivInstr[MAX_INSTR_SIZE];
     61    uint32_t              cbPrivInstr;
     62    uint32_t              opcode;      //opcode for priv instr (OP_*)
     63    uint32_t              cbPatchJump; //patch jump size
     64
     65    /* Only valid for PATMFL_JUMP_CONFLICT patches */
     66    RTRCPTR               pPatchJumpDestGC;
     67
     68    RTGCUINTPTR32         pPatchBlockOffset;
     69    uint32_t              cbPatchBlockSize;
     70    uint32_t              uCurPatchOffset;
     71#if HC_ARCH_BITS == 64
     72    uint32_t              Alignment0;         /**< Align flags correctly. */
     73#endif
     74
     75    uint64_t              flags;
     76
     77    /**
     78     * Lowest and highest patched GC instruction address. To optimize searches.
     79     */
     80    RTRCPTR               pInstrGCLowest;
     81    RTRCPTR               pInstrGCHighest;
     82
     83    /* Tree of fixup records for the patch. */
     84    R3PTRTYPE(PAVLPVNODECORE) FixupTree;
     85    uint32_t                  nrFixups;
     86
     87    /* Tree of jumps inside the generated patch code. */
     88    uint32_t                  nrJumpRecs;
     89    R3PTRTYPE(PAVLPVNODECORE) JumpTree;
     90
     91    /**
     92     * Lookup trees for determining the corresponding guest address of an
     93     * instruction in the patch block.
     94     */
     95    R3PTRTYPE(PAVLU32NODECORE) Patch2GuestAddrTree;
     96    R3PTRTYPE(PAVLU32NODECORE) Guest2PatchAddrTree;
     97    uint32_t                  nrPatch2GuestRecs;
     98#if HC_ARCH_BITS == 64
     99    uint32_t        Alignment1;
     100#endif
     101
     102    /* Unused, but can't remove due to structure size dependencies in the saved state. */
     103    PATMP2GLOOKUPREC_OBSOLETE    unused;
     104
     105    /* Temporary information during patch creation. Don't waste hypervisor memory for this. */
     106    R3PTRTYPE(PPATCHINFOTEMP) pTempInfo;
     107
     108    /* Count the number of writes to the corresponding guest code. */
     109    uint32_t        cCodeWrites;
     110
     111    /* Count the number of invalid writes to pages monitored for the patch. */
     112    //some statistics to determine if we should keep this patch activated
     113    uint32_t        cTraps;
     114
     115    uint32_t        cInvalidWrites;
     116
     117    // Index into the uPatchRun and uPatchTrap arrays (0..MAX_PATCHES-1)
     118    uint32_t        uPatchIdx;
     119
     120    /* First opcode byte, that's overwritten when a patch is marked dirty. */
     121    uint8_t         bDirtyOpcode;
     122    uint8_t         Alignment2[7];      /**< Align the structure size on a 8-byte boundary. */
     123} PATCHINFOSSM, *PPATCHINFOSSM;
     124
     125/**
     126 * Lookup record for patches - SSM version.
     127 */
     128typedef struct PATMPATCHRECSSM
     129{
     130    /** The key is a GC virtual address. */
     131    AVLOU32NODECORE  Core;
     132    /** The key is a patch offset. */
     133    AVLOU32NODECORE  CoreOffset;
     134
     135    PATCHINFOSSM     patch;
     136} PATMPATCHRECSSM, *PPATMPATCHRECSSM;
    44137
    45138/*******************************************************************************
     
    184277static SSMFIELD const g_aPatmPatchRecFields[] =
    185278{
    186     SSMFIELD_ENTRY(                 PATMPATCHREC, Core.Key),
    187     SSMFIELD_ENTRY_IGNORE(          PATMPATCHREC, Core.pLeft),
    188     SSMFIELD_ENTRY_IGNORE(          PATMPATCHREC, Core.pRight),
    189     SSMFIELD_ENTRY_IGNORE(          PATMPATCHREC, Core.uchHeight),
     279    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, Core.Key),
     280    SSMFIELD_ENTRY_IGNORE(          PATMPATCHRECSSM, Core.pLeft),
     281    SSMFIELD_ENTRY_IGNORE(          PATMPATCHRECSSM, Core.pRight),
     282    SSMFIELD_ENTRY_IGNORE(          PATMPATCHRECSSM, Core.uchHeight),
    190283    SSMFIELD_ENTRY_PAD_HC_AUTO(     3, 3),
    191     SSMFIELD_ENTRY(                 PATMPATCHREC, CoreOffset.Key),
    192     SSMFIELD_ENTRY_IGNORE(          PATMPATCHREC, CoreOffset.pLeft),
    193     SSMFIELD_ENTRY_IGNORE(          PATMPATCHREC, CoreOffset.pRight),
    194     SSMFIELD_ENTRY_IGNORE(          PATMPATCHREC, CoreOffset.uchHeight),
     284    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, CoreOffset.Key),
     285    SSMFIELD_ENTRY_IGNORE(          PATMPATCHRECSSM, CoreOffset.pLeft),
     286    SSMFIELD_ENTRY_IGNORE(          PATMPATCHRECSSM, CoreOffset.pRight),
     287    SSMFIELD_ENTRY_IGNORE(          PATMPATCHRECSSM, CoreOffset.uchHeight),
    195288    SSMFIELD_ENTRY_PAD_HC_AUTO(     3, 3),
    196     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.uState),
    197     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.uOldState),
    198     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.uOpMode),
    199     SSMFIELD_ENTRY_RCPTR(           PATMPATCHREC, patch.pPrivInstrGC),
    200     SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHREC, patch.unusedHC),
    201     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.aPrivInstr),
    202     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.cbPrivInstr),
    203     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.opcode),
    204     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.cbPatchJump),
    205     SSMFIELD_ENTRY_RCPTR(           PATMPATCHREC, patch.pPatchJumpDestGC),
    206     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.pPatchBlockOffset),
    207     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.cbPatchBlockSize),
    208     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.uCurPatchOffset),
    209     SSMFIELD_ENTRY_PAD_HC64(        PATMPATCHREC, patch.Alignment0, sizeof(uint32_t)),
    210     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.flags),
    211     SSMFIELD_ENTRY_RCPTR(           PATMPATCHREC, patch.pInstrGCLowest),
    212     SSMFIELD_ENTRY_RCPTR(           PATMPATCHREC, patch.pInstrGCHighest),
    213     SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHREC, patch.FixupTree),
    214     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.nrFixups),
    215     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.nrJumpRecs), // should be zero?
    216     SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHREC, patch.JumpTree),
    217     SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHREC, patch.Patch2GuestAddrTree),
    218     SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHREC, patch.Guest2PatchAddrTree),
    219     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.nrPatch2GuestRecs),
    220     SSMFIELD_ENTRY_PAD_HC64(        PATMPATCHREC, patch.Alignment1, sizeof(uint32_t)),
    221     SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHREC, patch.unused.pPatchLocStartHC), // saved as zero
    222     SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHREC, patch.unused.pPatchLocEndHC),   // ditto
    223     SSMFIELD_ENTRY_IGN_RCPTR(       PATMPATCHREC, patch.unused.pGuestLoc),        // ditto
    224     SSMFIELD_ENTRY_IGNORE(          PATMPATCHREC, patch.unused.opsize),           // ditto
    225     SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHREC, patch.pTempInfo),
    226     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.cCodeWrites),
    227     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.cTraps),
    228     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.cInvalidWrites),
    229     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.uPatchIdx),
    230     SSMFIELD_ENTRY(                 PATMPATCHREC, patch.bDirtyOpcode),
    231     SSMFIELD_ENTRY_IGNORE(          PATMPATCHREC, patch.Alignment2),
     289    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.uState),
     290    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.uOldState),
     291    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.uOpMode),
     292    SSMFIELD_ENTRY_RCPTR(           PATMPATCHRECSSM, patch.pPrivInstrGC),
     293    SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHRECSSM, patch.unusedHC),
     294    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.aPrivInstr),
     295    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.cbPrivInstr),
     296    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.opcode),
     297    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.cbPatchJump),
     298    SSMFIELD_ENTRY_RCPTR(           PATMPATCHRECSSM, patch.pPatchJumpDestGC),
     299    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.pPatchBlockOffset),
     300    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.cbPatchBlockSize),
     301    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.uCurPatchOffset),
     302    SSMFIELD_ENTRY_PAD_HC64(        PATMPATCHRECSSM, patch.Alignment0, sizeof(uint32_t)),
     303    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.flags),
     304    SSMFIELD_ENTRY_RCPTR(           PATMPATCHRECSSM, patch.pInstrGCLowest),
     305    SSMFIELD_ENTRY_RCPTR(           PATMPATCHRECSSM, patch.pInstrGCHighest),
     306    SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHRECSSM, patch.FixupTree),
     307    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.nrFixups),
     308    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.nrJumpRecs), // should be zero?
     309    SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHRECSSM, patch.JumpTree),
     310    SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHRECSSM, patch.Patch2GuestAddrTree),
     311    SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHRECSSM, patch.Guest2PatchAddrTree),
     312    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.nrPatch2GuestRecs),
     313    SSMFIELD_ENTRY_PAD_HC64(        PATMPATCHRECSSM, patch.Alignment1, sizeof(uint32_t)),
     314    SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHRECSSM, patch.unused.pPatchLocStartHC), // saved as zero
     315    SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHRECSSM, patch.unused.pPatchLocEndHC),   // ditto
     316    SSMFIELD_ENTRY_IGN_RCPTR(       PATMPATCHRECSSM, patch.unused.pGuestLoc),        // ditto
     317    SSMFIELD_ENTRY_IGNORE(          PATMPATCHRECSSM, patch.unused.opsize),           // ditto
     318    SSMFIELD_ENTRY_IGN_HCPTR(       PATMPATCHRECSSM, patch.pTempInfo),
     319    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.cCodeWrites),
     320    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.cTraps),
     321    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.cInvalidWrites),
     322    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.uPatchIdx),
     323    SSMFIELD_ENTRY(                 PATMPATCHRECSSM, patch.bDirtyOpcode),
     324    SSMFIELD_ENTRY_IGNORE(          PATMPATCHRECSSM, patch.Alignment2),
    232325    SSMFIELD_ENTRY_TERM()
    233326};
     
    387480}
    388481
     482/**
     483 * Converts a saved state patch record to the memory record.
     484 *
     485 * @returns nothing.
     486 * @param   pPatch       The memory record.
     487 * @param   pPatchSSM    The SSM version of the patch record.
     488 */
     489static void patmR3PatchConvertSSM2Mem(PPATMPATCHREC pPatch, PPATMPATCHRECSSM pPatchSSM)
     490{
     491    /*
     492     * Only restore the patch part of the tree record; not the internal data (except the key of course)
     493     */
     494    pPatch->Core.Key                  = pPatchSSM->Core.Key;
     495    pPatch->CoreOffset.Key            = pPatchSSM->CoreOffset.Key;
     496    pPatch->patch.uState              = pPatchSSM->patch.uState;
     497    pPatch->patch.uOldState           = pPatchSSM->patch.uOldState;
     498    pPatch->patch.uOpMode             = pPatchSSM->patch.uOpMode;
     499    pPatch->patch.pPrivInstrGC        = pPatchSSM->patch.pPrivInstrGC;
     500    pPatch->patch.unusedHC            = pPatchSSM->patch.unusedHC;
     501    memcpy(&pPatch->patch.aPrivInstr[0], &pPatchSSM->patch.aPrivInstr[0], MAX_INSTR_SIZE);
     502    pPatch->patch.cbPrivInstr         = pPatchSSM->patch.cbPrivInstr;
     503    pPatch->patch.opcode              = pPatchSSM->patch.opcode;
     504    pPatch->patch.cbPatchJump         = pPatchSSM->patch.cbPatchJump;
     505    pPatch->patch.pPatchJumpDestGC    = pPatchSSM->patch.pPatchJumpDestGC;
     506    pPatch->patch.pPatchBlockOffset   = pPatchSSM->patch.pPatchBlockOffset;
     507    pPatch->patch.cbPatchBlockSize    = pPatchSSM->patch.cbPatchBlockSize;
     508    pPatch->patch.uCurPatchOffset     = pPatchSSM->patch.uCurPatchOffset;
     509    pPatch->patch.flags               = pPatchSSM->patch.flags;
     510    pPatch->patch.pInstrGCLowest      = pPatchSSM->patch.pInstrGCLowest;
     511    pPatch->patch.pInstrGCHighest     = pPatchSSM->patch.pInstrGCHighest;
     512    pPatch->patch.FixupTree           = pPatchSSM->patch.FixupTree;
     513    pPatch->patch.nrFixups            = pPatchSSM->patch.nrFixups;
     514    pPatch->patch.nrJumpRecs          = pPatchSSM->patch.nrJumpRecs;
     515    pPatch->patch.JumpTree            = pPatchSSM->patch.JumpTree;
     516    pPatch->patch.Patch2GuestAddrTree = pPatchSSM->patch.Patch2GuestAddrTree;
     517    pPatch->patch.Guest2PatchAddrTree = pPatchSSM->patch.Guest2PatchAddrTree;
     518    pPatch->patch.nrPatch2GuestRecs   = pPatchSSM->patch.nrPatch2GuestRecs;
     519    pPatch->patch.unused              = pPatchSSM->patch.unused;
     520    pPatch->patch.pTempInfo           = pPatchSSM->patch.pTempInfo;
     521    pPatch->patch.cCodeWrites         = pPatchSSM->patch.cCodeWrites;
     522    pPatch->patch.cTraps              = pPatchSSM->patch.cTraps;
     523    pPatch->patch.cInvalidWrites      = pPatchSSM->patch.cInvalidWrites;
     524    pPatch->patch.uPatchIdx           = pPatchSSM->patch.uPatchIdx;
     525    pPatch->patch.bDirtyOpcode        = pPatchSSM->patch.bDirtyOpcode;
     526    pPatch->patch.pTrampolinePatchesHead = NULL;
     527}
     528
     529/**
     530 * Converts a memory patch record to the saved state version.
     531 *
     532 * @returns nothing.
     533 * @param   pPatchSSM    The saved state record.
     534 * @param   pPatch       The memory version to save.
     535 */
     536static void patmR3PatchConvertMem2SSM(PPATMPATCHRECSSM pPatchSSM, PPATMPATCHREC pPatch)
     537{
     538    pPatchSSM->Core                      = pPatch->Core;
     539    pPatchSSM->CoreOffset                = pPatch->CoreOffset;
     540    pPatchSSM->patch.uState              = pPatch->patch.uState;
     541    pPatchSSM->patch.uOldState           = pPatch->patch.uOldState;
     542    pPatchSSM->patch.uOpMode             = pPatch->patch.uOpMode;
     543    pPatchSSM->patch.pPrivInstrGC        = pPatch->patch.pPrivInstrGC;
     544    pPatchSSM->patch.unusedHC            = pPatch->patch.unusedHC;
     545    memcpy(&pPatchSSM->patch.aPrivInstr[0], &pPatch->patch.aPrivInstr[0], MAX_INSTR_SIZE);
     546    pPatchSSM->patch.cbPrivInstr         = pPatch->patch.cbPrivInstr;
     547    pPatchSSM->patch.opcode              = pPatch->patch.opcode;
     548    pPatchSSM->patch.cbPatchJump         = pPatch->patch.cbPatchJump;
     549    pPatchSSM->patch.pPatchJumpDestGC    = pPatch->patch.pPatchJumpDestGC;
     550    pPatchSSM->patch.pPatchBlockOffset   = pPatch->patch.pPatchBlockOffset;
     551    pPatchSSM->patch.cbPatchBlockSize    = pPatch->patch.cbPatchBlockSize;
     552    pPatchSSM->patch.uCurPatchOffset     = pPatch->patch.uCurPatchOffset;
     553    pPatchSSM->patch.flags               = pPatch->patch.flags;
     554    pPatchSSM->patch.pInstrGCLowest      = pPatch->patch.pInstrGCLowest;
     555    pPatchSSM->patch.pInstrGCHighest     = pPatch->patch.pInstrGCHighest;
     556    pPatchSSM->patch.FixupTree           = pPatch->patch.FixupTree;
     557    pPatchSSM->patch.nrFixups            = pPatch->patch.nrFixups;
     558    pPatchSSM->patch.nrJumpRecs          = pPatch->patch.nrJumpRecs;
     559    pPatchSSM->patch.JumpTree            = pPatch->patch.JumpTree;
     560    pPatchSSM->patch.Patch2GuestAddrTree = pPatch->patch.Patch2GuestAddrTree;
     561    pPatchSSM->patch.Guest2PatchAddrTree = pPatch->patch.Guest2PatchAddrTree;
     562    pPatchSSM->patch.nrPatch2GuestRecs   = pPatch->patch.nrPatch2GuestRecs;
     563    pPatchSSM->patch.unused              = pPatch->patch.unused;
     564    pPatchSSM->patch.pTempInfo           = pPatch->patch.pTempInfo;
     565    pPatchSSM->patch.cCodeWrites         = pPatch->patch.cCodeWrites;
     566    pPatchSSM->patch.cTraps              = pPatch->patch.cTraps;
     567    pPatchSSM->patch.cInvalidWrites      = pPatch->patch.cInvalidWrites;
     568    pPatchSSM->patch.uPatchIdx           = pPatch->patch.uPatchIdx;
     569    pPatchSSM->patch.bDirtyOpcode        = pPatch->patch.bDirtyOpcode;
     570}
    389571
    390572/**
     
    399581static DECLCALLBACK(int) patmSavePatchState(PAVLOU32NODECORE pNode, void *pVM1)
    400582{
    401     PVM           pVM    = (PVM)pVM1;
    402     PPATMPATCHREC pPatch = (PPATMPATCHREC)pNode;
    403     PATMPATCHREC  patch  = *pPatch;
    404     PSSMHANDLE    pSSM   = pVM->patm.s.savedstate.pSSM;
    405     int           rc;
     583    PVM             pVM    = (PVM)pVM1;
     584    PPATMPATCHREC   pPatch = (PPATMPATCHREC)pNode;
     585    PATMPATCHRECSSM patch;
     586    PSSMHANDLE      pSSM   = pVM->patm.s.savedstate.pSSM;
     587    int             rc;
    406588
    407589    Assert(!(pPatch->patch.flags & PATMFL_GLOBAL_FUNCTIONS));
     590
     591    patmR3PatchConvertMem2SSM(&patch, pPatch);
    408592
    409593    /*
     
    602786    for (unsigned i = 0; i < patmInfo.savedstate.cPatches; i++)
    603787    {
    604         PATMPATCHREC patch, *pPatchRec;
     788        PATMPATCHRECSSM patch;
     789        PATMPATCHREC *pPatchRec;
    605790
    606791        RT_ZERO(patch);
     
    616801            return VERR_NO_MEMORY;
    617802        }
    618         /*
    619          * Only restore the patch part of the tree record; not the internal data (except the key of course)
    620          */
    621         pPatchRec->patch             = patch.patch;
    622         pPatchRec->Core.Key          = patch.Core.Key;
    623         pPatchRec->CoreOffset.Key    = patch.CoreOffset.Key;
     803
     804        /* Convert SSM version to memory. */
     805        patmR3PatchConvertSSM2Mem(pPatchRec, &patch);
    624806
    625807        Log(("Restoring patch %RRv -> %RRv\n", pPatchRec->patch.pPrivInstrGC, patmInfo.pPatchMemGC + pPatchRec->patch.pPatchBlockOffset));
  • trunk/src/VBox/VMM/include/PATMInternal.h

    r35348 r36669  
    241241} PATCHINFOTEMP, *PPATCHINFOTEMP;
    242242
     243/** Forward declaration for a pointer to a trampoline patch record. */
     244typedef struct TRAMPREC *PTRAMPREC;
     245
    243246typedef struct _PATCHINFO
    244247{
     
    298301    R3PTRTYPE(PPATCHINFOTEMP) pTempInfo;
    299302
     303    /* List of trampoline patches referencing this patch.
     304     * Used when refreshing the patch. (Only for function duplicates) */
     305    R3PTRTYPE(PTRAMPREC)      pTrampolinePatchesHead;
     306
    300307    /* Count the number of writes to the corresponding guest code. */
    301308    uint32_t        cCodeWrites;
     
    312319    /* First opcode byte, that's overwritten when a patch is marked dirty. */
    313320    uint8_t         bDirtyOpcode;
    314     uint8_t         Alignment2[7];      /**< Align the structure size on a 8-byte boundary. */
     321    uint8_t         Alignment2[HC_ARCH_BITS == 64 ? 7 : 3];      /**< Align the structure size on a 8-byte boundary. */
    315322} PATCHINFO, *PPATCHINFO;
    316323
     
    330337    PATCHINFO  patch;
    331338} PATMPATCHREC, *PPATMPATCHREC;
     339
     340/**
     341 * Record for a trampoline patch.
     342 */
     343typedef struct TRAMPREC
     344{
     345    /** Pointer to the next trampoline patch. */
     346    struct TRAMPREC    *pNext;
     347    /** Pointer to the trampoline patch record. */
     348    PPATMPATCHREC       pPatchTrampoline;
     349} TRAMPREC;
    332350
    333351/** Increment for allocating room for pointer array */
  • trunk/src/VBox/VMM/testcase/tstVMStructRC.cpp

    r36629 r36669  
    11721172    GEN_CHECK_OFF(PATCHINFO, unused.opsize);
    11731173    GEN_CHECK_OFF(PATCHINFO, pTempInfo);
     1174    GEN_CHECK_OFF(PATCHINFO, pTrampolinePatchesHead);
    11741175    GEN_CHECK_OFF(PATCHINFO, cCodeWrites);
    11751176    GEN_CHECK_OFF(PATCHINFO, cTraps);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette