On Wed, 2026-09-30 at 17:39 +0800, Wang Yechao wrote:
> 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]>
Thanks!
Applied to riscv-to-apply.next
Alistair
> ---
> 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;
> }
>