VirtualBox

Changeset 72569 in vbox


Ignore:
Timestamp:
Jun 15, 2018 7:04:01 PM (6 years ago)
Author:
vboxsync
Message:

EM,IEM,NEM: Started working on optimizing adjacent exits using IEM. Keep track of frequent exits, after 256 hits do a trial run in IEM to look for adjacent exits. Proof of concept using CPUID in NEMR3/win. bugref:9044

Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vmm/em.h

    r72565 r72569  
    238238#define EMEXIT_F_KIND_XCPT      UINT32_C(0x00004000)    /**< Exception numbers (raw-mode). */
    239239#define EMEXIT_F_KIND_MASK      UINT32_C(0x00007000)
    240 #define EMEXIT_F_CS_EIP         UINT32_C(0x00008000)    /**< The PC is EIP in the low dword and CS in the high. */
    241 #define EMEXIT_F_UNFLATTENED_PC UINT32_C(0x00010000)    /**< The PC hasn't had CS.BASE added to it. */
     240#define EMEXIT_F_CS_EIP         UINT32_C(0x00010000)    /**< The PC is EIP in the low dword and CS in the high. */
     241#define EMEXIT_F_UNFLATTENED_PC UINT32_C(0x00020000)    /**< The PC hasn't had CS.BASE added to it. */
    242242/** Combines flags and exit type into EMHistoryAddExit() input. */
    243243#define EMEXIT_MAKE_FLAGS_AND_TYPE(a_fFlags, a_uType)   ((a_fFlags) | (uint32_t)(a_uType))
     
    246246typedef enum EMEXITACTION
    247247{
     248    /** The record is free. */
     249    EMEXITACTION_FREE_RECORD = 0,
    248250    /** Take normal action on the exit. */
    249     EMEXITACTION_NORMAL = 0,
    250     EMEXITACTION_TODO
     251    EMEXITACTION_NORMAL,
     252    /** Take normal action on the exit, already probed and found nothing. */
     253    EMEXITACTION_NORMAL_PROBED,
     254    /** Do a probe execution. */
     255    EMEXITACTION_EXEC_PROBE,
     256    /** Execute using EMEXITREC::cMaxInstructionsWithoutExit. */
     257    EMEXITACTION_EXEC_WITH_MAX
    251258} EMEXITACTION;
    252259AssertCompileSize(EMEXITACTION, 4);
    253260
    254 VMM_INT_DECL(EMEXITACTION)      EMHistoryAddExit(PVMCPU pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC, uint64_t uTimestamp);
     261/**
     262 * Accumulative exit record.
     263 *
     264 * This could perhaps be squeezed down a bit, but there isn't too much point.
     265 * We'll probably need more data as time goes by.
     266 */
     267typedef struct EMEXITREC
     268{
     269    /** The flat PC of the exit. */
     270    uint64_t            uFlatPC;
     271    /** Flags and type, see EMEXIT_MAKE_FLAGS_AND_TYPE. */
     272    uint32_t            uFlagsAndType;
     273    /** The action to take (EMEXITACTION). */
     274    uint8_t             enmAction;
     275    uint8_t             bUnused;
     276    /** Maximum number of instructions to execute without hitting an exit. */
     277    uint16_t            cMaxInstructionsWithoutExit;
     278    /** The exit number (EMCPU::iNextExit) at which it was last updated. */
     279    uint64_t            uLastExitNo;
     280    /** Number of hits. */
     281    uint64_t            cHits;
     282} EMEXITREC;
     283AssertCompileSize(EMEXITREC, 32);
     284/** Pointer to an accumulative exit record. */
     285typedef EMEXITREC *PEMEXITREC;
     286/** Pointer to a const accumulative exit record. */
     287typedef EMEXITREC const *PCEMEXITREC;
     288
     289VMM_INT_DECL(PCEMEXITREC)       EMHistoryAddExit(PVMCPU pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC, uint64_t uTimestamp);
    255290#ifdef IN_RC
    256291VMMRC_INT_DECL(void)            EMRCHistoryAddExitCsEip(PVMCPU pVCpu, uint32_t uFlagsAndType, uint16_t uCs, uint32_t uEip,
     
    260295VMMR0_INT_DECL(void)            EMR0HistoryUpdatePC(PVMCPU pVCpu, uint64_t uFlatPC, bool fFlattened);
    261296#endif
    262 VMM_INT_DECL(EMEXITACTION)      EMHistoryUpdateFlagsAndType(PVMCPU pVCpu, uint32_t uFlagsAndType);
    263 VMM_INT_DECL(EMEXITACTION)      EMHistoryUpdateFlagsAndTypeAndPC(PVMCPU pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC);
     297VMM_INT_DECL(PCEMEXITREC)       EMHistoryUpdateFlagsAndType(PVMCPU pVCpu, uint32_t uFlagsAndType);
     298VMM_INT_DECL(PCEMEXITREC)       EMHistoryUpdateFlagsAndTypeAndPC(PVMCPU pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC);
     299VMM_INT_DECL(VBOXSTRICTRC)      EMHistoryExec(PVMCPU pVCpu, PCEMEXITREC pExitRec, uint32_t fWillExit);
    264300
    265301
  • trunk/include/VBox/vmm/iem.h

    r72493 r72569  
    210210                                                                      uint32_t *pcbWritten);
    211211VMMDECL(VBOXSTRICTRC)       IEMExecLots(PVMCPU pVCpu, uint32_t *pcInstructions);
     212/** Statistics returned by IEMExecForExits. */
     213typedef struct IEMEXECFOREXITSTATS
     214{
     215    uint32_t cInstructions;
     216    uint32_t cExits;
     217    uint32_t cMaxExitDistance;
     218    uint32_t cReserved;
     219} IEMEXECFOREXITSTATS;
     220/** Pointer to statistics returned by IEMExecForExits. */
     221typedef IEMEXECFOREXITSTATS *PIEMEXECFOREXITSTATS;
     222VMMDECL(VBOXSTRICTRC)       IEMExecForExits(PVMCPU pVCpu, uint32_t fWillExit, uint32_t cMinInstructions, uint32_t cMaxInstructions,
     223                                            uint32_t cMaxInstructionsWithoutExits, PIEMEXECFOREXITSTATS pStats);
    212224VMMDECL(VBOXSTRICTRC)       IEMInjectTrpmEvent(PVMCPU pVCpu);
    213225VMM_INT_DECL(VBOXSTRICTRC)  IEMInjectTrap(PVMCPU pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType, uint16_t uErrCode, RTGCPTR uCr2,
  • trunk/include/VBox/vmm/vm.h

    r72555 r72569  
    290290        struct EMCPU        s;
    291291#endif
    292         uint8_t             padding[8192];      /* multiple of 4096 */
     292        uint8_t             padding[40960];      /* multiple of 4096 */
    293293    } em;
    294294} VMCPU;
  • trunk/include/VBox/vmm/vm.mac

    r72555 r72569  
    8383    .cpum                   resb 4096
    8484    alignb 4096
    85     .em                     resb 8192
     85    .em                     resb 40960
    8686    alignb 4096
    8787endstruc
  • trunk/src/VBox/VMM/VMMAll/EMAll.cpp

    r72565 r72569  
    404404
    405405/**
     406 * Execute using history.
     407 *
     408 * This function will be called when EMHistoryAddExit() and friends returns a
     409 * non-NULL result.  This happens in response to probing or when probing has
     410 * uncovered adjacent exits which can more effectively be reached by using IEM
     411 * than restarting execution using the main execution engine and fielding an
     412 * regular exit.
     413 *
     414 * @returns VBox strict status code, see IEMExecForExits.
     415 * @param   pVCpu           The cross context virtual CPU structure.
     416 * @param   pExitRec        The exit record return by a previous history add
     417 *                          or update call.
     418 * @param   fWillExit       Flags indicating to IEM what will cause exits, TBD.
     419 */
     420VMM_INT_DECL(VBOXSTRICTRC) EMHistoryExec(PVMCPU pVCpu, PCEMEXITREC pExitRec, uint32_t fWillExit)
     421{
     422    Assert(pExitRec);
     423    VMCPU_ASSERT_EMT(pVCpu);
     424    IEMEXECFOREXITSTATS ExecStats;
     425    switch (pExitRec->enmAction)
     426    {
     427        /*
     428         * Executes multiple instruction stopping only when we've gone a given
     429         * number without perceived exits.
     430         */
     431        case EMEXITACTION_EXEC_WITH_MAX:
     432        {
     433            LogFlow(("EMHistoryExec/EXEC_WITH_MAX: %RX64, max %u\n", pExitRec->uFlatPC, pExitRec->cMaxInstructionsWithoutExit));
     434            VBOXSTRICTRC rcStrict = IEMExecForExits(pVCpu, fWillExit,
     435                                                    pExitRec->cMaxInstructionsWithoutExit /* cMinInstructions*/,
     436                                                    4096 /*cMaxInstructions*/,
     437                                                    pExitRec->cMaxInstructionsWithoutExit,
     438                                                    &ExecStats);
     439            LogFlow(("EMHistoryExec/EXEC_WITH_MAX: %Rrc cExits=%u cMaxExitDistance=%u cInstructions=%u\n",
     440                     VBOXSTRICTRC_VAL(rcStrict), ExecStats.cExits, ExecStats.cMaxExitDistance, ExecStats.cInstructions));
     441            return rcStrict;
     442        }
     443
     444        /*
     445         * Probe a exit for close by exits.
     446         */
     447        case EMEXITACTION_EXEC_PROBE:
     448        {
     449            LogFlow(("EMHistoryExec/EXEC_PROBE: %RX64, max %u\n", pExitRec->uFlatPC));
     450            PEMEXITREC   pExitRecUnconst = (PEMEXITREC)pExitRec;
     451            VBOXSTRICTRC rcStrict = IEMExecForExits(pVCpu, fWillExit,
     452                                                    64 /*cMinInstructions*/,
     453                                                    4096 /*cMaxInstructions*/,
     454                                                    32 /*cMaxInstructionsWithoutExit*/,
     455                                                    &ExecStats);
     456            LogFlow(("EMHistoryExec/EXEC_PROBE: %Rrc cExits=%u cMaxExitDistance=%u cInstructions=%u\n",
     457                     VBOXSTRICTRC_VAL(rcStrict), ExecStats.cExits, ExecStats.cMaxExitDistance, ExecStats.cInstructions));
     458            if (ExecStats.cExits >= 2)
     459            {
     460                Assert(ExecStats.cMaxExitDistance > 0 && ExecStats.cMaxExitDistance <= 32);
     461                pExitRecUnconst->cMaxInstructionsWithoutExit = ExecStats.cMaxExitDistance;
     462                pExitRecUnconst->enmAction = EMEXITACTION_EXEC_WITH_MAX;
     463                LogFlow(("EMHistoryExec/EXEC_PROBE: -> EXEC_WITH_MAX %u\n", ExecStats.cMaxExitDistance));
     464            }
     465            else
     466            {
     467                pExitRecUnconst->enmAction = EMEXITACTION_NORMAL_PROBED;
     468                LogFlow(("EMHistoryExec/EXEC_PROBE: -> PROBED\n"));
     469                /** @todo check for return to ring-3 and such and optimize/reprobe. */
     470            }
     471            return rcStrict;
     472        }
     473
     474        /* We shouldn't ever see these here! */
     475        case EMEXITACTION_FREE_RECORD:
     476        case EMEXITACTION_NORMAL:
     477        case EMEXITACTION_NORMAL_PROBED:
     478            break;
     479
     480        /* No default case, want compiler warnings. */
     481    }
     482    AssertLogRelFailedReturn(VERR_EM_INTERNAL_ERROR);
     483}
     484
     485
     486DECL_FORCE_INLINE(PCEMEXITREC) emHistoryRecordInit(PEMEXITREC pExitRec, uint64_t uFlatPC, uint32_t uFlagsAndType, uint64_t uExitNo)
     487{
     488    pExitRec->uFlatPC                     = uFlatPC;
     489    pExitRec->uFlagsAndType               = uFlagsAndType;
     490    pExitRec->enmAction                   = EMEXITACTION_NORMAL;
     491    pExitRec->bUnused                     = 0;
     492    pExitRec->cMaxInstructionsWithoutExit = 64;
     493    pExitRec->uLastExitNo                 = uExitNo;
     494    pExitRec->cHits                       = 1;
     495    return NULL;
     496}
     497
     498
     499DECL_FORCE_INLINE(PCEMEXITREC) emHistoryRecordInitNew(PVMCPU pVCpu, PEMEXITENTRY pHistEntry, uintptr_t idxSlot,
     500                                                      PEMEXITREC pExitRec, uint64_t uFlatPC,
     501                                                      uint32_t uFlagsAndType, uint64_t uExitNo)
     502{
     503    pHistEntry->idxSlot = (uint32_t)idxSlot;
     504    pVCpu->em.s.cExitRecordUsed++;
     505    LogFlow(("emHistoryRecordInitNew: [%#x] = %#07x %016RX64; (%u of %u used)\n", idxSlot, uFlagsAndType, uFlatPC,
     506             pVCpu->em.s.cExitRecordUsed, RT_ELEMENTS(pVCpu->em.s.aExitRecords) ));
     507    return emHistoryRecordInit(pExitRec, uFlatPC, uFlagsAndType, uExitNo);
     508}
     509
     510
     511/**
     512 * Adds or updates the EMEXITREC for this PC/type and decide on an action.
     513 *
     514 * @returns Pointer to an exit record if special action should be taken using
     515 *          EMHistoryExec().  Take normal exit action when NULL.
     516 *
     517 * @param   pVCpu           The cross context virtual CPU structure.
     518 * @param   uFlagsAndType   Combined flags and type, EMEXIT_F_KIND_EM set and
     519 *                          both EMEXIT_F_CS_EIP and EMEXIT_F_UNFLATTENED_PC are clear.
     520 * @param   uFlatPC         The flattened program counter.
     521 * @param   pHistEntry      The exit history entry.
     522 * @param   uExitNo         The current exit number.
     523 */
     524static PCEMEXITREC emHistoryAddOrUpdateRecord(PVMCPU pVCpu, uint64_t uFlagsAndType, uint64_t uFlatPC,
     525                                              PEMEXITENTRY pHistEntry, uint64_t uExitNo)
     526{
     527    /*
     528     * Work the hash table.
     529     */
     530    AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitRecords) == 1024);
     531#define EM_EXIT_RECORDS_IDX_MASK 1023
     532    uintptr_t  idxSlot  = ((uintptr_t)uFlatPC >> 1) & EM_EXIT_RECORDS_IDX_MASK;
     533    PEMEXITREC pExitRec = &pVCpu->em.s.aExitRecords[idxSlot];
     534    if (pExitRec->uFlatPC == uFlatPC)
     535    {
     536        Assert(pExitRec->enmAction != EMEXITACTION_FREE_RECORD);
     537        pHistEntry->idxSlot = (uint32_t)idxSlot;
     538        if (pExitRec->uFlagsAndType == uFlagsAndType)
     539            pExitRec->uLastExitNo = uExitNo;
     540        else
     541            return emHistoryRecordInit(pExitRec, uFlatPC, uFlagsAndType, uExitNo);
     542    }
     543    else if (pExitRec->enmAction == EMEXITACTION_FREE_RECORD)
     544        return emHistoryRecordInitNew(pVCpu, pHistEntry, idxSlot, pExitRec, uFlatPC, uFlagsAndType, uExitNo);
     545    else
     546    {
     547        /*
     548         * Collision. Figure out later.
     549         */
     550        return NULL;
     551    }
     552
     553
     554    /*
     555     * Found an existing record.
     556     */
     557    switch (pExitRec->enmAction)
     558    {
     559        case EMEXITACTION_NORMAL:
     560        {
     561            uint64_t const cHits = ++pExitRec->cHits;
     562            if (cHits < 256)
     563                return NULL;
     564            LogFlow(("emHistoryAddOrUpdateRecord: [%#x] %#07x %16RX64: -> EXEC_PROBE\n", idxSlot, uFlagsAndType, uFlatPC));
     565            pExitRec->enmAction = EMEXITACTION_EXEC_PROBE;
     566            return pExitRec;
     567        }
     568
     569        case EMEXITACTION_NORMAL_PROBED:
     570            pExitRec->cHits += 1;
     571            return NULL;
     572
     573        default:
     574            pExitRec->cHits += 1;
     575            return pExitRec;
     576
     577        /* This will happen if the caller ignores or cannot serve the probe
     578           request (forced to ring-3, whatever).  We retry this 256 times. */
     579        case EMEXITACTION_EXEC_PROBE:
     580        {
     581            uint64_t const cHits = ++pExitRec->cHits;
     582            if (cHits < 512)
     583                return pExitRec;
     584            pExitRec->enmAction = EMEXITACTION_NORMAL_PROBED;
     585            LogFlow(("emHistoryAddOrUpdateRecord: [%#x] %#07x %16RX64: -> PROBED\n", idxSlot, uFlagsAndType, uFlatPC));
     586            return NULL;
     587        }
     588    }
     589}
     590
     591
     592/**
    406593 * Adds an exit to the history for this CPU.
    407594 *
    408  * @returns Suggested action to take.
     595 * @returns Pointer to an exit record if special action should be taken using
     596 *          EMHistoryExec().  Take normal exit action when NULL.
     597 *
    409598 * @param   pVCpu           The cross context virtual CPU structure.
    410599 * @param   uFlagsAndType   Combined flags and type (see EMEXIT_MAKE_FLAGS_AND_TYPE).
     
    413602 * @thread  EMT(pVCpu)
    414603 */
    415 VMM_INT_DECL(EMEXITACTION) EMHistoryAddExit(PVMCPU pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC, uint64_t uTimestamp)
     604VMM_INT_DECL(PCEMEXITREC) EMHistoryAddExit(PVMCPU pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC, uint64_t uTimestamp)
    416605{
    417606    VMCPU_ASSERT_EMT(pVCpu);
     
    421610     */
    422611    AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitHistory) == 256);
    423     PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)(pVCpu->em.s.iNextExit++) & 0xff];
     612    uint64_t uExitNo = pVCpu->em.s.iNextExit++;
     613    PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)uExitNo & 0xff];
    424614    pHistEntry->uFlatPC       = uFlatPC;
    425615    pHistEntry->uTimestamp    = uTimestamp;
     
    428618
    429619    /*
    430      * If common exit type, we will insert/update the exit into the shared hash table.
     620     * If common exit type, we will insert/update the exit into the exit record hash table.
    431621     */
    432     if ((uFlagsAndType & EMEXIT_F_KIND_MASK) == EMEXIT_F_KIND_EM)
    433     {
    434         /** @todo later */
    435     }
    436 
    437     return EMEXITACTION_NORMAL;
     622    if (   (uFlagsAndType & (EMEXIT_F_KIND_MASK | EMEXIT_F_CS_EIP | EMEXIT_F_UNFLATTENED_PC)) == EMEXIT_F_KIND_EM
     623        && uFlatPC != UINT64_MAX)
     624        return emHistoryAddOrUpdateRecord(pVCpu, uFlagsAndType, uFlatPC, pHistEntry, uExitNo);
     625    return NULL;
    438626}
    439627
     
    476664{
    477665    AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitHistory) == 256);
    478     PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[((uintptr_t)pVCpu->em.s.iNextExit - 1) & 0xff];
     666    uint64_t     uExitNo    = pVCpu->em.s.iNextExit - 1;
     667    PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)uExitNo & 0xff];
    479668    pHistEntry->uFlatPC = uFlatPC;
    480669    if (fFlattened)
     
    489678 * Interface for convering a engine specific exit to a generic one and get guidance.
    490679 *
     680 * @returns Pointer to an exit record if special action should be taken using
     681 *          EMHistoryExec().  Take normal exit action when NULL.
     682 *
    491683 * @param   pVCpu           The cross context virtual CPU structure.
    492684 * @param   uFlagsAndType   Combined flags and type (see EMEXIT_MAKE_FLAGS_AND_TYPE).
    493685 * @thread  EMT(pVCpu)
    494686 */
    495 VMM_INT_DECL(EMEXITACTION) EMHistoryUpdateFlagsAndType(PVMCPU pVCpu, uint32_t uFlagsAndType)
     687VMM_INT_DECL(PCEMEXITREC) EMHistoryUpdateFlagsAndType(PVMCPU pVCpu, uint32_t uFlagsAndType)
    496688{
    497689    VMCPU_ASSERT_EMT(pVCpu);
     
    501693     */
    502694    AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitHistory) == 256);
    503     PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[((uintptr_t)pVCpu->em.s.iNextExit - 1) & 0xff];
     695    uint64_t     uExitNo    = pVCpu->em.s.iNextExit - 1;
     696    PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)uExitNo & 0xff];
    504697    pHistEntry->uFlagsAndType = uFlagsAndType | (pHistEntry->uFlagsAndType & (EMEXIT_F_CS_EIP | EMEXIT_F_UNFLATTENED_PC));
    505698
    506699    /*
    507      * If common exit type, we will insert/update the exit into the shared hash table.
     700     * If common exit type, we will insert/update the exit into the exit record hash table.
    508701     */
    509     if ((uFlagsAndType & EMEXIT_F_KIND_MASK) == EMEXIT_F_KIND_EM)
    510     {
    511         /** @todo later */
    512     }
    513 
    514     return EMEXITACTION_NORMAL;
     702    if (   (uFlagsAndType & (EMEXIT_F_KIND_MASK | EMEXIT_F_CS_EIP | EMEXIT_F_UNFLATTENED_PC)) == EMEXIT_F_KIND_EM
     703        && pHistEntry->uFlatPC != UINT64_MAX)
     704        return emHistoryAddOrUpdateRecord(pVCpu, uFlagsAndType, pHistEntry->uFlatPC, pHistEntry, uExitNo);
     705    return NULL;
    515706}
    516707
     
    519710 * Interface for convering a engine specific exit to a generic one and get
    520711 * guidance, supplying flattened PC too.
     712 *
     713 * @returns Pointer to an exit record if special action should be taken using
     714 *          EMHistoryExec().  Take normal exit action when NULL.
    521715 *
    522716 * @param   pVCpu           The cross context virtual CPU structure.
     
    525719 * @thread  EMT(pVCpu)
    526720 */
    527 VMM_INT_DECL(EMEXITACTION) EMHistoryUpdateFlagsAndTypeAndPC(PVMCPU pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC)
     721VMM_INT_DECL(PCEMEXITREC) EMHistoryUpdateFlagsAndTypeAndPC(PVMCPU pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC)
    528722{
    529723    VMCPU_ASSERT_EMT(pVCpu);
     724    Assert(uFlatPC != UINT64_MAX);
    530725
    531726    /*
     
    533728     */
    534729    AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitHistory) == 256);
    535     PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[((uintptr_t)pVCpu->em.s.iNextExit - 1) & 0xff];
     730    uint64_t     uExitNo    = pVCpu->em.s.iNextExit - 1;
     731    PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)uExitNo & 0xff];
    536732    pHistEntry->uFlagsAndType = uFlagsAndType;
    537733    pHistEntry->uFlatPC       = uFlatPC;
    538734
    539735    /*
    540      * If common exit type, we will insert/update the exit into the shared hash table.
     736     * If common exit type, we will insert/update the exit into the exit record hash table.
    541737     */
    542     if ((uFlagsAndType & EMEXIT_F_KIND_MASK) == EMEXIT_F_KIND_EM)
    543     {
    544         /** @todo later */
    545     }
    546 
    547     return EMEXITACTION_NORMAL;
     738    if ((uFlagsAndType & (EMEXIT_F_KIND_MASK | EMEXIT_F_CS_EIP | EMEXIT_F_UNFLATTENED_PC)) == EMEXIT_F_KIND_EM)
     739        return emHistoryAddOrUpdateRecord(pVCpu, uFlagsAndType, uFlatPC, pHistEntry, uExitNo);
     740    return NULL;
    548741}
    549742
  • trunk/src/VBox/VMM/VMMAll/IEMAll.cpp

    r72563 r72569  
    1415214152
    1415314153
     14154/**
     14155 * Interface used by EMExecuteExec, does exit statistics and limits.
     14156 *
     14157 * @returns Strict VBox status code.
     14158 * @param   pVCpu               The cross context virtual CPU structure.
     14159 * @param   fWillExit           To be defined.
     14160 * @param   cMinInstructions    Minimum number of instructions to execute before checking for FFs.
     14161 * @param   cMaxInstructions    Maximum number of instructions to execute.
     14162 * @param   cMaxInstructionsWithoutExits
     14163 *                              The max number of instructions without exits.
     14164 * @param   pStats              Where to return statistics.
     14165 */
     14166VMMDECL(VBOXSTRICTRC) IEMExecForExits(PVMCPU pVCpu, uint32_t fWillExit, uint32_t cMinInstructions, uint32_t cMaxInstructions,
     14167                                      uint32_t cMaxInstructionsWithoutExits, PIEMEXECFOREXITSTATS pStats)
     14168{
     14169    NOREF(fWillExit); /** @todo define flexible exit crits */
     14170
     14171    /*
     14172     * Initialize return stats.
     14173     */
     14174    pStats->cInstructions    = 0;
     14175    pStats->cExits           = 0;
     14176    pStats->cMaxExitDistance = 0;
     14177    pStats->cReserved        = 0;
     14178
     14179    /*
     14180     * Initial decoder init w/ prefetch, then setup setjmp.
     14181     */
     14182    VBOXSTRICTRC rcStrict = iemInitDecoderAndPrefetchOpcodes(pVCpu, false);
     14183    if (rcStrict == VINF_SUCCESS)
     14184    {
     14185        uint32_t cInstructionSinceLastExit = 0;
     14186
     14187#ifdef IEM_WITH_SETJMP
     14188        jmp_buf         JmpBuf;
     14189        jmp_buf        *pSavedJmpBuf = pVCpu->iem.s.CTX_SUFF(pJmpBuf);
     14190        pVCpu->iem.s.CTX_SUFF(pJmpBuf)   = &JmpBuf;
     14191        pVCpu->iem.s.cActiveMappings     = 0;
     14192        if ((rcStrict = setjmp(JmpBuf)) == 0)
     14193#endif
     14194        {
     14195            /*
     14196             * The run loop.  We limit ourselves to 4096 instructions right now.
     14197             */
     14198            PVM pVM = pVCpu->CTX_SUFF(pVM);
     14199            for (;;)
     14200            {
     14201                /*
     14202                 * Log the state.
     14203                 */
     14204#ifdef LOG_ENABLED
     14205                iemLogCurInstr(pVCpu, true);
     14206#endif
     14207
     14208                /*
     14209                 * Do the decoding and emulation.
     14210                 */
     14211                uint32_t const cPotentialExits = pVCpu->iem.s.cPotentialExits;
     14212
     14213                uint8_t b; IEM_OPCODE_GET_NEXT_U8(&b);
     14214                rcStrict = FNIEMOP_CALL(g_apfnOneByteMap[b]);
     14215
     14216                if (   cPotentialExits != pVCpu->iem.s.cPotentialExits
     14217                    && cInstructionSinceLastExit > 0 /* don't count the first */ )
     14218                {
     14219                    pStats->cExits += 1;
     14220                    if (cInstructionSinceLastExit > pStats->cMaxExitDistance)
     14221                        pStats->cMaxExitDistance = cInstructionSinceLastExit;
     14222                    cInstructionSinceLastExit = 0;
     14223                }
     14224
     14225                if (RT_LIKELY(rcStrict == VINF_SUCCESS))
     14226                {
     14227                    Assert(pVCpu->iem.s.cActiveMappings == 0);
     14228                    pVCpu->iem.s.cInstructions++;
     14229                    pStats->cInstructions++;
     14230                    cInstructionSinceLastExit++;
     14231                    if (RT_LIKELY(pVCpu->iem.s.rcPassUp == VINF_SUCCESS))
     14232                    {
     14233                        uint32_t fCpu = pVCpu->fLocalForcedActions
     14234                                      & ( VMCPU_FF_ALL_MASK & ~(  VMCPU_FF_PGM_SYNC_CR3
     14235                                                                | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL
     14236                                                                | VMCPU_FF_TLB_FLUSH
     14237#ifdef VBOX_WITH_RAW_MODE
     14238                                                                | VMCPU_FF_TRPM_SYNC_IDT
     14239                                                                | VMCPU_FF_SELM_SYNC_TSS
     14240                                                                | VMCPU_FF_SELM_SYNC_GDT
     14241                                                                | VMCPU_FF_SELM_SYNC_LDT
     14242#endif
     14243                                                                | VMCPU_FF_INHIBIT_INTERRUPTS
     14244                                                                | VMCPU_FF_BLOCK_NMIS
     14245                                                                | VMCPU_FF_UNHALT ));
     14246
     14247                        if (RT_LIKELY(   (   (   !fCpu
     14248                                              || (   !(fCpu & ~(VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
     14249                                                  && !pVCpu->cpum.GstCtx.rflags.Bits.u1IF))
     14250                                          && !VM_FF_IS_PENDING(pVM, VM_FF_ALL_MASK) )
     14251                                      || pStats->cInstructions < cMinInstructions))
     14252                        {
     14253                            if (cMaxInstructions-- > 0)
     14254                            {
     14255                                if (cInstructionSinceLastExit <= cMaxInstructionsWithoutExits)
     14256                                {
     14257                                    Assert(pVCpu->iem.s.cActiveMappings == 0);
     14258                                    iemReInitDecoder(pVCpu);
     14259                                    continue;
     14260                                }
     14261                            }
     14262                        }
     14263                    }
     14264                    Assert(pVCpu->iem.s.cActiveMappings == 0);
     14265                }
     14266                else if (pVCpu->iem.s.cActiveMappings > 0)
     14267                        iemMemRollback(pVCpu);
     14268                rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
     14269                break;
     14270            }
     14271        }
     14272#ifdef IEM_WITH_SETJMP
     14273        else
     14274        {
     14275            if (pVCpu->iem.s.cActiveMappings > 0)
     14276                iemMemRollback(pVCpu);
     14277            pVCpu->iem.s.cLongJumps++;
     14278        }
     14279        pVCpu->iem.s.CTX_SUFF(pJmpBuf) = pSavedJmpBuf;
     14280#endif
     14281
     14282        /*
     14283         * Assert hidden register sanity (also done in iemInitDecoder and iemReInitDecoder).
     14284         */
     14285        Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));
     14286        Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
     14287    }
     14288    else
     14289    {
     14290        if (pVCpu->iem.s.cActiveMappings > 0)
     14291            iemMemRollback(pVCpu);
     14292
     14293#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
     14294        /*
     14295         * When a nested-guest causes an exception intercept (e.g. #PF) when fetching
     14296         * code as part of instruction execution, we need this to fix-up VINF_SVM_VMEXIT.
     14297         */
     14298        rcStrict = iemExecStatusCodeFiddling(pVCpu, rcStrict);
     14299#endif
     14300    }
     14301
     14302    /*
     14303     * Maybe re-enter raw-mode and log.
     14304     */
     14305#ifdef IN_RC
     14306    rcStrict = iemRCRawMaybeReenter(pVCpu, rcStrict);
     14307#endif
     14308    if (rcStrict != VINF_SUCCESS)
     14309        LogFlow(("IEMExecForExits: cs:rip=%04x:%08RX64 ss:rsp=%04x:%08RX64 EFL=%06x - rcStrict=%Rrc; ins=%u exits=%u maxdist=%u\n",
     14310                 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.rsp,
     14311                 pVCpu->cpum.GstCtx.eflags.u, VBOXSTRICTRC_VAL(rcStrict), pStats->cInstructions, pStats->cExits, pStats->cMaxExitDistance));
     14312    return rcStrict;
     14313}
     14314
    1415414315
    1415514316/**
  • trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h

    r72553 r72569  
    68016801
    68026802    iemRegAddToRipAndClearRF(pVCpu, cbInstr);
     6803    pVCpu->iem.s.cPotentialExits++;
    68036804    return VINF_SUCCESS;
    68046805}
  • trunk/src/VBox/VMM/VMMAll/NEMAllNativeTemplate-win.cpp.h

    r72555 r72569  
    22932293        pCtx->rdi = pExit->IoPortAccess.Rdi;
    22942294        pCtx->rsi = pExit->IoPortAccess.Rsi;
    2295 # ifdef IN_RING0
    2296         rcStrict = nemR0WinImportStateStrict(pGVCpu->pGVM, pGVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM, "IOExit");
    2297         if (rcStrict != VINF_SUCCESS)
    2298             return rcStrict;
    2299 # else
    23002295        int rc = nemHCWinCopyStateFromHyperV(pVM, pVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM);
    23012296        AssertRCReturn(rc, rc);
    2302 # endif
    23032297
    23042298        Log4(("IOExit/%u: %04x:%08RX64/%s: %s%s %#x LB %u (emulating)\n",
     
    24772471     *       function and make everyone use it.
    24782472     */
    2479     EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_CPUID),
    2480                      pExit->VpContext.Rip + pExit->VpContext.Cs.Base, ASMReadTSC());
    2481 
    2482     /** @todo Combine implementations into IEMExecDecodedCpuId as this will
    2483      *        only get weirder with nested VT-x and AMD-V support. */
     2473    PCEMEXITREC pExitRec = EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_CPUID),
     2474                                            pExit->VpContext.Rip + pExit->VpContext.Cs.Base, ASMReadTSC());
    24842475    nemR3WinCopyStateFromX64Header(pVCpu, pCtx, &pExit->VpContext);
    2485 
    2486     /* Copy in the low register values (top is always cleared). */
    2487     pCtx->rax = (uint32_t)pExit->CpuidAccess.Rax;
    2488     pCtx->rcx = (uint32_t)pExit->CpuidAccess.Rcx;
    2489     pCtx->rdx = (uint32_t)pExit->CpuidAccess.Rdx;
    2490     pCtx->rbx = (uint32_t)pExit->CpuidAccess.Rbx;
     2476    if (!pExitRec)
     2477    {
     2478        /** @todo Combine implementations into IEMExecDecodedCpuId as this will
     2479         *        only get weirder with nested VT-x and AMD-V support. */
     2480
     2481        /* Copy in the low register values (top is always cleared). */
     2482        pCtx->rax = (uint32_t)pExit->CpuidAccess.Rax;
     2483        pCtx->rcx = (uint32_t)pExit->CpuidAccess.Rcx;
     2484        pCtx->rdx = (uint32_t)pExit->CpuidAccess.Rdx;
     2485        pCtx->rbx = (uint32_t)pExit->CpuidAccess.Rbx;
     2486        pCtx->fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX);
     2487
     2488        /* Get the correct values. */
     2489        CPUMGetGuestCpuId(pVCpu, pCtx->eax, pCtx->ecx, &pCtx->eax, &pCtx->ebx, &pCtx->ecx, &pCtx->edx);
     2490
     2491        Log4(("CpuIdExit/%u: %04x:%08RX64/%s: rax=%08RX64 / rcx=%08RX64 / rdx=%08RX64 / rbx=%08RX64 -> %08RX32 / %08RX32 / %08RX32 / %08RX32 (hv: %08RX64 / %08RX64 / %08RX64 / %08RX64)\n",
     2492              pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
     2493              pExit->CpuidAccess.Rax,                           pExit->CpuidAccess.Rcx,              pExit->CpuidAccess.Rdx,              pExit->CpuidAccess.Rbx,
     2494              pCtx->eax,                                                     pCtx->ecx,                           pCtx->edx,                           pCtx->ebx,
     2495              pExit->CpuidAccess.DefaultResultRax, pExit->CpuidAccess.DefaultResultRcx, pExit->CpuidAccess.DefaultResultRdx, pExit->CpuidAccess.DefaultResultRbx));
     2496
     2497        /* Move RIP and we're done. */
     2498        nemR3WinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pExit->VpContext);
     2499
     2500        RT_NOREF_PV(pVM);
     2501        return VINF_SUCCESS;
     2502    }
     2503
     2504    /* Get state and call EMHistoryExec. */
     2505    pCtx->rax = pExit->CpuidAccess.Rax;
     2506    pCtx->rcx = pExit->CpuidAccess.Rcx;
     2507    pCtx->rdx = pExit->CpuidAccess.Rdx;
     2508    pCtx->rbx = pExit->CpuidAccess.Rbx;
    24912509    pCtx->fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX);
    2492 
    2493     /* Get the correct values. */
    2494     CPUMGetGuestCpuId(pVCpu, pCtx->eax, pCtx->ecx, &pCtx->eax, &pCtx->ebx, &pCtx->ecx, &pCtx->edx);
    2495 
    2496     Log4(("CpuIdExit/%u: %04x:%08RX64/%s: rax=%08RX64 / rcx=%08RX64 / rdx=%08RX64 / rbx=%08RX64 -> %08RX32 / %08RX32 / %08RX32 / %08RX32 (hv: %08RX64 / %08RX64 / %08RX64 / %08RX64)\n",
     2510    Log4(("CpuIdExit/%u: %04x:%08RX64/%s: rax=%08RX64 / rcx=%08RX64 / rdx=%08RX64 / rbx=%08RX64 (hv: %08RX64 / %08RX64 / %08RX64 / %08RX64) ==> EMHistoryExec\n",
    24972511          pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
    24982512          pExit->CpuidAccess.Rax,                           pExit->CpuidAccess.Rcx,              pExit->CpuidAccess.Rdx,              pExit->CpuidAccess.Rbx,
    2499           pCtx->eax,                                                     pCtx->ecx,                           pCtx->edx,                           pCtx->ebx,
    25002513          pExit->CpuidAccess.DefaultResultRax, pExit->CpuidAccess.DefaultResultRcx, pExit->CpuidAccess.DefaultResultRdx, pExit->CpuidAccess.DefaultResultRbx));
    25012514
    2502     /* Move RIP and we're done. */
    2503     nemR3WinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pExit->VpContext);
    2504 
    2505     RT_NOREF_PV(pVM);
    2506     return VINF_SUCCESS;
     2515    int rc = nemHCWinCopyStateFromHyperV(pVM, pVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM);
     2516    AssertRCReturn(rc, rc);
     2517
     2518    VBOXSTRICTRC rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
     2519    return rcStrict;
    25072520}
    25082521#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
  • trunk/src/VBox/VMM/include/EMInternal.h

    r72560 r72569  
    493493    R3PTRTYPE(PAVLGCPTRNODECORE) pCliStatTree;
    494494    STAMCOUNTER             StatTotalClis;
    495 #if 0
    496     /** 64-bit Visual C++ rounds the struct size up to 16 byte. */
     495#if HC_ARCH_BITS == 32
    497496    uint64_t                padding1;
    498497#endif
     
    505504    /** Exit history table (6KB). */
    506505    EMEXITENTRY             aExitHistory[256];
     506    /** Number of exit records in use. */
     507    uint32_t                cExitRecordUsed;
     508    /** Number of exit records collisions. */
     509    uint32_t                cExitRecordCollisions;
     510    /** Exit records (32KB). (Aligned on 32 byte boundrary.) */
     511    EMEXITREC               aExitRecords[1024];
    507512} EMCPU;
    508513/** Pointer to EM VM instance data. */
  • trunk/src/VBox/VMM/include/NEMInternal.h

    r72555 r72569  
    4545 */
    4646# define NEM_WIN_USE_HYPERCALLS_FOR_PAGES
    47 # define NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
    48 # define NEM_WIN_USE_OUR_OWN_RUN_API
     47//# define NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
     48//# define NEM_WIN_USE_OUR_OWN_RUN_API
    4949# if defined(NEM_WIN_USE_OUR_OWN_RUN_API) && !defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS)
    5050#  error "NEM_WIN_USE_OUR_OWN_RUN_API requires NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS"
  • trunk/src/VBox/VMM/testcase/tstVMStructSize.cpp

    r70918 r72569  
    415415    CHECK_MEMBER_ALIGNMENT(EM, CritSectREM, sizeof(uintptr_t));
    416416#endif
     417    CHECK_MEMBER_ALIGNMENT(EMCPU, aExitRecords, sizeof(EMEXITREC));
    417418    CHECK_MEMBER_ALIGNMENT(PGM, CritSectX, sizeof(uintptr_t));
    418419    CHECK_MEMBER_ALIGNMENT(PDM, CritSect, sizeof(uintptr_t));
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