VirtualBox

Changeset 66701 in vbox


Ignore:
Timestamp:
Apr 27, 2017 4:49:12 PM (8 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
115095
Message:

VMM/HMVMXR0: Use IEM's event reflection logic.

File:
1 edited

Legend:

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

    r66390 r66701  
    58085808
    58095809/**
     5810 * Gets the IEM exception flags for the specified vector and IDT vectoring /
     5811 * VM-exit interruption info type.
     5812 *
     5813 * @returns The IEM exception flags.
     5814 * @param   uVector         The event vector.
     5815 * @param   uVmxVectorType  The VMX event type.
     5816 */
     5817static uint32_t hmR0VmxGetIemXcptFlags(uint8_t uVector, uint32_t uVmxVectorType)
     5818{
     5819    uint32_t fIemXcptFlags;
     5820    switch (uVmxVectorType)
     5821    {
     5822        case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
     5823        case VMX_IDT_VECTORING_INFO_TYPE_NMI:
     5824            fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
     5825            break;
     5826
     5827        case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
     5828            fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
     5829            break;
     5830
     5831        case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
     5832            fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_ICEBP_INSTR;
     5833            break;
     5834
     5835        case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
     5836        {
     5837            fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
     5838            if (uVector == X86_XCPT_BP)
     5839                fIemXcptFlags |= IEM_XCPT_FLAGS_BP_INSTR;
     5840            else if (uVector == X86_XCPT_OF)
     5841                fIemXcptFlags |= IEM_XCPT_FLAGS_OF_INSTR;
     5842            else
     5843            {
     5844                fIemXcptFlags = 0;
     5845                AssertMsgFailed(("Unexpected vector for software int. uVector=%#x", uVector));
     5846            }
     5847            break;
     5848        }
     5849
     5850        default:
     5851            fIemXcptFlags = 0;
     5852            AssertMsgFailed(("Unexpected vector type! uVmxVectorType=%#x uVector=%#x", uVmxVectorType, uVector));
     5853            break;
     5854    }
     5855    return fIemXcptFlags;
     5856}
     5857
     5858
     5859/**
    58105860 * Handle a condition that occurred while delivering an event through the guest
    58115861 * IDT.
     
    58385888        uint32_t uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo);
    58395889        uint32_t uIdtVector     = VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo);
    5840 
     5890#if 1
     5891        /* See Intel spec. 30.7.1.1 "Reflecting Exceptions to Guest Software". */
     5892        IEMXCPTRAISE     enmRaise;
     5893        IEMXCPTRAISEINFO fRaiseInfo;
     5894        if (VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo))
     5895        {
     5896            uint32_t const uExitVectorType  = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uExitIntInfo);
     5897            uint32_t const fIdtVectorFlags  = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType);
     5898            uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType);
     5899            AssertMsg(   uExitVectorType == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT
     5900                      || uExitVectorType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI,
     5901                      ("hmR0VmxCheckExitDueToEventDelivery: Unexpected VM-exit interruption info. type %#x!\n", uExitVectorType));
     5902            enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector,
     5903                                                &fRaiseInfo);
     5904        }
     5905        else
     5906        {
     5907            /*
     5908             * If event delivery caused an EPT violation/misconfig or APIC access VM-exit, then the VM-exit
     5909             * interruption-information will not be valid as it's not an exception and we end up here.
     5910             *
     5911             * If the event was an external interrupt or hardare exception (incl. NMI) it is sufficient to
     5912             * reflect this event to the guest after handling the VM-exit.
     5913             *
     5914             * If the event was a software interrupt (generated with INT n) or a software exception (generated
     5915             * by INT3/INTO) or a privileged software exception (generated by INT1), we can handle the VM-exit
     5916             * and continue guest execution which will re-execute the instruction rather than re-injecting the
     5917             * event, as that can cause premature trips to ring-3 before injection and involve TRPM which
     5918             * currently has no way of storing that the exceptions were caused by these special instructions.
     5919             */
     5920            if (   uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
     5921                || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
     5922                || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT)
     5923                enmRaise = IEMXCPTRAISE_PREV_EVENT;
     5924            else
     5925                enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
     5926            fRaiseInfo = IEMXCPTRAISEINFO_NONE;
     5927        }
     5928
     5929        /*
     5930         * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig
     5931         * etc.) occurred while delivering the NMI, we need to clear the block-by-NMI field in the guest
     5932         * interruptibility-state before re-delivering the NMI after handling the VM-exit. Otherwise the
     5933         * subsequent VM-entry would fail.
     5934         *
     5935         * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception". See @bugref{7445}.
     5936         */
     5937        if (   VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS)
     5938            && uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
     5939            && (   enmRaise   == IEMXCPTRAISE_PREV_EVENT
     5940                || fRaiseInfo == IEMXCPTRAISEINFO_NMI_PF)
     5941            && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI))
     5942        {
     5943            VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
     5944        }
     5945
     5946        switch (enmRaise)
     5947        {
     5948            case IEMXCPTRAISE_CURRENT_XCPT:
     5949            {
     5950                /*
     5951                 * Determine a vectoring #PF condition, see comment in hmR0VmxExitXcptPF().
     5952                 */
     5953                if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
     5954                    pVmxTransient->fVectoringPF = true;
     5955
     5956                /*
     5957                 * Determing a vectoring double #PF condition. Used later, when PGM evaluates the
     5958                 * second #PF as a guest #PF (and not a nested #PF) and needs to be converted into a #DF.
     5959                 */
     5960                if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
     5961                    pVmxTransient->fVectoringDoublePF = true;
     5962
     5963                Assert(rcStrict == VINF_SUCCESS);
     5964                break;
     5965            }
     5966
     5967            case IEMXCPTRAISE_PREV_EVENT:
     5968            {
     5969                /*
     5970                 * Re-raise the previous (first) exception/interrupt as delivery caused a premature VM-exit.
     5971                 */
     5972                Assert(   uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_SW_INT
     5973                       && uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
     5974                       && uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT);
     5975
     5976                uint32_t u32ErrCode;
     5977                if (VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uIdtVectoringInfo))
     5978                {
     5979                    rc2 = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
     5980                    AssertRCReturn(rc2, rc2);
     5981                    u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
     5982                }
     5983                else
     5984                    u32ErrCode = 0;
     5985
     5986                /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see hmR0VmxExitXcptPF(). */
     5987                STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
     5988                hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
     5989                                       0 /* cbInstr */, u32ErrCode, pMixedCtx->cr2);
     5990
     5991                Log4(("IDT: vcpu[%RU32] Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
     5992                      pVCpu->hm.s.Event.u32ErrCode));
     5993                Assert(rcStrict == VINF_SUCCESS);
     5994                break;
     5995            }
     5996
     5997            case IEMXCPTRAISE_DOUBLE_FAULT:
     5998            {
     5999                STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
     6000                hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
     6001
     6002                Log4(("IDT: vcpu[%RU32] Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->idCpu,
     6003                      pVCpu->hm.s.Event.u64IntInfo, uIdtVector, uExitVector));
     6004                rcStrict = VINF_HM_DOUBLE_FAULT;
     6005                break;
     6006            }
     6007
     6008            case IEMXCPTRAISE_TRIPLE_FAULT:
     6009            {
     6010                Log4(("IDT: vcpu[%RU32] Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", pVCpu->idCpu, uIdtVector,
     6011                      uExitVector));
     6012                rcStrict = VINF_EM_RESET;
     6013                break;
     6014            }
     6015
     6016            case IEMXCPTRAISE_CPU_HANG:
     6017            {
     6018                Log4(("IDT: vcpu[%RU32] Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", pVCpu->idCpu, fRaiseInfo));
     6019                rcStrict = VERR_EM_GUEST_CPU_HANG;
     6020                break;
     6021            }
     6022
     6023            case IEMXCPTRAISE_REEXEC_INSTR:
     6024                Assert(rcStrict == VINF_SUCCESS);
     6025                break;
     6026
     6027            default:
     6028            {
     6029                AssertMsgFailed(("IDT: vcpu[%RU32] Unexpected/invalid value! enmRaise=%#x\n", pVCpu->idCpu, enmRaise));
     6030                rcStrict = VERR_VMX_IPE_2;
     6031                break;
     6032            }
     6033        }
     6034#else
    58416035        typedef enum
    58426036        {
     
    59836177                break;
    59846178        }
     6179#endif
    59856180    }
    59866181    else if (   VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo)
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