Changeset 70781 in vbox for trunk/src/VBox/VMM
- Timestamp:
- Jan 29, 2018 5:24:06 AM (7 years ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/CPUMAllRegs.cpp
r70732 r70781 2585 2585 2586 2586 /** 2587 * Checks whether the SVM nested-guest is in a state to receive virtual 2588 * (injected by VMRUN) interrupts.2587 * Checks whether the SVM nested-guest is in a state to receive virtual (setup 2588 * for injection by VMRUN instruction) interrupts. 2589 2589 * 2590 2590 * @returns VBox status code. 2591 2591 * @retval true if it's ready, false otherwise. 2592 2592 * 2593 * @param pCtx The guest-CPU context. 2594 */ 2595 VMM_INT_DECL(bool) CPUMCanSvmNstGstTakeVirtIntr(PCCPUMCTX pCtx) 2593 * @param pVCpu The cross context virtual CPU structure of the calling EMT. 2594 * @param pCtx The guest-CPU context. 2595 */ 2596 VMM_INT_DECL(bool) CPUMCanSvmNstGstTakeVirtIntr(PVMCPU pVCpu, PCCPUMCTX pCtx) 2596 2597 { 2597 2598 #ifdef IN_RC 2598 RT_NOREF (pCtx);2599 RT_NOREF2(pVCpu, pCtx); 2599 2600 AssertReleaseFailedReturn(false); 2600 2601 #else 2601 2602 Assert(CPUMIsGuestInSvmNestedHwVirtMode(pCtx)); 2602 2603 Assert(pCtx->hwvirt.fGif); 2603 2604 PCSVMVMCBCTRL pVmcbCtrl = &pCtx->hwvirt.svm.CTX_SUFF(pVmcb)->ctrl; 2605 if ( !pVmcbCtrl->IntCtrl.n.u1IgnoreTPR 2606 && pVmcbCtrl->IntCtrl.n.u4VIntrPrio <= pVmcbCtrl->IntCtrl.n.u8VTPR) 2607 return false; 2608 2609 if (!pCtx->rflags.Bits.u1IF) 2610 return false; 2611 2612 return true; 2604 Assert(pCtx->hwvirt.fGif); 2605 2606 /* 2607 * Although at present, the V_TPR and V_INTR_PRIO fields are not modified 2608 * by SVM R0 code and we could inspect them directly here, we play it 2609 * safe and ask HM if it has cached the VMCB. 2610 */ 2611 if (!pCtx->hwvirt.svm.fHMCachedVmcb) 2612 { 2613 PCSVMVMCBCTRL pVmcbCtrl = &pCtx->hwvirt.svm.CTX_SUFF(pVmcb)->ctrl; 2614 if ( !pVmcbCtrl->IntCtrl.n.u1IgnoreTPR 2615 && pVmcbCtrl->IntCtrl.n.u4VIntrPrio <= pVmcbCtrl->IntCtrl.n.u8VTPR) 2616 return false; 2617 2618 X86EFLAGS fEFlags; 2619 if (pVmcbCtrl->IntCtrl.n.u1VIntrMasking) 2620 fEFlags.u = pCtx->eflags.u; 2621 else 2622 fEFlags.u = pCtx->hwvirt.svm.HostState.rflags.u; 2623 2624 return fEFlags.Bits.u1IF; 2625 } 2626 2627 return HMCanSvmNstGstTakeVirtIntr(pVCpu, pCtx); 2613 2628 #endif 2614 2629 } -
trunk/src/VBox/VMM/VMMAll/HMSVMAll.cpp
r70700 r70781 535 535 else 536 536 fEFlags.u = pCtx->eflags.u; 537 538 537 return fEFlags.Bits.u1IF; 539 538 } 540 539 540 541 /** 542 * Checks whether the SVM nested-guest is in a state to receive virtual (setup 543 * for injection by VMRUN instruction) interrupts. 544 * 545 * @returns true if it's ready, false otherwise. 546 * @param pVCpu The cross context virtual CPU structure of the calling EMT. 547 * @param pCtx The guest-CPU context. 548 * 549 * @remarks This function looks at the VMCB cache rather than directly at the 550 * nested-guest VMCB. The latter may have been modified for executing 551 * using hardware-assisted SVM. 552 * 553 * @sa CPUMCanSvmNstGstTakeVirtIntr. 554 */ 555 VMM_INT_DECL(bool) HMCanSvmNstGstTakeVirtIntr(PVMCPU pVCpu, PCCPUMCTX pCtx) 556 { 557 #ifdef IN_RC 558 RT_NOREF2(pVCpu, pCtx); 559 AssertReleaseFailedReturn(false); 560 #else 561 Assert(pCtx->hwvirt.svm.fHMCachedVmcb); 562 PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache; 563 564 PCSVMVMCBCTRL pVmcbCtrl = &pCtx->hwvirt.svm.CTX_SUFF(pVmcb)->ctrl; 565 if ( !pVmcbCtrl->IntCtrl.n.u1IgnoreTPR 566 && pVmcbCtrl->IntCtrl.n.u4VIntrPrio <= pVmcbCtrl->IntCtrl.n.u8VTPR) 567 return false; 568 569 X86EFLAGS fEFlags; 570 if (pVmcbNstGstCache->fVIntrMasking) 571 fEFlags.u = pCtx->eflags.u; 572 else 573 fEFlags.u = pCtx->hwvirt.svm.HostState.rflags.u; 574 return fEFlags.Bits.u1IF; 575 #endif 576 } 577 -
trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
r70732 r70781 3505 3505 * by the physical CPU. 3506 3506 */ 3507 /** @todo later explore this for performance reasons. Right now the hardware 3508 * takes care of virtual interrupt injection for nested-guest. */ 3507 3509 #if 0 3508 3510 if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST) 3509 3511 && (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_VINTR) 3510 && CPUMCanSvmNstGstTakeVirtIntr(p Ctx))3512 && CPUMCanSvmNstGstTakeVirtIntr(pVCpu, pCtx)) 3511 3513 { 3512 3514 Log4(("Intercepting virtual interrupt -> #VMEXIT\n")); … … 3641 3643 if (fGif) 3642 3644 { 3645 /* 3646 * For nested-guests we have no way to determine if we're injecting a physical or virtual 3647 * interrupt at this point. Hence the partial verification below. 3648 */ 3643 3649 if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx)) 3644 fAllowInt = CPUMCanSvmNstGstTakePhysIntr(pVCpu, pCtx) ;3650 fAllowInt = CPUMCanSvmNstGstTakePhysIntr(pVCpu, pCtx) || CPUMCanSvmNstGstTakeVirtIntr(pVCpu, pCtx); 3645 3651 else 3646 3652 fAllowInt = RT_BOOL(pCtx->eflags.u32 & X86_EFL_IF); … … 3681 3687 } 3682 3688 else 3683 {3684 #ifdef VBOX_WITH_NESTED_HWVIRT3685 /*3686 * If IEM emulated VMRUN and injected an event, it would not clear the EVENTINJ::Valid bit3687 * as a physical CPU clears it in the VMCB as part of the #VMEXIT (if the AMD spec. is to3688 * believed, real behavior might differ). Regardless, IEM does it only on #VMEXIT for now3689 * and since we are continuing nested-guest execution using hardware-assisted SVM, we need3690 * to clear this field otherwise we will inject the event twice, see @bugref{7243#78}.3691 */3692 if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))3693 pVmcb->ctrl.EventInject.n.u1Valid = 0;3694 #endif3695 3689 Assert(pVmcb->ctrl.EventInject.n.u1Valid == 0); 3696 }3697 3690 3698 3691 /* -
trunk/src/VBox/VMM/VMMR3/EM.cpp
r70732 r70781 1641 1641 } 1642 1642 1643 #ifdef VBOX_WITH_NESTED_HWVIRT 1644 /** 1645 * Helper for emR3ForcedActions() for injecting interrupts into the 1646 * nested-guest. 1647 * 1648 * @returns VBox status code. 1649 * @param pVCpu The cross context virtual CPU structure. 1650 * @param pCtx Pointer to the nested-guest CPU context. 1651 * @param pfResched Where to store whether a reschedule is required. 1652 * @param pfInject Where to store whether an interrupt was injected (and if 1653 * a wake up is pending). 1654 */ 1655 static int emR3NstGstInjectIntr(PVMCPU pVCpu, PCPUMCTX pCtx, bool *pfResched, bool *pfInject) 1656 { 1657 *pfResched = false; 1658 *pfInject = false; 1659 if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx)) 1660 { 1661 PVM pVM = pVCpu->CTX_SUFF(pVM); 1662 bool fGif = pCtx->hwvirt.fGif; 1663 #ifdef VBOX_WITH_RAW_MODE 1664 fGif &= !PATMIsPatchGCAddr(pVM, pCtx->eip); 1665 #endif 1666 if (fGif) 1667 { 1668 if (CPUMCanSvmNstGstTakePhysIntr(pVCpu, pCtx)) 1669 { 1670 Assert(pVCpu->em.s.enmState != EMSTATE_WAIT_SIPI); 1671 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)) 1672 { 1673 if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, pCtx, SVM_CTRL_INTERCEPT_INTR)) 1674 { 1675 VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_INTR, 0, 0); 1676 if (RT_SUCCESS(rcStrict)) 1677 { 1678 /** @todo r=ramshankar: Do we need to signal a wakeup here? If a nested-guest 1679 * doesn't intercept HLT but intercepts INTR? */ 1680 *pfResched = true; 1681 return VINF_EM_RESCHEDULE; 1682 } 1683 1684 AssertMsgFailed(("INTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict))); 1685 return VINF_EM_TRIPLE_FAULT; 1686 } 1687 1688 /* Note: it's important to make sure the return code from TRPMR3InjectEvent isn't ignored! */ 1689 /** @todo this really isn't nice, should properly handle this */ 1690 int rc = TRPMR3InjectEvent(pVM, pVCpu, TRPM_HARDWARE_INT); 1691 if (pVM->em.s.fIemExecutesAll && ( rc == VINF_EM_RESCHEDULE_REM 1692 || rc == VINF_EM_RESCHEDULE_HM 1693 || rc == VINF_EM_RESCHEDULE_RAW)) 1694 { 1695 rc = VINF_EM_RESCHEDULE; 1696 } 1697 1698 *pfResched = true; 1699 *pfInject = true; 1700 return rc; 1701 } 1702 } 1703 1704 if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST) 1705 && CPUMCanSvmNstGstTakeVirtIntr(pVCpu, pCtx)) 1706 { 1707 if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, pCtx, SVM_CTRL_INTERCEPT_VINTR)) 1708 { 1709 VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_VINTR, 0, 0); 1710 if (RT_SUCCESS(rcStrict)) 1711 { 1712 /** @todo r=ramshankar: Do we need to signal a wakeup here? If a nested-guest 1713 * doesn't intercept HLT but intercepts VINTR? */ 1714 *pfResched = true; 1715 return VINF_EM_RESCHEDULE; 1716 } 1717 1718 AssertMsgFailed(("VINTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict))); 1719 return VINF_EM_TRIPLE_FAULT; 1720 } 1721 1722 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST); 1723 uint8_t const uNstGstVector = CPUMGetSvmNstGstInterrupt(pCtx); 1724 AssertMsg(uNstGstVector > 0 && uNstGstVector <= X86_XCPT_LAST, ("Invalid VINTR vector %#x\n", uNstGstVector)); 1725 TRPMAssertTrap(pVCpu, uNstGstVector, TRPM_HARDWARE_INT); 1726 Log(("EM: Asserting nested-guest virt. hardware intr: %#x\n", uNstGstVector)); 1727 1728 *pfResched = true; 1729 *pfInject = true; 1730 return VINF_EM_RESCHEDULE; 1731 } 1732 } 1733 return VINF_SUCCESS; 1734 } 1735 1736 if (CPUMIsGuestInVmxNestedHwVirtMode(pCtx)) 1737 { /** @todo Nested VMX. */ } 1738 1739 /* Shouldn't really get here. */ 1740 AssertMsgFailed(("Unrecognized nested hwvirt. arch!\n")); 1741 return VERR_EM_INTERNAL_ERROR; 1742 } 1743 #endif 1643 1744 1644 1745 /** … … 1951 2052 * Interrupts. 1952 2053 */ 1953 /** @todo this can be optimized a bit. later. */1954 2054 bool fWakeupPending = false; 1955 2055 if ( !VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY) … … 1959 2059 && !TRPMHasTrap(pVCpu)) /* an interrupt could already be scheduled for dispatching in the recompiler. */ 1960 2060 { 2061 Assert(!HMR3IsEventPending(pVCpu)); 1961 2062 PCPUMCTX pCtx = pVCpu->em.s.pCtx; 1962 bool fGif = pCtx->hwvirt.fGif; 2063 #ifdef VBOX_WITH_NESTED_HWVIRT 2064 if (CPUMIsGuestInNestedHwVirtMode(pCtx)) 2065 { 2066 bool fResched, fInject; 2067 rc2 = emR3NstGstInjectIntr(pVCpu, pCtx, &fResched, &fInject); 2068 if (fInject) 2069 { 2070 fWakeupPending = true; 2071 #ifdef VBOX_STRICT 2072 rcIrq = rc2; 2073 #endif 2074 } 2075 if (fResched) 2076 UPDATE_RC(); 2077 } 2078 else 2079 #endif 2080 { 2081 if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC) 2082 #ifdef VBOX_WITH_NESTED_HWVIRT 2083 && pCtx->hwvirt.fGif 2084 #endif 1963 2085 #ifdef VBOX_WITH_RAW_MODE 1964 /* We cannot just inspect EFLAGS when nested hw.virt is enabled (see e.g. CPUMCanSvmNstGstTakePhysIntr). */ 1965 fGif &= !PATMIsPatchGCAddr(pVM, pCtx->eip); 1966 #endif 1967 if (fGif) 1968 { 1969 bool fIntrEnabled; 1970 #ifdef VBOX_WITH_NESTED_HWVIRT 1971 if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx)) 1972 fIntrEnabled = CPUMCanSvmNstGstTakePhysIntr(pVCpu, pCtx); 1973 else 1974 fIntrEnabled = pCtx->eflags.Bits.u1IF; 1975 #else 1976 fIntrEnabled = pCtx->eflags.Bits.u1IF; 1977 #endif 1978 if (fIntrEnabled) 2086 && !PATMIsPatchGCAddr(pVM, pCtx->eip) 2087 #endif 2088 && pCtx->eflags.Bits.u1IF) 1979 2089 { 1980 Assert(!HMR3IsEventPending(pVCpu));1981 2090 Assert(pVCpu->em.s.enmState != EMSTATE_WAIT_SIPI); 1982 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)) 2091 /* Note: it's important to make sure the return code from TRPMR3InjectEvent isn't ignored! */ 2092 /** @todo this really isn't nice, should properly handle this */ 2093 rc2 = TRPMR3InjectEvent(pVM, pVCpu, TRPM_HARDWARE_INT); 2094 if (pVM->em.s.fIemExecutesAll && ( rc2 == VINF_EM_RESCHEDULE_REM 2095 || rc2 == VINF_EM_RESCHEDULE_HM 2096 || rc2 == VINF_EM_RESCHEDULE_RAW)) 1983 2097 { 1984 #ifdef VBOX_WITH_NESTED_HWVIRT1985 if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, pCtx, SVM_CTRL_INTERCEPT_INTR))1986 {1987 VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_INTR, 0, 0);1988 if (RT_SUCCESS(rcStrict))1989 rc2 = VINF_EM_RESCHEDULE;1990 else1991 {1992 AssertMsgFailed(("INTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));1993 Log(("EM: SVM Nested-guest INTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));1994 /** @todo should we call iemInitiateCpuShutdown? Should this1995 * result in trapping triple-fault intercepts? */1996 rc2 = VINF_EM_TRIPLE_FAULT;1997 }1998 }1999 else2000 #endif2001 {2002 /* Note: it's important to make sure the return code from TRPMR3InjectEvent isn't ignored! */2003 /** @todo this really isn't nice, should properly handle this */2004 rc2 = TRPMR3InjectEvent(pVM, pVCpu, TRPM_HARDWARE_INT);2005 if (pVM->em.s.fIemExecutesAll && ( rc2 == VINF_EM_RESCHEDULE_REM2006 || rc2 == VINF_EM_RESCHEDULE_HM2007 || rc2 == VINF_EM_RESCHEDULE_RAW))2008 rc2 = VINF_EM_RESCHEDULE;2009 #ifdef VBOX_STRICT2010 rcIrq = rc2;2011 #endif2012 }2013 UPDATE_RC();2014 /* Reschedule required: We must not miss the wakeup below! */2015 fWakeupPending = true;2016 }2017 }2018 #ifdef VBOX_WITH_NESTED_HWVIRT2019 /*2020 * Check nested-guest virtual interrupts.2021 */2022 else if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST)2023 && CPUMCanSvmNstGstTakeVirtIntr(pCtx))2024 {2025 if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, pCtx, SVM_CTRL_INTERCEPT_VINTR))2026 {2027 VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_VINTR, 0, 0);2028 if (RT_SUCCESS(rcStrict))2029 rc2 = VINF_EM_RESCHEDULE;2030 else2031 {2032 AssertMsgFailed(("VINTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));2033 Log(("EM: SVM Nested-guest VINTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));2034 /** @todo should we call iemInitiateCpuShutdown? Should this2035 * result in trapping triple-fault intercepts? */2036 rc2 = VINF_EM_TRIPLE_FAULT;2037 }2038 }2039 else2040 {2041 /*2042 * Prepare the nested-guest interrupt for injection.2043 */2044 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST);2045 uint8_t uNstGstVector = CPUMGetSvmNstGstInterrupt(pCtx);2046 TRPMAssertTrap(pVCpu, uNstGstVector, TRPM_HARDWARE_INT);2047 Log(("EM: Asserting nested-guest virt. hardware intr: %#x\n", uNstGstVector));2048 /** @todo reschedule to HM/REM later, when the HMR0 nested-guest execution is2049 * done. For now just reschedule to IEM. */2050 2098 rc2 = VINF_EM_RESCHEDULE; 2051 2099 } 2100 #ifdef VBOX_STRICT 2101 rcIrq = rc2; 2102 #endif 2052 2103 UPDATE_RC(); 2053 2104 /* Reschedule required: We must not miss the wakeup below! */ 2054 2105 fWakeupPending = true; 2055 2106 } 2056 #endif /* VBOX_WITH_NESTED_HWVIRT */2057 2107 } 2058 2108 }
Note:
See TracChangeset
for help on using the changeset viewer.