Add kvm_riscv_get/put_regs_timer to synchronize virtual time context from KVM. The frequency of virtual time is not supported by KVM_SET_ONE_REG, So it's useless to synchronize the frequency of virtual time.
To set register of RISCV_TIMER_REG(state) will occur a error from KVM on kvm_timer_state == 0. It's better to adapt in KVM, but it doesn't matter that adaping in QEMU.
Signed-off-by: Yifei Jiang jiangyifei@huawei.com Signed-off-by: Yipeng Yin yinyipeng1@huawei.com --- target/riscv/cpu.h | 6 ++++ target/riscv/kvm.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index a7042e122e..d3e10ea92f 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -211,6 +211,12 @@ struct CPURISCVState {
hwaddr loader_start; hwaddr fdt_start; + + /* kvm timer */ + bool kvm_timer_dirty; + uint64_t kvm_timer_time; + uint64_t kvm_timer_compare; + uint64_t kvm_timer_state; };
#define RISCV_CPU_CLASS(klass) \ diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c index d0d02aad5c..7466787d79 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -59,6 +59,9 @@ static __u64 kvm_riscv_reg_id(__u64 type, __u64 idx) #define RISCV_CSR_REG(name) kvm_riscv_reg_id(KVM_REG_RISCV_CSR, \ KVM_REG_RISCV_CSR_REG(name))
+#define RISCV_TIMER_REG(name) kvm_riscv_reg_id(KVM_REG_RISCV_TIMER, \ + KVM_REG_RISCV_TIMER_REG(name)) + #define RISCV_FP_F_REG(idx) kvm_riscv_reg_id(KVM_REG_RISCV_FP_F, idx)
#define RISCV_FP_D_REG(idx) kvm_riscv_reg_id(KVM_REG_RISCV_FP_D, idx) @@ -294,6 +297,75 @@ static int kvm_riscv_put_regs_fp(CPUState *cs) return ret; }
+static void kvm_riscv_get_regs_timer(CPUState *cs) +{ + int ret; + uint64_t reg; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + if (env->kvm_timer_dirty) { + return; + } + + ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(time), ®); + if (ret) { + abort(); + } + env->kvm_timer_time = reg; + + ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(compare), ®); + if (ret) { + abort(); + } + env->kvm_timer_compare = reg; + + ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(state), ®); + if (ret) { + abort(); + } + env->kvm_timer_state = reg; + + env->kvm_timer_dirty = true; +} + +static void kvm_riscv_put_regs_timer(CPUState *cs) +{ + int ret; + uint64_t reg; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + if (!env->kvm_timer_dirty) { + return; + } + + reg = env->kvm_timer_time; + ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(time), ®); + if (ret) { + abort(); + } + + reg = env->kvm_timer_compare; + ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(compare), ®); + if (ret) { + abort(); + } + + /* + * To set register of RISCV_TIMER_REG(state) will occur a error from KVM + * on env->kvm_timer_state == 0, It's better to adapt in KVM, but it + * doesn't matter that adaping in QEMU now. + * TODO If KVM changes, adapt here. + */ + if (env->kvm_timer_state) { + reg = env->kvm_timer_state; + ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(state), ®); + if (ret) { + abort(); + } + } + + env->kvm_timer_dirty = false; +}
const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO