VirtualBox

Changeset 93964 in vbox for trunk


Ignore:
Timestamp:
Feb 28, 2022 8:39:45 AM (3 years ago)
Author:
vboxsync
Message:

VMM/IEM: Nested VMX: bugref:10092 Use the HM ring-0 API to construct nested-guest APIC-access VM-exits caused by EPT violations.

File:
1 edited

Legend:

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

    r93922 r93964  
    1646016460    RT_NOREF4(pVM, pRegFrame, pvFault, uUser);
    1646116461
    16462     /** @todo We lack information about such as the current instruction length, IDT
    16463      *        vectoring info etc. These need to be queried from HMR0. */
     16462    /*
     16463     * Handle the VMX APIC-access page only when the guest is in VMX non-root mode.
     16464     * Otherwise we must deregister the page and allow regular RAM access.
     16465     * Failing to do so lands us with endless EPT misconfiguration VM-exits.
     16466     */
    1646416467    RTGCPHYS const GCPhysAccessBase = GCPhysFault & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
    1646516468    if (CPUMIsGuestInVmxNonRootMode(IEM_GET_CTX(pVCpu)))
     
    1646816471        Assert(CPUMGetGuestVmxApicAccessPageAddrEx(IEM_GET_CTX(pVCpu)) == GCPhysAccessBase);
    1646916472
     16473        /*
     16474         * Check if the access causes an APIC-access VM-exit.
     16475         */
    1647016476        uint32_t fAccess;
    1647116477        if (uErr & X86_TRAP_PF_ID)
     
    1648016486        if (fIntercept)
    1648116487        {
    16482             /** @todo Once HMR0 interface for querying VMXTRANSIENT info is available, use
    16483              *        iemVmxVmexitApicAccessWithInfo instead. This is R0-only code anyway. */
    16484             VBOXSTRICTRC rcStrict = iemVmxVmexitApicAccess(pVCpu, offAccess, fAccess);
     16488            /*
     16489             * Query the source VM-exit (from the execution engine) that caused this access
     16490             * within the APIC-access page. Currently only HM is supported.
     16491             */
     16492            AssertMsgReturn(VM_IS_HM_ENABLED(pVM),
     16493                            ("VM-exit auxiliary info. fetching not supported for execution engine %d\n",
     16494                             pVM->bMainExecutionEngine), VERR_IEM_ASPECT_NOT_IMPLEMENTED);
     16495            HMEXITAUX HmExitAux;
     16496            RT_ZERO(HmExitAux);
     16497            int const rc = HMR0GetExitAuxInfo(pVCpu, &HmExitAux, HMVMX_READ_EXIT_INSTR_LEN
     16498                                                               | HMVMX_READ_EXIT_QUALIFICATION
     16499                                                               | HMVMX_READ_IDT_VECTORING_INFO
     16500                                                               | HMVMX_READ_IDT_VECTORING_ERROR_CODE);
     16501            AssertRCReturn(rc, rc);
     16502
     16503            /*
     16504             * Verify the VM-exit reason must be an EPT violation.
     16505             * Other accesses should go through the other handler (iemVmxApicAccessPageHandler).
     16506             */
     16507            AssertLogRelMsgReturn(HmExitAux.Vmx.uReason == VMX_EXIT_EPT_VIOLATION,
     16508                                  ("Unexpected call to the VMX APIC-access page #PF handler for %#RGp (off=%u) uReason=%#RX32\n",
     16509                                   GCPhysAccessBase, offAccess, HmExitAux.Vmx.uReason), VERR_IEM_IPE_9);
     16510
     16511            /*
     16512             * Construct the virtual APIC-access VM-exit.
     16513             */
     16514            VMXAPICACCESS enmAccess;
     16515            if (HmExitAux.Vmx.u64Qual & VMX_EXIT_QUAL_EPT_LINEAR_ADDR_VALID)
     16516            {
     16517                if (VMX_IDT_VECTORING_INFO_IS_VALID(HmExitAux.Vmx.uIdtVectoringInfo))
     16518                    enmAccess = VMXAPICACCESS_LINEAR_EVENT_DELIVERY;
     16519                else if (fAccess == IEM_ACCESS_INSTRUCTION)
     16520                    enmAccess = VMXAPICACCESS_LINEAR_INSTR_FETCH;
     16521                else if (fAccess & IEM_ACCESS_TYPE_WRITE)
     16522                    enmAccess = VMXAPICACCESS_LINEAR_WRITE;
     16523                else
     16524                    enmAccess = VMXAPICACCESS_LINEAR_READ;
     16525            }
     16526            else
     16527            {
     16528                if (VMX_IDT_VECTORING_INFO_IS_VALID(HmExitAux.Vmx.uIdtVectoringInfo))
     16529                    enmAccess = VMXAPICACCESS_PHYSICAL_EVENT_DELIVERY;
     16530                else
     16531                {
     16532                    /** @todo How to distinguish between monitoring/trace vs other instructions
     16533                     *        here? */
     16534                    enmAccess = VMXAPICACCESS_PHYSICAL_INSTR;
     16535                }
     16536            }
     16537
     16538            VMXVEXITINFO ExitInfo;
     16539            RT_ZERO(ExitInfo);
     16540            ExitInfo.uReason = VMX_EXIT_APIC_ACCESS;
     16541            ExitInfo.u64Qual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_APIC_ACCESS_OFFSET, offAccess)
     16542                             | RT_BF_MAKE(VMX_BF_EXIT_QUAL_APIC_ACCESS_TYPE,   enmAccess);
     16543            ExitInfo.cbInstr = HmExitAux.Vmx.cbInstr;
     16544
     16545            VMXVEXITEVENTINFO ExitEventInfo;
     16546            RT_ZERO(ExitEventInfo);
     16547            ExitEventInfo.uIdtVectoringInfo    = HmExitAux.Vmx.uIdtVectoringInfo;
     16548            ExitEventInfo.uIdtVectoringErrCode = HmExitAux.Vmx.uIdtVectoringErrCode;
     16549
     16550            /*
     16551             * Raise the APIC-access VM-exit.
     16552             */
     16553            VBOXSTRICTRC rcStrict = iemVmxVmexitApicAccessWithInfo(pVCpu, &ExitInfo, &ExitEventInfo);
    1648516554            return iemExecStatusCodeFiddling(pVCpu, rcStrict);
    1648616555        }
    1648716556
    16488         /* The access isn't intercepted, which means it needs to be virtualized. */
     16557        /*
     16558         * The access isn't intercepted, which means it needs to be virtualized.
     16559         *
     16560         * This requires emulating the instruction because we need the bytes being
     16561         * read/written by the instruction not just the offset being accessed within
     16562         * the APIC-access (which we derive from the faulting address).
     16563         */
    1648916564        return VINF_EM_RAW_EMULATE_INSTR;
    1649016565    }
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