Patchwork kvm: x86: Add support for VCPU event states

login
register
mail settings
Submitter Jan Kiszka
Date Nov. 24, 2009, 11:33 p.m.
Message ID <4B0C6D2F.6080701@web.de>
Download mbox | patch
Permalink /patch/39255/
State New
Headers show

Comments

Jan Kiszka - Nov. 24, 2009, 11:33 p.m.
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>
---
 kvm-all.c             |   11 +++++++
 kvm.h                 |    1 +
 target-i386/cpu.h     |    5 +++
 target-i386/kvm.c     |   77 +++++++++++++++++++++++++++++++++++++++++++++++++
 target-i386/machine.c |    6 ++++
 5 files changed, 100 insertions(+), 0 deletions(-)
Avi Kivity - Nov. 25, 2009, 2:34 p.m.
On 11/25/2009 01:33 AM, Jan Kiszka wrote:
> 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.
>    

Looks good.
Marcelo Tosatti - Dec. 8, 2009, 3:26 p.m.
On Wed, Nov 25, 2009 at 12:33:03AM +0100, Jan Kiszka wrote:
> 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>
> ---
>  kvm-all.c             |   11 +++++++
>  kvm.h                 |    1 +
>  target-i386/cpu.h     |    5 +++
>  target-i386/kvm.c     |   77 +++++++++++++++++++++++++++++++++++++++++++++++++
>  target-i386/machine.c |    6 ++++
>  5 files changed, 100 insertions(+), 0 deletions(-)

Jan, 

Where is exception_index in the migration data? I can't see it anywhere.
Jan Kiszka - Dec. 8, 2009, 4:18 p.m.
Marcelo Tosatti wrote:
> On Wed, Nov 25, 2009 at 12:33:03AM +0100, Jan Kiszka wrote:
>> 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>
>> ---
>>  kvm-all.c             |   11 +++++++
>>  kvm.h                 |    1 +
>>  target-i386/cpu.h     |    5 +++
>>  target-i386/kvm.c     |   77 +++++++++++++++++++++++++++++++++++++++++++++++++
>>  target-i386/machine.c |    6 ++++
>>  5 files changed, 100 insertions(+), 0 deletions(-)
> 
> Jan, 
> 
> Where is exception_index in the migration data? I can't see it anywhere.
> 

Good point, I missed that it's lacking. Will file an upstream patch for
0.12.

Jan

Patch

diff --git a/kvm-all.c b/kvm-all.c
index b605caa..c05e555 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -61,6 +61,7 @@  struct KVMState
     int coalesced_mmio;
     int broken_set_mem_region;
     int migration_log;
+    int vcpu_events;
 #ifdef KVM_CAP_SET_GUEST_DEBUG
     struct kvm_sw_breakpoint_head kvm_sw_breakpoints;
 #endif
@@ -479,6 +480,11 @@  int kvm_init(int smp_cpus)
     }
 #endif
 
+    s->vcpu_events = 0;
+#ifdef KVM_CAP_VCPU_EVENTS
+    s->vcpu_events = kvm_check_extension(s, KVM_CAP_VCPU_EVENTS);
+#endif
+
     ret = kvm_arch_init(s, smp_cpus);
     if (ret < 0)
         goto err;
@@ -868,6 +874,11 @@  int kvm_has_sync_mmu(void)
 #endif
 }
 
