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 <[email protected]> --- 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 5c19062c19..1fa755bd96 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -594,6 +594,12 @@ static int kvm_riscv_get_regs_core(CPUState *cs) } env->pc = reg; + ret = kvm_get_one_reg(cs, RISCV_CORE_REG(mode), ®); + if (ret) { + return ret; + } + env->priv = reg; + for (i = 1; i < 32; i++) { uint64_t id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, i); ret = kvm_get_one_reg(cs, id, ®); @@ -619,6 +625,12 @@ static int kvm_riscv_put_regs_core(CPUState *cs) return ret; } + reg = env->priv; + ret = kvm_set_one_reg(cs, RISCV_CORE_REG(mode), ®); + if (ret) { + return ret; + } + for (i = 1; i < 32; i++) { uint64_t id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, i); reg = env->gpr[i]; @@ -1348,25 +1360,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) @@ -1393,13 +1432,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 51e0567ed3..6e5be17c27 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -426,8 +426,8 @@ static const VMStateDescription vmstate_sstc = { 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), @@ -447,6 +447,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
