>From downstream: https://android-review.googlesource.com/c/platform/external/qemu/+/1515002
Based on v3 of Alexander Graf's patches https://patchew.org/QEMU/20201202190408.2041-1-ag...@csgraf.de We 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 <l...@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)