summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--target-arm/cpu-qom.h6
-rw-r--r--target-arm/kvm.c16
2 files changed, 21 insertions, 1 deletions
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 2242eee514..25239b8952 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -72,7 +72,11 @@ typedef struct ARMCPU {
     uint64_t *cpreg_indexes;
     /* Values of the registers (cpreg_indexes[i]'s value is cpreg_values[i]) */
     uint64_t *cpreg_values;
-    /* Length of the indexes, values arrays */
+    /* When using KVM, keeps a copy of the initial state of the VCPU,
+     * so that on reset we can feed the reset values back into the kernel.
+     */
+    uint64_t *cpreg_reset_values;
+    /* Length of the indexes, values, reset_values arrays */
     int32_t cpreg_array_len;
     /* These are used only for migration: incoming data arrives in
      * these fields and is sanity checked in post_load before copying
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index 66ce67a46f..49108cfd33 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -162,6 +162,13 @@ int kvm_arch_init_vcpu(CPUState *cs)
         goto out;
     }
 
+    /* Save a copy of the initial register values so that we can
+     * feed it back to the kernel on VCPU reset.
+     */
+    cpu->cpreg_reset_values = g_memdup(cpu->cpreg_values,
+                                       cpu->cpreg_array_len *
+                                       sizeof(cpu->cpreg_values[0]));
+
 out:
     g_free(rlp);
     return ret;
@@ -603,6 +610,15 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 
 void kvm_arch_reset_vcpu(CPUState *cs)
 {
+    /* Feed the kernel back its initial register state */
+    ARMCPU *cpu = ARM_CPU(cs);
+
+    memmove(cpu->cpreg_values, cpu->cpreg_reset_values,
+            cpu->cpreg_array_len * sizeof(cpu->cpreg_values[0]));
+
+    if (!write_list_to_kvmstate(cpu)) {
+        abort();
+    }
 }
 
 bool kvm_arch_stop_on_emulation_error(CPUState *cs)