aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2014-03-07 14:03:12 -0500
committerPaolo Bonzini <pbonzini@redhat.com>2014-03-11 03:41:45 -0400
commitb6b8a1451fc40412c57d10c94b62e22acab28f94 (patch)
tree7a0d2a778c46831c596ab08190e0b7af05e86d52
parentb010926dc896366602b8dd2430bd3af8c3ef854a (diff)
KVM: nVMX: Rework interception of IRQs and NMIs
Move the check for leaving L2 on pending and intercepted IRQs or NMIs from the *_allowed handler into a dedicated callback. Invoke this callback at the relevant points before KVM checks if IRQs/NMIs can be injected. The callback has the task to switch from L2 to L1 if needed and inject the proper vmexit events. The rework fixes L2 wakeups from HLT and provides the foundation for preemption timer emulation. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--arch/x86/include/asm/kvm_host.h2
-rw-r--r--arch/x86/kvm/vmx.c67
-rw-r--r--arch/x86/kvm/x86.c26
3 files changed, 59 insertions, 36 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 85be627ef5de..461d00a554e0 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -767,6 +767,8 @@ struct kvm_x86_ops {
767 enum x86_intercept_stage stage); 767 enum x86_intercept_stage stage);
768 void (*handle_external_intr)(struct kvm_vcpu *vcpu); 768 void (*handle_external_intr)(struct kvm_vcpu *vcpu);
769 bool (*mpx_supported)(void); 769 bool (*mpx_supported)(void);
770
771 int (*check_nested_events)(struct kvm_vcpu *vcpu, bool external_intr);
770}; 772};
771 773
772struct kvm_arch_async_pf { 774struct kvm_arch_async_pf {
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 53c324f3cc5e..11718b44a62d 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -4631,22 +4631,8 @@ static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
4631 4631
4632static int vmx_nmi_allowed(struct kvm_vcpu *vcpu) 4632static int vmx_nmi_allowed(struct kvm_vcpu *vcpu)
4633{ 4633{
4634 if (is_guest_mode(vcpu)) { 4634 if (to_vmx(vcpu)->nested.nested_run_pending)
4635 if (to_vmx(vcpu)->nested.nested_run_pending) 4635 return 0;
4636 return 0;
4637 if (nested_exit_on_nmi(vcpu)) {
4638 nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI,
4639 NMI_VECTOR | INTR_TYPE_NMI_INTR |
4640 INTR_INFO_VALID_MASK, 0);
4641 /*
4642 * The NMI-triggered VM exit counts as injection:
4643 * clear this one and block further NMIs.
4644 */
4645 vcpu->arch.nmi_pending = 0;
4646 vmx_set_nmi_mask(vcpu, true);
4647 return 0;
4648 }
4649 }
4650 4636
4651 if (!cpu_has_virtual_nmis() && to_vmx(vcpu)->soft_vnmi_blocked) 4637 if (!cpu_has_virtual_nmis() && to_vmx(vcpu)->soft_vnmi_blocked)
4652 return 0; 4638 return 0;
@@ -4658,19 +4644,8 @@ static int vmx_nmi_allowed(struct kvm_vcpu *vcpu)
4658 4644
4659static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu) 4645static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu)
4660{ 4646{
4661 if (is_guest_mode(vcpu)) { 4647 return (!to_vmx(vcpu)->nested.nested_run_pending &&
4662 if (to_vmx(vcpu)->nested.nested_run_pending) 4648 vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
4663 return 0;
4664 if (nested_exit_on_intr(vcpu)) {
4665 nested_vmx_vmexit(vcpu, EXIT_REASON_EXTERNAL_INTERRUPT,
4666 0, 0);
4667 /*
4668 * fall through to normal code, but now in L1, not L2
4669 */
4670 }
4671 }
4672
4673 return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
4674 !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 4649 !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
4675 (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)); 4650 (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS));
4676} 4651}
@@ -8172,6 +8147,35 @@ static void vmcs12_save_pending_event(struct kvm_vcpu *vcpu,
8172 } 8147 }
8173} 8148}
8174 8149
8150static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr)
8151{
8152 struct vcpu_vmx *vmx = to_vmx(vcpu);
8153
8154 if (vcpu->arch.nmi_pending && nested_exit_on_nmi(vcpu)) {
8155 if (vmx->nested.nested_run_pending)
8156 return -EBUSY;
8157 nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI,
8158 NMI_VECTOR | INTR_TYPE_NMI_INTR |
8159 INTR_INFO_VALID_MASK, 0);
8160 /*
8161 * The NMI-triggered VM exit counts as injection:
8162 * clear this one and block further NMIs.
8163 */
8164 vcpu->arch.nmi_pending = 0;
8165 vmx_set_nmi_mask(vcpu, true);
8166 return 0;
8167 }
8168
8169 if ((kvm_cpu_has_interrupt(vcpu) || external_intr) &&
8170 nested_exit_on_intr(vcpu)) {
8171 if (vmx->nested.nested_run_pending)
8172 return -EBUSY;
8173 nested_vmx_vmexit(vcpu, EXIT_REASON_EXTERNAL_INTERRUPT, 0, 0);
8174 }
8175
8176 return 0;
8177}
8178
8175/* 8179/*
8176 * prepare_vmcs12 is part of what we need to do when the nested L2 guest exits 8180 * prepare_vmcs12 is part of what we need to do when the nested L2 guest exits
8177 * and we want to prepare to run its L1 parent. L1 keeps a vmcs for L2 (vmcs12), 8181 * and we want to prepare to run its L1 parent. L1 keeps a vmcs for L2 (vmcs12),
@@ -8512,6 +8516,9 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
8512 nested_vmx_succeed(vcpu); 8516 nested_vmx_succeed(vcpu);
8513 if (enable_shadow_vmcs) 8517 if (enable_shadow_vmcs)
8514 vmx->nested.sync_shadow_vmcs = true; 8518 vmx->nested.sync_shadow_vmcs = true;
8519
8520 /* in case we halted in L2 */
8521 vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
8515} 8522}
8516 8523
8517/* 8524/*
@@ -8652,6 +8659,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
8652 .check_intercept = vmx_check_intercept, 8659 .check_intercept = vmx_check_intercept,
8653 .handle_external_intr = vmx_handle_external_intr, 8660 .handle_external_intr = vmx_handle_external_intr,
8654 .mpx_supported = vmx_mpx_supported, 8661 .mpx_supported = vmx_mpx_supported,
8662
8663 .check_nested_events = vmx_check_nested_events,
8655}; 8664};
8656 8665
8657static int __init vmx_init(void) 8666static int __init vmx_init(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index a45bcac45645..738262595706 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5821,8 +5821,10 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
5821 kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr); 5821 kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr);
5822} 5822}
5823 5823
5824static void inject_pending_event(struct kvm_vcpu *vcpu) 5824static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
5825{ 5825{
5826 int r;
5827
5826 /* try to reinject previous events if any */ 5828 /* try to reinject previous events if any */
5827 if (vcpu->arch.exception.pending) { 5829 if (vcpu->arch.exception.pending) {
5828 trace_kvm_inj_exception(vcpu->arch.exception.nr, 5830 trace_kvm_inj_exception(vcpu->arch.exception.nr,
@@ -5832,17 +5834,23 @@ static void inject_pending_event(struct kvm_vcpu *vcpu)
5832 vcpu->arch.exception.has_error_code, 5834 vcpu->arch.exception.has_error_code,
5833 vcpu->arch.exception.error_code, 5835 vcpu->arch.exception.error_code,
5834 vcpu->arch.exception.reinject); 5836 vcpu->arch.exception.reinject);
5835 return; 5837 return 0;
5836 } 5838 }
5837 5839
5838 if (vcpu->arch.nmi_injected) { 5840 if (vcpu->arch.nmi_injected) {
5839 kvm_x86_ops->set_nmi(vcpu); 5841 kvm_x86_ops->set_nmi(vcpu);
5840 return; 5842 return 0;
5841 } 5843 }
5842 5844
5843 if (vcpu->arch.interrupt.pending) { 5845 if (vcpu->arch.interrupt.pending) {
5844 kvm_x86_ops->set_irq(vcpu); 5846 kvm_x86_ops->set_irq(vcpu);
5845 return; 5847 return 0;
5848 }
5849
5850 if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events) {
5851 r = kvm_x86_ops->check_nested_events(vcpu, req_int_win);
5852 if (r != 0)
5853 return r;
5846 } 5854 }
5847 5855
5848 /* try to inject new event if pending */ 5856 /* try to inject new event if pending */
@@ -5859,6 +5867,7 @@ static void inject_pending_event(struct kvm_vcpu *vcpu)
5859 kvm_x86_ops->set_irq(vcpu); 5867 kvm_x86_ops->set_irq(vcpu);
5860 } 5868 }
5861 } 5869 }
5870 return 0;
5862} 5871}
5863 5872
5864static void process_nmi(struct kvm_vcpu *vcpu) 5873static void process_nmi(struct kvm_vcpu *vcpu)
@@ -5963,10 +5972,10 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
5963 goto out; 5972 goto out;
5964 } 5973 }
5965 5974
5966 inject_pending_event(vcpu); 5975 if (inject_pending_event(vcpu, req_int_win) != 0)
5967 5976 req_immediate_exit = true;
5968 /* enable NMI/IRQ window open exits if needed */ 5977 /* enable NMI/IRQ window open exits if needed */
5969 if (vcpu->arch.nmi_pending) 5978 else if (vcpu->arch.nmi_pending)
5970 req_immediate_exit = 5979 req_immediate_exit =
5971 kvm_x86_ops->enable_nmi_window(vcpu) != 0; 5980 kvm_x86_ops->enable_nmi_window(vcpu) != 0;
5972 else if (kvm_cpu_has_injectable_intr(vcpu) || req_int_win) 5981 else if (kvm_cpu_has_injectable_intr(vcpu) || req_int_win)
@@ -7296,6 +7305,9 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
7296 7305
7297int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) 7306int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
7298{ 7307{
7308 if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events)
7309 kvm_x86_ops->check_nested_events(vcpu, false);
7310
7299 return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE && 7311 return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE &&
7300 !vcpu->arch.apf.halted) 7312 !vcpu->arch.apf.halted)
7301 || !list_empty_careful(&vcpu->async_pf.done) 7313 || !list_empty_careful(&vcpu->async_pf.done)