VirtualBox

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


Ignore:
Timestamp:
Oct 10, 2018 12:05:41 PM (6 years ago)
Author:
vboxsync
Message:

VMM/IEM: Nested VMX: bugref:9180 VM-exit bits; Added exception and external interrupt intercepts. The
"acknowledge interrupt on exit" control needs to be implemented as well, todo currently.

Location:
trunk/src/VBox/VMM/VMMAll
Files:
2 edited

Legend:

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

    r74709 r74736  
    968968#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    969969IEM_STATIC VBOXSTRICTRC     iemVmxVmexitTaskSwitch(PVMCPU pVCpu, IEMTASKSWITCH enmTaskSwitch, RTSEL SelNewTss);
     970IEM_STATIC VBOXSTRICTRC     iemVmxVmexitEvent(PVMCPU pVCpu, uint8_t uVector, uint32_t fFlags, uint32_t uErrCode, uint64_t uCr2);
    970971#endif
    971972
     
    55105511#endif
    55115512
     5513#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
     5514    if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
     5515    {
     5516        VBOXSTRICTRC rcStrict0 = iemVmxVmexitEvent(pVCpu, u8Vector, fFlags, uErr, uCr2);
     5517        if (rcStrict0 != VINF_VMX_INTERCEPT_NOT_ACTIVE)
     5518            return rcStrict0;
     5519    }
     5520#endif
     5521
    55125522#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
    55135523    if (CPUMIsGuestInSvmNestedHwVirtMode(IEM_GET_CTX(pVCpu)))
     
    55175527         * intercepts in the nested-guest. However, secondary exceptions that occur
    55185528         * during injection of any event -are- subject to exception intercepts.
     5529         *
    55195530         * See AMD spec. 15.20 "Event Injection".
    55205531         */
    55215532        if (!pVCpu->cpum.GstCtx.hwvirt.svm.fInterceptEvents)
    5522             pVCpu->cpum.GstCtx.hwvirt.svm.fInterceptEvents = 1;
     5533            pVCpu->cpum.GstCtx.hwvirt.svm.fInterceptEvents = true;
    55235534        else
    55245535        {
  • trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h

    r74729 r74736  
    192192        /*     1 */ RT_UOFFSETOF(VMXVVMCS, u32RoExitReason),
    193193        /*     2 */ RT_UOFFSETOF(VMXVVMCS, u32RoExitIntInfo),
    194         /*     3 */ RT_UOFFSETOF(VMXVVMCS, u32RoExitErrCode),
     194        /*     3 */ RT_UOFFSETOF(VMXVVMCS, u32RoExitIntErrCode),
    195195        /*     4 */ RT_UOFFSETOF(VMXVVMCS, u32RoIdtVectoringInfo),
    196196        /*     5 */ RT_UOFFSETOF(VMXVVMCS, u32RoIdtVectoringErrCode),
     
    13361336
    13371337/**
     1338 * Converts an IEM exception event type to a VMX event type.
     1339 *
     1340 * @returns The VMX event type.
     1341 * @param   uVector     The interrupt / exception vector number.
     1342 * @param   fFlags      The IEM event flag (see IEM_XCPT_FLAGS_XXX).
     1343 */
     1344DECLINLINE(uint8_t) iemVmxGetEventType(uint32_t uVector, uint32_t fFlags)
     1345{
     1346    /* Paranoia (callers may use these interchangeably). */
     1347    AssertCompile(VMX_EXIT_INT_INFO_TYPE_NMI          == VMX_IDT_VECTORING_INFO_TYPE_NMI);
     1348    AssertCompile(VMX_EXIT_INT_INFO_TYPE_HW_XCPT      == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT);
     1349    AssertCompile(VMX_EXIT_INT_INFO_TYPE_EXT_INT      == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT);
     1350    AssertCompile(VMX_EXIT_INT_INFO_TYPE_SW_XCPT      == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT);
     1351    AssertCompile(VMX_EXIT_INT_INFO_TYPE_SW_INT       == VMX_IDT_VECTORING_INFO_TYPE_SW_INT);
     1352    AssertCompile(VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT);
     1353    AssertCompile(VMX_EXIT_INT_INFO_TYPE_NMI          == VMX_ENTRY_INT_INFO_TYPE_NMI);
     1354    AssertCompile(VMX_EXIT_INT_INFO_TYPE_HW_XCPT      == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT);
     1355    AssertCompile(VMX_EXIT_INT_INFO_TYPE_EXT_INT      == VMX_ENTRY_INT_INFO_TYPE_EXT_INT);
     1356    AssertCompile(VMX_EXIT_INT_INFO_TYPE_SW_XCPT      == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT);
     1357    AssertCompile(VMX_EXIT_INT_INFO_TYPE_SW_INT       == VMX_ENTRY_INT_INFO_TYPE_SW_INT);
     1358    AssertCompile(VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT == VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT);
     1359
     1360    if (fFlags & IEM_XCPT_FLAGS_T_CPU_XCPT)
     1361    {
     1362        if (uVector == X86_XCPT_NMI)
     1363            return VMX_EXIT_INT_INFO_TYPE_NMI;
     1364        return VMX_EXIT_INT_INFO_TYPE_HW_XCPT;
     1365    }
     1366
     1367    if (fFlags & IEM_XCPT_FLAGS_T_SOFT_INT)
     1368    {
     1369        if (fFlags & (IEM_XCPT_FLAGS_BP_INSTR | IEM_XCPT_FLAGS_OF_INSTR))
     1370            return VMX_EXIT_INT_INFO_TYPE_SW_XCPT;
     1371        if (fFlags & IEM_XCPT_FLAGS_ICEBP_INSTR)
     1372            return VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT;
     1373        return VMX_EXIT_INT_INFO_TYPE_SW_INT;
     1374    }
     1375
     1376    Assert(fFlags & IEM_XCPT_FLAGS_T_EXT_INT);
     1377    return VMX_EXIT_INT_INFO_TYPE_EXT_INT;
     1378}
     1379
     1380
     1381/**
    13381382 * Sets the VM-instruction error VMCS field.
    13391383 *
     
    13521396 *
    13531397 * @param   pVCpu       The cross context virtual CPU structure.
    1354  * @param   uExitQual   The VM-exit qualification field.
     1398 * @param   uExitQual   The VM-exit qualification.
    13551399 */
    13561400DECL_FORCE_INLINE(void) iemVmxVmcsSetExitQual(PVMCPU pVCpu, uint64_t uExitQual)
     
    13621406
    13631407/**
     1408 * Sets the VM-exit interruption information field.
     1409 *
     1410 * @param   pVCpu       The cross context virtual CPU structure.
     1411 * @param   uExitQual   The VM-exit interruption information.
     1412 */
     1413DECL_FORCE_INLINE(void) iemVmxVmcsSetExitIntInfo(PVMCPU pVCpu, uint32_t uExitIntInfo)
     1414{
     1415    PVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     1416    pVmcs->u32RoExitIntInfo = uExitIntInfo;
     1417}
     1418
     1419
     1420/**
     1421 * Sets the VM-exit interruption error code.
     1422 *
     1423 * @param   pVCpu       The cross context virtual CPU structure.
     1424 * @param   uErrCode    The error code.
     1425 */
     1426DECL_FORCE_INLINE(void) iemVmxVmcsSetExitIntErrCode(PVMCPU pVCpu, uint32_t uErrCode)
     1427{
     1428    PVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     1429    pVmcs->u32RoExitIntErrCode = uErrCode;
     1430}
     1431
     1432
     1433/**
     1434 * Sets the IDT-vectoring information field.
     1435 *
     1436 * @param   pVCpu           The cross context virtual CPU structure.
     1437 * @param   uIdtVectorInfo  The IDT-vectoring information.
     1438 */
     1439DECL_FORCE_INLINE(void) iemVmxVmcsSetIdtVectoringInfo(PVMCPU pVCpu, uint32_t uIdtVectorInfo)
     1440{
     1441    PVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     1442    pVmcs->u32RoIdtVectoringInfo = uIdtVectorInfo;
     1443}
     1444
     1445
     1446/**
     1447 * Sets the IDT-vectoring error code field.
     1448 *
     1449 * @param   pVCpu       The cross context virtual CPU structure.
     1450 * @param   uErrCode    The error code.
     1451 */
     1452DECL_FORCE_INLINE(void) iemVmxVmcsSetIdtVectoringErrCode(PVMCPU pVCpu, uint32_t uErrCode)
     1453{
     1454    PVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     1455    pVmcs->u32RoIdtVectoringErrCode = uErrCode;
     1456}
     1457
     1458
     1459/**
    13641460 * Sets the VM-exit guest-linear address VMCS field.
    13651461 *
    13661462 * @param   pVCpu               The cross context virtual CPU structure.
    1367  * @param   uGuestLinearAddr    The VM-exit guest-linear address field.
     1463 * @param   uGuestLinearAddr    The VM-exit guest-linear address.
    13681464 */
    13691465DECL_FORCE_INLINE(void) iemVmxVmcsSetExitGuestLinearAddr(PVMCPU pVCpu, uint64_t uGuestLinearAddr)
     
    13781474 *
    13791475 * @param   pVCpu           The cross context virtual CPU structure.
    1380  * @param   uGuestPhysAddr  The VM-exit guest-physical address field.
     1476 * @param   uGuestPhysAddr  The VM-exit guest-physical address.
    13811477 */
    13821478DECL_FORCE_INLINE(void) iemVmxVmcsSetExitGuestPhysAddr(PVMCPU pVCpu, uint64_t uGuestPhysAddr)
     
    14071503 *
    14081504 * @param   pVCpu           The cross context virtual CPU structure.
    1409  * @param   uExitInstrInfo  The VM-exit instruction info. field.
     1505 * @param   uExitInstrInfo  The VM-exit instruction information.
    14101506 */
    14111507DECL_FORCE_INLINE(void) iemVmxVmcsSetExitInstrInfo(PVMCPU pVCpu, uint32_t uExitInstrInfo)
     
    34743570    iemVmxVmcsSetExitQual(pVCpu, uExitQual);
    34753571    return iemVmxVmexit(pVCpu, VMX_EXIT_TASK_SWITCH);
     3572}
     3573
     3574
     3575/**
     3576 * VMX VM-exit handler for VM-exits due to delivery of an event (indirectly).
     3577 *
     3578 * @returns VBox strict status code.
     3579 * @param   pVCpu       The cross context virtual CPU structure.
     3580 * @param   uVector     The interrupt / exception vector number.
     3581 * @param   fFlags      The flags (see IEM_XCPT_FLAGS_XXX).
     3582 * @param   uErrCode    The error code associated with the event.
     3583 * @param   uCr2        The CR2 value in case of a \#PF exception.
     3584 */
     3585IEM_STATIC VBOXSTRICTRC iemVmxVmexitEvent(PVMCPU pVCpu, uint8_t uVector, uint32_t fFlags, uint32_t uErrCode, uint64_t uCr2)
     3586{
     3587    PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     3588    Assert(pVmcs);
     3589
     3590    /*
     3591     * If the event is being injected as part of VM-entry, it isn't subject to event
     3592     * intercepts in the nested-guest. However, secondary exceptions that occur during
     3593     * injection of any event -are- subject to event interception.
     3594     *
     3595     * See Intel spec. 26.5.1.2 "VM Exits During Event Injection".
     3596     */
     3597    if (!pVCpu->cpum.GstCtx.hwvirt.vmx.fInterceptEvents)
     3598    {
     3599        /* Update the IDT-vectoring event in the VMCS as the source of the upcoming event. */
     3600        uint8_t  const uIdtVectoringType = iemVmxGetEventType(uVector, fFlags);
     3601        uint8_t  const fErrCodeValid     = (fFlags & IEM_XCPT_FLAGS_ERR);
     3602        uint32_t const uIdtVectoringInfo = RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VECTOR,         uVector)
     3603                                         | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_TYPE,           uIdtVectoringType)
     3604                                         | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_ERR_CODE_VALID, fErrCodeValid)
     3605                                         | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VALID,          1);
     3606        iemVmxVmcsSetIdtVectoringInfo(pVCpu, uIdtVectoringInfo);
     3607        iemVmxVmcsSetIdtVectoringErrCode(pVCpu, uErrCode);
     3608
     3609        pVCpu->cpum.GstCtx.hwvirt.vmx.fInterceptEvents = true;
     3610        return VINF_VMX_INTERCEPT_NOT_ACTIVE;
     3611    }
     3612
     3613    /*
     3614     * Evaluate intercepts for hardware exceptions including #BP, #DB, #OF
     3615     * generated by INT3, INT1 (ICEBP) and INTO respectively.
     3616     */
     3617    bool     fIntercept = false;
     3618    bool     fIsHwXcpt  = false;
     3619    if (fFlags & (IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_T_SOFT_INT))
     3620    {
     3621        if (   !(fFlags & IEM_XCPT_FLAGS_T_SOFT_INT)
     3622            ||  (fFlags & (IEM_XCPT_FLAGS_BP_INSTR | IEM_XCPT_FLAGS_OF_INSTR | IEM_XCPT_FLAGS_ICEBP_INSTR)))
     3623        {
     3624            fIsHwXcpt = true;
     3625            do
     3626            {
     3627                /* NMIs have a dedicated VM-execution control for causing VM-exits. */
     3628                if (uVector == X86_XCPT_NMI)
     3629                {
     3630                    fIntercept = RT_BOOL(pVmcs->u32PinCtls & VMX_PIN_CTLS_NMI_EXIT);
     3631                    break;
     3632                }
     3633
     3634                /* Page-faults are subject to masking using its error code. */
     3635                uint32_t fXcptBitmap = pVmcs->u32XcptBitmap;
     3636                if (uVector == X86_XCPT_PF)
     3637                {
     3638                    uint32_t const fXcptPFMask  = pVmcs->u32XcptPFMask;
     3639                    uint32_t const fXcptPFMatch = pVmcs->u32XcptPFMatch;
     3640                    if ((uErrCode & fXcptPFMask) != fXcptPFMatch)
     3641                        fXcptBitmap ^= RT_BIT(X86_XCPT_PF);
     3642                }
     3643
     3644                /* Consult the exception bitmap. */
     3645                if (fXcptBitmap & RT_BIT(uVector))
     3646                    fIntercept = true;
     3647            } while (0);
     3648        }
     3649        /* else: Software interrupts cannot be intercepted and therefore do not cause a VM-exit. */
     3650    }
     3651    else if (fFlags & IEM_XCPT_FLAGS_T_EXT_INT)
     3652    {
     3653        /* External interrupts have a dedicated VM-execution control for causing VM-exits. */
     3654        fIntercept  = RT_BOOL(pVmcs->u32PinCtls & VMX_PIN_CTLS_EXT_INT_EXIT);
     3655
     3656        /** @todo NSTVMX: What about "acknowledge interrupt on exit" control? */
     3657    }
     3658
     3659    /*
     3660     * Now that we've determined whether the external interrupt or hardware exception
     3661     * causes a VM-exit, we need to construct the relevant VM-exit information and
     3662     * cause the VM-exit.
     3663     */
     3664    if (fIntercept)
     3665    {
     3666        uint64_t uExitQual = 0;
     3667        if (fIsHwXcpt)
     3668        {
     3669            if (uVector == X86_XCPT_PF)
     3670                uExitQual = uCr2;
     3671            else if (uVector == X86_XCPT_DB)
     3672            {
     3673                IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DR6);
     3674                uExitQual = pVCpu->cpum.GstCtx.dr[6] & VMX_VMCS_EXIT_QUAL_VALID_MASK;
     3675            }
     3676        }
     3677
     3678        /* Construct the rest of the event related information fields and cause the VM-exit. */
     3679        uint32_t const uExitReason    = (fFlags & IEM_XCPT_FLAGS_T_EXT_INT) ? VMX_EXIT_EXT_INT : VMX_EXIT_XCPT_OR_NMI;
     3680        uint8_t  const fNmiUnblocking = 0;  /** @todo NSTVMX: Implement NMI-unblocking due to IRET. */
     3681        uint8_t  const fErrCodeValid  = (fFlags & IEM_XCPT_FLAGS_ERR);
     3682        uint8_t  const uIntInfoType   = iemVmxGetEventType(uVector, fFlags);
     3683        uint32_t const uExitIntInfo   = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR,           uVector)
     3684                                      | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_TYPE,             uIntInfoType)
     3685                                      | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_ERR_CODE_VALID,   fErrCodeValid)
     3686                                      | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_NMI_UNBLOCK_IRET, fNmiUnblocking)
     3687                                      | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VALID,            1);
     3688        iemVmxVmcsSetExitIntInfo(pVCpu, uExitIntInfo);
     3689        iemVmxVmcsSetExitIntErrCode(pVCpu, uErrCode);
     3690        iemVmxVmcsSetExitQual(pVCpu, uExitQual);
     3691        iemVmxVmexit(pVCpu, uExitReason);
     3692    }
     3693
     3694    return VINF_VMX_INTERCEPT_NOT_ACTIVE;
    34763695}
    34773696
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