diff options
author | Jan Kiszka <jan.kiszka@web.de> | 2009-11-11 19:04:25 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-12-03 02:32:25 -0500 |
commit | 3cfc3092f40bc37c57ba556cfd8de4218f2135ab (patch) | |
tree | 562d61febfe7d3c99ea08e376b3f3c016cff613c | |
parent | 65ac7264043740572ba804edca03c374d70427c9 (diff) |
KVM: x86: Add KVM_GET/SET_VCPU_EVENTS
This new IOCTL exports all yet user-invisible states related to
exceptions, interrupts, and NMIs. Together with appropriate user space
changes, this fixes sporadic problems of vmsave/restore, live migration
and system reset.
[avi: future-proof abi by adding a flags field]
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | Documentation/kvm/api.txt | 49 | ||||
-rw-r--r-- | arch/x86/include/asm/kvm.h | 28 | ||||
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 2 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 22 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 30 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 77 | ||||
-rw-r--r-- | include/linux/kvm.h | 6 |
7 files changed, 214 insertions, 0 deletions
diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt index 36594ba57723..e1a114161027 100644 --- a/Documentation/kvm/api.txt +++ b/Documentation/kvm/api.txt | |||
@@ -653,6 +653,55 @@ struct kvm_clock_data { | |||
653 | __u32 pad[9]; | 653 | __u32 pad[9]; |
654 | }; | 654 | }; |
655 | 655 | ||
656 | 4.29 KVM_GET_VCPU_EVENTS | ||
657 | |||
658 | Capability: KVM_CAP_VCPU_EVENTS | ||
659 | Architectures: x86 | ||
660 | Type: vm ioctl | ||
661 | Parameters: struct kvm_vcpu_event (out) | ||
662 | Returns: 0 on success, -1 on error | ||
663 | |||
664 | Gets currently pending exceptions, interrupts, and NMIs as well as related | ||
665 | states of the vcpu. | ||
666 | |||
667 | struct kvm_vcpu_events { | ||
668 | struct { | ||
669 | __u8 injected; | ||
670 | __u8 nr; | ||
671 | __u8 has_error_code; | ||
672 | __u8 pad; | ||
673 | __u32 error_code; | ||
674 | } exception; | ||
675 | struct { | ||
676 | __u8 injected; | ||
677 | __u8 nr; | ||
678 | __u8 soft; | ||
679 | __u8 pad; | ||
680 | } interrupt; | ||
681 | struct { | ||
682 | __u8 injected; | ||
683 | __u8 pending; | ||
684 | __u8 masked; | ||
685 | __u8 pad; | ||
686 | } nmi; | ||
687 | __u32 sipi_vector; | ||
688 | __u32 flags; /* must be zero */ | ||
689 | }; | ||
690 | |||
691 | 4.30 KVM_SET_VCPU_EVENTS | ||
692 | |||
693 | Capability: KVM_CAP_VCPU_EVENTS | ||
694 | Architectures: x86 | ||
695 | Type: vm ioctl | ||
696 | Parameters: struct kvm_vcpu_event (in) | ||
697 | Returns: 0 on success, -1 on error | ||
698 | |||
699 | Set pending exceptions, interrupts, and NMIs as well as related states of the | ||
700 | vcpu. | ||
701 | |||
702 | See KVM_GET_VCPU_EVENTS for the data structure. | ||
703 | |||
704 | |||
656 | 5. The kvm_run structure | 705 | 5. The kvm_run structure |
657 | 706 | ||
658 | Application code obtains a pointer to the kvm_run structure by | 707 | Application code obtains a pointer to the kvm_run structure by |
diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h index ef9b4b73cce4..950df434763f 100644 --- a/arch/x86/include/asm/kvm.h +++ b/arch/x86/include/asm/kvm.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #define __KVM_HAVE_MCE | 20 | #define __KVM_HAVE_MCE |
21 | #define __KVM_HAVE_PIT_STATE2 | 21 | #define __KVM_HAVE_PIT_STATE2 |
22 | #define __KVM_HAVE_XEN_HVM | 22 | #define __KVM_HAVE_XEN_HVM |
23 | #define __KVM_HAVE_VCPU_EVENTS | ||
23 | 24 | ||
24 | /* Architectural interrupt line count. */ | 25 | /* Architectural interrupt line count. */ |
25 | #define KVM_NR_INTERRUPTS 256 | 26 | #define KVM_NR_INTERRUPTS 256 |
@@ -252,4 +253,31 @@ struct kvm_reinject_control { | |||
252 | __u8 pit_reinject; | 253 | __u8 pit_reinject; |
253 | __u8 reserved[31]; | 254 | __u8 reserved[31]; |
254 | }; | 255 | }; |
256 | |||
257 | /* for KVM_GET/SET_VCPU_EVENTS */ | ||
258 | struct kvm_vcpu_events { | ||
259 | struct { | ||
260 | __u8 injected; | ||
261 | __u8 nr; | ||
262 | __u8 has_error_code; | ||
263 | __u8 pad; | ||
264 | __u32 error_code; | ||
265 | } exception; | ||
266 | struct { | ||
267 | __u8 injected; | ||
268 | __u8 nr; | ||
269 | __u8 soft; | ||
270 | __u8 pad; | ||
271 | } interrupt; | ||
272 | struct { | ||
273 | __u8 injected; | ||
274 | __u8 pending; | ||
275 | __u8 masked; | ||
276 | __u8 pad; | ||
277 | } nmi; | ||
278 | __u32 sipi_vector; | ||
279 | __u32 flags; | ||
280 | __u32 reserved[10]; | ||
281 | }; | ||
282 | |||
255 | #endif /* _ASM_X86_KVM_H */ | 283 | #endif /* _ASM_X86_KVM_H */ |
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 26a74b7bb6bc..06e085614dad 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -523,6 +523,8 @@ struct kvm_x86_ops { | |||
523 | bool has_error_code, u32 error_code); | 523 | bool has_error_code, u32 error_code); |
524 | int (*interrupt_allowed)(struct kvm_vcpu *vcpu); | 524 | int (*interrupt_allowed)(struct kvm_vcpu *vcpu); |
525 | int (*nmi_allowed)(struct kvm_vcpu *vcpu); | 525 | int (*nmi_allowed)(struct kvm_vcpu *vcpu); |
526 | bool (*get_nmi_mask)(struct kvm_vcpu *vcpu); | ||
527 | void (*set_nmi_mask)(struct kvm_vcpu *vcpu, bool masked); | ||
526 | void (*enable_nmi_window)(struct kvm_vcpu *vcpu); | 528 | void (*enable_nmi_window)(struct kvm_vcpu *vcpu); |
527 | void (*enable_irq_window)(struct kvm_vcpu *vcpu); | 529 | void (*enable_irq_window)(struct kvm_vcpu *vcpu); |
528 | void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr); | 530 | void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr); |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 34b700f9e498..3de0b37ec038 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -2499,6 +2499,26 @@ static int svm_nmi_allowed(struct kvm_vcpu *vcpu) | |||
2499 | !(svm->vcpu.arch.hflags & HF_NMI_MASK); | 2499 | !(svm->vcpu.arch.hflags & HF_NMI_MASK); |
2500 | } | 2500 | } |
2501 | 2501 | ||
2502 | static bool svm_get_nmi_mask(struct kvm_vcpu *vcpu) | ||
2503 | { | ||
2504 | struct vcpu_svm *svm = to_svm(vcpu); | ||
2505 | |||
2506 | return !!(svm->vcpu.arch.hflags & HF_NMI_MASK); | ||
2507 | } | ||
2508 | |||
2509 | static void svm_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked) | ||
2510 | { | ||
2511 | struct vcpu_svm *svm = to_svm(vcpu); | ||
2512 | |||
2513 | if (masked) { | ||
2514 | svm->vcpu.arch.hflags |= HF_NMI_MASK; | ||
2515 | svm->vmcb->control.intercept |= (1UL << INTERCEPT_IRET); | ||
2516 | } else { | ||
2517 | svm->vcpu.arch.hflags &= ~HF_NMI_MASK; | ||
2518 | svm->vmcb->control.intercept &= ~(1UL << INTERCEPT_IRET); | ||
2519 | } | ||
2520 | } | ||
2521 | |||
2502 | static int svm_interrupt_allowed(struct kvm_vcpu *vcpu) | 2522 | static int svm_interrupt_allowed(struct kvm_vcpu *vcpu) |
2503 | { | 2523 | { |
2504 | struct vcpu_svm *svm = to_svm(vcpu); | 2524 | struct vcpu_svm *svm = to_svm(vcpu); |
@@ -2946,6 +2966,8 @@ static struct kvm_x86_ops svm_x86_ops = { | |||
2946 | .queue_exception = svm_queue_exception, | 2966 | .queue_exception = svm_queue_exception, |
2947 | .interrupt_allowed = svm_interrupt_allowed, | 2967 | .interrupt_allowed = svm_interrupt_allowed, |
2948 | .nmi_allowed = svm_nmi_allowed, | 2968 | .nmi_allowed = svm_nmi_allowed, |
2969 | .get_nmi_mask = svm_get_nmi_mask, | ||
2970 | .set_nmi_mask = svm_set_nmi_mask, | ||
2949 | .enable_nmi_window = enable_nmi_window, | 2971 | .enable_nmi_window = enable_nmi_window, |
2950 | .enable_irq_window = enable_irq_window, | 2972 | .enable_irq_window = enable_irq_window, |
2951 | .update_cr8_intercept = update_cr8_intercept, | 2973 | .update_cr8_intercept = update_cr8_intercept, |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 22fcd27a0b58..778f059ae423 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -2639,6 +2639,34 @@ static int vmx_nmi_allowed(struct kvm_vcpu *vcpu) | |||
2639 | GUEST_INTR_STATE_NMI)); | 2639 | GUEST_INTR_STATE_NMI)); |
2640 | } | 2640 | } |
2641 | 2641 | ||
2642 | static bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu) | ||
2643 | { | ||
2644 | if (!cpu_has_virtual_nmis()) | ||
2645 | return to_vmx(vcpu)->soft_vnmi_blocked; | ||
2646 | else | ||
2647 | return !!(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & | ||
2648 | GUEST_INTR_STATE_NMI); | ||
2649 | } | ||
2650 | |||
2651 | static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked) | ||
2652 | { | ||
2653 | struct vcpu_vmx *vmx = to_vmx(vcpu); | ||
2654 | |||
2655 | if (!cpu_has_virtual_nmis()) { | ||
2656 | if (vmx->soft_vnmi_blocked != masked) { | ||
2657 | vmx->soft_vnmi_blocked = masked; | ||
2658 | vmx->vnmi_blocked_time = 0; | ||
2659 | } | ||
2660 | } else { | ||
2661 | if (masked) | ||
2662 | vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, | ||
2663 | GUEST_INTR_STATE_NMI); | ||
2664 | else | ||
2665 | vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, | ||
2666 | GUEST_INTR_STATE_NMI); | ||
2667 | } | ||
2668 | } | ||
2669 | |||
2642 | static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu) | 2670 | static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu) |
2643 | { | 2671 | { |
2644 | return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && | 2672 | return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && |
@@ -3985,6 +4013,8 @@ static struct kvm_x86_ops vmx_x86_ops = { | |||
3985 | .queue_exception = vmx_queue_exception, | 4013 | .queue_exception = vmx_queue_exception, |
3986 | .interrupt_allowed = vmx_interrupt_allowed, | 4014 | .interrupt_allowed = vmx_interrupt_allowed, |
3987 | .nmi_allowed = vmx_nmi_allowed, | 4015 | .nmi_allowed = vmx_nmi_allowed, |
4016 | .get_nmi_mask = vmx_get_nmi_mask, | ||
4017 | .set_nmi_mask = vmx_set_nmi_mask, | ||
3988 | .enable_nmi_window = enable_nmi_window, | 4018 | .enable_nmi_window = enable_nmi_window, |
3989 | .enable_irq_window = enable_irq_window, | 4019 | .enable_irq_window = enable_irq_window, |
3990 | .update_cr8_intercept = update_cr8_intercept, | 4020 | .update_cr8_intercept = update_cr8_intercept, |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ba8958dca3c4..35eea30821d6 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -1342,6 +1342,7 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
1342 | case KVM_CAP_SET_IDENTITY_MAP_ADDR: | 1342 | case KVM_CAP_SET_IDENTITY_MAP_ADDR: |
1343 | case KVM_CAP_XEN_HVM: | 1343 | case KVM_CAP_XEN_HVM: |
1344 | case KVM_CAP_ADJUST_CLOCK: | 1344 | case KVM_CAP_ADJUST_CLOCK: |
1345 | case KVM_CAP_VCPU_EVENTS: | ||
1345 | r = 1; | 1346 | r = 1; |
1346 | break; | 1347 | break; |
1347 | case KVM_CAP_COALESCED_MMIO: | 1348 | case KVM_CAP_COALESCED_MMIO: |
@@ -1883,6 +1884,61 @@ static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu, | |||
1883 | return 0; | 1884 | return 0; |
1884 | } | 1885 | } |
1885 | 1886 | ||
1887 | static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu, | ||
1888 | struct kvm_vcpu_events *events) | ||
1889 | { | ||
1890 | vcpu_load(vcpu); | ||
1891 | |||
1892 | events->exception.injected = vcpu->arch.exception.pending; | ||
1893 | events->exception.nr = vcpu->arch.exception.nr; | ||
1894 | events->exception.has_error_code = vcpu->arch.exception.has_error_code; | ||
1895 | events->exception.error_code = vcpu->arch.exception.error_code; | ||
1896 | |||
1897 | events->interrupt.injected = vcpu->arch.interrupt.pending; | ||
1898 | events->interrupt.nr = vcpu->arch.interrupt.nr; | ||
1899 | events->interrupt.soft = vcpu->arch.interrupt.soft; | ||
1900 | |||
1901 | events->nmi.injected = vcpu->arch.nmi_injected; | ||
1902 | events->nmi.pending = vcpu->arch.nmi_pending; | ||
1903 | events->nmi.masked = kvm_x86_ops->get_nmi_mask(vcpu); | ||
1904 | |||
1905 | events->sipi_vector = vcpu->arch.sipi_vector; | ||
1906 | |||
1907 | events->flags = 0; | ||
1908 | |||
1909 | vcpu_put(vcpu); | ||
1910 | } | ||
1911 | |||
1912 | static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, | ||
1913 | struct kvm_vcpu_events *events) | ||
1914 | { | ||
1915 | if (events->flags) | ||
1916 | return -EINVAL; | ||
1917 | |||
1918 | vcpu_load(vcpu); | ||
1919 | |||
1920 | vcpu->arch.exception.pending = events->exception.injected; | ||
1921 | vcpu->arch.exception.nr = events->exception.nr; | ||
1922 | vcpu->arch.exception.has_error_code = events->exception.has_error_code; | ||
1923 | vcpu->arch.exception.error_code = events->exception.error_code; | ||
1924 | |||
1925 | vcpu->arch.interrupt.pending = events->interrupt.injected; | ||
1926 | vcpu->arch.interrupt.nr = events->interrupt.nr; | ||
1927 | vcpu->arch.interrupt.soft = events->interrupt.soft; | ||
1928 | if (vcpu->arch.interrupt.pending && irqchip_in_kernel(vcpu->kvm)) | ||
1929 | kvm_pic_clear_isr_ack(vcpu->kvm); | ||
1930 | |||
1931 | vcpu->arch.nmi_injected = events->nmi.injected; | ||
1932 | vcpu->arch.nmi_pending = events->nmi.pending; | ||
1933 | kvm_x86_ops->set_nmi_mask(vcpu, events->nmi.masked); | ||
1934 | |||
1935 | vcpu->arch.sipi_vector = events->sipi_vector; | ||
1936 | |||
1937 | vcpu_put(vcpu); | ||
1938 | |||
1939 | return 0; | ||
1940 | } | ||
1941 | |||
1886 | long kvm_arch_vcpu_ioctl(struct file *filp, | 1942 | long kvm_arch_vcpu_ioctl(struct file *filp, |
1887 | unsigned int ioctl, unsigned long arg) | 1943 | unsigned int ioctl, unsigned long arg) |
1888 | { | 1944 | { |
@@ -2040,6 +2096,27 @@ long kvm_arch_vcpu_ioctl(struct file *filp, | |||
2040 | r = kvm_vcpu_ioctl_x86_set_mce(vcpu, &mce); | 2096 | r = kvm_vcpu_ioctl_x86_set_mce(vcpu, &mce); |
2041 | break; | 2097 | break; |
2042 | } | 2098 | } |
2099 | case KVM_GET_VCPU_EVENTS: { | ||
2100 | struct kvm_vcpu_events events; | ||
2101 | |||
2102 | kvm_vcpu_ioctl_x86_get_vcpu_events(vcpu, &events); | ||
2103 | |||
2104 | r = -EFAULT; | ||
2105 | if (copy_to_user(argp, &events, sizeof(struct kvm_vcpu_events))) | ||
2106 | break; | ||
2107 | r = 0; | ||
2108 | break; | ||
2109 | } | ||
2110 | case KVM_SET_VCPU_EVENTS: { | ||
2111 | struct kvm_vcpu_events events; | ||
2112 | |||
2113 | r = -EFAULT; | ||
2114 | if (copy_from_user(&events, argp, sizeof(struct kvm_vcpu_events))) | ||
2115 | break; | ||
2116 | |||
2117 | r = kvm_vcpu_ioctl_x86_set_vcpu_events(vcpu, &events); | ||
2118 | break; | ||
2119 | } | ||
2043 | default: | 2120 | default: |
2044 | r = -EINVAL; | 2121 | r = -EINVAL; |
2045 | } | 2122 | } |
diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 976f4d181858..92045a92d714 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h | |||
@@ -489,6 +489,9 @@ struct kvm_ioeventfd { | |||
489 | #endif | 489 | #endif |
490 | #define KVM_CAP_ADJUST_CLOCK 39 | 490 | #define KVM_CAP_ADJUST_CLOCK 39 |
491 | #define KVM_CAP_INTERNAL_ERROR_DATA 40 | 491 | #define KVM_CAP_INTERNAL_ERROR_DATA 40 |
492 | #ifdef __KVM_HAVE_VCPU_EVENTS | ||
493 | #define KVM_CAP_VCPU_EVENTS 41 | ||
494 | #endif | ||
492 | 495 | ||
493 | #ifdef KVM_CAP_IRQ_ROUTING | 496 | #ifdef KVM_CAP_IRQ_ROUTING |
494 | 497 | ||
@@ -672,6 +675,9 @@ struct kvm_clock_data { | |||
672 | /* IA64 stack access */ | 675 | /* IA64 stack access */ |
673 | #define KVM_IA64_VCPU_GET_STACK _IOR(KVMIO, 0x9a, void *) | 676 | #define KVM_IA64_VCPU_GET_STACK _IOR(KVMIO, 0x9a, void *) |
674 | #define KVM_IA64_VCPU_SET_STACK _IOW(KVMIO, 0x9b, void *) | 677 | #define KVM_IA64_VCPU_SET_STACK _IOW(KVMIO, 0x9b, void *) |
678 | /* Available with KVM_CAP_VCPU_EVENTS */ | ||
679 | #define KVM_GET_VCPU_EVENTS _IOR(KVMIO, 0x9f, struct kvm_vcpu_events) | ||
680 | #define KVM_SET_VCPU_EVENTS _IOW(KVMIO, 0xa0, struct kvm_vcpu_events) | ||
675 | 681 | ||
676 | #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) | 682 | #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) |
677 | 683 | ||