From 60fbe0cbe9e0f769a4db560eca1e145cbd3a0065 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Wed, 16 Dec 2009 16:33:24 -0200 Subject: [PATCH 1/6] kvm: x86: Add support for VCPU event states RH-Author: Juan Quintela <quintela@redhat.com> Message-id: <m3tyvqc20b.fsf@neno.neno> Patchwork-id: 5740 O-Subject: [RHEL 5.5 v2 PATCH] kvm: x86: Add support for VCPU event states Bugzilla: 541084 RH-Acked-by: Marcelo Tosatti <mtosatti@redhat.com> RH-Acked-by: Michael S. Tsirkin <mst@redhat.com> RH-Acked-by: Gleb Natapov <gleb@redhat.com> ( quintela changes: new version, in top of -M 5.4.0 changes. Once there simplify it to use same version_id == 8). (new version fixing the "unused variable r" warning) commit a0fb002c6462d21ceb9eac8c5772e469ec189374 Author: Jan Kiszka <jan.kiszka@web.de> Date: Wed Nov 25 00:33:03 2009 +0100 kvm: x86: Add support for VCPU event states This patch extends the qemu-kvm state sync logic with support for KVM_GET/SET_VCPU_EVENTS, giving access to yet missing exception, interrupt and NMI states. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> Bugzilla: 541084 Signed-off-by: Juan Quintela <quintela@redhat.com> --- libkvm/libkvm-x86.c | 35 ++++++++++++++++++++++++++ libkvm/libkvm.h | 6 ++++ qemu/qemu-kvm-x86.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ qemu/qemu-kvm.h | 3 ++ qemu/target-i386/cpu.h | 6 ++++ qemu/target-i386/machine.c | 16 +++++++++++- 6 files changed, 124 insertions(+), 1 deletions(-) Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> --- libkvm/libkvm-x86.c | 35 ++++++++++++++++++++++++++ libkvm/libkvm.h | 6 ++++ qemu/qemu-kvm-x86.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ qemu/qemu-kvm.h | 3 ++ qemu/target-i386/cpu.h | 6 ++++ qemu/target-i386/machine.c | 14 ++++++++++ 6 files changed, 123 insertions(+), 0 deletions(-) diff --git a/libkvm/libkvm-x86.c b/libkvm/libkvm-x86.c index c10c7e5..3918f49 100644 --- a/libkvm/libkvm-x86.c +++ b/libkvm/libkvm-x86.c @@ -585,3 +585,38 @@ int kvm_set_clock(kvm_context_t kvm, struct kvm_clock_data *cl) } #endif +#ifdef KVM_CAP_VCPU_EVENTS +int kvm_has_vcpu_events(kvm_context_t kvm) +{ + int r; + r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_VCPU_EVENTS); + if (r == -1 || r == 0) + return 0; + return 1; +} + +int kvm_get_vcpu_events(kvm_context_t kvm, int vcpu, struct kvm_vcpu_events *ev) +{ + int r; + + r = ioctl(kvm->vcpu_fd[vcpu], KVM_GET_VCPU_EVENTS, ev); + if (r == -1) { + r = -errno; + perror("kvm_get_vcpu_events"); + } + return r; +} + +int kvm_set_vcpu_events(kvm_context_t kvm, int vcpu, struct kvm_vcpu_events *ev) +{ + int r; + + r = ioctl(kvm->vcpu_fd[vcpu], KVM_SET_VCPU_EVENTS, ev); + if (r == -1) { + r = -errno; + perror("kvm_set_vcpu_events"); + } + return r; +} +#endif + diff --git a/libkvm/libkvm.h b/libkvm/libkvm.h index be163e8..185285a 100644 --- a/libkvm/libkvm.h +++ b/libkvm/libkvm.h @@ -864,4 +864,10 @@ int kvm_assign_set_msix_entry(kvm_context_t kvm, int kvm_get_clock(kvm_context_t kvm, struct kvm_clock_data *cl); int kvm_set_clock(kvm_context_t kvm, struct kvm_clock_data *cl); int kvm_can_adjust_clock(kvm_context_t kvm); + +int kvm_has_vcpu_events(kvm_context_t kvm); +int kvm_get_vcpu_events(kvm_context_t kvm, int vcpu, + struct kvm_vcpu_events *ev); +int kvm_set_vcpu_events(kvm_context_t kvm, int vcpu, + struct kvm_vcpu_events *ev); #endif diff --git a/qemu/qemu-kvm-x86.c b/qemu/qemu-kvm-x86.c index fcf5a21..899f0ad 100644 --- a/qemu/qemu-kvm-x86.c +++ b/qemu/qemu-kvm-x86.c @@ -358,6 +358,61 @@ void kvm_load_mpstate(CPUState *env) #endif } +void kvm_save_vcpu_events(CPUState *env) +{ +#ifdef KVM_CAP_VCPU_EVENTS + struct kvm_vcpu_events events; + + if (!kvm_has_vcpu_events(kvm_context)) + return; + + if (kvm_get_vcpu_events(kvm_context, env->cpu_index, &events)) + exit(0); + + env->nmi_injected = events.nmi.injected; + env->nmi_pending = events.nmi.pending; + if (events.nmi.masked) { + env->hflags2 |= HF2_NMI_MASK; + } else { + env->hflags2 &= ~HF2_NMI_MASK; + } + + env->sipi_vector = events.sipi_vector; +#endif +} + +void kvm_load_vcpu_events(CPUState *env) +{ +#ifdef KVM_CAP_VCPU_EVENTS + struct kvm_vcpu_events events; + + if (!kvm_has_vcpu_events(kvm_context)) + return; + + events.flags = 0; + + /* Exceptions are regenerated */ + events.exception.injected = 0; + events.exception.nr = 0; + events.exception.has_error_code = 0; + events.exception.error_code = 0; + + /* Pending interrupts are restored through interrupt_bitmap */ + events.interrupt.injected = 0; + events.interrupt.nr = 0; + events.interrupt.soft = 0; + + events.nmi.injected = env->nmi_injected; + events.nmi.pending = env->nmi_pending; + events.nmi.masked = !!(env->hflags2 & HF2_NMI_MASK); + + events.sipi_vector = env->sipi_vector; + + if (kvm_set_vcpu_events(kvm_context, env->cpu_index, &events)) + exit(0); +#endif +} + void kvm_arch_save_regs(CPUState *env) { struct kvm_regs regs; @@ -714,6 +769,10 @@ int handle_tpr_access(void *opaque, int vcpu, void kvm_arch_cpu_reset(CPUState *env) { + env->nmi_injected = 0; + env->nmi_pending = 0; + kvm_load_vcpu_events(env); + kvm_arch_load_regs(env); if (env->cpu_index != 0) { if (kvm_irqchip_in_kernel(kvm_context)) { diff --git a/qemu/qemu-kvm.h b/qemu/qemu-kvm.h index f2063ce..37d8727 100644 --- a/qemu/qemu-kvm.h +++ b/qemu/qemu-kvm.h @@ -22,6 +22,9 @@ void kvm_load_registers(CPUState *env); void kvm_save_registers(CPUState *env); void kvm_load_mpstate(CPUState *env); void kvm_save_mpstate(CPUState *env); +void kvm_save_vcpu_events(CPUState *env); +void kvm_load_vcpu_events(CPUState *env); + int kvm_cpu_exec(CPUState *env); int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr, target_ulong len, int type); diff --git a/qemu/target-i386/cpu.h b/qemu/target-i386/cpu.h index b4c0bec..e1a7fc4 100644 --- a/qemu/target-i386/cpu.h +++ b/qemu/target-i386/cpu.h @@ -644,6 +644,12 @@ typedef struct CPUX86State { user */ struct APICState *apic_state; uint32_t mp_state; + uint8_t soft_interrupt; + uint8_t nmi_injected; + uint8_t nmi_pending; + uint8_t has_error_code; + uint32_t sipi_vector; + } CPUX86State; CPUX86State *cpu_x86_init(const char *cpu_model); diff --git a/qemu/target-i386/machine.c b/qemu/target-i386/machine.c index d77ed04..db344c3 100644 --- a/qemu/target-i386/machine.c +++ b/qemu/target-i386/machine.c @@ -43,6 +43,7 @@ void cpu_save(QEMUFile *f, void *opaque, int version_id) if (kvm_enabled()) { kvm_save_registers(env); kvm_save_mpstate(env); + kvm_save_vcpu_events(env); } for(i = 0; i < CPU_NB_REGS; i++) @@ -154,6 +155,12 @@ void cpu_save(QEMUFile *f, void *opaque, int version_id) if (version_id >= 8) { qemu_put_be64s(f, &env->system_time_msr); qemu_put_be64s(f, &env->wall_clock_msr); + + qemu_put_8s(f, &env->soft_interrupt); + qemu_put_8s(f, &env->nmi_injected); + qemu_put_8s(f, &env->nmi_pending); + qemu_put_8s(f, &env->has_error_code); + qemu_put_be32s(f, &env->sipi_vector); } } @@ -346,6 +353,13 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) if (version_id >= 8) { qemu_get_be64s(f, &env->system_time_msr); qemu_get_be64s(f, &env->wall_clock_msr); + + qemu_get_8s(f, &env->soft_interrupt); + qemu_get_8s(f, &env->nmi_injected); + qemu_get_8s(f, &env->nmi_pending); + qemu_get_8s(f, &env->has_error_code); + qemu_get_be32s(f, &env->sipi_vector); + kvm_load_vcpu_events(env); } return 0; } -- 1.6.3.rc4.29.g8146