VirtualBox

Ignore:
Timestamp:
Apr 14, 2013 4:19:03 PM (12 years ago)
Author:
vboxsync
Message:

VMM/VMMR0: HM bits.

File:
1 edited

Legend:

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

    r45534 r45543  
    124124                                   | RT_BIT(X86_XCPT_MF)             | RT_BIT(X86_XCPT_AC)    | RT_BIT(X86_XCPT_MC)    \
    125125                                   | RT_BIT(X86_XCPT_XF))
     126
     127/**
     128 * Exception bitmap mask for all contributory exceptions.
     129 */
     130#define VMX_CONTRIBUTORY_XCPT_BITMAP  ( RT_BIT(X86_XCPT_GP) | RT_BIT(X86_XCPT_NP) | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_TS) \
     131                                      | RT_BIT(X86_XCPT_DE))
    126132
    127133/** Maximum VM-instruction error number. */
     
    45774583
    45784584/**
     4585 * Determines if an exception is a contributory exception. Contributory
     4586 * exceptions are ones which can cause double-faults.
     4587 *
     4588 * @returns true if the exception is contributory, false otherwise.
     4589 * @param   uVector     The exception vector.
     4590 */
     4591DECLINLINE(bool) hmR0VmxIsContributoryXcpt(const uint32_t uVector)
     4592{
     4593    switch (uVector)
     4594    {
     4595        case X86_XCPT_GP:
     4596        case X86_XCPT_SS:
     4597        case X86_XCPT_NP:
     4598        case X86_XCPT_TS:
     4599        case X86_XCPT_DE:
     4600            return true;
     4601        default:
     4602            break;
     4603    }
     4604    return false;
     4605}
     4606
     4607
     4608/**
    45794609 * Determines if an exception is a benign exception. Benign exceptions
    45804610 * are ones which cannot cause double-faults.
     
    45854615DECLINLINE(bool) hmR0VmxIsBenignXcpt(const uint32_t uVector)
    45864616{
     4617    if (   uVector == X86_XCPT_PF
     4618        || uVector == X86_XCPT_DF)
     4619    {
     4620        return false;
     4621    }
     4622
     4623    bool fIsBenignXcpt = !hmR0VmxIsContributoryXcpt(uVector);
     4624#ifdef VBOX_STRICT
    45874625    switch (uVector)
    45884626    {
     
    45994637        case X86_XCPT_MC:
    46004638        case X86_XCPT_XF:
    4601             return true;
     4639            AssertMsg(fIsBenignXcpt, ("%#x\n", uVector));
     4640            break;
    46024641        default:
    4603             return false;
    4604     }
    4605 }
    4606 
    4607 
    4608 /**
    4609  * Determines if an exception is a contributory exception. Contributory
    4610  * exceptions are ones which can cause double-faults.
    4611  *
    4612  * @returns true if the exception is contributory, false otherwise.
    4613  * @param   uVector     The exception vector.
    4614  */
    4615 DECLINLINE(bool) hmR0VmxIsContributoryXcpt(const uint32_t uVector)
    4616 {
    4617     switch (uVector)
    4618     {
    4619         case X86_XCPT_GP:
    4620         case X86_XCPT_SS:
    4621         case X86_XCPT_NP:
    4622         case X86_XCPT_TS:
    4623         case X86_XCPT_DE:
    4624             return true;
    4625         default:
    4626             return false;
    4627     }
    4628     return false;
    4629 }
    4630 
    4631 
    4632 /**
    4633  * Determines if we are intercepting any contributory exceptions.
    4634  *
    4635  * @returns true if we are intercepting any contributory exception, false
    4636  *        otherwise.
     4642            AssertMsg(!fIsBenignXcpt, ("%#x\n", uVector));
     4643            break;
     4644    }
     4645#endif
     4646    return fIsBenignXcpt;
     4647}
     4648
     4649
     4650/**
     4651 * Determines if we are intercepting any contributory exceptions or page-faults.
     4652 *
     4653 * @returns true if we are intercepting them, false otherwise.
    46374654 * @param   pVCpu       Pointer to the VMCPU.
    46384655 */
    4639 DECLINLINE(bool) hmR0VmxInterceptingContributoryXcpts(PVMCPU pVCpu)
    4640 {
    4641     if (   (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_GP))
    4642         || (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_SS))
    4643         || (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_NP))
    4644         || (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_TS))
    4645         || (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_DE)))
    4646     {
     4656DECLINLINE(bool) hmR0VmxInterceptingContributoryXcptsOrPF(PVMCPU pVCpu)
     4657{
     4658    if (pVCpu->hm.s.vmx.u32XcptBitmap & (VMX_CONTRIBUTORY_XCPT_BITMAP | RT_BIT(X86_XCPT_PF)))
    46474659        return true;
    4648     }
    46494660    return false;
    46504661}
     
    46724683    pVCpu->hm.s.Event.cbInstr           = cbInstr;
    46734684    pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
     4685}
     4686
     4687
     4688/**
     4689 * Sets a double-fault (#DF) exception as pending-for-injection into the VM.
     4690 *
     4691 * @param   pVCpu           Pointer to the VMCPU.
     4692 * @param   pMixedCtx       Pointer to the guest-CPU context. The data may be
     4693 *                          out-of-sync. Make sure to update the required fields
     4694 *                          before using them.
     4695 */
     4696DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
     4697{
     4698    /* Inject the double-fault. */
     4699    uint32_t u32IntrInfo = X86_XCPT_DF | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
     4700    u32IntrInfo         |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
     4701    u32IntrInfo         |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
     4702    STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject);
     4703    hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo,  0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
    46744704}
    46754705
     
    47364766                enmReflect = VMXREFLECTXCPT_DF;
    47374767            }
    4738             else if (   hmR0VmxInterceptingContributoryXcpts(pVCpu)
     4768            else if (   hmR0VmxInterceptingContributoryXcptsOrPF(pVCpu)
    47394769                     && uIdtVector == X86_XCPT_PF
    47404770                     && hmR0VmxIsContributoryXcpt(uExitVector))
     
    47774807            case VMXREFLECTXCPT_DF:
    47784808            {
    4779                 uint32_t u32IntrInfo;
    4780                 u32IntrInfo  = X86_XCPT_DF | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
    4781                 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
    4782                 u32IntrInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
    4783                 hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
     4809                hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
    47844810                rc = VINF_VMX_DOUBLE_FAULT;
    4785                 Log(("Pending #DF %#RX64 uIdt=%#x uExit=%#x\n", pVCpu->hm.s.Event.u64IntrInfo, uIdtVector, uExitVector));
     4811                Log(("Pending #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntrInfo, uIdtVector,
     4812                     uExitVector));
    47864813                break;
    47874814            }
     
    55675594{
    55685595    if (!TRPMHasTrap(pVCpu))
     5596    {
     5597        Assert(!pVCpu->hm.s.Event.fPending);
    55695598        return;
     5599    }
    55705600
    55715601    uint8_t     uVector;
     
    55935623            }
    55945624
     5625            case X86_XCPT_PF:
     5626                pCtx->cr2 = GCPtrFaultAddress;
     5627                /* no break */
    55955628            case X86_XCPT_DF:
    55965629            case X86_XCPT_TS:
     
    55985631            case X86_XCPT_SS:
    55995632            case X86_XCPT_GP:
    5600             case X86_XCPT_PF:
    56015633            case X86_XCPT_AC:
    56025634                /* These exceptions must be delivered as hardware exceptions. They have error codes associated with
     
    56075639            {
    56085640                u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
    5609                 if (uVector == X86_XCPT_PF)
    5610                     pCtx->cr2 = TRPMGetFaultAddress(pVCpu);
    56115641                break;
    56125642            }
     
    56275657    rc = TRPMResetTrap(pVCpu);
    56285658    AssertRC(rc);
    5629     Log(("Converted TRPM trap: u32IntrInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u u32ErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
     5659    Log(("Converting TRPM trap: u32IntrInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u u32ErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
    56305660         u32IntrInfo, enmTrpmEvent, u32ErrCode, GCPtrFaultAddress));
    56315661    hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, cbInstr, u32ErrCode, GCPtrFaultAddress);
     
    58675897 *                          before using them.
    58685898 */
    5869 static int hmR0VmxInjectEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
     5899static int hmR0VmxInjectPendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
    58705900{
    58715901    /* Get the current interruptibility-state of the guest and then figure out what can be injected. */
    5872     uint32_t uIntrState  = hmR0VmxGetGuestIntrState(pVCpu, pMixedCtx);
     5902    uint32_t uIntrState    = hmR0VmxGetGuestIntrState(pVCpu, pMixedCtx);
    58735903    const bool fBlockMovSS = (uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
    58745904    const bool fBlockSti   = (uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
    58755905
    58765906    Assert(!fBlockSti || (pVCpu->hm.s.vmx.fUpdatedGuestState & VMX_UPDATED_GUEST_RFLAGS));
    5877     Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF);          /* Cannot set block-by-STI when interrupts are disabled. */
     5907    Assert(   !(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI)      /* We don't support block-by-NMI and SMI yet.*/
     5908           && !(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI));
     5909    Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF);       /* Cannot set block-by-STI when interrupts are disabled. */
    58785910
    58795911    int rc = VINF_SUCCESS;
    58805912    if (pVCpu->hm.s.Event.fPending)     /* First, inject any pending HM events. */
    58815913    {
    5882         uint32_t uIntrType = VMX_EXIT_INTERRUPTION_INFO_TYPE((uint32_t)pVCpu->hm.s.Event.u64IntrInfo);
     5914        uint32_t uIntrType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVCpu->hm.s.Event.u64IntrInfo);
    58835915        bool fInject = true;
    58845916        if (uIntrType == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
     
    59105942            pVCpu->hm.s.Event.fPending = false;
    59115943        }
     5944        else
     5945            hmR0VmxSetIntWindowExitVmcs(pVCpu);
    59125946    }                                                           /** @todo SMI. SMIs take priority over NMIs. */
    59135947    else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))    /* NMI. NMIs take priority over regular interrupts . */
    59145948    {
    59155949        /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
    5916         if (!fBlockMovSS && !fBlockSti)
     5950        if (   !fBlockMovSS
     5951            && !fBlockSti)
    59175952        {
    59185953            Log(("Injecting NMI\n"));
     
    59876022
    59886023/**
    5989  * Sets a double-fault (#DF) exception as pending-for-injection into the VM.
    5990  *
    5991  * @param   pVCpu           Pointer to the VMCPU.
    5992  * @param   pMixedCtx       Pointer to the guest-CPU context. The data may be
    5993  *                          out-of-sync. Make sure to update the required fields
    5994  *                          before using them.
    5995  */
    5996 DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
    5997 {
    5998     /* Inject the double-fault. */
    5999     uint32_t u32IntrInfo = X86_XCPT_DF | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
    6000     u32IntrInfo         |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
    6001     u32IntrInfo         |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
    6002     STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject);
    6003     hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo,  0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
    6004 }
    6005 
    6006 
    6007 /**
    60086024 * Injects a double-fault (#DF) exception into the VM.
    60096025 *
     
    65486564     * This is why this is done after all possible exits-to-ring-3 paths in this code.
    65496565     */
    6550     rc = hmR0VmxInjectEvent(pVCpu, pMixedCtx);
     6566    rc = hmR0VmxInjectPendingEvent(pVCpu, pMixedCtx);
    65516567    AssertRCReturn(rc, rc);
    65526568    return rc;
     
    80688084        {
    80698085            uint32_t uIntType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo);
     8086            /* Software interrupts and exceptions will be regenerated when the recompiler restarts the instruction. */
    80708087            if (   uIntType != VMX_IDT_VECTORING_INFO_TYPE_SW_INT
    80718088                && uIntType != VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
     
    80738090            {
    80748091                /* Save it as a pending event and it'll be converted to a TRPM event on the way out to ring-3. */
     8092                Log(("Pending event on TaskSwitch uIntrType=%#x uVector=%#x\n", uIntType,
     8093                     VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo)));
     8094                Assert(!pVCpu->hm.s.Event.fPending);
    80758095                pVCpu->hm.s.Event.fPending = true;
    80768096                pVCpu->hm.s.Event.u64IntrInfo = pVmxTransient->uIdtVectoringInfo;
     
    88048824        {
    88058825            /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
     8826            Log(("Pending #DF due to vectoring #PF.\n"));
    88068827            rc = hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
    88078828        }
     
    88838904            TRPMResetTrap(pVCpu);
    88848905            hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
    8885             Log(("#PF: Pending #DF injection\n"));
    8886         }
     8906            Log(("#PF: Pending #DF due to vectoring #PF\n"));
     8907        }
     8908
    88878909        STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
    88888910        return VINF_SUCCESS;
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