VirtualBox

Changeset 2030 in vbox for trunk


Ignore:
Timestamp:
Apr 11, 2007 1:33:28 PM (18 years ago)
Author:
vboxsync
Message:

Attempt to recreate patches who's dirty instruction(s) we can't correct.
Additional checks for dirty instructions that served as targets for trampoline patches.

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

Legend:

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

    r1926 r2030  
    233233    STAM_REG(pVM, &pVM->patm.s.StatPatchWriteInterpreted, STAMTYPE_COUNTER, "/PATM/Write/Interpreted/Success", STAMUNIT_OCCURENCES,  "Nr of interpreted patch writes.");
    234234    STAM_REG(pVM, &pVM->patm.s.StatPatchWriteInterpretedFailed, STAMTYPE_COUNTER, "/PATM/Write/Interpreted/Failed", STAMUNIT_OCCURENCES,  "Nr of failed interpreted patch writes.");
     235
     236    STAM_REG(pVM, &pVM->patm.s.StatPatchRefreshSuccess, STAMTYPE_COUNTER, "/PATM/Refresh/Success",    STAMUNIT_OCCURENCES, "Successful patch refreshes");
     237    STAM_REG(pVM, &pVM->patm.s.StatPatchRefreshFailed,  STAMTYPE_COUNTER, "/PATM/Refresh/Failure",    STAMUNIT_OCCURENCES, "Failed patch refreshes");
    235238
    236239    STAM_REG(pVM, &pVM->patm.s.StatPatchPageInserted, STAMTYPE_COUNTER, "/PATM/Page/Inserted",      STAMUNIT_OCCURENCES,     "Nr of inserted guest pages that were patched");
     
    11661169    pPatchToGuestRec->pOrgInstrGC = pInstrGC;
    11671170    pPatchToGuestRec->enmType     = enmType;
    1168     pPatchToGuestRec->fDirty      = fDirty;
     1171    pPatchToGuestRec->fDirty     = fDirty;
    11691172
    11701173    ret = RTAvlU32Insert(&pPatch->Patch2GuestAddrTree, &pPatchToGuestRec->Core);
     
    30753078 * @returns VBox status code.
    30763079 * @param   pVM         The VM to operate on.
    3077  * @param   pCpu        Disassembly CPU structure ptr
    30783080 * @param   pInstrGC    Guest context point to privileged instruction
    30793081 * @param   pPatchRec   Patch record
    30803082 *
    30813083 */
    3082 static int patmDuplicateFunction(PVM pVM, DISCPUSTATE *pCpu, RTGCPTR pInstrGC, PPATMPATCHREC pPatchRec)
     3084static int patmDuplicateFunction(PVM pVM, RTGCPTR pInstrGC, PPATMPATCHREC pPatchRec)
    30833085{
    30843086    PPATCHINFO pPatch = &pPatchRec->patch;
     
    32413243                    pPatchTargetGC = patmGuestGCPtrToPatchGCPtr(pVM, pPatch, pInstrGC);
    32423244                    if (pPatchTargetGC)
     3245                    {
     3246                        uint32_t         offsetPatch      = pPatchTargetGC - pVM->patm.s.pPatchMemGC;
     3247                        PRECPATCHTOGUEST pPatchToGuestRec = (PRECPATCHTOGUEST)RTAvlU32GetBestFit(&pPatch->Patch2GuestAddrTree, offsetPatch, false);
     3248                        Assert(pPatchToGuestRec);
     3249
     3250                        pPatchToGuestRec->fJumpTarget = true;
     3251                        Assert(pPatchTargetGC != pPatch->pPrivInstrGC);
     3252                        Log(("patmCreateTrampoline: generating jump to code inside patch at %VGv\n", pPatch->pPrivInstrGC));
     3253                        pPatch->flags |= PATMFL_EXTERNAL_JUMP_INSIDE;
    32433254                        break;
     3255                    }
    32443256                }
    32453257            }
     
    41564168    if (pPatchRec->patch.flags & (PATMFL_DUPLICATE_FUNCTION ))
    41574169    {
    4158         rc = patmDuplicateFunction(pVM, &cpu, pInstrGC, pPatchRec);
     4170        rc = patmDuplicateFunction(pVM, pInstrGC, pPatchRec);
    41594171    }
    41604172    else
     
    49004912            {
    49014913                TRPMR3SetGuestTrapHandler(pVM, iGate, TRPM_INVALID_HANDLER);
    4902                 LogRel(("Disabling IDT %x patch handler %VGv\n", iGate, pInstrGC));
     4914                LogRel(("PATM: Disabling IDT %x patch handler %VGv\n", iGate, pInstrGC));
    49034915            }
    49044916        }
     
    53075319
    53085320/**
     5321 * Attempt to refresh the patch by recompiling its entire code block
     5322 *
     5323 * @returns VBox status code.
     5324 * @param   pVM             The VM to operate on.
     5325 * @param   pPatchRec       Patch record
     5326 */
     5327int patmR3RefreshPatch(PVM pVM, PPATMPATCHREC pPatchRec)
     5328{
     5329    PPATCHINFO  pPatch;
     5330    int         rc;
     5331    RTGCPTR     pInstrGC = pPatchRec->patch.pPrivInstrGC;
     5332
     5333    Log(("patmR3RefreshPatch: attempt to refresh patch at %VGv\n", pInstrGC));
     5334
     5335    pPatch = &pPatchRec->patch;
     5336    AssertReturn(pPatch->flags & (PATMFL_DUPLICATE_FUNCTION|PATMFL_IDTHANDLER|PATMFL_TRAPHANDLER), VERR_PATCHING_REFUSED);
     5337    AssertReturn(!(pPatch->flags & PATMFL_EXTERNAL_JUMP_INSIDE), VERR_PATCHING_REFUSED);
     5338
     5339    /** Note: quite ugly to enable/disable/remove/insert old and new patches, but there's no easy way around it. */
     5340
     5341    rc = PATMR3DisablePatch(pVM, pInstrGC);
     5342    AssertRC(rc);
     5343
     5344    /** Kick it out of the lookup tree to make sure PATMR3InstallPatch doesn't fail (hack alert) */
     5345    RTAvloGCPtrRemove(&pVM->patm.s.PatchLookupTreeHC->PatchTree, pPatchRec->Core.Key);
     5346#ifdef VBOX_WITH_STATISTICS
     5347    if (PATM_STAT_INDEX_IS_VALID(pPatchRec->patch.uPatchIdx))
     5348    {
     5349        STAMR3Deregister(pVM, &pPatchRec->patch);
     5350#ifndef DEBUG_sandervl
     5351        STAMR3Deregister(pVM, &pVM->patm.s.pStatsHC[pPatchRec->patch.uPatchIdx]);
     5352        STAMR3Deregister(pVM, &pPatchRec->patch.cbPatchBlockSize);
     5353        STAMR3Deregister(pVM, &pPatchRec->patch.cbPatchJump);
     5354        STAMR3Deregister(pVM, &pPatchRec->patch.cbPrivInstr);
     5355        STAMR3Deregister(pVM, &pPatchRec->patch.cCodeWrites);
     5356        STAMR3Deregister(pVM, &pPatchRec->patch.cInvalidWrites);
     5357        STAMR3Deregister(pVM, &pPatchRec->patch.cTraps);
     5358        STAMR3Deregister(pVM, &pPatchRec->patch.flags);
     5359        STAMR3Deregister(pVM, &pPatchRec->patch.nrJumpRecs);
     5360        STAMR3Deregister(pVM, &pPatchRec->patch.nrFixups);
     5361        STAMR3Deregister(pVM, &pPatchRec->patch.opcode);
     5362        STAMR3Deregister(pVM, &pPatchRec->patch.uState);
     5363        STAMR3Deregister(pVM, &pPatchRec->patch.uOldState);
     5364        STAMR3Deregister(pVM, &pPatchRec->patch.uOpMode);
     5365#endif
     5366    }
     5367#endif
     5368
     5369    /** Note: We don't attempt to reuse patch memory here as it's quite common that the new code block requires more memory. */
     5370
     5371    /* Attempt to install a new patch. */
     5372    rc = PATMR3InstallPatch(pVM, pInstrGC, pPatch->flags & (PATMFL_CODE32|PATMFL_IDTHANDLER|PATMFL_INTHANDLER|PATMFL_TRAPHANDLER|PATMFL_DUPLICATE_FUNCTION|PATMFL_TRAPHANDLER_WITH_ERRORCODE|PATMFL_IDTHANDLER_WITHOUT_ENTRYPOINT));
     5373    if (VBOX_SUCCESS(rc))
     5374    {
     5375        RTGCPTR         pPatchTargetGC;
     5376        PPATMPATCHREC   pNewPatchRec;
     5377
     5378        /* Determine target address in new patch */
     5379        pPatchTargetGC = PATMR3QueryPatchGCPtr(pVM, pInstrGC);
     5380        Assert(pPatchTargetGC);
     5381        if (!pPatchTargetGC)
     5382        {
     5383            rc = VERR_PATCHING_REFUSED;
     5384            goto failure;
     5385        }
     5386
     5387        /* Reset offset into patch memory to put the next code blocks right at the beginning. */
     5388        pPatch->uCurPatchOffset   = 0;
     5389
     5390        /* insert jump to new patch in old patch block */
     5391        rc = patmPatchGenPatchJump(pVM, pPatch, pInstrGC, pPatchTargetGC, false /* no lookup record */);
     5392        if (VBOX_FAILURE(rc))
     5393            goto failure;
     5394
     5395        pNewPatchRec = (PPATMPATCHREC)RTAvloGCPtrGet(&pVM->patm.s.PatchLookupTreeHC->PatchTree, pInstrGC);
     5396        Assert(pNewPatchRec); /* can't fail */
     5397
     5398        /* Remove old patch (only do that when everything is finished) */
     5399        int rc2 = PATMRemovePatch(pVM, pPatchRec, true /* force removal */);
     5400        AssertRC(rc2);
     5401
     5402        /* Put the new patch back into the tree, because removing the old one kicked this one out. (hack alert) */
     5403        RTAvloGCPtrInsert(&pVM->patm.s.PatchLookupTreeHC->PatchTree, &pNewPatchRec->Core);
     5404
     5405        LogRel(("PATM: patmR3RefreshPatch: succeeded to refresh patch at %VGv \n", pInstrGC));
     5406        STAM_COUNTER_INC(&pVM->patm.s.StatPatchRefreshSuccess);
     5407    }
     5408
     5409failure:
     5410    if (VBOX_FAILURE(rc))
     5411    {
     5412        LogRel(("PATM: patmR3RefreshPatch: failed to refresh patch at %VGv. Reactiving old one. \n", pInstrGC));
     5413
     5414        /* Remove the new inactive patch */
     5415        rc = PATMR3RemovePatch(pVM, pInstrGC);
     5416        AssertRC(rc);
     5417
     5418        /* Put the old patch back into the tree (or else it won't be saved) (hack alert) */
     5419        RTAvloGCPtrInsert(&pVM->patm.s.PatchLookupTreeHC->PatchTree, &pPatchRec->Core);
     5420
     5421        /* Enable again in case the dirty instruction is near the end and there are safe code paths. */
     5422        int rc2 = PATMR3EnablePatch(pVM, pInstrGC);
     5423        AssertRC(rc2);
     5424
     5425        STAM_COUNTER_INC(&pVM->patm.s.StatPatchRefreshFailed);
     5426    }
     5427    return rc;
     5428}
     5429
     5430/**
    53095431 * Find patch for privileged instruction at specified location
    53105432 *
     
    56145736    while (true)
    56155737    {
     5738        if (pRec->fJumpTarget)
     5739        {
     5740            LogRel(("PATM: patmR3HandleDirtyInstr: dirty instruction at %VGv (%VGv) ignored, because instruction in function was reused as target of jump\n", pEip, pPatchToGuestRec->pOrgInstrGC));
     5741            pRec->fDirty = false;
     5742            return VERR_PATCHING_REFUSED;
     5743        }
     5744
    56165745        /* Restore original instruction opcode byte so we can check if the write was indeed safe. */
    56175746        pCurPatchInstrHC  = patmPatchGCPtr2PatchHCPtr(pVM, pCurPatchInstrGC);
     
    56205749        /* Only harmless instructions are acceptable. */
    56215750        rc = CPUMR3DisasmInstrCPU(pVM, pCtx, pCurPatchInstrGC, &CpuOld, 0);
    5622         if (VBOX_FAILURE(rc) || !(CpuOld.pCurInstr->optype & OPTYPE_HARMLESS))
     5751        if (    VBOX_FAILURE(rc)
     5752            ||  !(CpuOld.pCurInstr->optype & OPTYPE_HARMLESS))
    56235753            break;
    56245754
     
    57295859        /* Mark the whole instruction stream with breakpoints. */
    57305860        memset(pPatchInstrHC, 0xCC, cbDirty);
     5861
     5862        if (    pVM->patm.s.fOutOfMemory == false
     5863            &&  (pPatch->patch.flags & (PATMFL_DUPLICATE_FUNCTION|PATMFL_IDTHANDLER|PATMFL_TRAPHANDLER)))
     5864        {
     5865            rc = patmR3RefreshPatch(pVM, pPatch);
     5866            if (VBOX_FAILURE(rc))
     5867            {
     5868                LogRel(("PATM: Failed to refresh dirty patch at %VGv. Disabling it.\n", pPatch->patch.pPrivInstrGC));
     5869            }
     5870            /* Even if we succeed, we must go back to the original instruction as the patched one could be invalid. */
     5871            rc = VERR_PATCHING_REFUSED;
     5872        }
    57315873    }
    57325874    return rc;
     
    58736015        }
    58746016        else
     6017        {
     6018            /* Reset the PATM stack. */
     6019            CTXSUFF(pVM->patm.s.pGCState)->Psp = PATM_STACK_SIZE;
     6020
    58756021            rc = VINF_SUCCESS;  /* Continue at original instruction. */
     6022        }
    58766023
    58776024        *ppNewEip = pNewEip;
  • trunk/src/VBox/VMM/PATM/PATMInternal.h

    r1875 r2030  
    3737
    3838
    39 #define PATM_SSM_VERSION                    52
     39#define PATM_SSM_VERSION                    53
    4040
    4141/* Enable for call patching. */
     
    7070#define PATMFL_MUST_INSTALL_PATCHJMP        BIT64(31) /** Need to patch guest code in order to activate patch. */
    7171#define PATMFL_INT3_REPLACEMENT_BLOCK       BIT64(32) /** int 3 replacement block */
     72#define PATMFL_EXTERNAL_JUMP_INSIDE         BIT64(33) /** A trampoline patch was created that jumps to an instruction in the patch block */
    7273
    7374#define SIZEOF_NEARJUMP8                   2 //opcode byte + 1 byte relative offset
     
    9091#define PATM_MAX_CALL_DEPTH                32
    9192/* Maximum nr of writes before a patch is marked dirty. (disabled) */
    92 #define PATM_MAX_CODE_WRITES               16
     93#define PATM_MAX_CODE_WRITES               32
    9394/* Maximum nr of invalid writes before a patch is disabled. */
    9495#define PATM_MAX_INVALID_WRITES            16384
     
    178179    PATM_LOOKUP_TYPE enmType;
    179180    bool             fDirty;
     181    bool             fJumpTarget;
    180182    uint8_t          u8DirtyOpcode;  /* original opcode before writing 0xCC there to mark it dirty */
    181183} RECPATCHTOGUEST, *PRECPATCHTOGUEST;
     
    485487    STAMCOUNTER             StatPatchPageRemoved;
    486488
     489    STAMCOUNTER             StatPatchRefreshSuccess;
     490    STAMCOUNTER             StatPatchRefreshFailed;
     491
    487492    STAMCOUNTER             StatGenRet;
    488493    STAMCOUNTER             StatGenRetReused;
  • trunk/src/VBox/VMM/PATM/PATMPatch.cpp

    r1465 r2030  
    15311531 * Relative jump from patch code to patch code (no fixup required)
    15321532 */
    1533 int patmPatchGenPatchJump(PVM pVM, PPATCHINFO pPatch, RTGCPTR pCurInstrGC, GCPTRTYPE(uint8_t *)pPatchAddrGC)
     1533int patmPatchGenPatchJump(PVM pVM, PPATCHINFO pPatch, RTGCPTR pCurInstrGC, GCPTRTYPE(uint8_t *)pPatchAddrGC, bool fAddLookupRecord)
    15341534{
    15351535    int32_t displ;
     
    15391539    PATCHGEN_PROLOG(pVM, pPatch);
    15401540
    1541     /* Add lookup record for patch to guest address translation */
    1542     patmr3AddP2GLookupRecord(pVM, pPatch, pPB, pCurInstrGC, PATM_LOOKUP_PATCH2GUEST);
     1541    if (fAddLookupRecord)
     1542    {
     1543        /* Add lookup record for patch to guest address translation */
     1544        patmr3AddP2GLookupRecord(pVM, pPatch, pPB, pCurInstrGC, PATM_LOOKUP_PATCH2GUEST);
     1545    }
    15431546
    15441547    pPB[0] = 0xE9;  //JMP
  • trunk/src/VBox/VMM/PATM/PATMPatch.h

    r23 r2030  
    4646int patmPatchGenRet(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu, GCPTRTYPE(uint8_t *) pCurInstrGC);
    4747
    48 int patmPatchGenPatchJump(PVM pVM, PPATCHINFO pPatch, RTGCPTR pCurInstrGC, GCPTRTYPE(uint8_t *)pPatchAddrGC);
     48int patmPatchGenPatchJump(PVM pVM, PPATCHINFO pPatch, RTGCPTR pCurInstrGC, GCPTRTYPE(uint8_t *)pPatchAddrGC, bool fAddLookupRecord = true);
    4949
    5050/**
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