+int kvm_has_vcpu_events(void)
+{
+    return kvm_state->vcpu_events;
+}
+
 void kvm_setup_guest_memory(void *start, size_t size)
 {
     if (!kvm_has_sync_mmu()) {
diff --git a/kvm.h b/kvm.h
index e4cbedc..1c93ac5 100644
--- a/kvm.h
+++ b/kvm.h
@@ -47,6 +47,7 @@  int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size);
 int kvm_set_migration_log(int enable);
 
 int kvm_has_sync_mmu(void);
+int kvm_has_vcpu_events(void);
 
 void kvm_setup_guest_memory(void *start, size_t size);
 
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index eb9532a..9c3e905 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -693,6 +693,11 @@  typedef struct CPUX86State {
     /* For KVM */
     uint32_t mp_state;
     int32_t interrupt_injected;
+    uint8_t soft_interrupt;
+    uint8_t nmi_injected;
+    uint8_t nmi_pending;
+    uint8_t has_error_code;
+    uint32_t sipi_vector;
 
     /* in order to simplify APIC support, we leave this pointer to the
        user */
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 89fd7a5..3b61a7f 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -225,6 +225,8 @@  int kvm_arch_init_vcpu(CPUState *env)
 void kvm_arch_reset_vcpu(CPUState *env)
 {
     env->interrupt_injected = -1;
+    env->nmi_injected = 0;
+    env->nmi_pending = 0;
 }
 
 static int kvm_has_msr_star(CPUState *env)
@@ -694,6 +696,73 @@  static int kvm_get_mp_state(CPUState *env)
     return 0;
 }
 
+static int kvm_put_vcpu_events(CPUState *env)
+{
+#ifdef KVM_CAP_VCPU_EVENTS
+    struct kvm_vcpu_events events;
+
+    if (!kvm_has_vcpu_events()) {
+        return 0;
+    }
+
+    events.exception.injected = (env->exception_index >= 0);
+    events.exception.nr = env->exception_index;
+    events.exception.has_error_code = env->has_error_code;
+    events.exception.error_code = env->error_code;
+
+    events.interrupt.injected = (env->interrupt_injected >= 0);
+    events.interrupt.nr = env->interrupt_injected;
+    events.interrupt.soft = env->soft_interrupt;
+
+    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;
+
+    return kvm_vcpu_ioctl(env, KVM_SET_VCPU_EVENTS, &events);
+#else
+    return 0;
+#endif
+}
+
+static int kvm_get_vcpu_events(CPUState *env)
+{
+#ifdef KVM_CAP_VCPU_EVENTS
+    struct kvm_vcpu_events events;
+    int ret;
+
+    if (!kvm_has_vcpu_events()) {
+        return 0;
+    }
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_VCPU_EVENTS, &events);
+    if (ret < 0) {
+       return ret;
+    }
+    env->exception_index =
+       events.exception.injected ? events.exception.nr : -1;
+    env->has_error_code = events.exception.has_error_code;
+    env->error_code = events.exception.error_code;
+
+    env->interrupt_injected =
+        events.interrupt.injected ? events.interrupt.nr : -1;
+    env->soft_interrupt = events.interrupt.soft;
+
+    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
+
+    return 0;
+}
+
 int kvm_arch_put_registers(CPUState *env)
 {
     int ret;
@@ -718,6 +787,10 @@  int kvm_arch_put_registers(CPUState *env)
     if (ret < 0)
         return ret;
 
+    ret = kvm_put_vcpu_events(env);
+    if (ret < 0)
+        return ret;
+
     return 0;
 }
 
@@ -745,6 +818,10 @@  int kvm_arch_get_registers(CPUState *env)
     if (ret < 0)
         return ret;
 
+    ret = kvm_get_vcpu_events(env);
+    if (ret < 0)
+        return ret;
+
     return 0;
 }
 
diff --git a/target-i386/machine.c b/target-i386/machine.c
index c09b049..cdc8898 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -448,6 +448,11 @@  static const VMStateDescription vmstate_cpu = {
         VMSTATE_INT32_V(interrupt_injected, CPUState, 9),
         VMSTATE_UINT32_V(mp_state, CPUState, 9),
         VMSTATE_UINT64_V(tsc, CPUState, 9),
+        VMSTATE_UINT8_V(soft_interrupt, CPUState, 11),
+        VMSTATE_UINT8_V(nmi_injected, CPUState, 11),
+        VMSTATE_UINT8_V(nmi_pending, CPUState, 11),
+        VMSTATE_UINT8_V(has_error_code, CPUState, 11),
+        VMSTATE_UINT32_V(sipi_vector, CPUState, 11),
         /* MCE */
         VMSTATE_UINT64_V(mcg_cap, CPUState, 10),
         VMSTATE_UINT64_V(mcg_status, CPUState, 10),
@@ -456,6 +461,7 @@  static const VMStateDescription vmstate_cpu = {
         /* rdtscp */
         VMSTATE_UINT64_V(tsc_aux, CPUState, 11),
         VMSTATE_END_OF_LIST()
+        /* The above list is not sorted /wrt version numbers, watch out! */
     }
 };