target/riscv/cpu.h | 1 +
target/riscv/kvm/kvm-cpu.c | 40 +++++++++++++++++++++++-------------
target/riscv/kvm/kvm_riscv.h | 1 +
target/riscv/machine.c | 31 ++++++++++++++++++++++++++++
4 files changed, 59 insertions(+), 14 deletions(-)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index a5ec69c3cc..193f81f00d 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -541,6 +541,7 @@ struct CPUArchState {
uint64_t kvm_timer_compare;
uint64_t kvm_timer_state;
uint64_t kvm_timer_frequency;
+ bool kvm_timer_frequency_loaded;
/* KVM multiprocessor state */
uint32_t kvm_mp_state;
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index c8ccd9124e..1993bd446b 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -45,7 +45,6 @@
#include "kvm_riscv.h"
#include "sbi_ecall_interface.h"
#include "chardev/char-fe.h"
-#include "migration/misc.h"
#include "system/runstate.h"
#include "hw/riscv/numa.h"
@@ -822,9 +821,34 @@ static void kvm_riscv_get_regs_timer(CPUState *cs)
env->kvm_timer_dirty = true;
}
+int kvm_riscv_check_timer_frequency(RISCVCPU *cpu)
+{
+ CPUState *cs = CPU(cpu);
+ CPURISCVState *env = &cpu->env;
+ int ret;
+ uint64_t frequency;
+
+ if (!env->kvm_timer_frequency_loaded) {
+ return 0;
+ }
+
+ ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(frequency), &frequency);
+ if (ret) {
+ return ret;
+ }
+
+ if (frequency != env->kvm_timer_frequency) {
+ error_report("KVM timer frequency mismatch: source %" PRIu64
+ " Hz, destination %" PRIu64 " Hz",
+ env->kvm_timer_frequency, frequency);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static void kvm_riscv_put_regs_timer(CPUState *cs)
{
- uint64_t reg;
CPURISCVState *env = &RISCV_CPU(cs)->env;
if (!env->kvm_timer_dirty) {
@@ -844,18 +868,6 @@ static void kvm_riscv_put_regs_timer(CPUState *cs)
KVM_RISCV_SET_TIMER(cs, state, env->kvm_timer_state);
}
- /*
- * For now, migration will not work between Hosts with different timer
- * frequency. Therefore, we should check whether they are the same here
- * during the migration.
- */
- if (migration_is_running()) {
- KVM_RISCV_GET_TIMER(cs, frequency, reg);
- if (reg != env->kvm_timer_frequency) {
- error_report("Dst Hosts timer frequency != Src Hosts");
- }
- }
-
env->kvm_timer_dirty = false;
}
diff --git a/target/riscv/kvm/kvm_riscv.h b/target/riscv/kvm/kvm_riscv.h
index 61eaa12443..0e27ce8bf3 100644
--- a/target/riscv/kvm/kvm_riscv.h
+++ b/target/riscv/kvm/kvm_riscv.h
@@ -29,6 +29,7 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t
group_shift,
uint64_t guest_num);
void riscv_kvm_aplic_request(void *opaque, int irq, int level);
bool kvm_riscv_has_mp_state(void);
+int kvm_riscv_check_timer_frequency(RISCVCPU *cpu);
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 2685338901..14a50f1d33 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -198,6 +198,35 @@ static const VMStateDescription vmstate_rv128 = {
};
#ifdef CONFIG_KVM
+static bool kvm_timer_frequency_needed(void *opaque)
+{
+ return kvm_enabled();
+}
+
+static int kvm_timer_frequency_post_load(void *opaque, int version_id)
+{
+ RISCVCPU *cpu = opaque;
+
+ if (!kvm_enabled()) {
+ return -ENOTSUP;
+ }
+
+ cpu->env.kvm_timer_frequency_loaded = true;
+ return kvm_riscv_check_timer_frequency(cpu);
+}
+
+static const VMStateDescription vmstate_kvm_timer_frequency = {
+ .name = "cpu/kvm-timer-frequency",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = kvm_timer_frequency_needed,
+ .post_load = kvm_timer_frequency_post_load,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT64(env.kvm_timer_frequency, RISCVCPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static bool kvm_fcsr_needed(void *opaque)
{
RISCVCPU *cpu = opaque;
@@ -256,6 +285,7 @@ static int riscv_cpu_kvm_pre_load(void *opaque)
{
RISCVCPU *cpu = opaque;
+ cpu->env.kvm_timer_frequency_loaded = false;
cpu->env.kvm_mp_state_loaded = false;
return 0;
}
@@ -592,6 +622,7 @@ const VMStateDescription vmstate_riscv_cpu = {
&vmstate_rv128,
#ifdef CONFIG_KVM
&vmstate_kvm_fcsr,
+ &vmstate_kvm_timer_frequency,
&vmstate_kvmtimer,
&vmstate_kvm_mp_state,
#endif