aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2008-09-26 03:30:55 -0400
committerAvi Kivity <avi@redhat.com>2008-12-31 09:51:42 -0500
commitc4abb7c9cde24b7351a47328ef866e6a2bbb1ad0 (patch)
tree85cef82232898397e645e53334655712af54085f
parent26df99c6c5807115f06d4e1abae397b7f5f3e00c (diff)
KVM: x86: Support for user space injected NMIs
Introduces the KVM_NMI IOCTL to the generic x86 part of KVM for injecting NMIs from user space and also extends the statistic report accordingly. Based on the original patch by Sheng Yang. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Sheng Yang <sheng.yang@intel.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/x86/include/asm/kvm_host.h2
-rw-r--r--arch/x86/kvm/x86.c46
-rw-r--r--include/linux/kvm.h11
3 files changed, 55 insertions, 4 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index bfbbdea869bf..a40fa8478920 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -398,6 +398,7 @@ struct kvm_vcpu_stat {
398 u32 halt_exits; 398 u32 halt_exits;
399 u32 halt_wakeup; 399 u32 halt_wakeup;
400 u32 request_irq_exits; 400 u32 request_irq_exits;
401 u32 request_nmi_exits;
401 u32 irq_exits; 402 u32 irq_exits;
402 u32 host_state_reload; 403 u32 host_state_reload;
403 u32 efer_reload; 404 u32 efer_reload;
@@ -406,6 +407,7 @@ struct kvm_vcpu_stat {
406 u32 insn_emulation_fail; 407 u32 insn_emulation_fail;
407 u32 hypercalls; 408 u32 hypercalls;
408 u32 irq_injections; 409 u32 irq_injections;
410 u32 nmi_injections;
409}; 411};
410 412
411struct descriptor_table { 413struct descriptor_table {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 1fa9a6db633d..07971451b947 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -86,6 +86,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
86 { "halt_wakeup", VCPU_STAT(halt_wakeup) }, 86 { "halt_wakeup", VCPU_STAT(halt_wakeup) },
87 { "hypercalls", VCPU_STAT(hypercalls) }, 87 { "hypercalls", VCPU_STAT(hypercalls) },
88 { "request_irq", VCPU_STAT(request_irq_exits) }, 88 { "request_irq", VCPU_STAT(request_irq_exits) },
89 { "request_nmi", VCPU_STAT(request_nmi_exits) },
89 { "irq_exits", VCPU_STAT(irq_exits) }, 90 { "irq_exits", VCPU_STAT(irq_exits) },
90 { "host_state_reload", VCPU_STAT(host_state_reload) }, 91 { "host_state_reload", VCPU_STAT(host_state_reload) },
91 { "efer_reload", VCPU_STAT(efer_reload) }, 92 { "efer_reload", VCPU_STAT(efer_reload) },
@@ -93,6 +94,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
93 { "insn_emulation", VCPU_STAT(insn_emulation) }, 94 { "insn_emulation", VCPU_STAT(insn_emulation) },
94 { "insn_emulation_fail", VCPU_STAT(insn_emulation_fail) }, 95 { "insn_emulation_fail", VCPU_STAT(insn_emulation_fail) },
95 { "irq_injections", VCPU_STAT(irq_injections) }, 96 { "irq_injections", VCPU_STAT(irq_injections) },
97 { "nmi_injections", VCPU_STAT(nmi_injections) },
96 { "mmu_shadow_zapped", VM_STAT(mmu_shadow_zapped) }, 98 { "mmu_shadow_zapped", VM_STAT(mmu_shadow_zapped) },
97 { "mmu_pte_write", VM_STAT(mmu_pte_write) }, 99 { "mmu_pte_write", VM_STAT(mmu_pte_write) },
98 { "mmu_pte_updated", VM_STAT(mmu_pte_updated) }, 100 { "mmu_pte_updated", VM_STAT(mmu_pte_updated) },
@@ -1318,6 +1320,15 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
1318 return 0; 1320 return 0;
1319} 1321}
1320 1322
1323static int kvm_vcpu_ioctl_nmi(struct kvm_vcpu *vcpu)
1324{
1325 vcpu_load(vcpu);
1326 kvm_inject_nmi(vcpu);
1327 vcpu_put(vcpu);
1328
1329 return 0;
1330}
1331
1321static int vcpu_ioctl_tpr_access_reporting(struct kvm_vcpu *vcpu, 1332static int vcpu_ioctl_tpr_access_reporting(struct kvm_vcpu *vcpu,
1322 struct kvm_tpr_access_ctl *tac) 1333 struct kvm_tpr_access_ctl *tac)
1323{ 1334{
@@ -1377,6 +1388,13 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
1377 r = 0; 1388 r = 0;
1378 break; 1389 break;
1379 } 1390 }
1391 case KVM_NMI: {
1392 r = kvm_vcpu_ioctl_nmi(vcpu);
1393 if (r)
1394 goto out;
1395 r = 0;
1396 break;
1397 }
1380 case KVM_SET_CPUID: { 1398 case KVM_SET_CPUID: {
1381 struct kvm_cpuid __user *cpuid_arg = argp; 1399 struct kvm_cpuid __user *cpuid_arg = argp;
1382 struct kvm_cpuid cpuid; 1400 struct kvm_cpuid cpuid;
@@ -2812,18 +2830,37 @@ static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
2812 (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF)); 2830 (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF));
2813} 2831}
2814 2832
2833/*
2834 * Check if userspace requested a NMI window, and that the NMI window
2835 * is open.
2836 *
2837 * No need to exit to userspace if we already have a NMI queued.
2838 */
2839static int dm_request_for_nmi_injection(struct kvm_vcpu *vcpu,
2840 struct kvm_run *kvm_run)
2841{
2842 return (!vcpu->arch.nmi_pending &&
2843 kvm_run->request_nmi_window &&
2844 vcpu->arch.nmi_window_open);
2845}
2846
2815static void post_kvm_run_save(struct kvm_vcpu *vcpu, 2847static void post_kvm_run_save(struct kvm_vcpu *vcpu,
2816 struct kvm_run *kvm_run) 2848 struct kvm_run *kvm_run)
2817{ 2849{
2818 kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0; 2850 kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
2819 kvm_run->cr8 = kvm_get_cr8(vcpu); 2851 kvm_run->cr8 = kvm_get_cr8(vcpu);
2820 kvm_run->apic_base = kvm_get_apic_base(vcpu); 2852 kvm_run->apic_base = kvm_get_apic_base(vcpu);
2821 if (irqchip_in_kernel(vcpu->kvm)) 2853 if (irqchip_in_kernel(vcpu->kvm)) {
2822 kvm_run->ready_for_interrupt_injection = 1; 2854 kvm_run->ready_for_interrupt_injection = 1;
2823 else 2855 kvm_run->ready_for_nmi_injection = 1;
2856 } else {
2824 kvm_run->ready_for_interrupt_injection = 2857 kvm_run->ready_for_interrupt_injection =
2825 (vcpu->arch.interrupt_window_open && 2858 (vcpu->arch.interrupt_window_open &&
2826 vcpu->arch.irq_summary == 0); 2859 vcpu->arch.irq_summary == 0);
2860 kvm_run->ready_for_nmi_injection =
2861 (vcpu->arch.nmi_window_open &&
2862 vcpu->arch.nmi_pending == 0);
2863 }
2827} 2864}
2828 2865
2829static void vapic_enter(struct kvm_vcpu *vcpu) 2866static void vapic_enter(struct kvm_vcpu *vcpu)
@@ -2999,6 +3036,11 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
2999 } 3036 }
3000 3037
3001 if (r > 0) { 3038 if (r > 0) {
3039 if (dm_request_for_nmi_injection(vcpu, kvm_run)) {
3040 r = -EINTR;
3041 kvm_run->exit_reason = KVM_EXIT_NMI;
3042 ++vcpu->stat.request_nmi_exits;
3043 }
3002 if (dm_request_for_irq_injection(vcpu, kvm_run)) { 3044 if (dm_request_for_irq_injection(vcpu, kvm_run)) {
3003 r = -EINTR; 3045 r = -EINTR;
3004 kvm_run->exit_reason = KVM_EXIT_INTR; 3046 kvm_run->exit_reason = KVM_EXIT_INTR;
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index f18b86fa8655..44fd7fa0af2b 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -83,18 +83,22 @@ struct kvm_irqchip {
83#define KVM_EXIT_S390_SIEIC 13 83#define KVM_EXIT_S390_SIEIC 13
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
87#define KVM_EXIT_NMI_WINDOW_OPEN 17
86 88
87/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */ 89/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
88struct kvm_run { 90struct kvm_run {
89 /* in */ 91 /* in */
90 __u8 request_interrupt_window; 92 __u8 request_interrupt_window;
91 __u8 padding1[7]; 93 __u8 request_nmi_window;
94 __u8 padding1[6];
92 95
93 /* out */ 96 /* out */
94 __u32 exit_reason; 97 __u32 exit_reason;
95 __u8 ready_for_interrupt_injection; 98 __u8 ready_for_interrupt_injection;
96 __u8 if_flag; 99 __u8 if_flag;
97 __u8 padding2[2]; 100 __u8 ready_for_nmi_injection;
101 __u8 padding2;
98 102
99 /* in (pre_kvm_run), out (post_kvm_run) */ 103 /* in (pre_kvm_run), out (post_kvm_run) */
100 __u64 cr8; 104 __u64 cr8;
@@ -387,6 +391,7 @@ struct kvm_trace_rec {
387#define KVM_CAP_DEVICE_ASSIGNMENT 17 391#define KVM_CAP_DEVICE_ASSIGNMENT 17
388#endif 392#endif
389#define KVM_CAP_IOMMU 18 393#define KVM_CAP_IOMMU 18
394#define KVM_CAP_NMI 19
390 395
391/* 396/*
392 * ioctls for VM fds 397 * ioctls for VM fds
@@ -458,6 +463,8 @@ struct kvm_trace_rec {
458#define KVM_S390_INITIAL_RESET _IO(KVMIO, 0x97) 463#define KVM_S390_INITIAL_RESET _IO(KVMIO, 0x97)
459#define KVM_GET_MP_STATE _IOR(KVMIO, 0x98, struct kvm_mp_state) 464#define KVM_GET_MP_STATE _IOR(KVMIO, 0x98, struct kvm_mp_state)
460#define KVM_SET_MP_STATE _IOW(KVMIO, 0x99, struct kvm_mp_state) 465#define KVM_SET_MP_STATE _IOW(KVMIO, 0x99, struct kvm_mp_state)
466/* Available with KVM_CAP_NMI */
467#define KVM_NMI _IO(KVMIO, 0x9a)
461 468
462#define KVM_TRC_INJ_VIRQ (KVM_TRC_HANDLER + 0x02) 469#define KVM_TRC_INJ_VIRQ (KVM_TRC_HANDLER + 0x02)
463#define KVM_TRC_REDELIVER_EVT (KVM_TRC_HANDLER + 0x03) 470#define KVM_TRC_REDELIVER_EVT (KVM_TRC_HANDLER + 0x03)