When a VM reset is requested, KVM needs to reset the register state of the vCPUs. Without this, stale KVM-internal vCPU state (such as the SBI STA shared memory address) is preserved across the reset, which can cause KVM to keep writing steal-time data to an address that now belongs to firmware code, corrupting it.
Add support for the KVM_CAP_RISCV_MP_STATE_RESET capability. When enabled, QEMU resets the vCPU by setting MP_STATE_INIT_RECEIVED through the KVM_SET_MP_STATE ioctl during the KVM_PUT_RESET_STATE phase of kvm_arch_put_registers(). KVM performs the register reset while preserving the original MP_STATE, so no state restoration is needed on the QEMU side. This reset path is reached both when the guest initiates an SBI system reset and when userspace (e.g. the QEMU monitor) requests a VM reset, covering both reboot scenarios. The capability is optional and only activated if the host kernel advertises KVM_CAP_RISCV_MP_STATE_RESET, ensuring backward compatibility with older kernels. Signed-off-by: Wang Yechao <[email protected]> --- target/riscv/kvm/kvm-cpu.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 68e1501b21..30cea19dea 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -58,6 +58,7 @@ void riscv_kvm_aplic_request(void *opaque, int irq, int level) } static bool cap_has_mp_state; +static bool mp_state_reset; #define KVM_RISCV_REG_ID_U32(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U32 | \ type | idx) @@ -1405,10 +1406,31 @@ static int kvm_riscv_put_mp_state(CPUState *cs) return kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state); } +static int kvm_riscv_mp_state_init_received(CPUState *cs) +{ + struct kvm_mp_state mp_state = { + .mp_state = KVM_MP_STATE_INIT_RECEIVED, + }; + + if (!cap_has_mp_state || !mp_state_reset) { + return 0; + } + + /* Let KVM resets the VCPU, The original MP_STATE is preserved*/ + return kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state); +} + int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp) { int ret = 0; + if (KVM_PUT_RESET_STATE == level) { + ret = kvm_riscv_mp_state_init_received(cs); + if (ret) { + return ret; + } + } + ret = kvm_riscv_put_regs_core(cs); if (ret) { return ret; @@ -1585,6 +1607,11 @@ int kvm_arch_get_default_type(MachineState *ms) int kvm_arch_init(MachineState *ms, KVMState *s) { cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE); + + if (cap_has_mp_state) { + mp_state_reset = !kvm_vm_enable_cap(s, KVM_CAP_RISCV_MP_STATE_RESET, 0); + } + return 0; } -- 2.27.0
