From downstream:
https://android-review.googlesource.com/c/platform/external/qemu/+/1515002Based on v3 of Alexander Graf's patches
20201202190408.2041-1-agraf@csgraf.de">https://patchew.org/QEMU/
20201202190408.2041-1-agraf@csgraf.deWe need to adjust CNTVOFF_EL2 so that time doesnt warp. Even though we
can set separate CNTVOFF_EL2 values per vCPU, it just is not worth the
require effort to do that accurately---with individual values, even if
they are a tiny bit off it can result in a lockup due to inconsistent
time differences between vCPUs. So just use a global approximate value
for now.
Not tested in upstream yet, but Android emulator snapshots work without
time warp now.
Signed-off-by: Lingfeng Yang <
lfy@google.com>
---
accel/hvf/hvf-cpus.c | 3 +++
include/sysemu/hvf_int.h | 4 ++++
target/arm/hvf/hvf.c | 43 +++++++++++++++++++++++++++++++++++++++-
target/i386/hvf/hvf.c | 4 ++++
4 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/accel/hvf/hvf-cpus.c b/accel/hvf/hvf-cpus.c
index a981ccde70..484c7717f5 100644
--- a/accel/hvf/hvf-cpus.c
+++ b/accel/hvf/hvf-cpus.c
@@ -456,6 +456,9 @@ static int hvf_accel_init(MachineState *ms)
hvf_state = s;
memory_listener_register(&hvf_memory_listener, &address_space_memory);
cpus_register_accel(&hvf_cpus);
+
+ hvf_arch_init(s);
+
return 0;
}
diff --git a/include/sysemu/hvf_int.h b/include/sysemu/hvf_int.h
index 13adf6ea77..08830782c9 100644
--- a/include/sysemu/hvf_int.h
+++ b/include/sysemu/hvf_int.h
@@ -55,6 +55,9 @@ struct HVFState {
hvf_slot slots[32];
int num_slots;
+#if defined(__aarch64__)
+ uint64_t ticks;
+#endif
hvf_vcpu_caps *hvf_caps;
};
extern HVFState *hvf_state;
@@ -73,5 +76,6 @@ void hvf_arch_vcpu_destroy(CPUState *cpu);
int hvf_vcpu_exec(CPUState *cpu);
hvf_slot *hvf_find_overlap_slot(uint64_t, uint64_t);
void hvf_kick_vcpu_thread(CPUState *cpu);
+void hvf_arch_init(HVFState* s);
#endif
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 9442e2f232..37380c6c53 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -312,6 +312,10 @@ int hvf_put_registers(CPUState *cpu)
uint64_t val;
int i;
+ /* Sync up CNTVOFF_EL2 */
+ env->cp15.cntvoff_el2 = hvf_state->ticks;
+ hv_vcpu_set_vtimer_offset(cpu->hvf->fd, env->cp15.cntvoff_el2);
+
for (i = 0; i < ARRAY_SIZE(hvf_reg_match); i++) {
val = *(uint64_t *)((void *)env + hvf_reg_match[i].offset);
ret = hv_vcpu_set_reg(cpu->hvf->fd, hvf_reg_match[i].reg, val);
@@ -418,6 +422,8 @@ void hvf_arch_vcpu_destroy(CPUState *cpu)
{
}
+static HVFState* hvf_state = 0;
+
int hvf_arch_init_vcpu(CPUState *cpu)
{
ARMCPU *arm_cpu = ARM_CPU(cpu);
@@ -795,7 +801,11 @@ int hvf_vcpu_exec(CPUState *cpu)
&cval);
assert_hvf_ok(r);
- int64_t ticks_to_sleep = cval - mach_absolute_time();
+ /* mach_absolute_time() is an absolute host tick number. We
+ * have set up the guest to use the host tick number offset
+ * by env->cp15.cntvoff_el2.
+ */
+ int64_t ticks_to_sleep = cval - (mach_absolute_time() - env->cp15.cntvoff_el2);
if (ticks_to_sleep < 0) {
break;
}
@@ -855,3 +865,34 @@ int hvf_vcpu_exec(CPUState *cpu)
}
}
}
+
+static int hvf_mig_state_pre_save(void* opaque) {
+ struct HVFState* s = opaque;
+ s->ticks -= mach_absolute_time();
+ return 0;
+}
+
+static int hvf_mig_state_post_load(void* opaque) {
+ struct HVFState* s = opaque;
+ m->ticks += mach_absolute_time();
+ return 0;
+}
+
+
+const VMStateDescription vmstate_hvf_migration = {
+ .name = "hvf-migration",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = hvf_mig_state_pre_save,
+ .post_load = hvf_mig_state_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(ticks_to_save, HVFState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+void hvf_arch_init(HVFState* s) {
+ hvf_state = s;
+ hvf_state->ticks = 0;
+ vmstate_register(NULL, 0, &vmstate_hvf_migration, hvf_state);
+}
diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
index 08b4adecd9..7ca6387620 100644
--- a/target/i386/hvf/hvf.c
+++ b/target/i386/hvf/hvf.c
@@ -557,3 +557,7 @@ int hvf_vcpu_exec(CPUState *cpu)
return ret;
}
+
+void hvf_arch_init(HVFState* s) {
+ (void)s;
+}
--
2.24.3 (Apple Git-128)