Changeset 79687 in vbox
- Timestamp:
- Jul 11, 2019 9:08:08 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
r79665 r79687 11176 11176 if (!RTThreadPreemptIsPending(NIL_RTTHREAD)) 11177 11177 { 11178 pVCpu->hm.s.Event.fPending = false;11179 11180 11178 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX 11181 11179 /* 11182 11180 * If we are executing a nested-guest make sure that we should intercept subsequent 11183 * events. The one we are injecting might be part of VM-entry. 11181 * events. The one we are injecting might be part of VM-entry. This is mainly to keep 11182 * the VM-exit instruction emulation happy. 11184 11183 */ 11185 11184 if (pVmxTransient->fIsNestedGuest) … … 11191 11190 * 11192 11191 * Note! The caller expects to continue with interrupts & longjmps disabled on successful 11193 * returns from this function, so don'tenable them here.11192 * returns from this function, so do -not- enable them here. 11194 11193 */ 11194 pVCpu->hm.s.Event.fPending = false; 11195 11195 return VINF_SUCCESS; 11196 11196 } … … 13587 13587 13588 13588 13589 /** 13590 * Handle a condition that occurred while delivering an event through the guest 13591 * IDT. 13589 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX 13590 /** 13591 * Handle a condition that occurred while delivering an event through the 13592 * nested-guest IDT. 13593 * 13594 * @returns VBox status code. 13595 * @param pVCpu The cross context virtual CPU structure. 13596 * @param pVmxTransient The VMX-transient structure. 13597 * 13598 * @remarks No-long-jump zone!!! 13599 */ 13600 static int hmR0VmxCheckExitDueToEventDeliveryNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient) 13601 { 13602 Assert(pVmxTransient->fIsNestedGuest); 13603 Assert(!pVCpu->hm.s.Event.fPending); 13604 13605 /* 13606 * Construct a pending event from IDT vectoring information. 13607 * 13608 * This event could have originated from an event that we or the guest hypervisor injected 13609 * during nested-guest VM-entry or could arise from hardware-assisted VMX execution of the 13610 * nested-guest (for e.g. a #GP fault causing a #PF VM-exit). 13611 * 13612 * If the VM-exit is caused indirectly due to delivery of: 13613 * - #PF: the CPU would have updated CR2. 13614 * - NMI: NMI/virtual-NMI blocking is in effect. 13615 * 13616 * The main differences between this function and its non-nested version are as follows: 13617 * 13618 * - Here we record software interrupts, software exceptions and privileged software 13619 * exceptions as pending for re-injection when necessary along with gathering the 13620 * instruction length. The non-nested version would fix-up the VM-exit that occurred 13621 * during delivery of such an event and restart execution of the guest without 13622 * re-injecting the event and does not record the instruction length. 13623 * 13624 * - Here we record #PF as pending for re-injection while the non-nested version would 13625 * handle it via the page-fault VM-exit handler which isn't required when nested paging 13626 * is a requirement for hardware-assisted VMX execution of nested-guests. 13627 * 13628 * See Intel spec. 27.1 "Architectural State Before A VM Exit". 13629 */ 13630 int rc = hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient); 13631 AssertRCReturn(rc, rc); 13632 13633 uint32_t const uIdtVectorInfo = pVmxTransient->uIdtVectoringInfo; 13634 if (VMX_IDT_VECTORING_INFO_IS_VALID(uIdtVectorInfo)) 13635 { 13636 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(uIdtVectorInfo); 13637 uint8_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(uIdtVectorInfo); 13638 13639 /* 13640 * Get the nasty stuff out of the way. 13641 */ 13642 { 13643 int rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient); 13644 AssertRCReturn(rc, rc); 13645 13646 uint32_t const uExitIntInfo = pVmxTransient->uExitIntInfo; 13647 if (VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo)) 13648 { 13649 uint8_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo); 13650 uint32_t const uExitVectorType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo); 13651 Assert(uExitVectorType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT); 13652 13653 uint32_t const fIdtVectorFlags = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType); 13654 uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType); 13655 13656 IEMXCPTRAISEINFO fRaiseInfo; 13657 IEMXCPTRAISE const enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, 13658 uExitVector, &fRaiseInfo); 13659 if (enmRaise == IEMXCPTRAISE_CPU_HANG) 13660 { 13661 Log4Func(("IDT: Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", fRaiseInfo)); 13662 return VERR_EM_GUEST_CPU_HANG; 13663 } 13664 } 13665 } 13666 13667 /* 13668 * Things look legit, continue... 13669 */ 13670 uint32_t u32ErrCode; 13671 bool const fErrCodeValid = VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(uIdtVectorInfo); 13672 if (fErrCodeValid) 13673 { 13674 rc = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient); 13675 AssertRCReturn(rc, rc); 13676 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode; 13677 } 13678 else 13679 u32ErrCode = 0; 13680 13681 uint32_t cbInstr; 13682 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT 13683 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT 13684 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT) 13685 { 13686 rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient); 13687 AssertRCReturn(rc, rc); 13688 cbInstr = pVmxTransient->cbInstr; 13689 } 13690 else 13691 cbInstr = 0; 13692 13693 RTGCUINTPTR GCPtrFaultAddress; 13694 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(uIdtVectorInfo)) 13695 GCPtrFaultAddress = pVCpu->cpum.GstCtx.cr2; 13696 else 13697 GCPtrFaultAddress = 0; 13698 13699 if (VMX_IDT_VECTORING_INFO_IS_XCPT_NMI(uIdtVectorInfo)) 13700 CPUMSetGuestNmiBlocking(pVCpu, true); 13701 13702 hmR0VmxSetPendingEvent(pVCpu, uIdtVectorInfo, cbInstr, u32ErrCode, GCPtrFaultAddress); 13703 } 13704 13705 return VINF_SUCCESS; 13706 } 13707 #endif 13708 13709 13710 /** 13711 * Handle a condition that occurred while delivering an event through the guest or 13712 * nested-guest IDT. 13592 13713 * 13593 13714 * @returns Strict VBox status code (i.e. informational status codes too). … … 13605 13726 static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient) 13606 13727 { 13728 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX 13729 if (pVmxTransient->fIsNestedGuest) 13730 return hmR0VmxCheckExitDueToEventDeliveryNested(pVCpu, pVmxTransient); 13731 #endif 13732 13733 Assert(!pVmxTransient->fIsNestedGuest); 13734 VBOXSTRICTRC rcStrict = VINF_SUCCESS; 13735 13607 13736 /* Read the IDT vectoring info. and VM-exit interruption info. */ 13608 13737 { … … 13612 13741 } 13613 13742 13614 VBOXSTRICTRC rcStrict = VINF_SUCCESS; 13615 uint32_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo); 13616 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo)) 13617 { 13618 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo); 13619 uint32_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo); 13743 uint32_t const uExitIntInfo = pVmxTransient->uExitIntInfo; 13744 uint8_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo); 13745 uint32_t const uIdtVectorInfo = pVmxTransient->uIdtVectoringInfo; 13746 if (VMX_IDT_VECTORING_INFO_IS_VALID(uIdtVectorInfo)) 13747 { 13748 uint32_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(uIdtVectorInfo); 13749 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(uIdtVectorInfo); 13620 13750 13621 13751 /* … … 13637 13767 fRaiseInfo = IEMXCPTRAISEINFO_NONE; 13638 13768 } 13639 else if (VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo)) 13640 { 13641 uint32_t const uExitVectorType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo); 13769 else if (VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo)) 13770 { 13771 uint32_t const uExitVectorType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo); 13772 Assert(uExitVectorType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT); 13773 13642 13774 uint32_t const fIdtVectorFlags = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType); 13643 13775 uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType); 13644 13645 /** @todo Make AssertMsgReturn as just AssertMsg later. */13646 AssertMsgReturn(uExitVectorType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT,13647 ("Unexpected VM-exit interruption vector type %#x!\n", uExitVectorType), VERR_VMX_IPE_5);13648 13776 13649 13777 enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector, &fRaiseInfo); … … 13691 13819 case IEMXCPTRAISE_CURRENT_XCPT: 13692 13820 { 13693 Log4Func(("IDT: Pending secondary Xcpt: uIdtVectoringInfo=%#RX64 uExitIntInfo=%#RX64\n", 13694 pVmxTransient->uIdtVectoringInfo, pVmxTransient->uExitIntInfo));13821 Log4Func(("IDT: Pending secondary Xcpt: uIdtVectoringInfo=%#RX64 uExitIntInfo=%#RX64\n", uIdtVectorInfo, 13822 uExitIntInfo)); 13695 13823 Assert(rcStrict == VINF_SUCCESS); 13696 13824 break; … … 13700 13828 { 13701 13829 uint32_t u32ErrCode; 13702 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID( pVmxTransient->uIdtVectoringInfo))13830 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(uIdtVectorInfo)) 13703 13831 { 13704 13832 int rc = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient); … … 13711 13839 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see hmR0VmxExitXcptPF(). */ 13712 13840 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflect); 13713 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO( pVmxTransient->uIdtVectoringInfo),13714 0 /* cbInstr */,u32ErrCode, pVCpu->cpum.GstCtx.cr2);13841 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(uIdtVectorInfo), 0 /* cbInstr */, 13842 u32ErrCode, pVCpu->cpum.GstCtx.cr2); 13715 13843 13716 13844 Log4Func(("IDT: Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->hm.s.Event.u64IntInfo, … … 13770 13898 } 13771 13899 } 13772 else if ( VMX_EXIT_INT_INFO_IS_VALID( pVmxTransient->uExitIntInfo)13773 && VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET( pVmxTransient->uExitIntInfo)13900 else if ( VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo) 13901 && VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(uExitIntInfo) 13774 13902 && uExitVector != X86_XCPT_DF 13775 13903 && hmR0VmxIsPinCtlsSet(pVCpu, pVmxTransient, VMX_PIN_CTLS_VIRT_NMI)) 13776 13904 { 13777 Assert(!VMX_IDT_VECTORING_INFO_IS_VALID( pVmxTransient->uIdtVectoringInfo));13905 Assert(!VMX_IDT_VECTORING_INFO_IS_VALID(uIdtVectorInfo)); 13778 13906 13779 13907 /* … … 16297 16425 * using hardware-assisted VMX would would trigger the same EPT misconfig VM-exit again. 16298 16426 */ 16299 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending)) 16427 if (!pVCpu->hm.s.Event.fPending) 16428 { /* likely */ } 16429 else 16300 16430 { 16301 16431 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret); 16432 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX 16433 /** @todo NSTVMX: Think about how this should be handled. */ 16434 if (pVmxTransient->fIsNestedGuest) 16435 return VERR_VMX_IPE_3; 16436 #endif 16302 16437 return VINF_EM_RAW_INJECT_TRPM_EVENT; 16303 16438 } … … 16414 16549 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode); 16415 16550 16416 16417 16551 /* Handle the pagefault trap for the nested shadow table. */ 16418 16552 PVM pVM = pVCpu->CTX_SUFF(pVM); … … 16815 16949 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient); 16816 16950 16817 int rc = hmR0Vmx ReadExitIntInfoVmcs(pVmxTransient);16951 int rc = hmR0VmxCheckExitDueToEventDeliveryNested(pVCpu, pVmxTransient); 16818 16952 AssertRCReturn(rc, rc); 16819 16953 16954 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient); 16955 AssertRCReturn(rc, rc); 16956 16820 16957 uint64_t const uExitIntInfo = pVmxTransient->uExitIntInfo; 16821 uint32_t const uEx tIntType= VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);16958 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo); 16822 16959 Assert(VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo)); 16823 16960 16824 /* 16825 * Make sure not to use stale/previous VM-exit instruction length since we read the 16826 * instruction length from the VMCS below only for software exceptions and privileged 16827 * software exceptions but we pass it for all exception VM-exits below. 16828 */ 16829 pVmxTransient->cbInstr = 0; 16830 16831 switch (uExtIntType) 16961 switch (uExitIntType) 16832 16962 { 16833 16963 /* 16834 16964 * Physical NMIs: 16835 * 16965 * We shouldn't direct host physical NMIs to the nested-guest. Dispatch it to the host. 16836 16966 */ 16837 16967 case VMX_EXIT_INT_INFO_TYPE_NMI: … … 16842 16972 * Software exceptions, 16843 16973 * Privileged software exceptions: 16844 * 16974 * Figure out if the exception must be delivered to the guest or the nested-guest. 16845 16975 * 16846 * For VM-exits due to software exceptions (those generated by INT3 or INTO) and privileged 16847 * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction 16848 * length. 16976 * For VM-exits due to software exceptions (those generated by INT3 or INTO) and privileged 16977 * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction 16978 * length. However, if delivery of a software interrupt, software exception or privileged 16979 * software exception causes a VM-exit, that too provides the VM-exit instruction length. 16980 * Hence, we read it for all exception types below to keep it simple. 16849 16981 */ 16850 16982 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT: 16851 16983 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT: 16852 { 16853 rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient); 16984 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT: 16985 { 16986 rc = hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient); 16987 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient); 16854 16988 AssertRCReturn(rc, rc); 16855 RT_FALL_THRU(); 16856 } 16857 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT: 16858 { 16859 rc = hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient); 16860 AssertRCReturn(rc, rc); 16989 16990 /* Nested paging is currently a requirement, otherwise we would need to handle shadow #PFs. */ 16991 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging); 16861 16992 16862 16993 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo); … … 16882 17013 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo; 16883 17014 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode; 16884 17015 if (pVCpu->hm.s.Event.fPending) 17016 { 17017 Assert(ExitEventInfo.uIdtVectoringInfo == pVCpu->hm.s.Event.u64IntInfo); 17018 Assert(ExitEventInfo.uIdtVectoringErrCode == pVCpu->hm.s.Event.u32ErrCode); 17019 pVCpu->hm.s.Event.fPending = false; 17020 } 16885 17021 return IEMExecVmxVmexitXcpt(pVCpu, &ExitInfo, &ExitEventInfo); 16886 17022 } … … 16889 17025 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging); 16890 17026 16891 /* If the guest hypervisor is not intercepting the exception, forward it to the guest. */ 16892 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(uExitIntInfo), pVmxTransient->cbInstr, 16893 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual); 17027 /* 17028 * If the guest hypervisor is not intercepting an exception that caused a VM-exit directly, 17029 * forward it to the guest (for e.g, an instruction raises a #GP that causes a VM-exit but 17030 * the guest hypervisor is not intercept #GPs, inject #GP into the guest). 17031 */ 17032 if (!pVCpu->hm.s.Event.fPending) 17033 { 17034 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(uExitIntInfo), pVmxTransient->cbInstr, 17035 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual); 17036 } 16894 17037 return VINF_SUCCESS; 16895 17038 } … … 17486 17629 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient); 17487 17630 17631 int rc = hmR0VmxCheckExitDueToEventDeliveryNested(pVCpu, pVmxTransient); 17632 AssertRCReturn(rc, rc); 17633 17488 17634 Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_APIC_ACCESS)); 17489 int rc= hmR0VmxReadExitQualVmcs(pVCpu, pVmxTransient);17490 rc 17491 rc 17492 rc 17635 rc = hmR0VmxReadExitQualVmcs(pVCpu, pVmxTransient); 17636 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient); 17637 rc |= hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient); 17638 rc |= hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient); 17493 17639 AssertRCReturn(rc, rc); 17494 17640 … … 17503 17649 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo; 17504 17650 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode; 17651 if (pVCpu->hm.s.Event.fPending) 17652 { 17653 Assert(ExitEventInfo.uIdtVectoringInfo == pVCpu->hm.s.Event.u64IntInfo); 17654 Assert(ExitEventInfo.uIdtVectoringErrCode == pVCpu->hm.s.Event.u32ErrCode); 17655 pVCpu->hm.s.Event.fPending = false; 17656 } 17505 17657 return IEMExecVmxVmexitApicAccess(pVCpu, &ExitInfo, &ExitEventInfo); 17506 17658 }
Note:
See TracChangeset
for help on using the changeset viewer.