On Wed, Sep 10, 2025 at 05:35:28PM +0800, Xie Bo wrote: > Fix two migration issues for virtual machines in KVM mode: > 1.It saves and restores the vCPU's privilege mode to ensure that the > vCPU's privilege mode is correct after migration. > 2.It saves and restores the vCPU's mp_state (runnable or stopped) and > includes this state in the migration sequence, upgrading the vmstate > version to ensure that the vCPU's mp_state is correct after migration. > > KVM_PUT_RUNTIME_STATE only synchronizes the vCPU’s runtime-modified > state (such as registers), whereas mp_state is related to system boot, > multi-core initialization, and is not modified during normal operation. > Therefore, mp_state is only synchronized to KVM during KVM_PUT_RESET_STATE > and KVM_PUT_FULL_STATE. > > Signed-off-by: Xie Bo <x...@ultrarisc.com> > --- > target/riscv/kvm/kvm-cpu.c | 60 ++++++++++++++++++++++++++++-------- > target/riscv/kvm/kvm_riscv.h | 3 +- > target/riscv/machine.c | 5 +-- > 3 files changed, 52 insertions(+), 16 deletions(-) > > diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c > index 0f4997a918..1434dd1c51 100644 > --- a/target/riscv/kvm/kvm-cpu.c > +++ b/target/riscv/kvm/kvm-cpu.c > @@ -576,6 +576,12 @@ static int kvm_riscv_get_regs_core(CPUState *cs) > } > env->pc = reg; > > + ret = kvm_get_one_reg(cs, RISCV_CORE_REG(env, mode), ®); > + if (ret) { > + return ret; > + } > + env->priv = reg; > + > for (i = 1; i < 32; i++) { > uint64_t id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, i); > ret = kvm_get_one_reg(cs, id, ®); > @@ -601,6 +607,12 @@ static int kvm_riscv_put_regs_core(CPUState *cs) > return ret; > } > > + reg = env->priv; > + ret = kvm_set_one_reg(cs, RISCV_CORE_REG(env, mode), ®); > + if (ret) { > + return ret; > + } > + > for (i = 1; i < 32; i++) { > uint64_t id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, i); > reg = env->gpr[i]; > @@ -1244,25 +1256,52 @@ int kvm_arch_get_registers(CPUState *cs, Error **errp) > return ret; > } > > + ret = kvm_riscv_sync_mpstate_to_qemu(cs); > + if (ret) { > + return ret; > + } > + > return ret; > } > > -int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state) > +int kvm_riscv_sync_mpstate_to_kvm(CPUState *cs) > { > + int ret = 0; > + CPURISCVState *env = &RISCV_CPU(cs)->env; > + > if (cap_has_mp_state) { > struct kvm_mp_state mp_state = { > - .mp_state = state > + .mp_state = env->mp_state > }; > > - int ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MP_STATE, &mp_state); > + ret = kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state); > if (ret) { > - fprintf(stderr, "%s: failed to sync MP_STATE %d/%s\n", > + fprintf(stderr, "%s: failed to sync MP_STATE to KVM %d/%s\n", > __func__, ret, strerror(-ret)); > - return -1; > } > } > > - return 0; > + return ret; > +} > + > +int kvm_riscv_sync_mpstate_to_qemu(CPUState *cs) > +{ > + int ret = 0; > + CPURISCVState *env = &RISCV_CPU(cs)->env; > + > + if (cap_has_mp_state) { > + struct kvm_mp_state mp_state; > + > + ret = kvm_vcpu_ioctl(cs, KVM_GET_MP_STATE, &mp_state); > + if (ret) { > + fprintf(stderr, "%s: failed to sync MP_STATE to QEMU %d/%s\n", > + __func__, ret, strerror(-ret)); > + return ret; > + } > + env->mp_state = mp_state.mp_state; > + } > + > + return ret; > } > > int kvm_arch_put_registers(CPUState *cs, int level, Error **errp) > @@ -1289,13 +1328,8 @@ int kvm_arch_put_registers(CPUState *cs, int level, > Error **errp) > return ret; > } > > - if (KVM_PUT_RESET_STATE == level) { > - RISCVCPU *cpu = RISCV_CPU(cs); > - if (cs->cpu_index == 0) { > - ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_RUNNABLE); > - } else { > - ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_STOPPED); > - } > + if (level >= KVM_PUT_RESET_STATE) { > + ret = kvm_riscv_sync_mpstate_to_kvm(cs); > if (ret) { > return ret; > } > diff --git a/target/riscv/kvm/kvm_riscv.h b/target/riscv/kvm/kvm_riscv.h > index b2bcd1041f..953db94160 100644 > --- a/target/riscv/kvm/kvm_riscv.h > +++ b/target/riscv/kvm/kvm_riscv.h > @@ -28,7 +28,8 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t > group_shift, > uint64_t aplic_base, uint64_t imsic_base, > uint64_t guest_num); > void riscv_kvm_aplic_request(void *opaque, int irq, int level); > -int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state); > +int kvm_riscv_sync_mpstate_to_kvm(CPUState *cs); > +int kvm_riscv_sync_mpstate_to_qemu(CPUState *cs); > void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp); > uint64_t kvm_riscv_get_timebase_frequency(RISCVCPU *cpu); > > diff --git a/target/riscv/machine.c b/target/riscv/machine.c > index 889e2b6570..8562a0a1d6 100644 > --- a/target/riscv/machine.c > +++ b/target/riscv/machine.c > @@ -401,8 +401,8 @@ static const VMStateDescription vmstate_ssp = { > > const VMStateDescription vmstate_riscv_cpu = { > .name = "cpu", > - .version_id = 10, > - .minimum_version_id = 10, > + .version_id = 11, > + .minimum_version_id = 11, > .post_load = riscv_cpu_post_load, > .fields = (const VMStateField[]) { > VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), > @@ -422,6 +422,7 @@ const VMStateDescription vmstate_riscv_cpu = { > VMSTATE_UNUSED(4), > VMSTATE_UINT32(env.misa_ext_mask, RISCVCPU), > VMSTATE_UINTTL(env.priv, RISCVCPU), > + VMSTATE_UINT32(env.mp_state, RISCVCPU), > VMSTATE_BOOL(env.virt_enabled, RISCVCPU), > VMSTATE_UINT64(env.resetvec, RISCVCPU), > VMSTATE_UINTTL(env.mhartid, RISCVCPU), > -- > 2.43.0 >
Reviewed-by: Andrew Jones <ajo...@ventanamicro.com>