When saving the guest "timebase" we look to the first_cpu for its tb_offset. If that CPU happens to be running a nested guest at this time, the tb_offset will have the nested guest value.
This was caught by code inspection. Signed-off-by: Fabiano Rosas <faro...@linux.ibm.com> --- hw/ppc/ppc.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index 9e99625ea9..093cd87014 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -36,6 +36,7 @@ #include "kvm_ppc.h" #include "migration/vmstate.h" #include "trace.h" +#include "hw/ppc/spapr_cpu_core.h" static void cpu_ppc_tb_stop (CPUPPCState *env); static void cpu_ppc_tb_start (CPUPPCState *env); @@ -961,19 +962,33 @@ static void timebase_save(PPCTimebase *tb) { uint64_t ticks = cpu_get_host_ticks(); PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); + int64_t tb_offset; if (!first_ppc_cpu->env.tb_env) { error_report("No timebase object"); return; } + tb_offset = first_ppc_cpu->env.tb_env->tb_offset; + + if (first_ppc_cpu->vhyp && vhyp_cpu_in_nested(first_ppc_cpu)) { + SpaprCpuState *spapr_cpu = spapr_cpu_state(first_ppc_cpu); + + /* + * If the first_cpu happens to be running a nested guest at + * this time, tb_env->tb_offset will contain the nested guest + * offset. + */ + tb_offset -= spapr_cpu->nested_tb_offset; + } + /* not used anymore, we keep it for compatibility */ tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); /* * tb_offset is only expected to be changed by QEMU so * there is no need to update it from KVM here */ - tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset; + tb->guest_timebase = ticks + tb_offset; tb->runstate_paused = runstate_check(RUN_STATE_PAUSED) || runstate_check(RUN_STATE_SAVE_VM); -- 2.34.1