VirtualBox

Changeset 61648 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Jun 10, 2016 10:14:16 AM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
107998
Message:

VMM/HM: Better handling of edge-cases during exceptions caused as a result of event injection.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp

    r61605 r61648  
    22692269    /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
    22702270       and if we're injecting an event we should have a TRPM trap pending. */
    2271     AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("rcExit=%Rrc\n", rcExit));
    2272     AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("rcExit=%Rrc\n", rcExit));
     2271    AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT ||  TRPMHasTrap(pVCpu), ("rcExit=%Rrc\n", rcExit));
     2272    AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR     || !TRPMHasTrap(pVCpu), ("rcExit=%Rrc\n", rcExit));
    22732273
    22742274    /* Sync. the necessary state for going back to ring-3. */
     
    23662366    Log4(("hmR0SvmSetPendingEvent: u=%#RX64 u8Vector=%#x Type=%#x ErrorCodeValid=%RTbool ErrorCode=%#RX32\n", pEvent->u,
    23672367          pEvent->n.u8Vector, (uint8_t)pEvent->n.u3Type, !!pEvent->n.u1ErrorCodeValid, pEvent->n.u32ErrorCode));
    2368 
    2369     STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
    23702368}
    23712369
     
    24612459
    24622460    hmR0SvmSetPendingEvent(pVCpu, &Event, GCPtrFaultAddress);
    2463     STAM_COUNTER_DEC(&pVCpu->hm.s.StatInjectPendingReflect);
    24642461}
    24652462
     
    41984195
    41994196                Assert(pVmcb->ctrl.ExitIntInfo.n.u3Type != SVM_EVENT_SOFTWARE_INT);
     4197                STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
    42004198                hmR0SvmSetPendingEvent(pVCpu, &pVmcb->ctrl.ExitIntInfo, 0 /* GCPtrFaultAddress */);
    42014199
     
    42084206            case SVMREFLECTXCPT_DF:
    42094207            {
     4208                STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
    42104209                hmR0SvmSetPendingXcptDF(pVCpu);
    42114210                rc = VINF_HM_DOUBLE_FAULT;
     
    51085107    if ((u32ErrCode & (X86_TRAP_PF_RSVD | X86_TRAP_PF_P)) == (X86_TRAP_PF_RSVD | X86_TRAP_PF_P))
    51095108    {
     5109        /* If event delivery causes an MMIO #NPF, go back to instruction emulation as
     5110           otherwise injecting the original pending event would most likely cause the same MMIO #NPF. */
     5111        if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
     5112            return VERR_EM_INTERPRETER;
     5113
    51105114        VBOXSTRICTRC rc2 = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, enmNestedPagingMode, CPUMCTX2CORE(pCtx), GCPhysFaultAddr,
    51115115                                                         u32ErrCode);
     
    51895193
    51905194    /* Check if this task-switch occurred while delivering an event through the guest IDT. */
    5191     PSVMVMCB pVmcb = (PSVMVMCB)pVCpu->hm.s.svm.pvVmcb;
    5192     if (   !(pVmcb->ctrl.u64ExitInfo2 & (SVM_EXIT2_TASK_SWITCH_IRET | SVM_EXIT2_TASK_SWITCH_JMP))
    5193         && pVCpu->hm.s.Event.fPending)  /**  Can happen with exceptions/NMI. See @bugref{8411}.*/
     5195    if (pVCpu->hm.s.Event.fPending)  /* Can happen with exceptions/NMI. See @bugref{8411}. */
    51945196    {
    51955197        /*
     
    54165418    HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
    54175419
    5418     HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
     5420    /* Paranoia; Ensure we cannot be called as a result of event delivery. */
     5421    PSVMVMCB pVmcb = (PSVMVMCB)pVCpu->hm.s.svm.pvVmcb;
     5422    Assert(!pVmcb->ctrl.ExitIntInfo.n.u1Valid);
    54195423
    54205424    /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
     
    54685472    HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
    54695473
    5470     HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
     5474    /* Paranoia; Ensure we cannot be called as a result of event delivery. */
     5475    PSVMVMCB pVmcb = (PSVMVMCB)pVCpu->hm.s.svm.pvVmcb;
     5476    Assert(!pVmcb->ctrl.ExitIntInfo.n.u1Valid);
    54715477
    54725478    int rc = VERR_SVM_UNEXPECTED_XCPT_EXIT;
     
    55095515    HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
    55105516
    5511     HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
     5517    /* Paranoia; Ensure we cannot be called as a result of event delivery. */
     5518    PSVMVMCB pVmcb = (PSVMVMCB)pVCpu->hm.s.svm.pvVmcb;
     5519    Assert(!pVmcb->ctrl.ExitIntInfo.n.u1Valid);
    55125520
    55135521    STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
     
    55445552    HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
    55455553
     5554    /* If this #DB is the result of delivering an event, go back to the interpreter. */
    55465555    HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
     5556    if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
     5557    {
     5558        STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingInterpret);
     5559        return VERR_EM_INTERPRETER;
     5560    }
    55475561
    55485562    STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
  • trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp

    r61627 r61648  
    56595659    pVCpu->hm.s.Event.cbInstr           = cbInstr;
    56605660    pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
    5661 
    5662     STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
    56635661}
    56645662
     
    58195817
    58205818                /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF. See hmR0VmxExitXcptPF(). */
     5819                STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
    58215820                hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
    58225821                                       0 /* cbInstr */,  u32ErrCode, pMixedCtx->cr2);
     
    58305829            case VMXREFLECTXCPT_DF:
    58315830            {
     5831                STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
    58325832                hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
    58335833                rcStrict = VINF_HM_DOUBLE_FAULT;
     
    69136913
    69146914    hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
    6915     STAM_COUNTER_DEC(&pVCpu->hm.s.StatInjectPendingReflect);
    69166915}
    69176916
     
    1116811167        case VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT:
    1116911168        {
     11169            /*
     11170             * If there's any exception caused as a result of event injection, go back to
     11171             * the interpreter. The page-fault case is complicated and we manually handle
     11172             * any currently pending event in hmR0VmxExitXcptPF. Nested #ACs are already
     11173             * handled in hmR0VmxCheckExitDueToEventDelivery.
     11174             */
     11175            if (!pVCpu->hm.s.Event.fPending)
     11176            { /* likely */ }
     11177            else if (   uVector != X86_XCPT_PF
     11178                     && uVector != X86_XCPT_AC)
     11179            {
     11180                STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingInterpret);
     11181                rc = VERR_EM_INTERPRETER;
     11182                break;
     11183            }
     11184
    1117011185            switch (uVector)
    1117111186            {
     
    1252012535    HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
    1252112536
     12537    STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
     12538
    1252212539    /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
    1252312540    VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
    1252412541    if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
    12525     { /* likely */ }
     12542    {
     12543        /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
     12544        if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
     12545        {
     12546            STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingInterpret);
     12547            return VERR_EM_INTERPRETER;
     12548        }
     12549    }
    1252612550    else
    1252712551    {
     
    1258612610    }
    1258712611
    12588     STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
    1258912612    if (rcStrict2 != VINF_SUCCESS)
    1259012613        STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
     
    1269312716    VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
    1269412717    if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
    12695     { /* likely */ }
     12718    {
     12719        /* If event delivery causes an EPT misconfig (MMIO), go back to instruction emulation as otherwise
     12720           injecting the original pending event would most likely cause the same EPT misconfig VM-exit. */
     12721        if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
     12722        {
     12723            STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingInterpret);
     12724            return VERR_EM_INTERPRETER;
     12725        }
     12726    }
    1269612727    else
    1269712728    {
     
    1275112782    VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
    1275212783    if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
    12753     { /* likely */ }
     12784    {
     12785        /* In the unlikely case that the EPT violation happened as a result of delivering an event, log it. */
     12786        if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
     12787            Log4(("EPT violation with an event pending u64IntInfo=%#RX64\n", pVCpu->hm.s.Event.u64IntInfo));
     12788    }
    1275412789    else
    1275512790    {
  • trunk/src/VBox/VMM/VMMR3/HM.cpp

    r61647 r61648  
    897897        HM_REG_COUNTER(&pVCpu->hm.s.StatInjectInterrupt,        "/HM/CPU%d/EventInject/Interrupt", "Injected an external interrupt into the guest.");
    898898        HM_REG_COUNTER(&pVCpu->hm.s.StatInjectXcpt,             "/HM/CPU%d/EventInject/Trap", "Injected an exception into the guest.");
    899         HM_REG_COUNTER(&pVCpu->hm.s.StatInjectPendingReflect,   "/HM/CPU%d/EventInject/PendingReflect", "Reflecting an exception back to the guest.");
     899        HM_REG_COUNTER(&pVCpu->hm.s.StatInjectPendingReflect,   "/HM/CPU%d/EventInject/PendingReflect", "Reflecting an exception (or #DF) caused due to event injection.");
     900        HM_REG_COUNTER(&pVCpu->hm.s.StatInjectPendingInterpret, "/HM/CPU%d/EventInject/PendingInterpret", "Falling to interpreter for handling exception caused due to event injection.");
    900901
    901902        HM_REG_COUNTER(&pVCpu->hm.s.StatFlushPage,              "/HM/CPU%d/Flush/Page", "Invalidating a guest page on all guest CPUs.");
  • trunk/src/VBox/VMM/include/HMInternal.h

    r60850 r61648  
    929929    STAMCOUNTER             StatInjectXcpt;
    930930    STAMCOUNTER             StatInjectPendingReflect;
     931    STAMCOUNTER             StatInjectPendingInterpret;
    931932
    932933    STAMCOUNTER             StatExitAll;
Note: See TracChangeset for help on using the changeset viewer.

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