VirtualBox

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


Ignore:
Timestamp:
May 8, 2023 7:08:35 AM (21 months ago)
Author:
vboxsync
Message:

VMM/EM: Nested VMX: bugref:10318 Handle NMI-window and interrupt-window VM-exits in emR3ForcedActions.

File:
1 edited

Legend:

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

    r99576 r99652  
    14121412#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    14131413    /* Handle the "external interrupt" VM-exit intercept. */
    1414     if (CPUMIsGuestVmxPinCtlsSet(&pVCpu->cpum.GstCtx, VMX_PIN_CTLS_EXT_INT_EXIT))
     1414    if (    CPUMIsGuestVmxPinCtlsSet(&pVCpu->cpum.GstCtx, VMX_PIN_CTLS_EXT_INT_EXIT)
     1415        && !CPUMIsGuestVmxExitCtlsSet(&pVCpu->cpum.GstCtx, VMX_EXIT_CTLS_ACK_EXT_INT))
    14151416    {
    14161417        VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, 0 /* uVector */, true /* fIntPending */);
    1417         AssertMsg(   rcStrict != VINF_VMX_VMEXIT
    1418                   && rcStrict != VINF_NO_CHANGE, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
    1419         if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
    1420             return VBOXSTRICTRC_TODO(rcStrict);
     1418        AssertMsg(   rcStrict != VINF_VMX_VMEXIT    /* VM-exit should have been converted to VINF_SUCCESS. */
     1419                  && rcStrict != VINF_NO_CHANGE
     1420                  && rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
     1421        return VBOXSTRICTRC_VAL(rcStrict);
    14211422    }
    14221423#else
     
    17811782
    17821783# ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    1783         if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER))
     1784        if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER
     1785                                     | VMCPU_FF_VMX_NMI_WINDOW | VMCPU_FF_VMX_INT_WINDOW))
    17841786        {
    17851787            /*
     
    17961798
    17971799            /*
    1798              * VMX Nested-guest monitor-trap flag (MTF) VM-exit.
    1799              * Takes priority over "Traps on the previous instruction".
    1800              * See Intel spec. 6.9 "Priority Among Simultaneous Exceptions And Interrupts".
     1800             * APIC write emulation MAY have a caused a VM-exit.
     1801             * If it did cause a VM-exit, there's no point checking the other VMX non-root mode FFs here.
    18011802             */
    1802             if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_MTF))
     1803            if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
    18031804            {
    1804                 rc2 = VBOXSTRICTRC_VAL(IEMExecVmxVmexit(pVCpu, VMX_EXIT_MTF, 0 /* uExitQual */));
    1805                 Assert(rc2 != VINF_VMX_INTERCEPT_NOT_ACTIVE);
    1806                 UPDATE_RC();
     1805                /*
     1806                 * VMX Nested-guest monitor-trap flag (MTF) VM-exit.
     1807                 * Takes priority over "Traps on the previous instruction".
     1808                 * See Intel spec. 6.9 "Priority Among Simultaneous Exceptions And Interrupts".
     1809                 */
     1810                if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_MTF))
     1811                {
     1812                    rc2 = VBOXSTRICTRC_VAL(IEMExecVmxVmexit(pVCpu, VMX_EXIT_MTF, 0 /* uExitQual */));
     1813                    Assert(rc2 != VINF_VMX_INTERCEPT_NOT_ACTIVE);
     1814                    UPDATE_RC();
     1815                }
     1816                /*
     1817                 * VMX Nested-guest preemption timer VM-exit.
     1818                 * Takes priority over NMI-window VM-exits.
     1819                 */
     1820                else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER))
     1821                {
     1822                    rc2 = VBOXSTRICTRC_VAL(IEMExecVmxVmexitPreemptTimer(pVCpu));
     1823                    Assert(rc2 != VINF_VMX_INTERCEPT_NOT_ACTIVE);
     1824                    UPDATE_RC();
     1825                }
     1826                /*
     1827                 * VMX interrupt-window and NMI-window VM-exits.
     1828                 * Takes priority over non-maskable interrupts (NMIs) and external interrupts respectively.
     1829                 * If we are in an interrupt shadow or if we already in the process of delivering
     1830                 * an event then these VM-exits cannot occur.
     1831                 *
     1832                 * Interrupt shadows block NMI-window VM-exits.
     1833                 * Any event that is already in TRPM (e.g. injected during VM-entry) takes priority.
     1834                 * NMIs block delivery of other interrupts including NMIs.
     1835                 *
     1836                 * See Intel spec. 25.2 "Other Causes Of VM Exits".
     1837                 * See Intel spec. 26.7.6 "NMI-Window Exiting".
     1838                 * See Intel spec. 6.7 "Nonmaskable Interrupt (NMI)".
     1839                 */
     1840                else if (   !CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx)
     1841                         && !CPUMAreInterruptsInhibitedByNmi(&pVCpu->cpum.GstCtx)
     1842                         && !TRPMHasTrap(pVCpu))
     1843                {
     1844                    /*
     1845                     * VMX NMI-window VM-exit.
     1846                     */
     1847                    if (    VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW)
     1848                        && !CPUMIsGuestVmxVirtNmiBlocking(&pVCpu->cpum.GstCtx))
     1849                    {
     1850                        Assert(CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT));
     1851                        Assert(CPUMIsGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx));
     1852                        rc2 = VBOXSTRICTRC_VAL(IEMExecVmxVmexit(pVCpu, VMX_EXIT_NMI_WINDOW, 0 /* uExitQual */));
     1853                        AssertMsg(   rc2 != VINF_VMX_INTERCEPT_NOT_ACTIVE
     1854                                  && rc2 != VINF_VMX_VMEXIT
     1855                                  && rc2 != VINF_NO_CHANGE, ("%Rrc\n", rc2));
     1856                        UPDATE_RC();
     1857                    }
     1858                    /*
     1859                     * VMX interrupt-window VM-exit.
     1860                     * This is a bit messy with the way the code below is currently structured,
     1861                     * but checking VMCPU_FF_INTERRUPT_NMI here should allow pending NMI to be delivered
     1862                     * prior to causing an interrupt-window VM-exit.
     1863                     */
     1864                    /** @todo Restructure this later to happen after injecting NMI/causing NMI-exit, see
     1865                     *        code in VMX R0 event delivery. */
     1866                    else if (    VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_INT_WINDOW)
     1867                             && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI)
     1868                             &&  CPUMIsGuestVmxVirtIntrEnabled(&pVCpu->cpum.GstCtx))
     1869                    {
     1870                        Assert(CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT));
     1871                        Assert(CPUMIsGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx));
     1872                        rc2 = VBOXSTRICTRC_VAL(IEMExecVmxVmexit(pVCpu, VMX_EXIT_INT_WINDOW, 0 /* uExitQual */));
     1873                        AssertMsg(   rc2 != VINF_VMX_INTERCEPT_NOT_ACTIVE
     1874                                  && rc2 != VINF_VMX_VMEXIT
     1875                                  && rc2 != VINF_NO_CHANGE, ("%Rrc\n", rc2));
     1876                        UPDATE_RC();
     1877                    }
     1878                }
    18071879            }
    18081880
    18091881            /*
    1810              * VMX Nested-guest preemption timer VM-exit.
    1811              * Takes priority over NMI-window VM-exits.
     1882             * Interrupt-window and NMI-window force flags might still be pending if we didn't actually cause
     1883             * a VM-exit above. They will get cleared eventually when ANY nested-guest VM-exit occurs.
     1884             * However, the force flags asserted below MUST have been cleared at this point.
    18121885             */
    1813             if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER))
    1814             {
    1815                 rc2 = VBOXSTRICTRC_VAL(IEMExecVmxVmexitPreemptTimer(pVCpu));
    1816                 Assert(rc2 != VINF_VMX_INTERCEPT_NOT_ACTIVE);
    1817                 UPDATE_RC();
    1818             }
    18191886            Assert(!VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER));
    18201887        }
     
    18321899            && (!rc || rc >= VINF_EM_RESCHEDULE_HM)
    18331900            && !CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx)             /* Interrupt shadows block both NMIs and interrupts. */
    1834             /** @todo r=bird: But interrupt shadows probably do not block vmexits due to host interrupts... */
    18351901            && !TRPMHasTrap(pVCpu))                                      /* An event could already be scheduled for dispatching. */
    18361902        {
     
    18501916                }
    18511917
    1852                 if (0)
    1853                 { }
    1854 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    1855                 /*
    1856                  * VMX NMI-window VM-exit.
    1857                  * Takes priority over non-maskable interrupts (NMIs).
    1858                  * Interrupt shadows block NMI-window VM-exits.
    1859                  * Any event that is already in TRPM (e.g. injected during VM-entry) takes priority.
    1860                  *
    1861                  * See Intel spec. 25.2 "Other Causes Of VM Exits".
    1862                  * See Intel spec. 26.7.6 "NMI-Window Exiting".
    1863                  */
    1864                 else if (    VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW)
    1865                          && !CPUMIsGuestVmxVirtNmiBlocking(&pVCpu->cpum.GstCtx))
    1866                 {
    1867                     Assert(CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT));
    1868                     Assert(CPUMIsGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx));
    1869                     rc2 = VBOXSTRICTRC_VAL(IEMExecVmxVmexit(pVCpu, VMX_EXIT_NMI_WINDOW, 0 /* uExitQual */));
    1870                     AssertMsg(   rc2 != VINF_VMX_INTERCEPT_NOT_ACTIVE
    1871                               && rc2 != VINF_VMX_VMEXIT
    1872                               && rc2 != VINF_NO_CHANGE, ("%Rrc\n", rc2));
    1873                     UPDATE_RC();
    1874                 }
    1875 # endif
    18761918                /*
    18771919                 * NMIs (take priority over external interrupts).
    18781920                 */
    1879                 else if (   VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI)
    1880                          && !CPUMAreInterruptsInhibitedByNmi(&pVCpu->cpum.GstCtx))
     1921                if (   VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI)
     1922                    && !CPUMAreInterruptsInhibitedByNmi(&pVCpu->cpum.GstCtx))
    18811923                {
    18821924# ifdef VBOX_WITH_NESTED_HWVIRT_VMX
     
    18841926                        && CPUMIsGuestVmxPinCtlsSet(&pVCpu->cpum.GstCtx, VMX_PIN_CTLS_NMI_EXIT))
    18851927                    {
     1928                        /* We MUST clear the NMI force-flag here, see @bugref{10318#c19}. */
     1929                        VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
    18861930                        rc2 = VBOXSTRICTRC_VAL(IEMExecVmxVmexitXcptNmi(pVCpu));
    18871931                        Assert(rc2 != VINF_VMX_INTERCEPT_NOT_ACTIVE);
     
    19191963                    }
    19201964                }
    1921 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    1922                 /*
    1923                  * VMX Interrupt-window VM-exits.
    1924                  * Takes priority over external interrupts.
    1925                  */
    1926                 else if (   VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_INT_WINDOW)
    1927                          && CPUMIsGuestVmxVirtIntrEnabled(&pVCpu->cpum.GstCtx))
    1928                 {
    1929                     Assert(CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT));
    1930                     Assert(CPUMIsGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx));
    1931                     rc2 = VBOXSTRICTRC_VAL(IEMExecVmxVmexit(pVCpu, VMX_EXIT_INT_WINDOW, 0 /* uExitQual */));
    1932                     AssertMsg(   rc2 != VINF_VMX_INTERCEPT_NOT_ACTIVE
    1933                               && rc2 != VINF_VMX_VMEXIT
    1934                               && rc2 != VINF_NO_CHANGE, ("%Rrc\n", rc2));
    1935                     UPDATE_RC();
    1936                 }
    1937 # endif
    19381965# ifdef VBOX_WITH_NESTED_HWVIRT_SVM
    19391966                /** @todo NSTSVM: Handle this for SVM here too later not when an interrupt is
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