From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jan Kiszka Subject: [PATCH] KVM: x86: Add KVM_GET/SET_VCPU_EVENTS Date: Thu, 12 Nov 2009 01:04:25 +0100 Message-ID: <4AFB5109.3070402@web.de> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="------------enig328716DEF0A06F9417776FCA" Cc: kvm To: Avi Kivity , Marcelo Tosatti Return-path: Received: from fmmailgate02.web.de ([217.72.192.227]:47805 "EHLO fmmailgate02.web.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1759719AbZKLAES (ORCPT ); Wed, 11 Nov 2009 19:04:18 -0500 Sender: kvm-owner@vger.kernel.org List-ID: This is an OpenPGP/MIME signed message (RFC 2440 and 3156) --------------enig328716DEF0A06F9417776FCA Content-Type: text/plain; charset=ISO-8859-15 Content-Transfer-Encoding: quoted-printable 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. Signed-off-by: Jan Kiszka --- Documentation/kvm/api.txt | 48 ++++++++++++++++++++++++++ arch/x86/include/asm/kvm.h | 26 ++++++++++++++ arch/x86/include/asm/kvm_host.h | 2 + arch/x86/kvm/svm.c | 22 ++++++++++++ arch/x86/kvm/vmx.c | 30 ++++++++++++++++ arch/x86/kvm/x86.c | 72 +++++++++++++++++++++++++++++++++= ++++++ include/linux/kvm.h | 6 +++ 7 files changed, 206 insertions(+), 0 deletions(-) diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt index 36594ba..fa3e59e 100644 --- a/Documentation/kvm/api.txt +++ b/Documentation/kvm/api.txt @@ -653,6 +653,54 @@ struct kvm_clock_data { __u32 pad[9]; }; =20 +4.29 KVM_GET_VCPU_EVENTS + +Capability: KVM_CAP_VCPU_EVENTS +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_vcpu_event (out) +Returns: 0 on success, -1 on error + +Gets currently pending exceptions, interrupts, and NMIs as well as relat= ed +states of the vcpu. + +struct kvm_vcpu_events { + struct { + __u8 injected; + __u8 nr; + __u8 has_error_code; + __u8 pad; + __u32 error_code; + } exception; + struct { + __u8 injected; + __u8 nr; + __u8 soft; + __u8 pad; + } interrupt; + struct { + __u8 injected; + __u8 pending; + __u8 masked; + __u8 pad; + } nmi; + __u32 sipi_vector; +}; + +4.30 KVM_SET_VCPU_EVENTS + +Capability: KVM_CAP_VCPU_EVENTS +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_vcpu_event (in) +Returns: 0 on success, -1 on error + +Set pending exceptions, interrupts, and NMIs as well as related states o= f the +vcpu. + +See KVM_GET_VCPU_EVENTS for the data structure. + + 5. The kvm_run structure =20 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 ef9b4b7..03fd136 100644 --- a/arch/x86/include/asm/kvm.h +++ b/arch/x86/include/asm/kvm.h @@ -20,6 +20,7 @@ #define __KVM_HAVE_MCE #define __KVM_HAVE_PIT_STATE2 #define __KVM_HAVE_XEN_HVM +#define __KVM_HAVE_VCPU_EVENTS =20 /* Architectural interrupt line count. */ #define KVM_NR_INTERRUPTS 256 @@ -252,4 +253,29 @@ struct kvm_reinject_control { __u8 pit_reinject; __u8 reserved[31]; }; + +/* for KVM_GET/SET_VCPU_EVENTS */ +struct kvm_vcpu_events { + struct { + __u8 injected; + __u8 nr; + __u8 has_error_code; + __u8 pad; + __u32 error_code; + } exception; + struct { + __u8 injected; + __u8 nr; + __u8 soft; + __u8 pad; + } interrupt; + struct { + __u8 injected; + __u8 pending; + __u8 masked; + __u8 pad; + } nmi; + __u32 sipi_vector; +}; + #endif /* _ASM_X86_KVM_H */ diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_h= ost.h index 26a74b7..06e0856 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 { bool has_error_code, u32 error_code); int (*interrupt_allowed)(struct kvm_vcpu *vcpu); int (*nmi_allowed)(struct kvm_vcpu *vcpu); + bool (*get_nmi_mask)(struct kvm_vcpu *vcpu); + void (*set_nmi_mask)(struct kvm_vcpu *vcpu, bool masked); void (*enable_nmi_window)(struct kvm_vcpu *vcpu); void (*enable_irq_window)(struct kvm_vcpu *vcpu); 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 34b700f..3de0b37 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) !(svm->vcpu.arch.hflags & HF_NMI_MASK); } =20 +static bool svm_get_nmi_mask(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm =3D to_svm(vcpu); + + return !!(svm->vcpu.arch.hflags & HF_NMI_MASK); +} + +static void svm_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked) +{ + struct vcpu_svm *svm =3D to_svm(vcpu); + + if (masked) { + svm->vcpu.arch.hflags |=3D HF_NMI_MASK; + svm->vmcb->control.intercept |=3D (1UL << INTERCEPT_IRET); + } else { + svm->vcpu.arch.hflags &=3D ~HF_NMI_MASK; + svm->vmcb->control.intercept &=3D ~(1UL << INTERCEPT_IRET); + } +} + static int svm_interrupt_allowed(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm =3D to_svm(vcpu); @@ -2946,6 +2966,8 @@ static struct kvm_x86_ops svm_x86_ops =3D { .queue_exception =3D svm_queue_exception, .interrupt_allowed =3D svm_interrupt_allowed, .nmi_allowed =3D svm_nmi_allowed, + .get_nmi_mask =3D svm_get_nmi_mask, + .set_nmi_mask =3D svm_set_nmi_mask, .enable_nmi_window =3D enable_nmi_window, .enable_irq_window =3D enable_irq_window, .update_cr8_intercept =3D update_cr8_intercept, diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index b923f2a..63e4a50 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2633,6 +2633,34 @@ static int vmx_nmi_allowed(struct kvm_vcpu *vcpu) GUEST_INTR_STATE_NMI)); } =20 +static bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu) +{ + if (!cpu_has_virtual_nmis()) + return to_vmx(vcpu)->soft_vnmi_blocked; + else + return !!(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & + GUEST_INTR_STATE_NMI); +} + +static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked) +{ + struct vcpu_vmx *vmx =3D to_vmx(vcpu); + + if (!cpu_has_virtual_nmis()) { + if (vmx->soft_vnmi_blocked !=3D masked) { + vmx->soft_vnmi_blocked =3D masked; + vmx->vnmi_blocked_time =3D 0; + } + } else { + if (masked) + vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, + GUEST_INTR_STATE_NMI); + else + vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, + GUEST_INTR_STATE_NMI); + } +} + static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu) { return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && @@ -3973,6 +4001,8 @@ static struct kvm_x86_ops vmx_x86_ops =3D { .queue_exception =3D vmx_queue_exception, .interrupt_allowed =3D vmx_interrupt_allowed, .nmi_allowed =3D vmx_nmi_allowed, + .get_nmi_mask =3D vmx_get_nmi_mask, + .set_nmi_mask =3D vmx_set_nmi_mask, .enable_nmi_window =3D enable_nmi_window, .enable_irq_window =3D enable_irq_window, .update_cr8_intercept =3D update_cr8_intercept, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ba8958d..862ecb4 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) case KVM_CAP_SET_IDENTITY_MAP_ADDR: case KVM_CAP_XEN_HVM: case KVM_CAP_ADJUST_CLOCK: + case KVM_CAP_VCPU_EVENTS: r =3D 1; break; case KVM_CAP_COALESCED_MMIO: @@ -1883,6 +1884,54 @@ static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_v= cpu *vcpu, return 0; } =20 +static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu, + struct kvm_vcpu_events *events) +{ + vcpu_load(vcpu); + + events->exception.injected =3D vcpu->arch.exception.pending; + events->exception.nr =3D vcpu->arch.exception.nr; + events->exception.has_error_code =3D vcpu->arch.exception.has_error_cod= e; + events->exception.error_code =3D vcpu->arch.exception.error_code; + + events->interrupt.injected =3D vcpu->arch.interrupt.pending; + events->interrupt.nr =3D vcpu->arch.interrupt.nr; + events->interrupt.soft =3D vcpu->arch.interrupt.soft; + + events->nmi.injected =3D vcpu->arch.nmi_injected; + events->nmi.pending =3D vcpu->arch.nmi_pending; + events->nmi.masked =3D kvm_x86_ops->get_nmi_mask(vcpu); + + events->sipi_vector =3D vcpu->arch.sipi_vector; + + vcpu_put(vcpu); +} + +static void kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, + struct kvm_vcpu_events *events) +{ + vcpu_load(vcpu); + + vcpu->arch.exception.pending =3D events->exception.injected; + vcpu->arch.exception.nr =3D events->exception.nr; + vcpu->arch.exception.has_error_code =3D events->exception.has_error_cod= e; + vcpu->arch.exception.error_code =3D events->exception.error_code; + + vcpu->arch.interrupt.pending =3D events->interrupt.injected; + vcpu->arch.interrupt.nr =3D events->interrupt.nr; + vcpu->arch.interrupt.soft =3D events->interrupt.soft; + if (vcpu->arch.interrupt.pending && irqchip_in_kernel(vcpu->kvm)) + kvm_pic_clear_isr_ack(vcpu->kvm); + + vcpu->arch.nmi_injected =3D events->nmi.injected; + vcpu->arch.nmi_pending =3D events->nmi.pending; + kvm_x86_ops->set_nmi_mask(vcpu, events->nmi.masked); + + vcpu->arch.sipi_vector =3D events->sipi_vector; + + vcpu_put(vcpu); +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -2040,6 +2089,29 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r =3D kvm_vcpu_ioctl_x86_set_mce(vcpu, &mce); break; } + case KVM_GET_VCPU_EVENTS: { + struct kvm_vcpu_events events; + + kvm_vcpu_ioctl_x86_get_vcpu_events(vcpu, &events); + + r =3D -EFAULT; + if (copy_to_user(argp, &events, sizeof(struct kvm_vcpu_events))) + break; + r =3D 0; + break; + } + case KVM_SET_VCPU_EVENTS: { + struct kvm_vcpu_events events; + + r =3D -EFAULT; + if (copy_from_user(&events, argp, sizeof(struct kvm_vcpu_events))) + break; + + kvm_vcpu_ioctl_x86_set_vcpu_events(vcpu, &events); + + r =3D 0; + break; + } default: r =3D -EINVAL; } diff --git a/include/linux/kvm.h b/include/linux/kvm.h index ca62b8e..9049dc3 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -484,6 +484,9 @@ struct kvm_ioeventfd { #define KVM_CAP_XEN_HVM 38 #endif #define KVM_CAP_ADJUST_CLOCK 39 +#ifdef __KVM_HAVE_VCPU_EVENTS +#define KVM_CAP_VCPU_EVENTS 40 +#endif =20 #ifdef KVM_CAP_IRQ_ROUTING =20 @@ -667,6 +670,9 @@ struct kvm_clock_data { /* IA64 stack access */ #define KVM_IA64_VCPU_GET_STACK _IOR(KVMIO, 0x9a, void *) #define KVM_IA64_VCPU_SET_STACK _IOW(KVMIO, 0x9b, void *) +/* Available with KVM_CAP_VCPU_EVENTS */ +#define KVM_GET_VCPU_EVENTS _IOR(KVMIO, 0x9f, struct kvm_vcpu_eve= nts) +#define KVM_SET_VCPU_EVENTS _IOW(KVMIO, 0xa0, struct kvm_vcpu_eve= nts) =20 #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) =20 --------------enig328716DEF0A06F9417776FCA Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (GNU/Linux) Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org iEYEARECAAYFAkr7UQ4ACgkQitSsb3rl5xS2HQCeLH84jrqYzQr1PEYqIusKiHm4 JhcAnR5pIMvPzEu2P17zr5YnYvd1DtWI =fAIV -----END PGP SIGNATURE----- --------------enig328716DEF0A06F9417776FCA--