aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2008-12-11 10:54:54 -0500
committerAvi Kivity <avi@redhat.com>2008-12-31 09:55:47 -0500
commit4531220b71f0399e71cda0c4cf749e7281a7416a (patch)
tree2d0b71b97a15bdd6ede42d05b7b9b791c3891eb3
parent264ff01d55b456932cef03082448b41d2edeb6a1 (diff)
KVM: x86: Rework user space NMI injection as KVM_CAP_USER_NMI
There is no point in doing the ready_for_nmi_injection/ request_nmi_window dance with user space. First, we don't do this for in-kernel irqchip anyway, while the code path is the same as for user space irqchip mode. And second, there is nothing to loose if a pending NMI is overwritten by another one (in contrast to IRQs where we have to save the number). Actually, there is even the risk of raising spurious NMIs this way because the reason for the held-back NMI might already be handled while processing the first one. Therefore this patch creates a simplified user space NMI injection interface, exporting it under KVM_CAP_USER_NMI and dropping the old KVM_CAP_NMI capability. And this time we also take care to provide the interface only on archs supporting NMIs via KVM (right now only x86). Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/x86/kvm/vmx.c24
-rw-r--r--arch/x86/kvm/x86.c28
-rw-r--r--include/linux/kvm.h11
3 files changed, 9 insertions, 54 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 487e1dcdce33..6259d7467648 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2498,15 +2498,13 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu,
2498 } 2498 }
2499 if (vcpu->arch.nmi_injected) { 2499 if (vcpu->arch.nmi_injected) {
2500 vmx_inject_nmi(vcpu); 2500 vmx_inject_nmi(vcpu);
2501 if (vcpu->arch.nmi_pending || kvm_run->request_nmi_window) 2501 if (vcpu->arch.nmi_pending)
2502 enable_nmi_window(vcpu); 2502 enable_nmi_window(vcpu);
2503 else if (vcpu->arch.irq_summary 2503 else if (vcpu->arch.irq_summary
2504 || kvm_run->request_interrupt_window) 2504 || kvm_run->request_interrupt_window)
2505 enable_irq_window(vcpu); 2505 enable_irq_window(vcpu);
2506 return; 2506 return;
2507 } 2507 }
2508 if (!vcpu->arch.nmi_window_open || kvm_run->request_nmi_window)
2509 enable_nmi_window(vcpu);
2510 2508
2511 if (vcpu->arch.interrupt_window_open) { 2509 if (vcpu->arch.interrupt_window_open) {
2512 if (vcpu->arch.irq_summary && !vcpu->arch.interrupt.pending) 2510 if (vcpu->arch.irq_summary && !vcpu->arch.interrupt.pending)
@@ -3040,14 +3038,6 @@ static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
3040 vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); 3038 vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
3041 ++vcpu->stat.nmi_window_exits; 3039 ++vcpu->stat.nmi_window_exits;
3042 3040
3043 /*
3044 * If the user space waits to inject a NMI, exit as soon as possible
3045 */
3046 if (kvm_run->request_nmi_window && !vcpu->arch.nmi_pending) {
3047 kvm_run->exit_reason = KVM_EXIT_NMI_WINDOW_OPEN;
3048 return 0;
3049 }
3050
3051 return 1; 3041 return 1;
3052} 3042}
3053 3043
@@ -3162,7 +3152,7 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
3162 vmx->soft_vnmi_blocked = 0; 3152 vmx->soft_vnmi_blocked = 0;
3163 vcpu->arch.nmi_window_open = 1; 3153 vcpu->arch.nmi_window_open = 1;
3164 } else if (vmx->vnmi_blocked_time > 1000000000LL && 3154 } else if (vmx->vnmi_blocked_time > 1000000000LL &&
3165 (kvm_run->request_nmi_window || vcpu->arch.nmi_pending)) { 3155 vcpu->arch.nmi_pending) {
3166 /* 3156 /*
3167 * This CPU don't support us in finding the end of an 3157 * This CPU don't support us in finding the end of an
3168 * NMI-blocked window if the guest runs with IRQs 3158 * NMI-blocked window if the guest runs with IRQs
@@ -3175,16 +3165,6 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
3175 vmx->soft_vnmi_blocked = 0; 3165 vmx->soft_vnmi_blocked = 0;
3176 vmx->vcpu.arch.nmi_window_open = 1; 3166 vmx->vcpu.arch.nmi_window_open = 1;
3177 } 3167 }
3178
3179 /*
3180 * If the user space waits to inject an NNI, exit ASAP
3181 */
3182 if (vcpu->arch.nmi_window_open && kvm_run->request_nmi_window
3183 && !vcpu->arch.nmi_pending) {
3184 kvm_run->exit_reason = KVM_EXIT_NMI_WINDOW_OPEN;
3185 ++vcpu->stat.nmi_window_exits;
3186 return 0;
3187 }
3188 } 3168 }
3189 3169
3190 if (exit_reason < kvm_vmx_max_exit_handlers 3170 if (exit_reason < kvm_vmx_max_exit_handlers
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 10302d3bd415..0e6aa8141dcd 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2887,37 +2887,18 @@ static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
2887 (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF)); 2887 (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF));
2888} 2888}
2889 2889
2890/*
2891 * Check if userspace requested a NMI window, and that the NMI window
2892 * is open.
2893 *
2894 * No need to exit to userspace if we already have a NMI queued.
2895 */
2896static int dm_request_for_nmi_injection(struct kvm_vcpu *vcpu,
2897 struct kvm_run *kvm_run)
2898{
2899 return (!vcpu->arch.nmi_pending &&
2900 kvm_run->request_nmi_window &&
2901 vcpu->arch.nmi_window_open);
2902}
2903
2904static void post_kvm_run_save(struct kvm_vcpu *vcpu, 2890static void post_kvm_run_save(struct kvm_vcpu *vcpu,
2905 struct kvm_run *kvm_run) 2891 struct kvm_run *kvm_run)
2906{ 2892{
2907 kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0; 2893 kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
2908 kvm_run->cr8 = kvm_get_cr8(vcpu); 2894 kvm_run->cr8 = kvm_get_cr8(vcpu);
2909 kvm_run->apic_base = kvm_get_apic_base(vcpu); 2895 kvm_run->apic_base = kvm_get_apic_base(vcpu);
2910 if (irqchip_in_kernel(vcpu->kvm)) { 2896 if (irqchip_in_kernel(vcpu->kvm))
2911 kvm_run->ready_for_interrupt_injection = 1; 2897 kvm_run->ready_for_interrupt_injection = 1;
2912 kvm_run->ready_for_nmi_injection = 1; 2898 else
2913 } else {
2914 kvm_run->ready_for_interrupt_injection = 2899 kvm_run->ready_for_interrupt_injection =
2915 (vcpu->arch.interrupt_window_open && 2900 (vcpu->arch.interrupt_window_open &&
2916 vcpu->arch.irq_summary == 0); 2901 vcpu->arch.irq_summary == 0);
2917 kvm_run->ready_for_nmi_injection =
2918 (vcpu->arch.nmi_window_open &&
2919 vcpu->arch.nmi_pending == 0);
2920 }
2921} 2902}
2922 2903
2923static void vapic_enter(struct kvm_vcpu *vcpu) 2904static void vapic_enter(struct kvm_vcpu *vcpu)
@@ -3093,11 +3074,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
3093 } 3074 }
3094 3075
3095 if (r > 0) { 3076 if (r > 0) {
3096 if (dm_request_for_nmi_injection(vcpu, kvm_run)) {
3097 r = -EINTR;
3098 kvm_run->exit_reason = KVM_EXIT_NMI;
3099 ++vcpu->stat.request_nmi_exits;
3100 }
3101 if (dm_request_for_irq_injection(vcpu, kvm_run)) { 3077 if (dm_request_for_irq_injection(vcpu, kvm_run)) {
3102 r = -EINTR; 3078 r = -EINTR;
3103 kvm_run->exit_reason = KVM_EXIT_INTR; 3079 kvm_run->exit_reason = KVM_EXIT_INTR;
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 48807767e726..35525ac63337 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -84,21 +84,18 @@ struct kvm_irqchip {
84#define KVM_EXIT_S390_RESET 14 84#define KVM_EXIT_S390_RESET 14
85#define KVM_EXIT_DCR 15 85#define KVM_EXIT_DCR 15
86#define KVM_EXIT_NMI 16 86#define KVM_EXIT_NMI 16
87#define KVM_EXIT_NMI_WINDOW_OPEN 17
88 87
89/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */ 88/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
90struct kvm_run { 89struct kvm_run {
91 /* in */ 90 /* in */
92 __u8 request_interrupt_window; 91 __u8 request_interrupt_window;
93 __u8 request_nmi_window; 92 __u8 padding1[7];
94 __u8 padding1[6];
95 93
96 /* out */ 94 /* out */
97 __u32 exit_reason; 95 __u32 exit_reason;
98 __u8 ready_for_interrupt_injection; 96 __u8 ready_for_interrupt_injection;
99 __u8 if_flag; 97 __u8 if_flag;
100 __u8 ready_for_nmi_injection; 98 __u8 padding2[2];
101 __u8 padding2;
102 99
103 /* in (pre_kvm_run), out (post_kvm_run) */ 100 /* in (pre_kvm_run), out (post_kvm_run) */
104 __u64 cr8; 101 __u64 cr8;
@@ -391,12 +388,14 @@ struct kvm_trace_rec {
391#define KVM_CAP_DEVICE_ASSIGNMENT 17 388#define KVM_CAP_DEVICE_ASSIGNMENT 17
392#endif 389#endif
393#define KVM_CAP_IOMMU 18 390#define KVM_CAP_IOMMU 18
394#define KVM_CAP_NMI 19
395#if defined(CONFIG_X86) 391#if defined(CONFIG_X86)
396#define KVM_CAP_DEVICE_MSI 20 392#define KVM_CAP_DEVICE_MSI 20
397#endif 393#endif
398/* Bug in KVM_SET_USER_MEMORY_REGION fixed: */ 394/* Bug in KVM_SET_USER_MEMORY_REGION fixed: */
399#define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21 395#define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21
396#if defined(CONFIG_X86)
397#define KVM_CAP_USER_NMI 22
398#endif
400 399
401/* 400/*
402 * ioctls for VM fds 401 * ioctls for VM fds