VirtualBox

Changeset 79100 in vbox


Ignore:
Timestamp:
Jun 12, 2019 8:17:21 AM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
131262
Message:

VMM/HMVMXR0: Nested VMX: bugref:9180 Add hmR0VmxIs[Pin|Proc|Proc2|Entry|Exit]CtlsSet for use in VM-exit handlers to get the nested-guest controls (rather than the merged ones).
Fix places that need to set/clear virtual-NMI blocking rather than guest physical NMI blocking.
Adjusted some assertions for use with nested-guest execution.
Add const VMXTRANSIENT pointer and use it in places where it's possible.
Fix when when merging MSR bitmaps and the nested-guest does not specify use of MSR bitmap, comment clarifies.

File:
1 edited

Legend:

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

    r79090 r79100  
    291291/** Pointer to VMX transient state. */
    292292typedef VMXTRANSIENT *PVMXTRANSIENT;
     293/** Pointer to a const VMX transient state. */
     294typedef const VMXTRANSIENT *PCVMXTRANSIENT;
     295
    293296
    294297/**
     
    743746
    744747/**
     748 * Checks whether one of the given Pin-based VM-execution controls are set.
     749 *
     750 * @returns @c true if set, @c false otherwise.
     751 * @param   pVCpu           The cross context virtual CPU structure.
     752 * @param   pVmxTransient   The VMX-transient structure.
     753 * @param   uPinCtls        The Pin-based VM-execution controls to check.
     754 *
     755 * @remarks This will not check merged controls when executing a nested-guest
     756 *          but the original control specified by the guest hypervisor.
     757 */
     758static bool hmR0VmxIsPinCtlsSet(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uPinCtls)
     759{
     760    if (!pVmxTransient->fIsNestedGuest)
     761    {
     762        PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     763        return RT_BOOL(pVmcsInfo->u32PinCtls & uPinCtls);
     764    }
     765    return CPUMIsGuestVmxPinCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uPinCtls);
     766}
     767
     768
     769/**
     770 * Checks whether one of the given Processor-based VM-execution controls are set.
     771 *
     772 * @returns @c true if set, @c false otherwise.
     773 * @param   pVCpu           The cross context virtual CPU structure.
     774 * @param   pVmxTransient   The VMX-transient structure.
     775 * @param   uPinCtls        The Processor-based VM-execution controls to check.
     776 *
     777 * @remarks This will not check merged controls when executing a nested-guest
     778 *          but the original control specified by the guest hypervisor.
     779 */
     780static bool hmR0VmxIsProcCtlsSet(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
     781{
     782    if (!pVmxTransient->fIsNestedGuest)
     783    {
     784        PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     785        return RT_BOOL(pVmcsInfo->u32ProcCtls & uProcCtls);
     786    }
     787    return CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uProcCtls);
     788}
     789
     790
     791/**
     792 * Checks whether one of the given Secondary Processor-based VM-execution controls
     793 * are set.
     794 *
     795 * @returns @c true if set, @c false otherwise.
     796 * @param   pVCpu           The cross context virtual CPU structure.
     797 * @param   pVmxTransient   The VMX-transient structure.
     798 * @param   uPinCtls        The Secondary Processor-based VM-execution controls to
     799 *                          check.
     800 *
     801 * @remarks This will not check merged controls when executing a nested-guest
     802 *          but the original control specified by the guest hypervisor.
     803 */
     804static bool hmR0VmxIsProcCtls2Set(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uProcCtls2)
     805{
     806    if (!pVmxTransient->fIsNestedGuest)
     807    {
     808        PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     809        return RT_BOOL(pVmcsInfo->u32ProcCtls2 & uProcCtls2);
     810    }
     811    return CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, uProcCtls2);
     812}
     813
     814
     815#if 0
     816/**
     817 * Checks whether one of the given VM-entry controls are set.
     818 *
     819 * @returns @c true if set, @c false otherwise.
     820 * @param   pVCpu           The cross context virtual CPU structure.
     821 * @param   pVmxTransient   The VMX-transient structure.
     822 * @param   uPinCtls        The VM-entry controls to check.
     823 *
     824 * @remarks This will not check merged controls when executing a nested-guest
     825 *          but the original control specified by the guest hypervisor.
     826 */
     827static bool hmR0VmxIsEntryCtlsSet(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uEntryCtls)
     828{
     829    if (!pVmxTransient->fIsNestedGuest)
     830    {
     831        PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     832        return RT_BOOL(pVmcsInfo->u32EntryCtls & uEntryCtls);
     833    }
     834    return CPUMIsGuestVmxEntryCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uEntryCtls);
     835}
     836
     837
     838/**
     839 * Checks whether one of the given VM-exit controls are set.
     840 *
     841 * @returns @c true if set, @c false otherwise.
     842 * @param   pVCpu           The cross context virtual CPU structure.
     843 * @param   pVmxTransient   The VMX-transient structure.
     844 * @param   uPinCtls        The VM-exit controls to check.
     845 *
     846 * @remarks This will not check merged controls when executing a nested-guest
     847 *          but the original control specified by the guest hypervisor.
     848 */
     849static bool hmR0VmxIsExitCtlsSet(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uExitCtls)
     850{
     851    if (!pVmxTransient->fIsNestedGuest)
     852    {
     853        PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     854        return RT_BOOL(pVmcsInfo->u32ExitCtls & uExitCtls);
     855    }
     856    return CPUMIsGuestVmxExitCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uExitCtls);
     857}
     858#endif
     859
     860
     861/**
    745862 * Adds one or more exceptions to the exception bitmap and commits it to the current
    746863 * VMCS.
     
    45574674 *
    45584675 * @returns Guest's interruptibility-state.
    4559  * @param   pVCpu       The cross context virtual CPU structure.
    4560  * @param   pVmcsInfo   The VMCS info. object.
     4676 * @param   pVCpu           The cross context virtual CPU structure.
     4677 * @param   pVmxTransient   The VMX-transient structure.
    45614678 *
    45624679 * @remarks No-long-jump zone!!!
    45634680 */
    4564 static uint32_t hmR0VmxGetGuestIntrState(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
     4681static uint32_t hmR0VmxGetGuestIntrState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
    45654682{
    45664683    /*
     
    46054722     * See Intel spec. 26.6.1 "Interruptibility state". See @bugref{7445}.
    46064723     */
    4607     if (   (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
     4724    if (   hmR0VmxIsPinCtlsSet(pVCpu, pVmxTransient, VMX_PIN_CTLS_VIRT_NMI)
    46084725        && CPUMIsGuestNmiBlocking(pVCpu))
    46094726        fIntrState |= VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI;
     
    61016218 * @remarks No-long-jump zone!!!
    61026219 */
    6103 DECLINLINE(int) hmR0VmxRunGuest(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
     6220DECLINLINE(int) hmR0VmxRunGuest(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient)
    61046221{
    61056222    /* Mark that HM is the keeper of all guest-CPU registers now that we're going to execute guest code. */
     
    73477464                VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
    73487465
    7349             if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
    7350                 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
     7466            CPUMSetGuestNmiBlocking(pVCpu, false);
    73517467        }
    73527468        else
     
    73667482                    VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
    73677483
    7368                 if (u32Val & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI)
    7369                 {
    7370                     if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
    7371                         VMCPU_FF_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
    7372                 }
    7373                 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
    7374                     VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
     7484                bool const fNmiBlocking = RT_BOOL(u32Val & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
     7485                CPUMSetGuestNmiBlocking(pVCpu, fNmiBlocking);
    73757486            }
    73767487        }
     
    87688879
    87698880    /* Get the current interruptibility-state of the guest and then figure out what can be injected. */
    8770     uint32_t const fIntrState = hmR0VmxGetGuestIntrState(pVCpu, pVmcsInfo);
     8881    uint32_t const fIntrState = hmR0VmxGetGuestIntrState(pVCpu, pVmxTransient);
    87718882    bool const fBlockMovSS    = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
    87728883    bool const fBlockSti      = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
     
    1002410135static void hmR0VmxMergeMsrBitmapNested(PCVMCPU pVCpu, PVMXVMCSINFO pVmcsInfoNstGst, PCVMXVMCSINFO pVmcsInfoGst)
    1002510136{
    10026     uint64_t const *pu64MsrBitmapNstGst = (uint64_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
    10027     uint64_t const *pu64MsrBitmapGst    = (uint64_t const *)pVmcsInfoGst->pvMsrBitmap;
    10028     uint64_t       *pu64MsrBitmap       = (uint64_t *)pVmcsInfoNstGst->pvMsrBitmap;
    10029     Assert(pu64MsrBitmapNstGst);
    10030     Assert(pu64MsrBitmapGst);
     10137    uint32_t const cbMsrBitmap    = X86_PAGE_4K_SIZE;
     10138    uint64_t       *pu64MsrBitmap = (uint64_t *)pVmcsInfoNstGst->pvMsrBitmap;
    1003110139    Assert(pu64MsrBitmap);
    1003210140
     
    1003510143     * MSR that is intercepted by the guest is also intercepted while executing the
    1003610144     * nested-guest using hardware-assisted VMX.
     10145     *
     10146     * Note! If the nested-guest is not using an MSR bitmap, ever MSR must cause a
     10147     *       nested-guest VM-exit even if the outer guest is not intercepting some
     10148     *       MSRs. We cannot assume the caller has initialized the nested-guest
     10149     *       MSR bitmap in this case.
     10150     *
     10151     *       The guest hypervisor may also switch whether it uses MSR bitmaps for
     10152     *       each VM-entry, hence initializing it once per-VM while setting up the
     10153     *       nested-guest VMCS is not sufficient.
    1003710154     */
    10038     uint32_t const cFrags = X86_PAGE_4K_SIZE / sizeof(uint64_t);
    10039     for (uint32_t i = 0; i < cFrags; i++)
    10040         pu64MsrBitmap[i] = pu64MsrBitmapNstGst[i] | pu64MsrBitmapGst[i];
     10155    PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     10156    if (pVmcsNstGst->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
     10157    {
     10158        uint64_t const *pu64MsrBitmapNstGst = (uint64_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
     10159        uint64_t const *pu64MsrBitmapGst    = (uint64_t const *)pVmcsInfoGst->pvMsrBitmap;
     10160        Assert(pu64MsrBitmapNstGst);
     10161        Assert(pu64MsrBitmapGst);
     10162
     10163        uint32_t const cFrags = cbMsrBitmap / sizeof(uint64_t);
     10164        for (uint32_t i = 0; i < cFrags; i++)
     10165            pu64MsrBitmap[i] = pu64MsrBitmapNstGst[i] | pu64MsrBitmapGst[i];
     10166    }
     10167    else
     10168        ASMMemFill32(pu64MsrBitmap, cbMsrBitmap, UINT32_C(0xffffffff));
    1004110169}
    1004210170
     
    1041710545    /*
    1041810546     * Virtualize memory-mapped accesses to the physical APIC (may take locks).
    10419      * We look at the guest VMCS control here as we always set it when supported by
    10420      * the physical CPU. Looking at the nested-guest control here would not be
    10421      * possible because they are not merged yet.
    1042210547     */
    1042310548    PVM pVM = pVCpu->CTX_SUFF(pVM);
     
    1042510550    Assert(pVmcsInfo);
    1042610551    if (   !pVCpu->hm.s.vmx.u64GstMsrApicBase
    10427         && (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
     10552        && hmR0VmxIsProcCtls2Set(pVCpu, pVmxTransient, VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
    1042810553        && PDMHasApic(pVM))
    1042910554    {
     
    1115211277 * @param   pDbgState       The debug state to initialize.
    1115311278 */
    11154 static void hmR0VmxRunDebugStateInit(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
     11279static void hmR0VmxRunDebugStateInit(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
    1115511280{
    1115611281    pDbgState->uRipStart            = pVCpu->cpum.GstCtx.rip;
     
    1282712952static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
    1282812953{
    12829     VBOXSTRICTRC  rcStrict  = VINF_SUCCESS;
    12830     PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
    12831 
    1283212954    /* Read the IDT vectoring info. and VM-exit interruption info. */
    1283312955    {
     
    1283712959    }
    1283812960
     12961    VBOXSTRICTRC   rcStrict    = VINF_SUCCESS;
    1283912962    uint32_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
    1284012963    if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
     
    1290213025         * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception". See @bugref{7445}.
    1290313026         */
    12904         if (   VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS)
    12905             && uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
     13027        if (   uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
    1290613028            && (   enmRaise   == IEMXCPTRAISE_PREV_EVENT
    1290713029                || (fRaiseInfo & IEMXCPTRAISEINFO_NMI_PF))
    12908             && (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI))
    12909         {
    12910             VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
     13030            && hmR0VmxIsPinCtlsSet(pVCpu, pVmxTransient, VMX_PIN_CTLS_VIRT_NMI)
     13031            && CPUMIsGuestNmiBlocking(pVCpu))
     13032        {
     13033            CPUMSetGuestNmiBlocking(pVCpu, false);
    1291113034        }
    1291213035
     
    1299713120             && VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(pVmxTransient->uExitIntInfo)
    1299813121             && uExitVector != X86_XCPT_DF
    12999              && (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI))
     13122             && hmR0VmxIsPinCtlsSet(pVCpu, pVmxTransient, VMX_PIN_CTLS_VIRT_NMI))
    1300013123    {
    1300113124        /*
     
    1300413127         * See Intel spec. 30.7.1.2 "Resuming guest software after handling an exception".
    1300513128         */
    13006         if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
    13007         {
    13008             Log4Func(("Setting VMCPU_FF_BLOCK_NMIS. fValid=%RTbool uExitReason=%u\n",
    13009                       VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo), pVmxTransient->uExitReason));
    13010             VMCPU_FF_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
    13011         }
     13129        CPUMSetGuestNmiBlocking(pVCpu, true);
     13130        Log4Func(("Set NMI blocking. fValid=%RTbool uExitReason=%u\n", VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo),
     13131                  pVmxTransient->uExitReason));
    1301213132    }
    1301313133
     
    1320613326    }
    1320713327
    13208     Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS));
     13328    Assert(!CPUMIsGuestNmiBlocking(pVCpu));
    1320913329
    1321013330    /*
     
    1380413924
    1380513925#ifdef VBOX_STRICT
    13806     if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
     13926    if (hmR0VmxIsProcCtlsSet(pVCpu, pVmxTransient, VMX_PROC_CTLS_USE_MSR_BITMAPS))
    1380713927    {
    1380813928        if (   hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr)
     
    1390714027
    1390814028        /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not supported. */
    13909         if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
     14029        if (!hmR0VmxIsProcCtlsSet(pVCpu, pVmxTransient, VMX_PROC_CTLS_USE_MSR_BITMAPS))
    1391014030        {
    1391114031            switch (idMsr)
     
    1506515185    {
    1506615186#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
    15067         Assert(pVCpu->hm.s.fUsingDebugLoop || pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv);
     15187        Assert(pVCpu->hm.s.fUsingDebugLoop || pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv || pVmxTransient->fIsNestedGuest);
    1506815188#endif
    1506915189        /* If the guest is not in real-mode or we have unrestricted guest execution support, reflect #GP to the guest. */
     
    1507615196                  pVmxTransient->uExitIntErrorCode, pCtx->cr0, CPUMGetGuestCPL(pVCpu), pCtx->tr.Sel));
    1507715197
    15078         if (   !pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv
     15198        if (    pVmxTransient->fIsNestedGuest
     15199            || !pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv
    1507915200            || !hmR0VmxIsMesaDrvGp(pVCpu, pVmxTransient, pCtx))
    1508015201            hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
     
    1508715208    Assert(CPUMIsGuestInRealModeEx(pCtx));
    1508815209    Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest);
     15210    Assert(!pVmxTransient->fIsNestedGuest);
    1508915211
    1509015212    int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
     
    1513615258#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
    1513715259    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
    15138     AssertMsg(pVCpu->hm.s.fUsingDebugLoop || pVmcsInfo->RealMode.fRealOnV86Active,
     15260    AssertMsg(pVCpu->hm.s.fUsingDebugLoop || pVmcsInfo->RealMode.fRealOnV86Active || pVmxTransient->fIsNestedGuest,
    1513915261              ("uVector=%#x u32XcptBitmap=%#X32\n",
    1514015262               VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo), pVmcsInfo->u32XcptBitmap));
     
    1514215264#endif
    1514315265
    15144     /* Re-inject the exception into the guest. This cannot be a double-fault condition which would have been handled in
    15145        hmR0VmxCheckExitDueToEventDelivery(). */
     15266    /*
     15267     * Re-inject the exception into the guest. This cannot be a double-fault condition which
     15268     * would have been handled while checking exits due to event delivery.
     15269     */
    1514615270    int rc = hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
    1514715271    rc    |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
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