Changeset 81168 in vbox for trunk/src/VBox
- Timestamp:
- Oct 9, 2019 8:36:00 AM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 133804
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
r81166 r81168 320 320 * external interrupt or NMI. */ 321 321 bool fVectoringPF; 322 } SVMTRANSIENT, *PSVMTRANSIENT; 322 } SVMTRANSIENT; 323 /** Pointer to SVM transient state. */ 324 typedef SVMTRANSIENT *PSVMTRANSIENT; 325 /** Pointer to a const SVM transient state. */ 326 typedef const SVMTRANSIENT *PCSVMTRANSIENT; 327 323 328 AssertCompileMemberAlignment(SVMTRANSIENT, u64ExitCode, sizeof(uint64_t)); 324 329 AssertCompileMemberAlignment(SVMTRANSIENT, pVmcb, sizeof(uint64_t)); … … 3521 3526 static void hmR0SvmSetIntWindowExiting(PVMCPUCC pVCpu, PSVMVMCB pVmcb) 3522 3527 { 3528 HMSVM_ASSERT_NOT_IN_NESTED_GUEST(&pVCpu->cpum.GstCtx); 3529 3523 3530 /* 3524 3531 * When AVIC isn't supported, set up an interrupt window to cause a #VMEXIT when the guest … … 3532 3539 * is pending), V_IGN_TPR (ignore TPR priorities) and the VINTR intercept all being set. 3533 3540 */ 3534 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM 3535 /* 3536 * Currently we don't overlay interupt windows and if there's any V_IRQ pending in the 3537 * nested-guest VMCB, we avoid setting up any interrupt window on behalf of the outer 3538 * guest. 3539 */ 3540 /** @todo Does this mean we end up prioritizing virtual interrupt 3541 * delivery/window over a physical interrupt (from the outer guest) 3542 * might be pending? */ 3543 bool const fEnableIntWindow = !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST); 3544 if (!fEnableIntWindow) 3545 { 3546 Assert(CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.GstCtx)); 3547 Log4(("Nested-guest V_IRQ already pending\n")); 3548 } 3549 #else 3550 bool const fEnableIntWindow = true; 3551 RT_NOREF(pVCpu); 3552 #endif 3553 if (fEnableIntWindow) 3554 { 3555 Assert(pVmcb->ctrl.IntCtrl.n.u1IgnoreTPR); 3556 pVmcb->ctrl.IntCtrl.n.u1VIrqPending = 1; 3557 pVmcb->ctrl.u32VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INT_CTRL; 3558 hmR0SvmSetCtrlIntercept(pVmcb, SVM_CTRL_INTERCEPT_VINTR); 3559 Log4(("Set VINTR intercept\n")); 3560 } 3541 Assert(pVmcb->ctrl.IntCtrl.n.u1IgnoreTPR); 3542 pVmcb->ctrl.IntCtrl.n.u1VIrqPending = 1; 3543 pVmcb->ctrl.u32VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INT_CTRL; 3544 hmR0SvmSetCtrlIntercept(pVmcb, SVM_CTRL_INTERCEPT_VINTR); 3545 Log4(("Set VINTR intercept\n")); 3561 3546 } 3562 3547 … … 3572 3557 static void hmR0SvmClearIntWindowExiting(PVMCPUCC pVCpu, PSVMVMCB pVmcb) 3573 3558 { 3559 HMSVM_ASSERT_NOT_IN_NESTED_GUEST(&pVCpu->cpum.GstCtx); 3560 3574 3561 PSVMVMCBCTRL pVmcbCtrl = &pVmcb->ctrl; 3575 3562 if ( pVmcbCtrl->IntCtrl.n.u1VIrqPending … … 3583 3570 } 3584 3571 3585 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM 3586 /** 3587 * Evaluates the event to be delivered to the nested-guest and sets it as the 3588 * pending event. 3589 * 3590 * @returns VBox strict status code. 3591 * @param pVCpu The cross context virtual CPU structure. 3592 */ 3593 static VBOXSTRICTRC hmR0SvmEvaluatePendingEventNested(PVMCPUCC pVCpu) 3572 3573 /** 3574 * Evaluates the event to be delivered to the guest and sets it as the pending 3575 * event. 3576 * 3577 * @returns Strict VBox status code. 3578 * @param pVCpu The cross context virtual CPU structure. 3579 * @param pSvmTransient Pointer to the SVM transient structure. 3580 */ 3581 static VBOXSTRICTRC hmR0SvmEvaluatePendingEvent(PVMCPUCC pVCpu, PCSVMTRANSIENT pSvmTransient) 3594 3582 { 3595 3583 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx; 3596 HMSVM_ASSERT_IN_NESTED_GUEST(pCtx);3597 3584 HMSVM_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_HWVIRT 3598 3585 | CPUMCTX_EXTRN_RFLAGS … … 3615 3602 3616 3603 /* 3617 * Check if the guest can receive NMIs.3604 * Check if the guest or nested-guest can receive NMIs. 3618 3605 * Nested NMIs are not allowed, see AMD spec. 8.1.4 "Masking External Interrupts". 3619 3606 * NMIs take priority over maskable interrupts, see AMD spec. 8.5 "Priorities". … … 3625 3612 && !fIntShadow) 3626 3613 { 3614 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM 3627 3615 if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, pCtx, SVM_CTRL_INTERCEPT_NMI)) 3628 3616 { … … 3631 3619 return IEMExecSvmVmexit(pVCpu, SVM_EXIT_NMI, 0, 0); 3632 3620 } 3633 3621 #endif 3634 3622 Log4(("Setting NMI pending for injection\n")); 3635 3623 SVMEVENT Event; … … 3643 3631 else if (!fGif) 3644 3632 hmR0SvmSetCtrlIntercept(pVmcb, SVM_CTRL_INTERCEPT_STGI); 3645 else 3633 else if (!pSvmTransient->fIsNestedGuest) 3646 3634 hmR0SvmSetIntWindowExiting(pVCpu, pVmcb); 3635 /* else: for nested-guests, interrupt-window exiting will be picked up when merging VMCB controls. */ 3647 3636 } 3648 3637 /* 3649 * Check if the nested-guest can receive external interrupts (generated by the guest's 3650 * PIC/APIC). 3638 * Check if the guest can receive external interrupts (PIC/APIC). Once PDMGetInterrupt() 3639 * returns a valid interrupt we -must- deliver the interrupt. We can no longer re-request 3640 * it from the APIC device. 3651 3641 * 3652 * External intercepts, NMI, SMI etc. from the physical CPU are -always- intercepted 3653 * when executing using hardware-assisted SVM, see HMSVM_MANDATORY_GUEST_CTRL_INTERCEPTS. 3654 * 3655 * External interrupts that are generated for the outer guest may be intercepted 3656 * depending on how the nested-guest VMCB was programmed by guest software. 3657 * 3658 * Physical interrupts always take priority over virtual interrupts, 3659 * see AMD spec. 15.21.4 "Injecting Virtual (INTR) Interrupts". 3660 * 3642 * For nested-guests, physical interrupts always take priority over virtual interrupts. 3661 3643 * We don't need to inject nested-guest virtual interrupts here, we can let the hardware 3662 * do that work when we execute nested 3644 * do that work when we execute nested-guest code esp. since all the required information 3663 3645 * is in the VMCB, unlike physical interrupts where we need to fetch the interrupt from 3664 3646 * the virtual interrupt controller. 3647 * 3648 * See AMD spec. 15.21.4 "Injecting Virtual (INTR) Interrupts". 3665 3649 */ 3666 3650 else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC) 3667 3651 && !pVCpu->hm.s.fSingleInstruction) 3668 3652 { 3653 bool const fBlockInt = !pSvmTransient->fIsNestedGuest ? !(pCtx->eflags.u32 & X86_EFL_IF) 3654 : CPUMIsGuestSvmPhysIntrEnabled(pVCpu, pCtx); 3669 3655 if ( fGif 3670 && !fIntShadow 3671 && CPUMIsGuestSvmPhysIntrEnabled(pVCpu, pCtx)) 3672 { 3656 && !fBlockInt 3657 && !fIntShadow) 3658 { 3659 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM 3673 3660 if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, pCtx, SVM_CTRL_INTERCEPT_INTR)) 3674 3661 { … … 3677 3664 return IEMExecSvmVmexit(pVCpu, SVM_EXIT_INTR, 0, 0); 3678 3665 } 3679 3666 #endif 3680 3667 uint8_t u8Interrupt; 3681 3668 int rc = PDMGetInterrupt(pVCpu, &u8Interrupt); … … 3703 3690 else if (!fGif) 3704 3691 hmR0SvmSetCtrlIntercept(pVmcb, SVM_CTRL_INTERCEPT_STGI); 3705 else 3692 else if (!pSvmTransient->fIsNestedGuest) 3706 3693 hmR0SvmSetIntWindowExiting(pVCpu, pVmcb); 3694 /* else: for nested-guests, interrupt-window exiting will be picked up when merging VMCB controls. */ 3707 3695 } 3708 3696 3709 3697 return VINF_SUCCESS; 3710 }3711 #endif3712 3713 /**3714 * Evaluates the event to be delivered to the guest and sets it as the pending3715 * event.3716 *3717 * @param pVCpu The cross context virtual CPU structure.3718 */3719 static void hmR0SvmEvaluatePendingEvent(PVMCPUCC pVCpu)3720 {3721 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;3722 HMSVM_ASSERT_NOT_IN_NESTED_GUEST(pCtx);3723 HMSVM_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_HWVIRT3724 | CPUMCTX_EXTRN_RFLAGS3725 | CPUMCTX_EXTRN_HM_SVM_INT_SHADOW);3726 3727 Assert(!pVCpu->hm.s.Event.fPending);3728 PSVMVMCB pVmcb = hmR0SvmGetCurrentVmcb(pVCpu);3729 Assert(pVmcb);3730 3731 bool const fGif = CPUMGetGuestGif(pCtx);3732 bool const fIntShadow = hmR0SvmIsIntrShadowActive(pVCpu);3733 bool const fBlockInt = !(pCtx->eflags.u32 & X86_EFL_IF);3734 bool const fBlockNmi = VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);3735 3736 Log4Func(("fGif=%RTbool fBlockNmi=%RTbool fBlockInt=%RTbool fIntShadow=%RTbool fIntPending=%RTbool NMI pending=%RTbool\n",3737 fGif, fBlockNmi, fBlockInt, fIntShadow,3738 VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC),3739 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI)));3740 3741 /** @todo SMI. SMIs take priority over NMIs. */3742 3743 /*3744 * Check if the guest can receive NMIs.3745 * Nested NMIs are not allowed, see AMD spec. 8.1.4 "Masking External Interrupts".3746 * NMIs take priority over maskable interrupts, see AMD spec. 8.5 "Priorities".3747 */3748 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI)3749 && !fBlockNmi)3750 {3751 if ( fGif3752 && !fIntShadow)3753 {3754 Log4(("Setting NMI pending for injection\n"));3755 SVMEVENT Event;3756 Event.u = 0;3757 Event.n.u1Valid = 1;3758 Event.n.u8Vector = X86_XCPT_NMI;3759 Event.n.u3Type = SVM_EVENT_NMI;3760 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);3761 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);3762 }3763 else if (!fGif)3764 hmR0SvmSetCtrlIntercept(pVmcb, SVM_CTRL_INTERCEPT_STGI);3765 else3766 hmR0SvmSetIntWindowExiting(pVCpu, pVmcb);3767 }3768 /*3769 * Check if the guest can receive external interrupts (PIC/APIC). Once PDMGetInterrupt()3770 * returns a valid interrupt we -must- deliver the interrupt. We can no longer re-request3771 * it from the APIC device.3772 */3773 else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)3774 && !pVCpu->hm.s.fSingleInstruction)3775 {3776 if ( fGif3777 && !fBlockInt3778 && !fIntShadow)3779 {3780 uint8_t u8Interrupt;3781 int rc = PDMGetInterrupt(pVCpu, &u8Interrupt);3782 if (RT_SUCCESS(rc))3783 {3784 Log4(("Setting external interrupt %#x pending for injection\n", u8Interrupt));3785 SVMEVENT Event;3786 Event.u = 0;3787 Event.n.u1Valid = 1;3788 Event.n.u8Vector = u8Interrupt;3789 Event.n.u3Type = SVM_EVENT_EXTERNAL_IRQ;3790 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);3791 }3792 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)3793 {3794 /*3795 * AMD-V has no TPR thresholding feature. TPR and the force-flag will be3796 * updated eventually when the TPR is written by the guest.3797 */3798 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);3799 }3800 else3801 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);3802 }3803 else if (!fGif)3804 hmR0SvmSetCtrlIntercept(pVmcb, SVM_CTRL_INTERCEPT_STGI);3805 else3806 hmR0SvmSetIntWindowExiting(pVCpu, pVmcb);3807 }3808 3698 } 3809 3699 … … 4190 4080 else if (!pVCpu->hm.s.Event.fPending) 4191 4081 { 4192 if (!pSvmTransient->fIsNestedGuest) 4193 hmR0SvmEvaluatePendingEvent(pVCpu); 4194 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM 4195 else 4196 { 4197 VBOXSTRICTRC rcStrict = hmR0SvmEvaluatePendingEventNested(pVCpu); 4198 if ( rcStrict != VINF_SUCCESS 4199 || !CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.GstCtx)) 4200 { 4201 if (!CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.GstCtx)) 4202 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit); 4203 return VBOXSTRICTRC_VAL(rcStrict); 4204 } 4205 } 4206 #endif 4082 VBOXSTRICTRC rcStrict = hmR0SvmEvaluatePendingEvent(pVCpu, pSvmTransient); 4083 if ( rcStrict != VINF_SUCCESS 4084 || pSvmTransient->fIsNestedGuest != CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.GstCtx)) 4085 { 4086 /* If a nested-guest VM-exit occurred, bail. */ 4087 if (pSvmTransient->fIsNestedGuest) 4088 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit); 4089 return VBOXSTRICTRC_VAL(rcStrict); 4090 } 4207 4091 } 4208 4092
Note:
See TracChangeset
for help on using the changeset viewer.