VirtualBox

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


Ignore:
Timestamp:
Jan 29, 2018 5:24:06 AM (7 years ago)
Author:
vboxsync
Message:

VMM: Nested Hw.virt: Clean up interrupt injection for nested-guests.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/CPUMAllRegs.cpp

    r70732 r70781  
    25852585
    25862586/**
    2587  * Checks whether the SVM nested-guest is in a state to receive virtual
    2588  * (injected by VMRUN) interrupts.
     2587 * Checks whether the SVM nested-guest is in a state to receive virtual (setup
     2588 * for injection by VMRUN instruction) interrupts.
    25892589 *
    25902590 * @returns VBox status code.
    25912591 * @retval  true if it's ready, false otherwise.
    25922592 *
    2593  * @param   pCtx        The guest-CPU context.
    2594  */
    2595 VMM_INT_DECL(bool) CPUMCanSvmNstGstTakeVirtIntr(PCCPUMCTX pCtx)
     2593 * @param   pVCpu   The cross context virtual CPU structure of the calling EMT.
     2594 * @param   pCtx    The guest-CPU context.
     2595 */
     2596VMM_INT_DECL(bool) CPUMCanSvmNstGstTakeVirtIntr(PVMCPU pVCpu, PCCPUMCTX pCtx)
    25962597{
    25972598#ifdef IN_RC
    2598     RT_NOREF(pCtx);
     2599    RT_NOREF2(pVCpu, pCtx);
    25992600    AssertReleaseFailedReturn(false);
    26002601#else
    26012602    Assert(CPUMIsGuestInSvmNestedHwVirtMode(pCtx));
    26022603    Assert(pCtx->hwvirt.fGif);
    2603 
    2604     PCSVMVMCBCTRL pVmcbCtrl = &pCtx->hwvirt.svm.CTX_SUFF(pVmcb)->ctrl;
    2605     if (   !pVmcbCtrl->IntCtrl.n.u1IgnoreTPR
    2606         &&  pVmcbCtrl->IntCtrl.n.u4VIntrPrio <= pVmcbCtrl->IntCtrl.n.u8VTPR)
    2607         return false;
    2608 
    2609     if (!pCtx->rflags.Bits.u1IF)
    2610         return false;
    2611 
    2612     return true;
     2604    Assert(pCtx->hwvirt.fGif);
     2605
     2606    /*
     2607     * Although at present, the V_TPR and V_INTR_PRIO fields are not modified
     2608     * by SVM R0 code and we could inspect them directly here, we play it
     2609     * safe and ask HM if it has cached the VMCB.
     2610     */
     2611    if (!pCtx->hwvirt.svm.fHMCachedVmcb)
     2612    {
     2613        PCSVMVMCBCTRL pVmcbCtrl = &pCtx->hwvirt.svm.CTX_SUFF(pVmcb)->ctrl;
     2614        if (   !pVmcbCtrl->IntCtrl.n.u1IgnoreTPR
     2615            &&  pVmcbCtrl->IntCtrl.n.u4VIntrPrio <= pVmcbCtrl->IntCtrl.n.u8VTPR)
     2616            return false;
     2617
     2618        X86EFLAGS fEFlags;
     2619        if (pVmcbCtrl->IntCtrl.n.u1VIntrMasking)
     2620            fEFlags.u = pCtx->eflags.u;
     2621        else
     2622            fEFlags.u = pCtx->hwvirt.svm.HostState.rflags.u;
     2623
     2624        return fEFlags.Bits.u1IF;
     2625    }
     2626
     2627    return HMCanSvmNstGstTakeVirtIntr(pVCpu, pCtx);
    26132628#endif
    26142629}
  • trunk/src/VBox/VMM/VMMAll/HMSVMAll.cpp

    r70700 r70781  
    535535    else
    536536        fEFlags.u = pCtx->eflags.u;
    537 
    538537    return fEFlags.Bits.u1IF;
    539538}
    540539
     540
     541/**
     542 * Checks whether the SVM nested-guest is in a state to receive virtual (setup
     543 * for injection by VMRUN instruction) interrupts.
     544 *
     545 * @returns true if it's ready, false otherwise.
     546 * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
     547 * @param   pCtx        The guest-CPU context.
     548 *
     549 * @remarks This function looks at the VMCB cache rather than directly at the
     550 *          nested-guest VMCB. The latter may have been modified for executing
     551 *          using hardware-assisted SVM.
     552 *
     553 * @sa      CPUMCanSvmNstGstTakeVirtIntr.
     554 */
     555VMM_INT_DECL(bool) HMCanSvmNstGstTakeVirtIntr(PVMCPU pVCpu, PCCPUMCTX pCtx)
     556{
     557#ifdef IN_RC
     558    RT_NOREF2(pVCpu, pCtx);
     559    AssertReleaseFailedReturn(false);
     560#else
     561    Assert(pCtx->hwvirt.svm.fHMCachedVmcb);
     562    PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
     563
     564    PCSVMVMCBCTRL pVmcbCtrl = &pCtx->hwvirt.svm.CTX_SUFF(pVmcb)->ctrl;
     565    if (   !pVmcbCtrl->IntCtrl.n.u1IgnoreTPR
     566        &&  pVmcbCtrl->IntCtrl.n.u4VIntrPrio <= pVmcbCtrl->IntCtrl.n.u8VTPR)
     567        return false;
     568
     569    X86EFLAGS fEFlags;
     570    if (pVmcbNstGstCache->fVIntrMasking)
     571        fEFlags.u = pCtx->eflags.u;
     572    else
     573        fEFlags.u = pCtx->hwvirt.svm.HostState.rflags.u;
     574    return fEFlags.Bits.u1IF;
     575#endif
     576}
     577
  • trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp

    r70732 r70781  
    35053505             * by the physical CPU.
    35063506             */
     3507            /** @todo later explore this for performance reasons. Right now the hardware
     3508             *        takes care of virtual interrupt injection for nested-guest. */
    35073509#if 0
    35083510            if (   VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST)
    35093511                && (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_VINTR)
    3510                 && CPUMCanSvmNstGstTakeVirtIntr(pCtx))
     3512                && CPUMCanSvmNstGstTakeVirtIntr(pVCpu, pCtx))
    35113513            {
    35123514                Log4(("Intercepting virtual interrupt -> #VMEXIT\n"));
     
    36413643    if (fGif)
    36423644    {
     3645        /*
     3646         * For nested-guests we have no way to determine if we're injecting a physical or virtual
     3647         * interrupt at this point. Hence the partial verification below.
     3648         */
    36433649        if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
    3644             fAllowInt = CPUMCanSvmNstGstTakePhysIntr(pVCpu, pCtx);
     3650            fAllowInt = CPUMCanSvmNstGstTakePhysIntr(pVCpu, pCtx) || CPUMCanSvmNstGstTakeVirtIntr(pVCpu, pCtx);
    36453651        else
    36463652            fAllowInt = RT_BOOL(pCtx->eflags.u32 & X86_EFL_IF);
     
    36813687    }
    36823688    else
    3683     {
    3684 #ifdef VBOX_WITH_NESTED_HWVIRT
    3685         /*
    3686          * If IEM emulated VMRUN and injected an event, it would not clear the EVENTINJ::Valid bit
    3687          * as a physical CPU clears it in the VMCB as part of the #VMEXIT (if the AMD spec. is to
    3688          * believed, real behavior might differ). Regardless, IEM does it only on #VMEXIT for now
    3689          * and since we are continuing nested-guest execution using hardware-assisted SVM, we need
    3690          * to clear this field otherwise we will inject the event twice, see @bugref{7243#78}.
    3691          */
    3692         if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
    3693             pVmcb->ctrl.EventInject.n.u1Valid = 0;
    3694 #endif
    36953689        Assert(pVmcb->ctrl.EventInject.n.u1Valid == 0);
    3696     }
    36973690
    36983691    /*
  • trunk/src/VBox/VMM/VMMR3/EM.cpp

    r70732 r70781  
    16411641}
    16421642
     1643#ifdef VBOX_WITH_NESTED_HWVIRT
     1644/**
     1645 * Helper for emR3ForcedActions() for injecting interrupts into the
     1646 * nested-guest.
     1647 *
     1648 * @returns VBox status code.
     1649 * @param   pVCpu       The cross context virtual CPU structure.
     1650 * @param   pCtx        Pointer to the nested-guest CPU context.
     1651 * @param   pfResched   Where to store whether a reschedule is required.
     1652 * @param   pfInject    Where to store whether an interrupt was injected (and if
     1653 *                      a wake up is pending).
     1654 */
     1655static int emR3NstGstInjectIntr(PVMCPU pVCpu, PCPUMCTX pCtx, bool *pfResched, bool *pfInject)
     1656{
     1657    *pfResched = false;
     1658    *pfInject  = false;
     1659    if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
     1660    {
     1661        PVM  pVM  = pVCpu->CTX_SUFF(pVM);
     1662        bool fGif = pCtx->hwvirt.fGif;
     1663#ifdef VBOX_WITH_RAW_MODE
     1664        fGif &= !PATMIsPatchGCAddr(pVM, pCtx->eip);
     1665#endif
     1666        if (fGif)
     1667        {
     1668            if (CPUMCanSvmNstGstTakePhysIntr(pVCpu, pCtx))
     1669            {
     1670                Assert(pVCpu->em.s.enmState != EMSTATE_WAIT_SIPI);
     1671                if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
     1672                {
     1673                    if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, pCtx, SVM_CTRL_INTERCEPT_INTR))
     1674                    {
     1675                        VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_INTR, 0, 0);
     1676                        if (RT_SUCCESS(rcStrict))
     1677                        {
     1678                            /** @todo r=ramshankar: Do we need to signal a wakeup here? If a nested-guest
     1679                             *        doesn't intercept HLT but intercepts INTR? */
     1680                            *pfResched = true;
     1681                            return VINF_EM_RESCHEDULE;
     1682                        }
     1683
     1684                        AssertMsgFailed(("INTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
     1685                        return VINF_EM_TRIPLE_FAULT;
     1686                    }
     1687
     1688                    /* Note: it's important to make sure the return code from TRPMR3InjectEvent isn't ignored! */
     1689                    /** @todo this really isn't nice, should properly handle this */
     1690                    int rc = TRPMR3InjectEvent(pVM, pVCpu, TRPM_HARDWARE_INT);
     1691                    if (pVM->em.s.fIemExecutesAll && (   rc == VINF_EM_RESCHEDULE_REM
     1692                                                      || rc == VINF_EM_RESCHEDULE_HM
     1693                                                      || rc == VINF_EM_RESCHEDULE_RAW))
     1694                    {
     1695                        rc = VINF_EM_RESCHEDULE;
     1696                    }
     1697
     1698                    *pfResched = true;
     1699                    *pfInject  = true;
     1700                    return rc;
     1701                }
     1702            }
     1703
     1704            if (   VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST)
     1705                && CPUMCanSvmNstGstTakeVirtIntr(pVCpu, pCtx))
     1706            {
     1707                if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, pCtx, SVM_CTRL_INTERCEPT_VINTR))
     1708                {
     1709                    VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_VINTR, 0, 0);
     1710                    if (RT_SUCCESS(rcStrict))
     1711                    {
     1712                        /** @todo r=ramshankar: Do we need to signal a wakeup here? If a nested-guest
     1713                         *        doesn't intercept HLT but intercepts VINTR? */
     1714                        *pfResched = true;
     1715                        return VINF_EM_RESCHEDULE;
     1716                    }
     1717
     1718                    AssertMsgFailed(("VINTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
     1719                    return VINF_EM_TRIPLE_FAULT;
     1720                }
     1721
     1722                VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST);
     1723                uint8_t const uNstGstVector = CPUMGetSvmNstGstInterrupt(pCtx);
     1724                AssertMsg(uNstGstVector > 0 && uNstGstVector <= X86_XCPT_LAST, ("Invalid VINTR vector %#x\n", uNstGstVector));
     1725                TRPMAssertTrap(pVCpu, uNstGstVector, TRPM_HARDWARE_INT);
     1726                Log(("EM: Asserting nested-guest virt. hardware intr: %#x\n", uNstGstVector));
     1727
     1728                *pfResched = true;
     1729                *pfInject  = true;
     1730                return VINF_EM_RESCHEDULE;
     1731            }
     1732        }
     1733        return VINF_SUCCESS;
     1734    }
     1735
     1736    if (CPUMIsGuestInVmxNestedHwVirtMode(pCtx))
     1737    { /** @todo Nested VMX. */ }
     1738
     1739    /* Shouldn't really get here. */
     1740    AssertMsgFailed(("Unrecognized nested hwvirt. arch!\n"));
     1741    return VERR_EM_INTERNAL_ERROR;
     1742}
     1743#endif
    16431744
    16441745/**
     
    19512052         * Interrupts.
    19522053         */
    1953         /** @todo this can be optimized a bit. later.   */
    19542054        bool fWakeupPending = false;
    19552055        if (    !VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY)
     
    19592059                && !TRPMHasTrap(pVCpu)) /* an interrupt could already be scheduled for dispatching in the recompiler. */
    19602060            {
     2061                Assert(!HMR3IsEventPending(pVCpu));
    19612062                PCPUMCTX pCtx = pVCpu->em.s.pCtx;
    1962                 bool fGif     = pCtx->hwvirt.fGif;
     2063#ifdef VBOX_WITH_NESTED_HWVIRT
     2064                if (CPUMIsGuestInNestedHwVirtMode(pCtx))
     2065                {
     2066                    bool fResched, fInject;
     2067                    rc2 = emR3NstGstInjectIntr(pVCpu, pCtx, &fResched, &fInject);
     2068                    if (fInject)
     2069                    {
     2070                        fWakeupPending = true;
     2071#ifdef VBOX_STRICT
     2072                        rcIrq = rc2;
     2073#endif
     2074                    }
     2075                    if (fResched)
     2076                        UPDATE_RC();
     2077                }
     2078                else
     2079#endif
     2080                {
     2081                    if (   VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
     2082#ifdef VBOX_WITH_NESTED_HWVIRT
     2083                        && pCtx->hwvirt.fGif
     2084#endif
    19632085#ifdef VBOX_WITH_RAW_MODE
    1964                 /* We cannot just inspect EFLAGS when nested hw.virt is enabled (see e.g. CPUMCanSvmNstGstTakePhysIntr). */
    1965                 fGif &= !PATMIsPatchGCAddr(pVM, pCtx->eip);
    1966 #endif
    1967                 if (fGif)
    1968                 {
    1969                     bool fIntrEnabled;
    1970 #ifdef VBOX_WITH_NESTED_HWVIRT
    1971                     if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
    1972                         fIntrEnabled = CPUMCanSvmNstGstTakePhysIntr(pVCpu, pCtx);
    1973                     else
    1974                         fIntrEnabled = pCtx->eflags.Bits.u1IF;
    1975 #else
    1976                     fIntrEnabled = pCtx->eflags.Bits.u1IF;
    1977 #endif
    1978                     if (fIntrEnabled)
     2086                        && !PATMIsPatchGCAddr(pVM, pCtx->eip)
     2087#endif
     2088                        && pCtx->eflags.Bits.u1IF)
    19792089                    {
    1980                         Assert(!HMR3IsEventPending(pVCpu));
    19812090                        Assert(pVCpu->em.s.enmState != EMSTATE_WAIT_SIPI);
    1982                         if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
     2091                        /* Note: it's important to make sure the return code from TRPMR3InjectEvent isn't ignored! */
     2092                        /** @todo this really isn't nice, should properly handle this */
     2093                        rc2 = TRPMR3InjectEvent(pVM, pVCpu, TRPM_HARDWARE_INT);
     2094                        if (pVM->em.s.fIemExecutesAll && (   rc2 == VINF_EM_RESCHEDULE_REM
     2095                                                          || rc2 == VINF_EM_RESCHEDULE_HM
     2096                                                          || rc2 == VINF_EM_RESCHEDULE_RAW))
    19832097                        {
    1984 #ifdef VBOX_WITH_NESTED_HWVIRT
    1985                             if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, pCtx, SVM_CTRL_INTERCEPT_INTR))
    1986                             {
    1987                                 VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_INTR, 0, 0);
    1988                                 if (RT_SUCCESS(rcStrict))
    1989                                     rc2 = VINF_EM_RESCHEDULE;
    1990                                 else
    1991                                 {
    1992                                     AssertMsgFailed(("INTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
    1993                                     Log(("EM: SVM Nested-guest INTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
    1994                                     /** @todo should we call iemInitiateCpuShutdown? Should this
    1995                                      *        result in trapping triple-fault intercepts? */
    1996                                     rc2 = VINF_EM_TRIPLE_FAULT;
    1997                                 }
    1998                             }
    1999                             else
    2000 #endif
    2001                             {
    2002                                 /* Note: it's important to make sure the return code from TRPMR3InjectEvent isn't ignored! */
    2003                                 /** @todo this really isn't nice, should properly handle this */
    2004                                 rc2 = TRPMR3InjectEvent(pVM, pVCpu, TRPM_HARDWARE_INT);
    2005                                 if (pVM->em.s.fIemExecutesAll && (   rc2 == VINF_EM_RESCHEDULE_REM
    2006                                                                   || rc2 == VINF_EM_RESCHEDULE_HM
    2007                                                                   || rc2 == VINF_EM_RESCHEDULE_RAW))
    2008                                     rc2 = VINF_EM_RESCHEDULE;
    2009 #ifdef VBOX_STRICT
    2010                                 rcIrq = rc2;
    2011 #endif
    2012                             }
    2013                             UPDATE_RC();
    2014                             /* Reschedule required: We must not miss the wakeup below! */
    2015                             fWakeupPending = true;
    2016                         }
    2017                     }
    2018 #ifdef VBOX_WITH_NESTED_HWVIRT
    2019                     /*
    2020                      * Check nested-guest virtual interrupts.
    2021                      */
    2022                     else if (   VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST)
    2023                              && CPUMCanSvmNstGstTakeVirtIntr(pCtx))
    2024                     {
    2025                         if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, pCtx, SVM_CTRL_INTERCEPT_VINTR))
    2026                         {
    2027                             VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_VINTR, 0, 0);
    2028                             if (RT_SUCCESS(rcStrict))
    2029                                 rc2 = VINF_EM_RESCHEDULE;
    2030                             else
    2031                             {
    2032                                 AssertMsgFailed(("VINTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
    2033                                 Log(("EM: SVM Nested-guest VINTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
    2034                                 /** @todo should we call iemInitiateCpuShutdown? Should this
    2035                                  *        result in trapping triple-fault intercepts? */
    2036                                 rc2 = VINF_EM_TRIPLE_FAULT;
    2037                             }
    2038                         }
    2039                         else
    2040                         {
    2041                             /*
    2042                              * Prepare the nested-guest interrupt for injection.
    2043                              */
    2044                             VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST);
    2045                             uint8_t uNstGstVector = CPUMGetSvmNstGstInterrupt(pCtx);
    2046                             TRPMAssertTrap(pVCpu, uNstGstVector, TRPM_HARDWARE_INT);
    2047                             Log(("EM: Asserting nested-guest virt. hardware intr: %#x\n", uNstGstVector));
    2048                             /** @todo reschedule to HM/REM later, when the HMR0 nested-guest execution is
    2049                              *  done. For now just reschedule to IEM. */
    20502098                            rc2 = VINF_EM_RESCHEDULE;
    20512099                        }
     2100#ifdef VBOX_STRICT
     2101                        rcIrq = rc2;
     2102#endif
    20522103                        UPDATE_RC();
    20532104                        /* Reschedule required: We must not miss the wakeup below! */
    20542105                        fWakeupPending = true;
    20552106                    }
    2056 #endif  /* VBOX_WITH_NESTED_HWVIRT */
    20572107                }
    20582108            }
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