xref: /qemu/target/riscv/kvm/kvm-cpu.c (revision df817297d7a5397a3383207b0e0174b464cf42ab)
191654e61SYifei Jiang /*
291654e61SYifei Jiang  * RISC-V implementation of KVM hooks
391654e61SYifei Jiang  *
491654e61SYifei Jiang  * Copyright (c) 2020 Huawei Technologies Co., Ltd
591654e61SYifei Jiang  *
691654e61SYifei Jiang  * This program is free software; you can redistribute it and/or modify it
791654e61SYifei Jiang  * under the terms and conditions of the GNU General Public License,
891654e61SYifei Jiang  * version 2 or later, as published by the Free Software Foundation.
991654e61SYifei Jiang  *
1091654e61SYifei Jiang  * This program is distributed in the hope it will be useful, but WITHOUT
1191654e61SYifei Jiang  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1291654e61SYifei Jiang  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
1391654e61SYifei Jiang  * more details.
1491654e61SYifei Jiang  *
1591654e61SYifei Jiang  * You should have received a copy of the GNU General Public License along with
1691654e61SYifei Jiang  * this program.  If not, see <http://www.gnu.org/licenses/>.
1791654e61SYifei Jiang  */
1891654e61SYifei Jiang 
1991654e61SYifei Jiang #include "qemu/osdep.h"
2091654e61SYifei Jiang #include <sys/ioctl.h>
2191654e61SYifei Jiang 
2291654e61SYifei Jiang #include <linux/kvm.h>
2391654e61SYifei Jiang 
2491654e61SYifei Jiang #include "qemu/timer.h"
2592becce5SDaniel Henrique Barboza #include "qapi/error.h"
2691654e61SYifei Jiang #include "qemu/error-report.h"
2791654e61SYifei Jiang #include "qemu/main-loop.h"
2892becce5SDaniel Henrique Barboza #include "qapi/visitor.h"
2991654e61SYifei Jiang #include "sysemu/sysemu.h"
3091654e61SYifei Jiang #include "sysemu/kvm.h"
3191654e61SYifei Jiang #include "sysemu/kvm_int.h"
3291654e61SYifei Jiang #include "cpu.h"
3391654e61SYifei Jiang #include "trace.h"
3491654e61SYifei Jiang #include "hw/pci/pci.h"
3591654e61SYifei Jiang #include "exec/memattrs.h"
3691654e61SYifei Jiang #include "exec/address-spaces.h"
3791654e61SYifei Jiang #include "hw/boards.h"
3891654e61SYifei Jiang #include "hw/irq.h"
3991654e61SYifei Jiang #include "qemu/log.h"
4091654e61SYifei Jiang #include "hw/loader.h"
41ad40be27SYifei Jiang #include "kvm_riscv.h"
424eb47125SYifei Jiang #include "sbi_ecall_interface.h"
434eb47125SYifei Jiang #include "chardev/char-fe.h"
4427abe66fSYifei Jiang #include "migration/migration.h"
459ad3e016SYifei Jiang #include "sysemu/runstate.h"
4691654e61SYifei Jiang 
470a312b85SYifei Jiang static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type,
480a312b85SYifei Jiang                                  uint64_t idx)
490a312b85SYifei Jiang {
500a312b85SYifei Jiang     uint64_t id = KVM_REG_RISCV | type | idx;
510a312b85SYifei Jiang 
520a312b85SYifei Jiang     switch (riscv_cpu_mxl(env)) {
530a312b85SYifei Jiang     case MXL_RV32:
540a312b85SYifei Jiang         id |= KVM_REG_SIZE_U32;
550a312b85SYifei Jiang         break;
560a312b85SYifei Jiang     case MXL_RV64:
570a312b85SYifei Jiang         id |= KVM_REG_SIZE_U64;
580a312b85SYifei Jiang         break;
590a312b85SYifei Jiang     default:
600a312b85SYifei Jiang         g_assert_not_reached();
610a312b85SYifei Jiang     }
620a312b85SYifei Jiang     return id;
630a312b85SYifei Jiang }
640a312b85SYifei Jiang 
65937f0b45SYifei Jiang #define RISCV_CORE_REG(env, name)  kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, \
66937f0b45SYifei Jiang                  KVM_REG_RISCV_CORE_REG(name))
67937f0b45SYifei Jiang 
68937f0b45SYifei Jiang #define RISCV_CSR_REG(env, name)  kvm_riscv_reg_id(env, KVM_REG_RISCV_CSR, \
69937f0b45SYifei Jiang                  KVM_REG_RISCV_CSR_REG(name))
70937f0b45SYifei Jiang 
7127abe66fSYifei Jiang #define RISCV_TIMER_REG(env, name)  kvm_riscv_reg_id(env, KVM_REG_RISCV_TIMER, \
7227abe66fSYifei Jiang                  KVM_REG_RISCV_TIMER_REG(name))
7327abe66fSYifei Jiang 
74937f0b45SYifei Jiang #define RISCV_FP_F_REG(env, idx)  kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_F, idx)
75937f0b45SYifei Jiang 
76937f0b45SYifei Jiang #define RISCV_FP_D_REG(env, idx)  kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_D, idx)
77937f0b45SYifei Jiang 
78937f0b45SYifei Jiang #define KVM_RISCV_GET_CSR(cs, env, csr, reg) \
79937f0b45SYifei Jiang     do { \
80937f0b45SYifei Jiang         int ret = kvm_get_one_reg(cs, RISCV_CSR_REG(env, csr), &reg); \
81937f0b45SYifei Jiang         if (ret) { \
82937f0b45SYifei Jiang             return ret; \
83937f0b45SYifei Jiang         } \
84937f0b45SYifei Jiang     } while (0)
85937f0b45SYifei Jiang 
869997cc1eSYifei Jiang #define KVM_RISCV_SET_CSR(cs, env, csr, reg) \
879997cc1eSYifei Jiang     do { \
889997cc1eSYifei Jiang         int ret = kvm_set_one_reg(cs, RISCV_CSR_REG(env, csr), &reg); \
899997cc1eSYifei Jiang         if (ret) { \
909997cc1eSYifei Jiang             return ret; \
919997cc1eSYifei Jiang         } \
929997cc1eSYifei Jiang     } while (0)
939997cc1eSYifei Jiang 
9427abe66fSYifei Jiang #define KVM_RISCV_GET_TIMER(cs, env, name, reg) \
9527abe66fSYifei Jiang     do { \
9627abe66fSYifei Jiang         int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(env, name), &reg); \
9727abe66fSYifei Jiang         if (ret) { \
9827abe66fSYifei Jiang             abort(); \
9927abe66fSYifei Jiang         } \
10027abe66fSYifei Jiang     } while (0)
10127abe66fSYifei Jiang 
10227abe66fSYifei Jiang #define KVM_RISCV_SET_TIMER(cs, env, name, reg) \
10327abe66fSYifei Jiang     do { \
104c5cc248bSyang.zhang         int ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(env, name), &reg); \
10527abe66fSYifei Jiang         if (ret) { \
10627abe66fSYifei Jiang             abort(); \
10727abe66fSYifei Jiang         } \
10827abe66fSYifei Jiang     } while (0)
10927abe66fSYifei Jiang 
11092becce5SDaniel Henrique Barboza typedef struct KVMCPUConfig {
11192becce5SDaniel Henrique Barboza     const char *name;
11292becce5SDaniel Henrique Barboza     const char *description;
11392becce5SDaniel Henrique Barboza     target_ulong offset;
11492becce5SDaniel Henrique Barboza     int kvm_reg_id;
11592becce5SDaniel Henrique Barboza     bool user_set;
116f7a69fa6SDaniel Henrique Barboza     bool supported;
11792becce5SDaniel Henrique Barboza } KVMCPUConfig;
11892becce5SDaniel Henrique Barboza 
11992becce5SDaniel Henrique Barboza #define KVM_MISA_CFG(_bit, _reg_id) \
12092becce5SDaniel Henrique Barboza     {.offset = _bit, .kvm_reg_id = _reg_id}
12192becce5SDaniel Henrique Barboza 
12292becce5SDaniel Henrique Barboza /* KVM ISA extensions */
12392becce5SDaniel Henrique Barboza static KVMCPUConfig kvm_misa_ext_cfgs[] = {
12492becce5SDaniel Henrique Barboza     KVM_MISA_CFG(RVA, KVM_RISCV_ISA_EXT_A),
12592becce5SDaniel Henrique Barboza     KVM_MISA_CFG(RVC, KVM_RISCV_ISA_EXT_C),
12692becce5SDaniel Henrique Barboza     KVM_MISA_CFG(RVD, KVM_RISCV_ISA_EXT_D),
12792becce5SDaniel Henrique Barboza     KVM_MISA_CFG(RVF, KVM_RISCV_ISA_EXT_F),
12892becce5SDaniel Henrique Barboza     KVM_MISA_CFG(RVH, KVM_RISCV_ISA_EXT_H),
12992becce5SDaniel Henrique Barboza     KVM_MISA_CFG(RVI, KVM_RISCV_ISA_EXT_I),
13092becce5SDaniel Henrique Barboza     KVM_MISA_CFG(RVM, KVM_RISCV_ISA_EXT_M),
13192becce5SDaniel Henrique Barboza };
13292becce5SDaniel Henrique Barboza 
13392becce5SDaniel Henrique Barboza static void kvm_cpu_set_misa_ext_cfg(Object *obj, Visitor *v,
13492becce5SDaniel Henrique Barboza                                      const char *name,
13592becce5SDaniel Henrique Barboza                                      void *opaque, Error **errp)
13692becce5SDaniel Henrique Barboza {
13792becce5SDaniel Henrique Barboza     KVMCPUConfig *misa_ext_cfg = opaque;
13892becce5SDaniel Henrique Barboza     target_ulong misa_bit = misa_ext_cfg->offset;
13992becce5SDaniel Henrique Barboza     RISCVCPU *cpu = RISCV_CPU(obj);
14092becce5SDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
14192becce5SDaniel Henrique Barboza     bool value, host_bit;
14292becce5SDaniel Henrique Barboza 
14392becce5SDaniel Henrique Barboza     if (!visit_type_bool(v, name, &value, errp)) {
14492becce5SDaniel Henrique Barboza         return;
14592becce5SDaniel Henrique Barboza     }
14692becce5SDaniel Henrique Barboza 
14792becce5SDaniel Henrique Barboza     host_bit = env->misa_ext_mask & misa_bit;
14892becce5SDaniel Henrique Barboza 
14992becce5SDaniel Henrique Barboza     if (value == host_bit) {
15092becce5SDaniel Henrique Barboza         return;
15192becce5SDaniel Henrique Barboza     }
15292becce5SDaniel Henrique Barboza 
15392becce5SDaniel Henrique Barboza     if (!value) {
15492becce5SDaniel Henrique Barboza         misa_ext_cfg->user_set = true;
15592becce5SDaniel Henrique Barboza         return;
15692becce5SDaniel Henrique Barboza     }
15792becce5SDaniel Henrique Barboza 
15892becce5SDaniel Henrique Barboza     /*
15992becce5SDaniel Henrique Barboza      * Forbid users to enable extensions that aren't
16092becce5SDaniel Henrique Barboza      * available in the hart.
16192becce5SDaniel Henrique Barboza      */
16292becce5SDaniel Henrique Barboza     error_setg(errp, "Enabling MISA bit '%s' is not allowed: it's not "
16392becce5SDaniel Henrique Barboza                "enabled in the host", misa_ext_cfg->name);
16492becce5SDaniel Henrique Barboza }
16592becce5SDaniel Henrique Barboza 
1667313fffbSDaniel Henrique Barboza static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs)
1677313fffbSDaniel Henrique Barboza {
1687313fffbSDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
1697313fffbSDaniel Henrique Barboza     uint64_t id, reg;
1707313fffbSDaniel Henrique Barboza     int i, ret;
1717313fffbSDaniel Henrique Barboza 
1727313fffbSDaniel Henrique Barboza     for (i = 0; i < ARRAY_SIZE(kvm_misa_ext_cfgs); i++) {
1737313fffbSDaniel Henrique Barboza         KVMCPUConfig *misa_cfg = &kvm_misa_ext_cfgs[i];
1747313fffbSDaniel Henrique Barboza         target_ulong misa_bit = misa_cfg->offset;
1757313fffbSDaniel Henrique Barboza 
1767313fffbSDaniel Henrique Barboza         if (!misa_cfg->user_set) {
1777313fffbSDaniel Henrique Barboza             continue;
1787313fffbSDaniel Henrique Barboza         }
1797313fffbSDaniel Henrique Barboza 
1807313fffbSDaniel Henrique Barboza         /* If we're here we're going to disable the MISA bit */
1817313fffbSDaniel Henrique Barboza         reg = 0;
1827313fffbSDaniel Henrique Barboza         id = kvm_riscv_reg_id(env, KVM_REG_RISCV_ISA_EXT,
1837313fffbSDaniel Henrique Barboza                               misa_cfg->kvm_reg_id);
1847313fffbSDaniel Henrique Barboza         ret = kvm_set_one_reg(cs, id, &reg);
1857313fffbSDaniel Henrique Barboza         if (ret != 0) {
1867313fffbSDaniel Henrique Barboza             /*
1877313fffbSDaniel Henrique Barboza              * We're not checking for -EINVAL because if the bit is about
1887313fffbSDaniel Henrique Barboza              * to be disabled, it means that it was already enabled by
1897313fffbSDaniel Henrique Barboza              * KVM. We determined that by fetching the 'isa' register
1907313fffbSDaniel Henrique Barboza              * during init() time. Any error at this point is worth
1917313fffbSDaniel Henrique Barboza              * aborting.
1927313fffbSDaniel Henrique Barboza              */
1937313fffbSDaniel Henrique Barboza             error_report("Unable to set KVM reg %s, error %d",
1947313fffbSDaniel Henrique Barboza                          misa_cfg->name, ret);
1957313fffbSDaniel Henrique Barboza             exit(EXIT_FAILURE);
1967313fffbSDaniel Henrique Barboza         }
1977313fffbSDaniel Henrique Barboza         env->misa_ext &= ~misa_bit;
1987313fffbSDaniel Henrique Barboza     }
1997313fffbSDaniel Henrique Barboza }
2007313fffbSDaniel Henrique Barboza 
201f7a69fa6SDaniel Henrique Barboza #define CPUCFG(_prop) offsetof(struct RISCVCPUConfig, _prop)
202f7a69fa6SDaniel Henrique Barboza 
203f7a69fa6SDaniel Henrique Barboza #define KVM_EXT_CFG(_name, _prop, _reg_id) \
204f7a69fa6SDaniel Henrique Barboza     {.name = _name, .offset = CPUCFG(_prop), \
205f7a69fa6SDaniel Henrique Barboza      .kvm_reg_id = _reg_id}
206f7a69fa6SDaniel Henrique Barboza 
207f7a69fa6SDaniel Henrique Barboza static KVMCPUConfig kvm_multi_ext_cfgs[] = {
208f7a69fa6SDaniel Henrique Barboza     KVM_EXT_CFG("zicbom", ext_icbom, KVM_RISCV_ISA_EXT_ZICBOM),
209f7a69fa6SDaniel Henrique Barboza     KVM_EXT_CFG("zicboz", ext_icboz, KVM_RISCV_ISA_EXT_ZICBOZ),
210f7a69fa6SDaniel Henrique Barboza     KVM_EXT_CFG("zihintpause", ext_zihintpause, KVM_RISCV_ISA_EXT_ZIHINTPAUSE),
211f7a69fa6SDaniel Henrique Barboza     KVM_EXT_CFG("zbb", ext_zbb, KVM_RISCV_ISA_EXT_ZBB),
212f7a69fa6SDaniel Henrique Barboza     KVM_EXT_CFG("ssaia", ext_ssaia, KVM_RISCV_ISA_EXT_SSAIA),
213f7a69fa6SDaniel Henrique Barboza     KVM_EXT_CFG("sstc", ext_sstc, KVM_RISCV_ISA_EXT_SSTC),
214f7a69fa6SDaniel Henrique Barboza     KVM_EXT_CFG("svinval", ext_svinval, KVM_RISCV_ISA_EXT_SVINVAL),
215f7a69fa6SDaniel Henrique Barboza     KVM_EXT_CFG("svpbmt", ext_svpbmt, KVM_RISCV_ISA_EXT_SVPBMT),
216f7a69fa6SDaniel Henrique Barboza };
217f7a69fa6SDaniel Henrique Barboza 
218f7a69fa6SDaniel Henrique Barboza static void kvm_cpu_cfg_set(RISCVCPU *cpu, KVMCPUConfig *multi_ext,
219f7a69fa6SDaniel Henrique Barboza                             uint32_t val)
220f7a69fa6SDaniel Henrique Barboza {
221f7a69fa6SDaniel Henrique Barboza     int cpu_cfg_offset = multi_ext->offset;
222f7a69fa6SDaniel Henrique Barboza     bool *ext_enabled = (void *)&cpu->cfg + cpu_cfg_offset;
223f7a69fa6SDaniel Henrique Barboza 
224f7a69fa6SDaniel Henrique Barboza     *ext_enabled = val;
225f7a69fa6SDaniel Henrique Barboza }
226f7a69fa6SDaniel Henrique Barboza 
227f7a69fa6SDaniel Henrique Barboza static uint32_t kvm_cpu_cfg_get(RISCVCPU *cpu,
228f7a69fa6SDaniel Henrique Barboza                                 KVMCPUConfig *multi_ext)
229f7a69fa6SDaniel Henrique Barboza {
230f7a69fa6SDaniel Henrique Barboza     int cpu_cfg_offset = multi_ext->offset;
231f7a69fa6SDaniel Henrique Barboza     bool *ext_enabled = (void *)&cpu->cfg + cpu_cfg_offset;
232f7a69fa6SDaniel Henrique Barboza 
233f7a69fa6SDaniel Henrique Barboza     return *ext_enabled;
234f7a69fa6SDaniel Henrique Barboza }
235f7a69fa6SDaniel Henrique Barboza 
236f7a69fa6SDaniel Henrique Barboza static void kvm_cpu_set_multi_ext_cfg(Object *obj, Visitor *v,
237f7a69fa6SDaniel Henrique Barboza                                       const char *name,
238f7a69fa6SDaniel Henrique Barboza                                       void *opaque, Error **errp)
239f7a69fa6SDaniel Henrique Barboza {
240f7a69fa6SDaniel Henrique Barboza     KVMCPUConfig *multi_ext_cfg = opaque;
241f7a69fa6SDaniel Henrique Barboza     RISCVCPU *cpu = RISCV_CPU(obj);
242f7a69fa6SDaniel Henrique Barboza     bool value, host_val;
243f7a69fa6SDaniel Henrique Barboza 
244f7a69fa6SDaniel Henrique Barboza     if (!visit_type_bool(v, name, &value, errp)) {
245f7a69fa6SDaniel Henrique Barboza         return;
246f7a69fa6SDaniel Henrique Barboza     }
247f7a69fa6SDaniel Henrique Barboza 
248f7a69fa6SDaniel Henrique Barboza     host_val = kvm_cpu_cfg_get(cpu, multi_ext_cfg);
249f7a69fa6SDaniel Henrique Barboza 
250f7a69fa6SDaniel Henrique Barboza     /*
251f7a69fa6SDaniel Henrique Barboza      * Ignore if the user is setting the same value
252f7a69fa6SDaniel Henrique Barboza      * as the host.
253f7a69fa6SDaniel Henrique Barboza      */
254f7a69fa6SDaniel Henrique Barboza     if (value == host_val) {
255f7a69fa6SDaniel Henrique Barboza         return;
256f7a69fa6SDaniel Henrique Barboza     }
257f7a69fa6SDaniel Henrique Barboza 
258f7a69fa6SDaniel Henrique Barboza     if (!multi_ext_cfg->supported) {
259f7a69fa6SDaniel Henrique Barboza         /*
260f7a69fa6SDaniel Henrique Barboza          * Error out if the user is trying to enable an
261f7a69fa6SDaniel Henrique Barboza          * extension that KVM doesn't support. Ignore
262f7a69fa6SDaniel Henrique Barboza          * option otherwise.
263f7a69fa6SDaniel Henrique Barboza          */
264f7a69fa6SDaniel Henrique Barboza         if (value) {
265f7a69fa6SDaniel Henrique Barboza             error_setg(errp, "KVM does not support disabling extension %s",
266f7a69fa6SDaniel Henrique Barboza                        multi_ext_cfg->name);
267f7a69fa6SDaniel Henrique Barboza         }
268f7a69fa6SDaniel Henrique Barboza 
269f7a69fa6SDaniel Henrique Barboza         return;
270f7a69fa6SDaniel Henrique Barboza     }
271f7a69fa6SDaniel Henrique Barboza 
272f7a69fa6SDaniel Henrique Barboza     multi_ext_cfg->user_set = true;
273f7a69fa6SDaniel Henrique Barboza     kvm_cpu_cfg_set(cpu, multi_ext_cfg, value);
274f7a69fa6SDaniel Henrique Barboza }
275f7a69fa6SDaniel Henrique Barboza 
276*df817297SDaniel Henrique Barboza static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs)
277*df817297SDaniel Henrique Barboza {
278*df817297SDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
279*df817297SDaniel Henrique Barboza     uint64_t id, reg;
280*df817297SDaniel Henrique Barboza     int i, ret;
281*df817297SDaniel Henrique Barboza 
282*df817297SDaniel Henrique Barboza     for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) {
283*df817297SDaniel Henrique Barboza         KVMCPUConfig *multi_ext_cfg = &kvm_multi_ext_cfgs[i];
284*df817297SDaniel Henrique Barboza 
285*df817297SDaniel Henrique Barboza         if (!multi_ext_cfg->user_set) {
286*df817297SDaniel Henrique Barboza             continue;
287*df817297SDaniel Henrique Barboza         }
288*df817297SDaniel Henrique Barboza 
289*df817297SDaniel Henrique Barboza         id = kvm_riscv_reg_id(env, KVM_REG_RISCV_ISA_EXT,
290*df817297SDaniel Henrique Barboza                               multi_ext_cfg->kvm_reg_id);
291*df817297SDaniel Henrique Barboza         reg = kvm_cpu_cfg_get(cpu, multi_ext_cfg);
292*df817297SDaniel Henrique Barboza         ret = kvm_set_one_reg(cs, id, &reg);
293*df817297SDaniel Henrique Barboza         if (ret != 0) {
294*df817297SDaniel Henrique Barboza             error_report("Unable to %s extension %s in KVM, error %d",
295*df817297SDaniel Henrique Barboza                          reg ? "enable" : "disable",
296*df817297SDaniel Henrique Barboza                          multi_ext_cfg->name, ret);
297*df817297SDaniel Henrique Barboza             exit(EXIT_FAILURE);
298*df817297SDaniel Henrique Barboza         }
299*df817297SDaniel Henrique Barboza     }
300*df817297SDaniel Henrique Barboza }
301*df817297SDaniel Henrique Barboza 
30292becce5SDaniel Henrique Barboza static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj)
30392becce5SDaniel Henrique Barboza {
30492becce5SDaniel Henrique Barboza     int i;
30592becce5SDaniel Henrique Barboza 
30692becce5SDaniel Henrique Barboza     for (i = 0; i < ARRAY_SIZE(kvm_misa_ext_cfgs); i++) {
30792becce5SDaniel Henrique Barboza         KVMCPUConfig *misa_cfg = &kvm_misa_ext_cfgs[i];
30892becce5SDaniel Henrique Barboza         int bit = misa_cfg->offset;
30992becce5SDaniel Henrique Barboza 
31092becce5SDaniel Henrique Barboza         misa_cfg->name = riscv_get_misa_ext_name(bit);
31192becce5SDaniel Henrique Barboza         misa_cfg->description = riscv_get_misa_ext_description(bit);
31292becce5SDaniel Henrique Barboza 
31392becce5SDaniel Henrique Barboza         object_property_add(cpu_obj, misa_cfg->name, "bool",
31492becce5SDaniel Henrique Barboza                             NULL,
31592becce5SDaniel Henrique Barboza                             kvm_cpu_set_misa_ext_cfg,
31692becce5SDaniel Henrique Barboza                             NULL, misa_cfg);
31792becce5SDaniel Henrique Barboza         object_property_set_description(cpu_obj, misa_cfg->name,
31892becce5SDaniel Henrique Barboza                                         misa_cfg->description);
31992becce5SDaniel Henrique Barboza     }
320f7a69fa6SDaniel Henrique Barboza 
321f7a69fa6SDaniel Henrique Barboza     for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) {
322f7a69fa6SDaniel Henrique Barboza         KVMCPUConfig *multi_cfg = &kvm_multi_ext_cfgs[i];
323f7a69fa6SDaniel Henrique Barboza 
324f7a69fa6SDaniel Henrique Barboza         object_property_add(cpu_obj, multi_cfg->name, "bool",
325f7a69fa6SDaniel Henrique Barboza                             NULL,
326f7a69fa6SDaniel Henrique Barboza                             kvm_cpu_set_multi_ext_cfg,
327f7a69fa6SDaniel Henrique Barboza                             NULL, multi_cfg);
328f7a69fa6SDaniel Henrique Barboza     }
32992becce5SDaniel Henrique Barboza }
33092becce5SDaniel Henrique Barboza 
331937f0b45SYifei Jiang static int kvm_riscv_get_regs_core(CPUState *cs)
332937f0b45SYifei Jiang {
333937f0b45SYifei Jiang     int ret = 0;
334937f0b45SYifei Jiang     int i;
335937f0b45SYifei Jiang     target_ulong reg;
336937f0b45SYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
337937f0b45SYifei Jiang 
338937f0b45SYifei Jiang     ret = kvm_get_one_reg(cs, RISCV_CORE_REG(env, regs.pc), &reg);
339937f0b45SYifei Jiang     if (ret) {
340937f0b45SYifei Jiang         return ret;
341937f0b45SYifei Jiang     }
342937f0b45SYifei Jiang     env->pc = reg;
343937f0b45SYifei Jiang 
344937f0b45SYifei Jiang     for (i = 1; i < 32; i++) {
345937f0b45SYifei Jiang         uint64_t id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, i);
346937f0b45SYifei Jiang         ret = kvm_get_one_reg(cs, id, &reg);
347937f0b45SYifei Jiang         if (ret) {
348937f0b45SYifei Jiang             return ret;
349937f0b45SYifei Jiang         }
350937f0b45SYifei Jiang         env->gpr[i] = reg;
351937f0b45SYifei Jiang     }
352937f0b45SYifei Jiang 
353937f0b45SYifei Jiang     return ret;
354937f0b45SYifei Jiang }
355937f0b45SYifei Jiang 
3569997cc1eSYifei Jiang static int kvm_riscv_put_regs_core(CPUState *cs)
3579997cc1eSYifei Jiang {
3589997cc1eSYifei Jiang     int ret = 0;
3599997cc1eSYifei Jiang     int i;
3609997cc1eSYifei Jiang     target_ulong reg;
3619997cc1eSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
3629997cc1eSYifei Jiang 
3639997cc1eSYifei Jiang     reg = env->pc;
3649997cc1eSYifei Jiang     ret = kvm_set_one_reg(cs, RISCV_CORE_REG(env, regs.pc), &reg);
3659997cc1eSYifei Jiang     if (ret) {
3669997cc1eSYifei Jiang         return ret;
3679997cc1eSYifei Jiang     }
3689997cc1eSYifei Jiang 
3699997cc1eSYifei Jiang     for (i = 1; i < 32; i++) {
3709997cc1eSYifei Jiang         uint64_t id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, i);
3719997cc1eSYifei Jiang         reg = env->gpr[i];
3729997cc1eSYifei Jiang         ret = kvm_set_one_reg(cs, id, &reg);
3739997cc1eSYifei Jiang         if (ret) {
3749997cc1eSYifei Jiang             return ret;
3759997cc1eSYifei Jiang         }
3769997cc1eSYifei Jiang     }
3779997cc1eSYifei Jiang 
3789997cc1eSYifei Jiang     return ret;
3799997cc1eSYifei Jiang }
3809997cc1eSYifei Jiang 
381937f0b45SYifei Jiang static int kvm_riscv_get_regs_csr(CPUState *cs)
382937f0b45SYifei Jiang {
383937f0b45SYifei Jiang     int ret = 0;
384937f0b45SYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
385937f0b45SYifei Jiang 
386937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sstatus, env->mstatus);
387937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sie, env->mie);
388937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, stvec, env->stvec);
389937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sscratch, env->sscratch);
390937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sepc, env->sepc);
391937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, scause, env->scause);
392937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, stval, env->stval);
393937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sip, env->mip);
394937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, satp, env->satp);
395937f0b45SYifei Jiang     return ret;
396937f0b45SYifei Jiang }
397937f0b45SYifei Jiang 
3989997cc1eSYifei Jiang static int kvm_riscv_put_regs_csr(CPUState *cs)
3999997cc1eSYifei Jiang {
4009997cc1eSYifei Jiang     int ret = 0;
4019997cc1eSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
4029997cc1eSYifei Jiang 
4039997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sstatus, env->mstatus);
4049997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sie, env->mie);
4059997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, stvec, env->stvec);
4069997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sscratch, env->sscratch);
4079997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sepc, env->sepc);
4089997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, scause, env->scause);
4099997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, stval, env->stval);
4109997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sip, env->mip);
4119997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, satp, env->satp);
4129997cc1eSYifei Jiang 
4139997cc1eSYifei Jiang     return ret;
4149997cc1eSYifei Jiang }
4159997cc1eSYifei Jiang 
416937f0b45SYifei Jiang static int kvm_riscv_get_regs_fp(CPUState *cs)
417937f0b45SYifei Jiang {
418937f0b45SYifei Jiang     int ret = 0;
419937f0b45SYifei Jiang     int i;
420937f0b45SYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
421937f0b45SYifei Jiang 
422937f0b45SYifei Jiang     if (riscv_has_ext(env, RVD)) {
423937f0b45SYifei Jiang         uint64_t reg;
424937f0b45SYifei Jiang         for (i = 0; i < 32; i++) {
425937f0b45SYifei Jiang             ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(env, i), &reg);
426937f0b45SYifei Jiang             if (ret) {
427937f0b45SYifei Jiang                 return ret;
428937f0b45SYifei Jiang             }
429937f0b45SYifei Jiang             env->fpr[i] = reg;
430937f0b45SYifei Jiang         }
431937f0b45SYifei Jiang         return ret;
432937f0b45SYifei Jiang     }
433937f0b45SYifei Jiang 
434937f0b45SYifei Jiang     if (riscv_has_ext(env, RVF)) {
435937f0b45SYifei Jiang         uint32_t reg;
436937f0b45SYifei Jiang         for (i = 0; i < 32; i++) {
437937f0b45SYifei Jiang             ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(env, i), &reg);
438937f0b45SYifei Jiang             if (ret) {
439937f0b45SYifei Jiang                 return ret;
440937f0b45SYifei Jiang             }
441937f0b45SYifei Jiang             env->fpr[i] = reg;
442937f0b45SYifei Jiang         }
443937f0b45SYifei Jiang         return ret;
444937f0b45SYifei Jiang     }
445937f0b45SYifei Jiang 
446937f0b45SYifei Jiang     return ret;
447937f0b45SYifei Jiang }
448937f0b45SYifei Jiang 
4499997cc1eSYifei Jiang static int kvm_riscv_put_regs_fp(CPUState *cs)
4509997cc1eSYifei Jiang {
4519997cc1eSYifei Jiang     int ret = 0;
4529997cc1eSYifei Jiang     int i;
4539997cc1eSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
4549997cc1eSYifei Jiang 
4559997cc1eSYifei Jiang     if (riscv_has_ext(env, RVD)) {
4569997cc1eSYifei Jiang         uint64_t reg;
4579997cc1eSYifei Jiang         for (i = 0; i < 32; i++) {
4589997cc1eSYifei Jiang             reg = env->fpr[i];
4599997cc1eSYifei Jiang             ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(env, i), &reg);
4609997cc1eSYifei Jiang             if (ret) {
4619997cc1eSYifei Jiang                 return ret;
4629997cc1eSYifei Jiang             }
4639997cc1eSYifei Jiang         }
4649997cc1eSYifei Jiang         return ret;
4659997cc1eSYifei Jiang     }
4669997cc1eSYifei Jiang 
4679997cc1eSYifei Jiang     if (riscv_has_ext(env, RVF)) {
4689997cc1eSYifei Jiang         uint32_t reg;
4699997cc1eSYifei Jiang         for (i = 0; i < 32; i++) {
4709997cc1eSYifei Jiang             reg = env->fpr[i];
4719997cc1eSYifei Jiang             ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(env, i), &reg);
4729997cc1eSYifei Jiang             if (ret) {
4739997cc1eSYifei Jiang                 return ret;
4749997cc1eSYifei Jiang             }
4759997cc1eSYifei Jiang         }
4769997cc1eSYifei Jiang         return ret;
4779997cc1eSYifei Jiang     }
4789997cc1eSYifei Jiang 
4799997cc1eSYifei Jiang     return ret;
4809997cc1eSYifei Jiang }
4819997cc1eSYifei Jiang 
48227abe66fSYifei Jiang static void kvm_riscv_get_regs_timer(CPUState *cs)
48327abe66fSYifei Jiang {
48427abe66fSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
48527abe66fSYifei Jiang 
48627abe66fSYifei Jiang     if (env->kvm_timer_dirty) {
48727abe66fSYifei Jiang         return;
48827abe66fSYifei Jiang     }
48927abe66fSYifei Jiang 
49027abe66fSYifei Jiang     KVM_RISCV_GET_TIMER(cs, env, time, env->kvm_timer_time);
49127abe66fSYifei Jiang     KVM_RISCV_GET_TIMER(cs, env, compare, env->kvm_timer_compare);
49227abe66fSYifei Jiang     KVM_RISCV_GET_TIMER(cs, env, state, env->kvm_timer_state);
49327abe66fSYifei Jiang     KVM_RISCV_GET_TIMER(cs, env, frequency, env->kvm_timer_frequency);
49427abe66fSYifei Jiang 
49527abe66fSYifei Jiang     env->kvm_timer_dirty = true;
49627abe66fSYifei Jiang }
49727abe66fSYifei Jiang 
49827abe66fSYifei Jiang static void kvm_riscv_put_regs_timer(CPUState *cs)
49927abe66fSYifei Jiang {
50027abe66fSYifei Jiang     uint64_t reg;
50127abe66fSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
50227abe66fSYifei Jiang 
50327abe66fSYifei Jiang     if (!env->kvm_timer_dirty) {
50427abe66fSYifei Jiang         return;
50527abe66fSYifei Jiang     }
50627abe66fSYifei Jiang 
50727abe66fSYifei Jiang     KVM_RISCV_SET_TIMER(cs, env, time, env->kvm_timer_time);
50827abe66fSYifei Jiang     KVM_RISCV_SET_TIMER(cs, env, compare, env->kvm_timer_compare);
50927abe66fSYifei Jiang 
51027abe66fSYifei Jiang     /*
51127abe66fSYifei Jiang      * To set register of RISCV_TIMER_REG(state) will occur a error from KVM
51227abe66fSYifei Jiang      * on env->kvm_timer_state == 0, It's better to adapt in KVM, but it
51327abe66fSYifei Jiang      * doesn't matter that adaping in QEMU now.
51427abe66fSYifei Jiang      * TODO If KVM changes, adapt here.
51527abe66fSYifei Jiang      */
51627abe66fSYifei Jiang     if (env->kvm_timer_state) {
51727abe66fSYifei Jiang         KVM_RISCV_SET_TIMER(cs, env, state, env->kvm_timer_state);
51827abe66fSYifei Jiang     }
51927abe66fSYifei Jiang 
52027abe66fSYifei Jiang     /*
52127abe66fSYifei Jiang      * For now, migration will not work between Hosts with different timer
52227abe66fSYifei Jiang      * frequency. Therefore, we should check whether they are the same here
52327abe66fSYifei Jiang      * during the migration.
52427abe66fSYifei Jiang      */
52527abe66fSYifei Jiang     if (migration_is_running(migrate_get_current()->state)) {
52627abe66fSYifei Jiang         KVM_RISCV_GET_TIMER(cs, env, frequency, reg);
52727abe66fSYifei Jiang         if (reg != env->kvm_timer_frequency) {
52827abe66fSYifei Jiang             error_report("Dst Hosts timer frequency != Src Hosts");
52927abe66fSYifei Jiang         }
53027abe66fSYifei Jiang     }
53127abe66fSYifei Jiang 
53227abe66fSYifei Jiang     env->kvm_timer_dirty = false;
53327abe66fSYifei Jiang }
5349997cc1eSYifei Jiang 
535492265aeSDaniel Henrique Barboza typedef struct KVMScratchCPU {
536492265aeSDaniel Henrique Barboza     int kvmfd;
537492265aeSDaniel Henrique Barboza     int vmfd;
538492265aeSDaniel Henrique Barboza     int cpufd;
539492265aeSDaniel Henrique Barboza } KVMScratchCPU;
540492265aeSDaniel Henrique Barboza 
541492265aeSDaniel Henrique Barboza /*
542492265aeSDaniel Henrique Barboza  * Heavily inspired by kvm_arm_create_scratch_host_vcpu()
543492265aeSDaniel Henrique Barboza  * from target/arm/kvm.c.
544492265aeSDaniel Henrique Barboza  */
545492265aeSDaniel Henrique Barboza static bool kvm_riscv_create_scratch_vcpu(KVMScratchCPU *scratch)
546492265aeSDaniel Henrique Barboza {
547492265aeSDaniel Henrique Barboza     int kvmfd = -1, vmfd = -1, cpufd = -1;
548492265aeSDaniel Henrique Barboza 
549492265aeSDaniel Henrique Barboza     kvmfd = qemu_open_old("/dev/kvm", O_RDWR);
550492265aeSDaniel Henrique Barboza     if (kvmfd < 0) {
551492265aeSDaniel Henrique Barboza         goto err;
552492265aeSDaniel Henrique Barboza     }
553492265aeSDaniel Henrique Barboza     do {
554492265aeSDaniel Henrique Barboza         vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);
555492265aeSDaniel Henrique Barboza     } while (vmfd == -1 && errno == EINTR);
556492265aeSDaniel Henrique Barboza     if (vmfd < 0) {
557492265aeSDaniel Henrique Barboza         goto err;
558492265aeSDaniel Henrique Barboza     }
559492265aeSDaniel Henrique Barboza     cpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);
560492265aeSDaniel Henrique Barboza     if (cpufd < 0) {
561492265aeSDaniel Henrique Barboza         goto err;
562492265aeSDaniel Henrique Barboza     }
563492265aeSDaniel Henrique Barboza 
564492265aeSDaniel Henrique Barboza     scratch->kvmfd =  kvmfd;
565492265aeSDaniel Henrique Barboza     scratch->vmfd = vmfd;
566492265aeSDaniel Henrique Barboza     scratch->cpufd = cpufd;
567492265aeSDaniel Henrique Barboza 
568492265aeSDaniel Henrique Barboza     return true;
569492265aeSDaniel Henrique Barboza 
570492265aeSDaniel Henrique Barboza  err:
571492265aeSDaniel Henrique Barboza     if (cpufd >= 0) {
572492265aeSDaniel Henrique Barboza         close(cpufd);
573492265aeSDaniel Henrique Barboza     }
574492265aeSDaniel Henrique Barboza     if (vmfd >= 0) {
575492265aeSDaniel Henrique Barboza         close(vmfd);
576492265aeSDaniel Henrique Barboza     }
577492265aeSDaniel Henrique Barboza     if (kvmfd >= 0) {
578492265aeSDaniel Henrique Barboza         close(kvmfd);
579492265aeSDaniel Henrique Barboza     }
580492265aeSDaniel Henrique Barboza 
581492265aeSDaniel Henrique Barboza     return false;
582492265aeSDaniel Henrique Barboza }
583492265aeSDaniel Henrique Barboza 
584492265aeSDaniel Henrique Barboza static void kvm_riscv_destroy_scratch_vcpu(KVMScratchCPU *scratch)
585492265aeSDaniel Henrique Barboza {
586492265aeSDaniel Henrique Barboza     close(scratch->cpufd);
587492265aeSDaniel Henrique Barboza     close(scratch->vmfd);
588492265aeSDaniel Henrique Barboza     close(scratch->kvmfd);
589492265aeSDaniel Henrique Barboza }
590492265aeSDaniel Henrique Barboza 
591492265aeSDaniel Henrique Barboza static void kvm_riscv_init_machine_ids(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
592492265aeSDaniel Henrique Barboza {
593492265aeSDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
594492265aeSDaniel Henrique Barboza     struct kvm_one_reg reg;
595492265aeSDaniel Henrique Barboza     int ret;
596492265aeSDaniel Henrique Barboza 
597492265aeSDaniel Henrique Barboza     reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
598492265aeSDaniel Henrique Barboza                               KVM_REG_RISCV_CONFIG_REG(mvendorid));
599492265aeSDaniel Henrique Barboza     reg.addr = (uint64_t)&cpu->cfg.mvendorid;
600492265aeSDaniel Henrique Barboza     ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
601492265aeSDaniel Henrique Barboza     if (ret != 0) {
602492265aeSDaniel Henrique Barboza         error_report("Unable to retrieve mvendorid from host, error %d", ret);
603492265aeSDaniel Henrique Barboza     }
604d758f884SDaniel Henrique Barboza 
605d758f884SDaniel Henrique Barboza     reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
606d758f884SDaniel Henrique Barboza                               KVM_REG_RISCV_CONFIG_REG(marchid));
607d758f884SDaniel Henrique Barboza     reg.addr = (uint64_t)&cpu->cfg.marchid;
608d758f884SDaniel Henrique Barboza     ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
609d758f884SDaniel Henrique Barboza     if (ret != 0) {
610d758f884SDaniel Henrique Barboza         error_report("Unable to retrieve marchid from host, error %d", ret);
611d758f884SDaniel Henrique Barboza     }
612d758f884SDaniel Henrique Barboza 
613d758f884SDaniel Henrique Barboza     reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
614d758f884SDaniel Henrique Barboza                               KVM_REG_RISCV_CONFIG_REG(mimpid));
615d758f884SDaniel Henrique Barboza     reg.addr = (uint64_t)&cpu->cfg.mimpid;
616d758f884SDaniel Henrique Barboza     ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
617d758f884SDaniel Henrique Barboza     if (ret != 0) {
618d758f884SDaniel Henrique Barboza         error_report("Unable to retrieve mimpid from host, error %d", ret);
619d758f884SDaniel Henrique Barboza     }
620492265aeSDaniel Henrique Barboza }
621492265aeSDaniel Henrique Barboza 
622e28b9c49SDaniel Henrique Barboza static void kvm_riscv_init_misa_ext_mask(RISCVCPU *cpu,
623e28b9c49SDaniel Henrique Barboza                                          KVMScratchCPU *kvmcpu)
624e28b9c49SDaniel Henrique Barboza {
625e28b9c49SDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
626e28b9c49SDaniel Henrique Barboza     struct kvm_one_reg reg;
627e28b9c49SDaniel Henrique Barboza     int ret;
628e28b9c49SDaniel Henrique Barboza 
629e28b9c49SDaniel Henrique Barboza     reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
630e28b9c49SDaniel Henrique Barboza                               KVM_REG_RISCV_CONFIG_REG(isa));
631e28b9c49SDaniel Henrique Barboza     reg.addr = (uint64_t)&env->misa_ext_mask;
632e28b9c49SDaniel Henrique Barboza     ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
633e28b9c49SDaniel Henrique Barboza 
634e28b9c49SDaniel Henrique Barboza     if (ret) {
635e28b9c49SDaniel Henrique Barboza         error_report("Unable to fetch ISA register from KVM, "
636e28b9c49SDaniel Henrique Barboza                      "error %d", ret);
637e28b9c49SDaniel Henrique Barboza         kvm_riscv_destroy_scratch_vcpu(kvmcpu);
638e28b9c49SDaniel Henrique Barboza         exit(EXIT_FAILURE);
639e28b9c49SDaniel Henrique Barboza     }
640e28b9c49SDaniel Henrique Barboza 
641e28b9c49SDaniel Henrique Barboza     env->misa_ext = env->misa_ext_mask;
642e28b9c49SDaniel Henrique Barboza }
643e28b9c49SDaniel Henrique Barboza 
644f7a69fa6SDaniel Henrique Barboza static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
645f7a69fa6SDaniel Henrique Barboza {
646f7a69fa6SDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
647f7a69fa6SDaniel Henrique Barboza     uint64_t val;
648f7a69fa6SDaniel Henrique Barboza     int i, ret;
649f7a69fa6SDaniel Henrique Barboza 
650f7a69fa6SDaniel Henrique Barboza     for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) {
651f7a69fa6SDaniel Henrique Barboza         KVMCPUConfig *multi_ext_cfg = &kvm_multi_ext_cfgs[i];
652f7a69fa6SDaniel Henrique Barboza         struct kvm_one_reg reg;
653f7a69fa6SDaniel Henrique Barboza 
654f7a69fa6SDaniel Henrique Barboza         reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_ISA_EXT,
655f7a69fa6SDaniel Henrique Barboza                                   multi_ext_cfg->kvm_reg_id);
656f7a69fa6SDaniel Henrique Barboza         reg.addr = (uint64_t)&val;
657f7a69fa6SDaniel Henrique Barboza         ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
658f7a69fa6SDaniel Henrique Barboza         if (ret != 0) {
659f7a69fa6SDaniel Henrique Barboza             if (errno == EINVAL) {
660f7a69fa6SDaniel Henrique Barboza                 /* Silently default to 'false' if KVM does not support it. */
661f7a69fa6SDaniel Henrique Barboza                 multi_ext_cfg->supported = false;
662f7a69fa6SDaniel Henrique Barboza                 val = false;
663f7a69fa6SDaniel Henrique Barboza             } else {
664f7a69fa6SDaniel Henrique Barboza                 error_report("Unable to read ISA_EXT KVM register %s, "
665f7a69fa6SDaniel Henrique Barboza                              "error %d", multi_ext_cfg->name, ret);
666f7a69fa6SDaniel Henrique Barboza                 kvm_riscv_destroy_scratch_vcpu(kvmcpu);
667f7a69fa6SDaniel Henrique Barboza                 exit(EXIT_FAILURE);
668f7a69fa6SDaniel Henrique Barboza             }
669f7a69fa6SDaniel Henrique Barboza         } else {
670f7a69fa6SDaniel Henrique Barboza             multi_ext_cfg->supported = true;
671f7a69fa6SDaniel Henrique Barboza         }
672f7a69fa6SDaniel Henrique Barboza 
673f7a69fa6SDaniel Henrique Barboza         kvm_cpu_cfg_set(cpu, multi_ext_cfg, val);
674f7a69fa6SDaniel Henrique Barboza     }
675f7a69fa6SDaniel Henrique Barboza }
676f7a69fa6SDaniel Henrique Barboza 
677492265aeSDaniel Henrique Barboza void kvm_riscv_init_user_properties(Object *cpu_obj)
678492265aeSDaniel Henrique Barboza {
679492265aeSDaniel Henrique Barboza     RISCVCPU *cpu = RISCV_CPU(cpu_obj);
680492265aeSDaniel Henrique Barboza     KVMScratchCPU kvmcpu;
681492265aeSDaniel Henrique Barboza 
682492265aeSDaniel Henrique Barboza     if (!kvm_riscv_create_scratch_vcpu(&kvmcpu)) {
683492265aeSDaniel Henrique Barboza         return;
684492265aeSDaniel Henrique Barboza     }
685492265aeSDaniel Henrique Barboza 
68692becce5SDaniel Henrique Barboza     kvm_riscv_add_cpu_user_properties(cpu_obj);
687492265aeSDaniel Henrique Barboza     kvm_riscv_init_machine_ids(cpu, &kvmcpu);
688e28b9c49SDaniel Henrique Barboza     kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu);
689f7a69fa6SDaniel Henrique Barboza     kvm_riscv_init_multiext_cfg(cpu, &kvmcpu);
690492265aeSDaniel Henrique Barboza 
691492265aeSDaniel Henrique Barboza     kvm_riscv_destroy_scratch_vcpu(&kvmcpu);
692492265aeSDaniel Henrique Barboza }
693492265aeSDaniel Henrique Barboza 
69491654e61SYifei Jiang const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
69591654e61SYifei Jiang     KVM_CAP_LAST_INFO
69691654e61SYifei Jiang };
69791654e61SYifei Jiang 
69891654e61SYifei Jiang int kvm_arch_get_registers(CPUState *cs)
69991654e61SYifei Jiang {
700937f0b45SYifei Jiang     int ret = 0;
701937f0b45SYifei Jiang 
702937f0b45SYifei Jiang     ret = kvm_riscv_get_regs_core(cs);
703937f0b45SYifei Jiang     if (ret) {
704937f0b45SYifei Jiang         return ret;
705937f0b45SYifei Jiang     }
706937f0b45SYifei Jiang 
707937f0b45SYifei Jiang     ret = kvm_riscv_get_regs_csr(cs);
708937f0b45SYifei Jiang     if (ret) {
709937f0b45SYifei Jiang         return ret;
710937f0b45SYifei Jiang     }
711937f0b45SYifei Jiang 
712937f0b45SYifei Jiang     ret = kvm_riscv_get_regs_fp(cs);
713937f0b45SYifei Jiang     if (ret) {
714937f0b45SYifei Jiang         return ret;
715937f0b45SYifei Jiang     }
716937f0b45SYifei Jiang 
717937f0b45SYifei Jiang     return ret;
71891654e61SYifei Jiang }
71991654e61SYifei Jiang 
72091654e61SYifei Jiang int kvm_arch_put_registers(CPUState *cs, int level)
72191654e61SYifei Jiang {
7229997cc1eSYifei Jiang     int ret = 0;
7239997cc1eSYifei Jiang 
7249997cc1eSYifei Jiang     ret = kvm_riscv_put_regs_core(cs);
7259997cc1eSYifei Jiang     if (ret) {
7269997cc1eSYifei Jiang         return ret;
7279997cc1eSYifei Jiang     }
7289997cc1eSYifei Jiang 
7299997cc1eSYifei Jiang     ret = kvm_riscv_put_regs_csr(cs);
7309997cc1eSYifei Jiang     if (ret) {
7319997cc1eSYifei Jiang         return ret;
7329997cc1eSYifei Jiang     }
7339997cc1eSYifei Jiang 
7349997cc1eSYifei Jiang     ret = kvm_riscv_put_regs_fp(cs);
7359997cc1eSYifei Jiang     if (ret) {
7369997cc1eSYifei Jiang         return ret;
7379997cc1eSYifei Jiang     }
7389997cc1eSYifei Jiang 
7399997cc1eSYifei Jiang     return ret;
74091654e61SYifei Jiang }
74191654e61SYifei Jiang 
74291654e61SYifei Jiang int kvm_arch_release_virq_post(int virq)
74391654e61SYifei Jiang {
74491654e61SYifei Jiang     return 0;
74591654e61SYifei Jiang }
74691654e61SYifei Jiang 
74791654e61SYifei Jiang int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
74891654e61SYifei Jiang                              uint64_t address, uint32_t data, PCIDevice *dev)
74991654e61SYifei Jiang {
75091654e61SYifei Jiang     return 0;
75191654e61SYifei Jiang }
75291654e61SYifei Jiang 
75391654e61SYifei Jiang int kvm_arch_destroy_vcpu(CPUState *cs)
75491654e61SYifei Jiang {
75591654e61SYifei Jiang     return 0;
75691654e61SYifei Jiang }
75791654e61SYifei Jiang 
75891654e61SYifei Jiang unsigned long kvm_arch_vcpu_id(CPUState *cpu)
75991654e61SYifei Jiang {
76091654e61SYifei Jiang     return cpu->cpu_index;
76191654e61SYifei Jiang }
76291654e61SYifei Jiang 
7639ad3e016SYifei Jiang static void kvm_riscv_vm_state_change(void *opaque, bool running,
7649ad3e016SYifei Jiang                                       RunState state)
7659ad3e016SYifei Jiang {
7669ad3e016SYifei Jiang     CPUState *cs = opaque;
7679ad3e016SYifei Jiang 
7689ad3e016SYifei Jiang     if (running) {
7699ad3e016SYifei Jiang         kvm_riscv_put_regs_timer(cs);
7709ad3e016SYifei Jiang     } else {
7719ad3e016SYifei Jiang         kvm_riscv_get_regs_timer(cs);
7729ad3e016SYifei Jiang     }
7739ad3e016SYifei Jiang }
7749ad3e016SYifei Jiang 
77591654e61SYifei Jiang void kvm_arch_init_irq_routing(KVMState *s)
77691654e61SYifei Jiang {
77791654e61SYifei Jiang }
77891654e61SYifei Jiang 
7791fb5a622SDaniel Henrique Barboza static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs)
7801fb5a622SDaniel Henrique Barboza {
7811fb5a622SDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
7821fb5a622SDaniel Henrique Barboza     uint64_t id;
7831fb5a622SDaniel Henrique Barboza     int ret;
7841fb5a622SDaniel Henrique Barboza 
7851fb5a622SDaniel Henrique Barboza     id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
7861fb5a622SDaniel Henrique Barboza                           KVM_REG_RISCV_CONFIG_REG(mvendorid));
7871fb5a622SDaniel Henrique Barboza     ret = kvm_set_one_reg(cs, id, &cpu->cfg.mvendorid);
7881fb5a622SDaniel Henrique Barboza     if (ret != 0) {
7891fb5a622SDaniel Henrique Barboza         return ret;
7901fb5a622SDaniel Henrique Barboza     }
7911fb5a622SDaniel Henrique Barboza 
7921fb5a622SDaniel Henrique Barboza     id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
7931fb5a622SDaniel Henrique Barboza                           KVM_REG_RISCV_CONFIG_REG(marchid));
7941fb5a622SDaniel Henrique Barboza     ret = kvm_set_one_reg(cs, id, &cpu->cfg.marchid);
7951fb5a622SDaniel Henrique Barboza     if (ret != 0) {
7961fb5a622SDaniel Henrique Barboza         return ret;
7971fb5a622SDaniel Henrique Barboza     }
7981fb5a622SDaniel Henrique Barboza 
7991fb5a622SDaniel Henrique Barboza     id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
8001fb5a622SDaniel Henrique Barboza                           KVM_REG_RISCV_CONFIG_REG(mimpid));
8011fb5a622SDaniel Henrique Barboza     ret = kvm_set_one_reg(cs, id, &cpu->cfg.mimpid);
8021fb5a622SDaniel Henrique Barboza 
8031fb5a622SDaniel Henrique Barboza     return ret;
8041fb5a622SDaniel Henrique Barboza }
8051fb5a622SDaniel Henrique Barboza 
80691654e61SYifei Jiang int kvm_arch_init_vcpu(CPUState *cs)
80791654e61SYifei Jiang {
8080a312b85SYifei Jiang     int ret = 0;
8090a312b85SYifei Jiang     RISCVCPU *cpu = RISCV_CPU(cs);
8100a312b85SYifei Jiang 
8119ad3e016SYifei Jiang     qemu_add_vm_change_state_handler(kvm_riscv_vm_state_change, cs);
8129ad3e016SYifei Jiang 
8131fb5a622SDaniel Henrique Barboza     if (!object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_CPU_HOST)) {
8141fb5a622SDaniel Henrique Barboza         ret = kvm_vcpu_set_machine_ids(cpu, cs);
8157313fffbSDaniel Henrique Barboza         if (ret != 0) {
8167313fffbSDaniel Henrique Barboza             return ret;
8171fb5a622SDaniel Henrique Barboza         }
8187313fffbSDaniel Henrique Barboza     }
8197313fffbSDaniel Henrique Barboza 
8207313fffbSDaniel Henrique Barboza     kvm_riscv_update_cpu_misa_ext(cpu, cs);
821*df817297SDaniel Henrique Barboza     kvm_riscv_update_cpu_cfg_isa_ext(cpu, cs);
8221fb5a622SDaniel Henrique Barboza 
8230a312b85SYifei Jiang     return ret;
82491654e61SYifei Jiang }
82591654e61SYifei Jiang 
82691654e61SYifei Jiang int kvm_arch_msi_data_to_gsi(uint32_t data)
82791654e61SYifei Jiang {
82891654e61SYifei Jiang     abort();
82991654e61SYifei Jiang }
83091654e61SYifei Jiang 
83191654e61SYifei Jiang int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
83291654e61SYifei Jiang                                 int vector, PCIDevice *dev)
83391654e61SYifei Jiang {
83491654e61SYifei Jiang     return 0;
83591654e61SYifei Jiang }
83691654e61SYifei Jiang 
83791654e61SYifei Jiang int kvm_arch_init(MachineState *ms, KVMState *s)
83891654e61SYifei Jiang {
83991654e61SYifei Jiang     return 0;
84091654e61SYifei Jiang }
84191654e61SYifei Jiang 
84291654e61SYifei Jiang int kvm_arch_irqchip_create(KVMState *s)
84391654e61SYifei Jiang {
84491654e61SYifei Jiang     return 0;
84591654e61SYifei Jiang }
84691654e61SYifei Jiang 
84791654e61SYifei Jiang int kvm_arch_process_async_events(CPUState *cs)
84891654e61SYifei Jiang {
84991654e61SYifei Jiang     return 0;
85091654e61SYifei Jiang }
85191654e61SYifei Jiang 
85291654e61SYifei Jiang void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
85391654e61SYifei Jiang {
85491654e61SYifei Jiang }
85591654e61SYifei Jiang 
85691654e61SYifei Jiang MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
85791654e61SYifei Jiang {
85891654e61SYifei Jiang     return MEMTXATTRS_UNSPECIFIED;
85991654e61SYifei Jiang }
86091654e61SYifei Jiang 
86191654e61SYifei Jiang bool kvm_arch_stop_on_emulation_error(CPUState *cs)
86291654e61SYifei Jiang {
86391654e61SYifei Jiang     return true;
86491654e61SYifei Jiang }
86591654e61SYifei Jiang 
8664eb47125SYifei Jiang static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run)
8674eb47125SYifei Jiang {
8684eb47125SYifei Jiang     int ret = 0;
8694eb47125SYifei Jiang     unsigned char ch;
8704eb47125SYifei Jiang     switch (run->riscv_sbi.extension_id) {
8714eb47125SYifei Jiang     case SBI_EXT_0_1_CONSOLE_PUTCHAR:
8724eb47125SYifei Jiang         ch = run->riscv_sbi.args[0];
8734eb47125SYifei Jiang         qemu_chr_fe_write(serial_hd(0)->be, &ch, sizeof(ch));
8744eb47125SYifei Jiang         break;
8754eb47125SYifei Jiang     case SBI_EXT_0_1_CONSOLE_GETCHAR:
8764eb47125SYifei Jiang         ret = qemu_chr_fe_read_all(serial_hd(0)->be, &ch, sizeof(ch));
8774eb47125SYifei Jiang         if (ret == sizeof(ch)) {
878947bf7feSVladimir Isaev             run->riscv_sbi.ret[0] = ch;
8794eb47125SYifei Jiang         } else {
880947bf7feSVladimir Isaev             run->riscv_sbi.ret[0] = -1;
8814eb47125SYifei Jiang         }
882947bf7feSVladimir Isaev         ret = 0;
8834eb47125SYifei Jiang         break;
8844eb47125SYifei Jiang     default:
8854eb47125SYifei Jiang         qemu_log_mask(LOG_UNIMP,
8864eb47125SYifei Jiang                       "%s: un-handled SBI EXIT, specific reasons is %lu\n",
8874eb47125SYifei Jiang                       __func__, run->riscv_sbi.extension_id);
8884eb47125SYifei Jiang         ret = -1;
8894eb47125SYifei Jiang         break;
8904eb47125SYifei Jiang     }
8914eb47125SYifei Jiang     return ret;
8924eb47125SYifei Jiang }
8934eb47125SYifei Jiang 
89491654e61SYifei Jiang int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
89591654e61SYifei Jiang {
8964eb47125SYifei Jiang     int ret = 0;
8974eb47125SYifei Jiang     switch (run->exit_reason) {
8984eb47125SYifei Jiang     case KVM_EXIT_RISCV_SBI:
8994eb47125SYifei Jiang         ret = kvm_riscv_handle_sbi(cs, run);
9004eb47125SYifei Jiang         break;
9014eb47125SYifei Jiang     default:
9024eb47125SYifei Jiang         qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
9034eb47125SYifei Jiang                       __func__, run->exit_reason);
9044eb47125SYifei Jiang         ret = -1;
9054eb47125SYifei Jiang         break;
9064eb47125SYifei Jiang     }
9074eb47125SYifei Jiang     return ret;
90891654e61SYifei Jiang }
90991654e61SYifei Jiang 
910ad40be27SYifei Jiang void kvm_riscv_reset_vcpu(RISCVCPU *cpu)
911ad40be27SYifei Jiang {
912ad40be27SYifei Jiang     CPURISCVState *env = &cpu->env;
913ad40be27SYifei Jiang 
914ad40be27SYifei Jiang     if (!kvm_enabled()) {
915ad40be27SYifei Jiang         return;
916ad40be27SYifei Jiang     }
917ad40be27SYifei Jiang     env->pc = cpu->env.kernel_addr;
918ad40be27SYifei Jiang     env->gpr[10] = kvm_arch_vcpu_id(CPU(cpu)); /* a0 */
919ad40be27SYifei Jiang     env->gpr[11] = cpu->env.fdt_addr;          /* a1 */
920ad40be27SYifei Jiang     env->satp = 0;
921ad40be27SYifei Jiang }
922ad40be27SYifei Jiang 
9232b650fbbSYifei Jiang void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level)
9242b650fbbSYifei Jiang {
9252b650fbbSYifei Jiang     int ret;
9262b650fbbSYifei Jiang     unsigned virq = level ? KVM_INTERRUPT_SET : KVM_INTERRUPT_UNSET;
9272b650fbbSYifei Jiang 
9282b650fbbSYifei Jiang     if (irq != IRQ_S_EXT) {
9292b650fbbSYifei Jiang         perror("kvm riscv set irq != IRQ_S_EXT\n");
9302b650fbbSYifei Jiang         abort();
9312b650fbbSYifei Jiang     }
9322b650fbbSYifei Jiang 
9332b650fbbSYifei Jiang     ret = kvm_vcpu_ioctl(CPU(cpu), KVM_INTERRUPT, &virq);
9342b650fbbSYifei Jiang     if (ret < 0) {
9352b650fbbSYifei Jiang         perror("Set irq failed");
9362b650fbbSYifei Jiang         abort();
9372b650fbbSYifei Jiang     }
9382b650fbbSYifei Jiang }
9392b650fbbSYifei Jiang 
94091654e61SYifei Jiang bool kvm_arch_cpu_check_are_resettable(void)
94191654e61SYifei Jiang {
94291654e61SYifei Jiang     return true;
94391654e61SYifei Jiang }
9443dba0a33SPaolo Bonzini 
9453dba0a33SPaolo Bonzini void kvm_arch_accel_class_init(ObjectClass *oc)
9463dba0a33SPaolo Bonzini {
9473dba0a33SPaolo Bonzini }
948