[patch 2/3] uqmaster: save/restore pio state

Marcelo Tosatti
2010-01-28T19:06:49Z

[-- Attachment #1: kvm-get-put-pio --]
[-- Type: text/plain, Size: 6012 bytes --]

Save/restore in-kernel KVM PIO state. This is necessary to allow
migration with in-progress PIO operation.

FIXME: adjust CPUState and VMState version.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>

Index: qemu-kvm/target-i386/cpu.h
===================================================================
--- qemu-kvm.orig/target-i386/cpu.h
+++ qemu-kvm/target-i386/cpu.h
@@ -570,6 +570,18 @@ typedef struct {
uint64_t mask;
} MTRRVar;

+typedef struct {
+ uint64_t guest_gva;
+ uint32_t count;
+ uint32_t cur_count;
+ uint16_t port;
+ uint8_t size;
+ uint8_t in;
+ uint8_t string;
+ uint8_t down;
+ uint8_t rep;
+} KVMPIOState;
+
#define CPU_NB_REGS64 16
#define CPU_NB_REGS32 8

@@ -702,7 +714,9 @@ typedef struct CPUX86State {
uint8_t has_error_code;
uint32_t sipi_vector;
uint32_t cpuid_kvm_features;
-
+
+ KVMPIOState kvm_pio;
+
/* in order to simplify APIC support, we leave this pointer to the
user */
struct APICState *apic_state;
Index: qemu-kvm/target-i386/kvm.c
===================================================================
--- qemu-kvm.orig/target-i386/kvm.c
+++ qemu-kvm/target-i386/kvm.c
@@ -289,6 +289,7 @@ void kvm_arch_reset_vcpu(CPUState *env)
env->interrupt_injected = -1;
env->nmi_injected = 0;
env->nmi_pending = 0;
+ memset(&env->kvm_pio, 0, sizeof(KVMPIOState));
}

static int kvm_has_msr_star(CPUState *env)
@@ -837,6 +838,57 @@ static int kvm_get_vcpu_events(CPUState
return 0;
}

+static int kvm_put_pio(CPUState *env)
+{
+#ifdef KVM_CAP_PIO
+ struct kvm_pio_request pio;
+
+ if (!kvm_has_vcpu_pio())
+ return 0;
+
+ pio.count = env->kvm_pio.count;
+ pio.cur_count = env->kvm_pio.cur_count;
+ pio.guest_gva = env->kvm_pio.guest_gva;
+ pio.in = env->kvm_pio.in;
+ pio.port = env->kvm_pio.port;
+ pio.size = env->kvm_pio.size;
+ pio.string = env->kvm_pio.string;
+ pio.down = env->kvm_pio.down;
+ pio.rep = env->kvm_pio.rep;
+
+ return kvm_vcpu_ioctl(env, KVM_SET_VCPU_PIO, &pio);
+#else
+ return 0;
+#endif
+}
+
+static int kvm_get_pio(CPUState *env)
+{
+#ifdef KVM_CAP_PIO
+ struct kvm_pio_request pio;
+ int ret;
+
+ if (!kvm_has_vcpu_pio())
+ return 0;
+
+ ret = kvm_vcpu_ioctl(env, KVM_GET_VCPU_PIO, &pio);
+ if (ret < 0)
+ return ret;
+
+ env->kvm_pio.count = pio.count;
+ env->kvm_pio.cur_count = pio.cur_count;
+ env->kvm_pio.guest_gva = pio.guest_gva;
+ env->kvm_pio.in = pio.in;
+ env->kvm_pio.port = pio.port;
+ env->kvm_pio.size = pio.size;
+ env->kvm_pio.string = pio.string;
+ env->kvm_pio.down = pio.down;
+ env->kvm_pio.rep = pio.rep;
+#endif
+
+ return 0;
+}
+
int kvm_arch_put_registers(CPUState *env)
{
int ret;
@@ -865,6 +917,10 @@ int kvm_arch_put_registers(CPUState *env
if (ret < 0)
return ret;

+ ret = kvm_put_pio(env);
+ if (ret < 0)
+ return ret;
+
return 0;
}

@@ -896,6 +952,10 @@ int kvm_arch_get_registers(CPUState *env
if (ret < 0)
return ret;

+ ret = kvm_get_pio(env);
+ if (ret < 0)
+ return ret;
+
return 0;
}

Index: qemu-kvm/target-i386/machine.c
===================================================================
--- qemu-kvm.orig/target-i386/machine.c
+++ qemu-kvm/target-i386/machine.c
@@ -62,6 +62,34 @@ static const VMStateDescription vmstate_
#define VMSTATE_MTRR_VARS(_field, _state, _n, _v) \
VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_mtrr_var, MTRRVar)

+static const VMStateDescription vmstate_kvm_pio = {
+ .name = "kvm_pio",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT64(guest_gva, KVMPIOState),
+ VMSTATE_UINT32(count, KVMPIOState),
+ VMSTATE_UINT32(cur_count, KVMPIOState),
+ VMSTATE_UINT8(in, KVMPIOState),
+ VMSTATE_UINT16(port, KVMPIOState),
+ VMSTATE_UINT8(size, KVMPIOState),
+ VMSTATE_UINT8(string, KVMPIOState),
+ VMSTATE_UINT8(down, KVMPIOState),
+ VMSTATE_UINT8(rep, KVMPIOState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+#define VMSTATE_KVM_PIO(_field, _state, _version) { \
+ .name = (stringify(_field)), \
+ .version_id = _version, \
+ .size = sizeof(KVMPIOState), \
+ .vmsd = &vmstate_kvm_pio, \
+ .flags = VMS_STRUCT, \
+ .offset = vmstate_offset_value(_state, _field, KVMPIOState),\
+}
+
static void put_fpreg_error(QEMUFile *f, void *opaque, size_t size)
{
fprintf(stderr, "call put_fpreg() with invalid arguments\n");
@@ -464,6 +492,9 @@ static const VMStateDescription vmstate_
/* KVM pvclock msr */
VMSTATE_UINT64_V(system_time_msr, CPUState, 11),
VMSTATE_UINT64_V(wall_clock_msr, CPUState, 11),
+
+ VMSTATE_KVM_PIO(kvm_pio, CPUState, 11),
+
VMSTATE_END_OF_LIST()
/* The above list is not sorted /wrt version numbers, watch out! */
}
Index: qemu-kvm/kvm.h
===================================================================
--- qemu-kvm.orig/kvm.h
+++ qemu-kvm/kvm.h
@@ -48,6 +48,7 @@ int kvm_set_migration_log(int enable);

int kvm_has_sync_mmu(void);
int kvm_has_vcpu_events(void);
+int kvm_has_vcpu_pio(void);

void kvm_setup_guest_memory(void *start, size_t size);

Index: qemu-kvm/kvm-all.c
===================================================================
--- qemu-kvm.orig/kvm-all.c
+++ qemu-kvm/kvm-all.c
@@ -881,6 +881,17 @@ int kvm_has_sync_mmu(void)
#endif
}

+int kvm_has_vcpu_pio(void)
+{
+#ifdef KVM_CAP_PIO
+ KVMState *s = kvm_state;
+
+ return kvm_check_extension(s, KVM_CAP_PIO);
+#else
+ return 0;
+#endif
+}
+
int kvm_has_vcpu_events(void)
{
return kvm_state->vcpu_events;