From d2fd6d1a5200b9a58863839d21d291cd4f76ac31 Mon Sep 17 00:00:00 2001 From: Ying Fang Date: Mon, 29 Jul 2019 15:47:27 +0800 Subject: [PATCH] ARM64: record vtimer tick when cpu is stopped The vtimer kick still increases even if the vcpu is stopped when VM has save/restore or suspend/resume operation. This will cause guest watchdog soft-lockup if the VM has lots of memory in use. Signed-off-by: Hao Hong Signed-off-by: Haibin Wang Signed-off-by: Ying Fang --- cpus.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ target/arm/cpu.h | 2 ++ target/arm/machine.c | 1 + 3 files changed, 61 insertions(+) diff --git a/cpus.c b/cpus.c index e83f72b4..f6ec48a2 100644 --- a/cpus.c +++ b/cpus.c @@ -1063,6 +1063,28 @@ void cpu_synchronize_all_pre_loadvm(void) } } +#ifdef __aarch64__ +static void get_vcpu_timer_tick(CPUState *cs) +{ + CPUARMState *env = &ARM_CPU(cs)->env; + int err; + struct kvm_one_reg reg; + uint64_t timer_tick; + + reg.id = KVM_REG_ARM_TIMER_CNT; + reg.addr = (uintptr_t) &timer_tick; + + err = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (err < 0) { + error_report("get vcpu tick failed, ret = %d", err); + env->vtimer = 0; + return; + } + env->vtimer = timer_tick; + return; +} +#endif + static int do_vm_stop(RunState state, bool send_stop) { int ret = 0; @@ -1070,6 +1092,11 @@ static int do_vm_stop(RunState state, bool send_stop) if (runstate_is_running()) { cpu_disable_ticks(); pause_all_vcpus(); +#ifdef __aarch64__ + if (first_cpu) { + get_vcpu_timer_tick(first_cpu); + } +#endif runstate_set(state); vm_state_notify(0, state); if (send_stop) { @@ -1909,11 +1936,42 @@ void cpu_resume(CPUState *cpu) qemu_cpu_kick(cpu); } +#ifdef __aarch64__ +static void set_vcpu_timer_tick(CPUState *cs) +{ + CPUARMState *env = &ARM_CPU(cs)->env; + + if (env->vtimer == 0) { + return; + } + + int err; + struct kvm_one_reg reg; + uint64_t timer_tick = env->vtimer; + env->vtimer = 0; + + reg.id = KVM_REG_ARM_TIMER_CNT; + reg.addr = (uintptr_t) &timer_tick; + + err = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (err < 0) { + error_report("Set vcpu tick failed, ret = %d", err); + return; + } + return; +} +#endif + void resume_all_vcpus(void) { CPUState *cpu; qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); +#ifdef __aarch64__ + if (first_cpu) { + set_vcpu_timer_tick(first_cpu); + } +#endif CPU_FOREACH(cpu) { cpu_resume(cpu); } diff --git a/target/arm/cpu.h b/target/arm/cpu.h index d4d28369..e107e395 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -270,6 +270,8 @@ typedef struct CPUARMState { uint64_t elr_el[4]; /* AArch64 exception link regs */ uint64_t sp_el[4]; /* AArch64 banked stack pointers */ + uint64_t vtimer; /* Timer tick when vcpu stop */ + /* System control coprocessor (cp15) */ struct { uint32_t c0_cpuid; diff --git a/target/arm/machine.c b/target/arm/machine.c index b2925496..d64a0057 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -792,6 +792,7 @@ const VMStateDescription vmstate_arm_cpu = { VMSTATE_UINT32(env.exception.syndrome, ARMCPU), VMSTATE_UINT32(env.exception.fsr, ARMCPU), VMSTATE_UINT64(env.exception.vaddress, ARMCPU), + VMSTATE_UINT64(env.vtimer, ARMCPU), VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU), VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU), { -- 2.23.0