Commit 3cfc3092f40bc37c57ba556cfd8de4218f2135ab

Authored by Jan Kiszka
Committed by Avi Kivity
1 parent 65ac726404

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>

Showing 7 changed files with 214 additions and 0 deletions Side-by-side Diff

Documentation/kvm/api.txt
... ... @@ -653,6 +653,55 @@
653 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 705 5. The kvm_run structure
657 706  
658 707 Application code obtains a pointer to the kvm_run structure by
arch/x86/include/asm/kvm.h
... ... @@ -20,6 +20,7 @@
20 20 #define __KVM_HAVE_MCE
21 21 #define __KVM_HAVE_PIT_STATE2
22 22 #define __KVM_HAVE_XEN_HVM
  23 +#define __KVM_HAVE_VCPU_EVENTS
23 24  
24 25 /* Architectural interrupt line count. */
25 26 #define KVM_NR_INTERRUPTS 256
... ... @@ -252,5 +253,32 @@
252 253 __u8 pit_reinject;
253 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 283 #endif /* _ASM_X86_KVM_H */
arch/x86/include/asm/kvm_host.h
... ... @@ -523,6 +523,8 @@
523 523 bool has_error_code, u32 error_code);
524 524 int (*interrupt_allowed)(struct kvm_vcpu *vcpu);
525 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 528 void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
527 529 void (*enable_irq_window)(struct kvm_vcpu *vcpu);
528 530 void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
... ... @@ -2499,6 +2499,26 @@
2499 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 2522 static int svm_interrupt_allowed(struct kvm_vcpu *vcpu)
2503 2523 {
2504 2524 struct vcpu_svm *svm = to_svm(vcpu);
... ... @@ -2946,6 +2966,8 @@
2946 2966 .queue_exception = svm_queue_exception,
2947 2967 .interrupt_allowed = svm_interrupt_allowed,
2948 2968 .nmi_allowed = svm_nmi_allowed,
  2969 + .get_nmi_mask = svm_get_nmi_mask,
  2970 + .set_nmi_mask = svm_set_nmi_mask,
2949 2971 .enable_nmi_window = enable_nmi_window,
2950 2972 .enable_irq_window = enable_irq_window,
2951 2973 .update_cr8_intercept = update_cr8_intercept,
... ... @@ -2639,6 +2639,34 @@
2639 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 2670 static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu)
2643 2671 {
2644 2672 return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
... ... @@ -3985,6 +4013,8 @@
3985 4013 .queue_exception = vmx_queue_exception,
3986 4014 .interrupt_allowed = vmx_interrupt_allowed,
3987 4015 .nmi_allowed = vmx_nmi_allowed,
  4016 + .get_nmi_mask = vmx_get_nmi_mask,
  4017 + .set_nmi_mask = vmx_set_nmi_mask,
3988 4018 .enable_nmi_window = enable_nmi_window,
3989 4019 .enable_irq_window = enable_irq_window,
3990 4020 .update_cr8_intercept = update_cr8_intercept,
... ... @@ -1342,6 +1342,7 @@
1342 1342 case KVM_CAP_SET_IDENTITY_MAP_ADDR:
1343 1343 case KVM_CAP_XEN_HVM:
1344 1344 case KVM_CAP_ADJUST_CLOCK:
  1345 + case KVM_CAP_VCPU_EVENTS:
1345 1346 r = 1;
1346 1347 break;
1347 1348 case KVM_CAP_COALESCED_MMIO:
... ... @@ -1883,6 +1884,61 @@
1883 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 1942 long kvm_arch_vcpu_ioctl(struct file *filp,
1887 1943 unsigned int ioctl, unsigned long arg)
1888 1944 {
... ... @@ -2038,6 +2094,27 @@
2038 2094 if (copy_from_user(&mce, argp, sizeof mce))
2039 2095 goto out;
2040 2096 r = kvm_vcpu_ioctl_x86_set_mce(vcpu, &mce);
  2097 + break;
  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);
2041 2118 break;
2042 2119 }
2043 2120 default:
... ... @@ -489,6 +489,9 @@
489 489 #endif
490 490 #define KVM_CAP_ADJUST_CLOCK 39
491 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 496 #ifdef KVM_CAP_IRQ_ROUTING
494 497  
... ... @@ -672,6 +675,9 @@
672 675 /* IA64 stack access */
673 676 #define KVM_IA64_VCPU_GET_STACK _IOR(KVMIO, 0x9a, void *)
674 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 682 #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
677 683