VirtualBox

Changeset 74876 in vbox


Ignore:
Timestamp:
Oct 17, 2018 8:30:25 AM (6 years ago)
Author:
vboxsync
Message:

VMM/EM: Nested VMX: bugref:9180 Add interrupt-window VM-exit and adjusted event injection code in EM.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR3/EM.cpp

    r74791 r74876  
    17101710}
    17111711
     1712
     1713/**
     1714 * Helper for emR3ForcedActions() for injecting interrupts into the
     1715 * guest.
     1716 *
     1717 * @returns VBox status code.
     1718 * @param   pVCpu               The cross context virtual CPU structure.
     1719 * @param   pfWakeupPending     Where to store whether a wake up from HLT state is
     1720 *                              pending.
     1721 * @param   pfInjected          Where to store whether an interrupt was injected.
     1722 */
     1723DECLINLINE(int) emR3GstInjectIntr(PVMCPU pVCpu, bool *pfWakeupPending, bool *pfInjected)
     1724{
     1725    CPUM_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RFLAGS);
     1726    *pfWakeupPending = false;
     1727    *pfInjected      = false;
     1728
     1729    if (   VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
    17121730#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
     1731        && pVCpu->cpum.GstCtx.hwvirt.fGif
     1732#endif
     1733#ifdef VBOX_WITH_RAW_MODE
     1734        && !PATMIsPatchGCAddr(pVCpu->CTX_SUFF(pVM), pVCpu->cpum.GstCtx.eip)
     1735#endif
     1736        && pVCpu->cpum.GstCtx.eflags.Bits.u1IF)
     1737    {
     1738        Assert(pVCpu->em.s.enmState != EMSTATE_WAIT_SIPI);
     1739        /* Note: it's important to make sure the return code from TRPMR3InjectEvent isn't ignored! */
     1740        /** @todo this really isn't nice, should properly handle this */
     1741        CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_XCPT_MASK);
     1742        int rc2 = TRPMR3InjectEvent(pVCpu->CTX_SUFF(pVM), pVCpu, TRPM_HARDWARE_INT);
     1743        Assert(rc2 != VINF_VMX_VMEXIT && rc2 != VINF_SVM_VMEXIT);
     1744        Log(("EM: TRPMR3InjectEvent -> %d\n", rc2));
     1745        *pfWakeupPending = true;
     1746        *pfInjected      = true;
     1747        return rc2;
     1748    }
     1749
     1750    return VINF_NO_CHANGE;
     1751}
     1752
     1753
     1754#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    17131755/**
    17141756 * Helper for emR3ForcedActions() for injecting interrupts into the
    1715  * nested-guest.
     1757 * VMX nested-guest.
    17161758 *
    17171759 * @returns VBox status code.
    1718  * @param   pVCpu       The cross context virtual CPU structure.
    1719  * @param   pfResched   Where to store whether a reschedule is required.
    1720  * @param   pfInject    Where to store whether an interrupt was injected (and if
    1721  *                      a wake up is pending).
    1722  */
    1723 static int emR3NstGstInjectIntr(PVMCPU pVCpu, bool *pfResched, bool *pfInject)
    1724 {
    1725     *pfResched = false;
    1726     *pfInject  = false;
    1727     if (CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.GstCtx))
    1728     {
    1729         PVM pVM  = pVCpu->CTX_SUFF(pVM);
    1730         Assert(pVCpu->cpum.GstCtx.hwvirt.fGif);
    1731         bool fVirtualGif = CPUMGetSvmNstGstVGif(&pVCpu->cpum.GstCtx);
     1760 * @param   pVCpu               The cross context virtual CPU structure.
     1761 * @param   pfWakeupPending     Where to store whether a wake up from HLT state is
     1762 *                              pending.
     1763 * @param   pfInjected          Where to store whether an interrrupt was injected.
     1764 */
     1765static int emR3VmxNstGstInjectIntr(PVMCPU pVCpu, bool *pfWakeupPending, bool *pfInjected)
     1766{
     1767    Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
     1768    *pfWakeupPending = false;
     1769    *pfInjected      = false;
     1770
     1771    /** @todo NSTVMX: Virtual interrupt injection. */
     1772    if (   pVCpu->cpum.GstCtx.eflags.Bits.u1IF
     1773        && VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
     1774    {
     1775        if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT))
     1776        {
     1777            /* CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_SVM_VMEXIT_MASK); */ /** @todo NSTVMX: Mask. */
     1778            VBOXSTRICTRC rcStrict = IEMExecVmxVmexitIntWindow(pVCpu);
     1779            if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
     1780            {
     1781                *pfWakeupPending = true;
     1782                if (RT_SUCCESS(rcStrict))
     1783                {
     1784                    Assert(rcStrict != VINF_PGM_CHANGE_MODE);
     1785                    if (rcStrict == VINF_VMX_VMEXIT)
     1786                        return VINF_SUCCESS;
     1787                    return VBOXSTRICTRC_VAL(rcStrict);
     1788                }
     1789                AssertMsgFailed(("Interrupt-window Vm-exit failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
     1790                return VINF_EM_TRIPLE_FAULT;
     1791            }
     1792        }
     1793
     1794        int rc = emR3GstInjectIntr(pVCpu, pfWakeupPending, pfInjected);
     1795        if (rc == VINF_VMX_VMEXIT)
     1796            rc = VINF_SUCCESS;
     1797        return rc;
     1798    }
     1799
     1800    return VINF_NO_CHANGE;
     1801}
     1802#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
     1803
     1804#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
     1805/**
     1806 * Helper for emR3ForcedActions() for injecting interrupts into the
     1807 * SVM nested-guest.
     1808 *
     1809 * @returns VBox status code.
     1810 * @param   pVCpu               The cross context virtual CPU structure.
     1811 * @param   pfWakeupPending     Where to store whether a wake up from HLT state is
     1812 *                              pending.
     1813 * @param   pfInjected          Where to store whether an interrupt was injected.
     1814 */
     1815static int emR3SvmNstGstInjectIntr(PVMCPU pVCpu, bool *pfWakeupPending, bool *pfInjected)
     1816{
     1817    Assert(CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.GstCtx));
     1818    *pfWakeupPending = false;
     1819    *pfInjected      = false;
     1820
     1821    PVM pVM  = pVCpu->CTX_SUFF(pVM);
     1822    Assert(pVCpu->cpum.GstCtx.hwvirt.fGif);
     1823    bool fVirtualGif = CPUMGetSvmNstGstVGif(&pVCpu->cpum.GstCtx);
    17321824#ifdef VBOX_WITH_RAW_MODE
    1733         fVirtualGif     &= !PATMIsPatchGCAddr(pVM, pVCpu->cpum.GstCtx.eip);
    1734 #endif
    1735         if (fVirtualGif)
    1736         {
    1737             if (CPUMCanSvmNstGstTakePhysIntr(pVCpu, &pVCpu->cpum.GstCtx))
     1825    fVirtualGif     &= !PATMIsPatchGCAddr(pVM, pVCpu->cpum.GstCtx.eip);
     1826#endif
     1827    if (fVirtualGif)
     1828    {
     1829        if (CPUMCanSvmNstGstTakePhysIntr(pVCpu, &pVCpu->cpum.GstCtx))
     1830        {
     1831            Assert(pVCpu->em.s.enmState != EMSTATE_WAIT_SIPI);
     1832            if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
    17381833            {
    1739                 Assert(pVCpu->em.s.enmState != EMSTATE_WAIT_SIPI);
    1740                 if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
    1741                 {
    1742                     if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, &pVCpu->cpum.GstCtx, SVM_CTRL_INTERCEPT_INTR))
    1743                     {
    1744                         CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_SVM_VMEXIT_MASK);
    1745                         VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_INTR, 0, 0);
    1746                         if (RT_SUCCESS(rcStrict))
    1747                         {
    1748                             /** @todo r=ramshankar: Do we need to signal a wakeup here? If a nested-guest
    1749                              *        doesn't intercept HLT but intercepts INTR? */
    1750                             *pfResched = true;
    1751                             Assert(rcStrict != VINF_PGM_CHANGE_MODE);
    1752                             if (rcStrict == VINF_SVM_VMEXIT)
    1753                                 return VINF_SUCCESS;
    1754                             return VBOXSTRICTRC_VAL(rcStrict);
    1755                         }
    1756 
    1757                         AssertMsgFailed(("INTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
    1758                         return VINF_EM_TRIPLE_FAULT;
    1759                     }
    1760 
    1761                     /* Note: it's important to make sure the return code from TRPMR3InjectEvent isn't ignored! */
    1762                     /** @todo this really isn't nice, should properly handle this */
    1763                     CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_XCPT_MASK);
    1764                     int rc = TRPMR3InjectEvent(pVM, pVCpu, TRPM_HARDWARE_INT);
    1765                     Assert(rc != VINF_PGM_CHANGE_MODE);
    1766                     if (rc == VINF_SVM_VMEXIT)
    1767                         rc = VINF_SUCCESS;
    1768                     if (pVM->em.s.fIemExecutesAll && (   rc == VINF_EM_RESCHEDULE_REM
    1769                                                       || rc == VINF_EM_RESCHEDULE_HM
    1770                                                       || rc == VINF_EM_RESCHEDULE_RAW))
    1771                     {
    1772                         rc = VINF_EM_RESCHEDULE;
    1773                     }
    1774 
    1775                     *pfResched = true;
    1776                     *pfInject  = true;
    1777                     return rc;
    1778                 }
    1779             }
    1780 
    1781             if (   VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST)
    1782                 && CPUMCanSvmNstGstTakeVirtIntr(pVCpu, &pVCpu->cpum.GstCtx))
    1783             {
    1784                 if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, &pVCpu->cpum.GstCtx, SVM_CTRL_INTERCEPT_VINTR))
     1834                if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, &pVCpu->cpum.GstCtx, SVM_CTRL_INTERCEPT_INTR))
    17851835                {
    17861836                    CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_SVM_VMEXIT_MASK);
    1787                     VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_VINTR, 0, 0);
     1837                    VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_INTR, 0, 0);
    17881838                    if (RT_SUCCESS(rcStrict))
    17891839                    {
    17901840                        /** @todo r=ramshankar: Do we need to signal a wakeup here? If a nested-guest
    1791                          *        doesn't intercept HLT but intercepts VINTR? */
    1792                         *pfResched = true;
     1841                         *        doesn't intercept HLT but intercepts INTR? */
    17931842                        Assert(rcStrict != VINF_PGM_CHANGE_MODE);
    17941843                        if (rcStrict == VINF_SVM_VMEXIT)
    1795                             return VINF_SUCCESS;
     1844                            rcStrict = VINF_SUCCESS;
     1845                        *pfWakeupPending = true;
    17961846                        return VBOXSTRICTRC_VAL(rcStrict);
    17971847                    }
    17981848
    1799                     AssertMsgFailed(("VINTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
     1849                    AssertMsgFailed(("INTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
    18001850                    return VINF_EM_TRIPLE_FAULT;
    18011851                }
    18021852
    1803                 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST);
    1804                 uint8_t const uNstGstVector = CPUMGetSvmNstGstInterrupt(&pVCpu->cpum.GstCtx);
    1805                 AssertMsg(uNstGstVector > 0 && uNstGstVector <= X86_XCPT_LAST, ("Invalid VINTR vector %#x\n", uNstGstVector));
    1806                 TRPMAssertTrap(pVCpu, uNstGstVector, TRPM_HARDWARE_INT);
    1807                 Log(("EM: Asserting nested-guest virt. hardware intr: %#x\n", uNstGstVector));
    1808 
    1809                 *pfResched = true;
    1810                 *pfInject  = true;
    1811                 return VINF_EM_RESCHEDULE;
     1853                CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_XCPT_MASK);
     1854                /** @todo this really isn't nice, should properly handle this */
     1855                int rc = TRPMR3InjectEvent(pVM, pVCpu, TRPM_HARDWARE_INT);
     1856                Assert(rc != VINF_PGM_CHANGE_MODE);
     1857                if (rc == VINF_SVM_VMEXIT)
     1858                    rc = VINF_SUCCESS;
     1859                *pfWakeupPending = true;
     1860                *pfInjected      = true;
     1861                return rc;
    18121862            }
    18131863        }
    1814         return VINF_SUCCESS;
    1815     }
    1816 
    1817     if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
    1818     { /** @todo Nested VMX. */ }
    1819 
    1820     /* Shouldn't really get here. */
    1821     AssertMsgFailed(("Unrecognized nested hwvirt. arch!\n"));
    1822     return VERR_EM_INTERNAL_ERROR;
    1823 }
    1824 #endif
     1864
     1865        if (   VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST)
     1866            && CPUMCanSvmNstGstTakeVirtIntr(pVCpu, &pVCpu->cpum.GstCtx))
     1867        {
     1868            if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, &pVCpu->cpum.GstCtx, SVM_CTRL_INTERCEPT_VINTR))
     1869            {
     1870                CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_SVM_VMEXIT_MASK);
     1871                VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_VINTR, 0, 0);
     1872                if (RT_SUCCESS(rcStrict))
     1873                {
     1874                    /** @todo r=ramshankar: Do we need to signal a wakeup here? If a nested-guest
     1875                     *        doesn't intercept HLT but intercepts VINTR? */
     1876                    Assert(rcStrict != VINF_PGM_CHANGE_MODE);
     1877                    if (rcStrict == VINF_SVM_VMEXIT)
     1878                        rcStrict = VINF_SUCCESS;
     1879                    *pfWakeupPending = true;
     1880                    return VBOXSTRICTRC_VAL(rcStrict);
     1881                }
     1882
     1883                AssertMsgFailed(("VINTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
     1884                return VINF_EM_TRIPLE_FAULT;
     1885            }
     1886
     1887            VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST);
     1888            uint8_t const uNstGstVector = CPUMGetSvmNstGstInterrupt(&pVCpu->cpum.GstCtx);
     1889            AssertMsg(uNstGstVector > 0 && uNstGstVector <= X86_XCPT_LAST, ("Invalid VINTR vector %#x\n", uNstGstVector));
     1890            TRPMAssertTrap(pVCpu, uNstGstVector, TRPM_HARDWARE_INT);
     1891            Log(("EM: Asserting nested-guest virt. hardware intr: %#x\n", uNstGstVector));
     1892
     1893            *pfWakeupPending = true;
     1894            *pfInjected      = true;
     1895            return VINF_EM_RESCHEDULE;
     1896        }
     1897    }
     1898
     1899    return VINF_SUCCESS;
     1900}
     1901#endif  /* VBOX_WITH_NESTED_HWVIRT_SVM */
    18251902
    18261903/**
     
    21402217        bool fWakeupPending = false;
    21412218        if (   !VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY)
    2142             && (!rc || rc >= VINF_EM_RESCHEDULE_HM))
    2143         {
    2144             if (   !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
    2145                 && !TRPMHasTrap(pVCpu)) /* an interrupt could already be scheduled for dispatching in the recompiler. */
     2219            && (!rc || rc >= VINF_EM_RESCHEDULE_HM)
     2220            && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
     2221            && !TRPMHasTrap(pVCpu)) /* an interrupt could already be scheduled for dispatching in the recompiler. */
     2222        {
     2223            Assert(!HMR3IsEventPending(pVCpu));
     2224
     2225            bool fInjected;
     2226#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
     2227            if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
     2228                rc2 = emR3VmxNstGstInjectIntr(pVCpu, &fWakeupPending, &fInjected);
     2229            else
     2230#endif
     2231#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
     2232            if (CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.GstCtx))
     2233                rc2 = emR3SvmNstGstInjectIntr(pVCpu, &fWakeupPending, &fInjected);
     2234            else
     2235#endif
    21462236            {
    2147                 Assert(!HMR3IsEventPending(pVCpu));
    2148 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM
    2149                 if (CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.GstCtx))
     2237                rc2 = emR3GstInjectIntr(pVCpu, &fWakeupPending, &fInjected);
     2238            }
     2239            if (rc2 != VINF_NO_CHANGE)
     2240            {
     2241                if (   pVM->em.s.fIemExecutesAll
     2242                    && (   rc2 == VINF_EM_RESCHEDULE_REM
     2243                        || rc2 == VINF_EM_RESCHEDULE_HM
     2244                        || rc2 == VINF_EM_RESCHEDULE_RAW))
    21502245                {
    2151                     bool fResched, fInject;
    2152                     rc2 = emR3NstGstInjectIntr(pVCpu, &fResched, &fInject);
    2153                     if (fInject)
    2154                     {
    2155                         fWakeupPending = true;
    2156 # ifdef VBOX_STRICT
    2157                         rcIrq = rc2;
    2158 # endif
    2159                     }
    2160                     if (fResched)
    2161                         UPDATE_RC();
     2246                    rc2 = VINF_EM_RESCHEDULE;
    21622247                }
    2163                 else
    2164 #endif
    2165                 {
    2166                     CPUM_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RFLAGS);
    2167                     if (   VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
    2168 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM
    2169                         && pVCpu->cpum.GstCtx.hwvirt.fGif
    2170 #endif
    2171 #ifdef VBOX_WITH_RAW_MODE
    2172                         && !PATMIsPatchGCAddr(pVM, pVCpu->cpum.GstCtx.eip)
    2173 #endif
    2174                         && pVCpu->cpum.GstCtx.eflags.Bits.u1IF)
    2175                     {
    2176                         Assert(pVCpu->em.s.enmState != EMSTATE_WAIT_SIPI);
    2177                         /* Note: it's important to make sure the return code from TRPMR3InjectEvent isn't ignored! */
    2178                         /** @todo this really isn't nice, should properly handle this */
    2179                         CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_XCPT_MASK);
    2180                         rc2 = TRPMR3InjectEvent(pVM, pVCpu, TRPM_HARDWARE_INT);
    2181                         Log(("EM: TRPMR3InjectEvent -> %d\n", rc2));
    2182                         if (pVM->em.s.fIemExecutesAll && (   rc2 == VINF_EM_RESCHEDULE_REM
    2183                                                           || rc2 == VINF_EM_RESCHEDULE_HM
    2184                                                           || rc2 == VINF_EM_RESCHEDULE_RAW))
    2185                         {
    2186                             rc2 = VINF_EM_RESCHEDULE;
    2187                         }
    21882248#ifdef VBOX_STRICT
    2189                         rcIrq = rc2;
    2190 #endif
    2191                         UPDATE_RC();
    2192                         /* Reschedule required: We must not miss the wakeup below! */
    2193                         fWakeupPending = true;
    2194                     }
    2195                 }
     2249                if (fInjected)
     2250                    rcIrq = rc2;
     2251#endif
     2252                UPDATE_RC();
    21962253            }
    21972254        }
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