kvm_riscv_get_regs_fp() and kvm_riscv_put_regs_fp() handle f0-f31
but not FCSR. KVM exposes FCSR as a separate 32-bit register in both
the F and D register groups, so frm and fflags are lost after migration.
Read and write FCSR together with the FP registers and save it in a
KVM-only subsection. Older streams do not contain the subsection; in
that case the destination keeps its reset value.
Fixes: 937f0b45120b ("target/riscv: Implement kvm_arch_get_registers")
Fixes: 9997cc1e19d1 ("target/riscv: Implement kvm_arch_put_registers")
Signed-off-by: Xie Bo <[email protected]>
Cc: [email protected]
---
target/riscv/cpu.h | 3 +++
target/riscv/kvm/kvm-cpu.c | 20 ++++++++++++++++----
target/riscv/machine.c | 27 +++++++++++++++++++++++++++
3 files changed, 46 insertions(+), 4 deletions(-)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 718b66487a..a5ec69c3cc 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -532,6 +532,9 @@ struct CPUArchState {
hwaddr fdt_addr;
#ifdef CONFIG_KVM
+ /* KVM floating-point state */
+ uint32_t kvm_fcsr;
+
/* kvm timer */
bool kvm_timer_dirty;
uint64_t kvm_timer_time;
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 68e1501b21..c8ccd9124e 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -111,6 +111,14 @@ static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu,
#define RISCV_FP_D_REG(idx) KVM_RISCV_REG_ID_U64(KVM_REG_RISCV_FP_D, idx)
+#define RISCV_FP_F_FCSR_REG \
+ KVM_RISCV_REG_ID_U32(KVM_REG_RISCV_FP_F, \
+ KVM_REG_RISCV_FP_F_REG(fcsr))
+
+#define RISCV_FP_D_FCSR_REG \
+ KVM_RISCV_REG_ID_U32(KVM_REG_RISCV_FP_D, \
+ KVM_REG_RISCV_FP_D_REG(fcsr))
+
#define RISCV_VECTOR_CSR_REG(name) \
KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_VECTOR, \
KVM_REG_RISCV_VECTOR_CSR_REG(name))
@@ -743,7 +751,8 @@ static int kvm_riscv_get_regs_fp(CPUState *cs)
}
env->fpr[i] = reg;
}
- return ret;
+ return kvm_get_one_reg(cs, RISCV_FP_D_FCSR_REG,
+ &env->kvm_fcsr);
}
if (riscv_has_ext(env, RVF)) {
@@ -755,7 +764,8 @@ static int kvm_riscv_get_regs_fp(CPUState *cs)
}
env->fpr[i] = reg;
}
- return ret;
+ return kvm_get_one_reg(cs, RISCV_FP_F_FCSR_REG,
+ &env->kvm_fcsr);
}
return ret;
@@ -776,7 +786,8 @@ static int kvm_riscv_put_regs_fp(CPUState *cs)
return ret;
}
}
- return ret;
+ return kvm_set_one_reg(cs, RISCV_FP_D_FCSR_REG,
+ &env->kvm_fcsr);
}
if (riscv_has_ext(env, RVF)) {
@@ -788,7 +799,8 @@ static int kvm_riscv_put_regs_fp(CPUState *cs)
return ret;
}
}
- return ret;
+ return kvm_set_one_reg(cs, RISCV_FP_F_FCSR_REG,
+ &env->kvm_fcsr);
}
return ret;
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 31c49ca3e6..2685338901 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -198,6 +198,32 @@ static const VMStateDescription vmstate_rv128 = {
};
#ifdef CONFIG_KVM
+static bool kvm_fcsr_needed(void *opaque)
+{
+ RISCVCPU *cpu = opaque;
+ CPURISCVState *env = &cpu->env;
+
+ return kvm_enabled() &&
+ (riscv_has_ext(env, RVF) || riscv_has_ext(env, RVD));
+}
+
+static int kvm_fcsr_post_load(void *opaque, int version_id)
+{
+ return kvm_enabled() ? 0 : -ENOTSUP;
+}
+
+static const VMStateDescription vmstate_kvm_fcsr = {
+ .name = "cpu/kvm-fcsr",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = kvm_fcsr_needed,
+ .post_load = kvm_fcsr_post_load,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(env.kvm_fcsr, RISCVCPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static bool kvmtimer_needed(void *opaque)
{
return kvm_enabled();
@@ -565,6 +591,7 @@ const VMStateDescription vmstate_riscv_cpu = {
&vmstate_pointermasking,
&vmstate_rv128,
#ifdef CONFIG_KVM
+ &vmstate_kvm_fcsr,
&vmstate_kvmtimer,
&vmstate_kvm_mp_state,
#endif
--
2.17.1