xref: /qemu/target/riscv/kvm/kvm-cpu.c (revision a1be1d9a77a8170822258663e5fb0580f5252536)
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 
218*a1be1d9aSDaniel Henrique Barboza static void *kvmconfig_get_cfg_addr(RISCVCPU *cpu, KVMCPUConfig *kvmcfg)
219*a1be1d9aSDaniel Henrique Barboza {
220*a1be1d9aSDaniel Henrique Barboza     return (void *)&cpu->cfg + kvmcfg->offset;
221*a1be1d9aSDaniel Henrique Barboza }
222*a1be1d9aSDaniel Henrique Barboza 
223f7a69fa6SDaniel Henrique Barboza static void kvm_cpu_cfg_set(RISCVCPU *cpu, KVMCPUConfig *multi_ext,
224f7a69fa6SDaniel Henrique Barboza                             uint32_t val)
225f7a69fa6SDaniel Henrique Barboza {
226*a1be1d9aSDaniel Henrique Barboza     bool *ext_enabled = kvmconfig_get_cfg_addr(cpu, multi_ext);
227f7a69fa6SDaniel Henrique Barboza 
228f7a69fa6SDaniel Henrique Barboza     *ext_enabled = val;
229f7a69fa6SDaniel Henrique Barboza }
230f7a69fa6SDaniel Henrique Barboza 
231f7a69fa6SDaniel Henrique Barboza static uint32_t kvm_cpu_cfg_get(RISCVCPU *cpu,
232f7a69fa6SDaniel Henrique Barboza                                 KVMCPUConfig *multi_ext)
233f7a69fa6SDaniel Henrique Barboza {
234*a1be1d9aSDaniel Henrique Barboza     bool *ext_enabled = kvmconfig_get_cfg_addr(cpu, multi_ext);
235f7a69fa6SDaniel Henrique Barboza 
236f7a69fa6SDaniel Henrique Barboza     return *ext_enabled;
237f7a69fa6SDaniel Henrique Barboza }
238f7a69fa6SDaniel Henrique Barboza 
239f7a69fa6SDaniel Henrique Barboza static void kvm_cpu_set_multi_ext_cfg(Object *obj, Visitor *v,
240f7a69fa6SDaniel Henrique Barboza                                       const char *name,
241f7a69fa6SDaniel Henrique Barboza                                       void *opaque, Error **errp)
242f7a69fa6SDaniel Henrique Barboza {
243f7a69fa6SDaniel Henrique Barboza     KVMCPUConfig *multi_ext_cfg = opaque;
244f7a69fa6SDaniel Henrique Barboza     RISCVCPU *cpu = RISCV_CPU(obj);
245f7a69fa6SDaniel Henrique Barboza     bool value, host_val;
246f7a69fa6SDaniel Henrique Barboza 
247f7a69fa6SDaniel Henrique Barboza     if (!visit_type_bool(v, name, &value, errp)) {
248f7a69fa6SDaniel Henrique Barboza         return;
249f7a69fa6SDaniel Henrique Barboza     }
250f7a69fa6SDaniel Henrique Barboza 
251f7a69fa6SDaniel Henrique Barboza     host_val = kvm_cpu_cfg_get(cpu, multi_ext_cfg);
252f7a69fa6SDaniel Henrique Barboza 
253f7a69fa6SDaniel Henrique Barboza     /*
254f7a69fa6SDaniel Henrique Barboza      * Ignore if the user is setting the same value
255f7a69fa6SDaniel Henrique Barboza      * as the host.
256f7a69fa6SDaniel Henrique Barboza      */
257f7a69fa6SDaniel Henrique Barboza     if (value == host_val) {
258f7a69fa6SDaniel Henrique Barboza         return;
259f7a69fa6SDaniel Henrique Barboza     }
260f7a69fa6SDaniel Henrique Barboza 
261f7a69fa6SDaniel Henrique Barboza     if (!multi_ext_cfg->supported) {
262f7a69fa6SDaniel Henrique Barboza         /*
263f7a69fa6SDaniel Henrique Barboza          * Error out if the user is trying to enable an
264f7a69fa6SDaniel Henrique Barboza          * extension that KVM doesn't support. Ignore
265f7a69fa6SDaniel Henrique Barboza          * option otherwise.
266f7a69fa6SDaniel Henrique Barboza          */
267f7a69fa6SDaniel Henrique Barboza         if (value) {
268f7a69fa6SDaniel Henrique Barboza             error_setg(errp, "KVM does not support disabling extension %s",
269f7a69fa6SDaniel Henrique Barboza                        multi_ext_cfg->name);
270f7a69fa6SDaniel Henrique Barboza         }
271f7a69fa6SDaniel Henrique Barboza 
272f7a69fa6SDaniel Henrique Barboza         return;
273f7a69fa6SDaniel Henrique Barboza     }
274f7a69fa6SDaniel Henrique Barboza 
275f7a69fa6SDaniel Henrique Barboza     multi_ext_cfg->user_set = true;
276f7a69fa6SDaniel Henrique Barboza     kvm_cpu_cfg_set(cpu, multi_ext_cfg, value);
277f7a69fa6SDaniel Henrique Barboza }
278f7a69fa6SDaniel Henrique Barboza 
279df817297SDaniel Henrique Barboza static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs)
280df817297SDaniel Henrique Barboza {
281df817297SDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
282df817297SDaniel Henrique Barboza     uint64_t id, reg;
283df817297SDaniel Henrique Barboza     int i, ret;
284df817297SDaniel Henrique Barboza 
285df817297SDaniel Henrique Barboza     for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) {
286df817297SDaniel Henrique Barboza         KVMCPUConfig *multi_ext_cfg = &kvm_multi_ext_cfgs[i];
287df817297SDaniel Henrique Barboza 
288df817297SDaniel Henrique Barboza         if (!multi_ext_cfg->user_set) {
289df817297SDaniel Henrique Barboza             continue;
290df817297SDaniel Henrique Barboza         }
291df817297SDaniel Henrique Barboza 
292df817297SDaniel Henrique Barboza         id = kvm_riscv_reg_id(env, KVM_REG_RISCV_ISA_EXT,
293df817297SDaniel Henrique Barboza                               multi_ext_cfg->kvm_reg_id);
294df817297SDaniel Henrique Barboza         reg = kvm_cpu_cfg_get(cpu, multi_ext_cfg);
295df817297SDaniel Henrique Barboza         ret = kvm_set_one_reg(cs, id, &reg);
296df817297SDaniel Henrique Barboza         if (ret != 0) {
297df817297SDaniel Henrique Barboza             error_report("Unable to %s extension %s in KVM, error %d",
298df817297SDaniel Henrique Barboza                          reg ? "enable" : "disable",
299df817297SDaniel Henrique Barboza                          multi_ext_cfg->name, ret);
300df817297SDaniel Henrique Barboza             exit(EXIT_FAILURE);
301df817297SDaniel Henrique Barboza         }
302df817297SDaniel Henrique Barboza     }
303df817297SDaniel Henrique Barboza }
304df817297SDaniel Henrique Barboza 
30592becce5SDaniel Henrique Barboza static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj)
30692becce5SDaniel Henrique Barboza {
30792becce5SDaniel Henrique Barboza     int i;
30892becce5SDaniel Henrique Barboza 
30992becce5SDaniel Henrique Barboza     for (i = 0; i < ARRAY_SIZE(kvm_misa_ext_cfgs); i++) {
31092becce5SDaniel Henrique Barboza         KVMCPUConfig *misa_cfg = &kvm_misa_ext_cfgs[i];
31192becce5SDaniel Henrique Barboza         int bit = misa_cfg->offset;
31292becce5SDaniel Henrique Barboza 
31392becce5SDaniel Henrique Barboza         misa_cfg->name = riscv_get_misa_ext_name(bit);
31492becce5SDaniel Henrique Barboza         misa_cfg->description = riscv_get_misa_ext_description(bit);
31592becce5SDaniel Henrique Barboza 
31692becce5SDaniel Henrique Barboza         object_property_add(cpu_obj, misa_cfg->name, "bool",
31792becce5SDaniel Henrique Barboza                             NULL,
31892becce5SDaniel Henrique Barboza                             kvm_cpu_set_misa_ext_cfg,
31992becce5SDaniel Henrique Barboza                             NULL, misa_cfg);
32092becce5SDaniel Henrique Barboza         object_property_set_description(cpu_obj, misa_cfg->name,
32192becce5SDaniel Henrique Barboza                                         misa_cfg->description);
32292becce5SDaniel Henrique Barboza     }
323f7a69fa6SDaniel Henrique Barboza 
324f7a69fa6SDaniel Henrique Barboza     for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) {
325f7a69fa6SDaniel Henrique Barboza         KVMCPUConfig *multi_cfg = &kvm_multi_ext_cfgs[i];
326f7a69fa6SDaniel Henrique Barboza 
327f7a69fa6SDaniel Henrique Barboza         object_property_add(cpu_obj, multi_cfg->name, "bool",
328f7a69fa6SDaniel Henrique Barboza                             NULL,
329f7a69fa6SDaniel Henrique Barboza                             kvm_cpu_set_multi_ext_cfg,
330f7a69fa6SDaniel Henrique Barboza                             NULL, multi_cfg);
331f7a69fa6SDaniel Henrique Barboza     }
33292becce5SDaniel Henrique Barboza }
33392becce5SDaniel Henrique Barboza 
334937f0b45SYifei Jiang static int kvm_riscv_get_regs_core(CPUState *cs)
335937f0b45SYifei Jiang {
336937f0b45SYifei Jiang     int ret = 0;
337937f0b45SYifei Jiang     int i;
338937f0b45SYifei Jiang     target_ulong reg;
339937f0b45SYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
340937f0b45SYifei Jiang 
341937f0b45SYifei Jiang     ret = kvm_get_one_reg(cs, RISCV_CORE_REG(env, regs.pc), &reg);
342937f0b45SYifei Jiang     if (ret) {
343937f0b45SYifei Jiang         return ret;
344937f0b45SYifei Jiang     }
345937f0b45SYifei Jiang     env->pc = reg;
346937f0b45SYifei Jiang 
347937f0b45SYifei Jiang     for (i = 1; i < 32; i++) {
348937f0b45SYifei Jiang         uint64_t id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, i);
349937f0b45SYifei Jiang         ret = kvm_get_one_reg(cs, id, &reg);
350937f0b45SYifei Jiang         if (ret) {
351937f0b45SYifei Jiang             return ret;
352937f0b45SYifei Jiang         }
353937f0b45SYifei Jiang         env->gpr[i] = reg;
354937f0b45SYifei Jiang     }
355937f0b45SYifei Jiang 
356937f0b45SYifei Jiang     return ret;
357937f0b45SYifei Jiang }
358937f0b45SYifei Jiang 
3599997cc1eSYifei Jiang static int kvm_riscv_put_regs_core(CPUState *cs)
3609997cc1eSYifei Jiang {
3619997cc1eSYifei Jiang     int ret = 0;
3629997cc1eSYifei Jiang     int i;
3639997cc1eSYifei Jiang     target_ulong reg;
3649997cc1eSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
3659997cc1eSYifei Jiang 
3669997cc1eSYifei Jiang     reg = env->pc;
3679997cc1eSYifei Jiang     ret = kvm_set_one_reg(cs, RISCV_CORE_REG(env, regs.pc), &reg);
3689997cc1eSYifei Jiang     if (ret) {
3699997cc1eSYifei Jiang         return ret;
3709997cc1eSYifei Jiang     }
3719997cc1eSYifei Jiang 
3729997cc1eSYifei Jiang     for (i = 1; i < 32; i++) {
3739997cc1eSYifei Jiang         uint64_t id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, i);
3749997cc1eSYifei Jiang         reg = env->gpr[i];
3759997cc1eSYifei Jiang         ret = kvm_set_one_reg(cs, id, &reg);
3769997cc1eSYifei Jiang         if (ret) {
3779997cc1eSYifei Jiang             return ret;
3789997cc1eSYifei Jiang         }
3799997cc1eSYifei Jiang     }
3809997cc1eSYifei Jiang 
3819997cc1eSYifei Jiang     return ret;
3829997cc1eSYifei Jiang }
3839997cc1eSYifei Jiang 
384937f0b45SYifei Jiang static int kvm_riscv_get_regs_csr(CPUState *cs)
385937f0b45SYifei Jiang {
386937f0b45SYifei Jiang     int ret = 0;
387937f0b45SYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
388937f0b45SYifei Jiang 
389937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sstatus, env->mstatus);
390937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sie, env->mie);
391937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, stvec, env->stvec);
392937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sscratch, env->sscratch);
393937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sepc, env->sepc);
394937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, scause, env->scause);
395937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, stval, env->stval);
396937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sip, env->mip);
397937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, satp, env->satp);
398937f0b45SYifei Jiang     return ret;
399937f0b45SYifei Jiang }
400937f0b45SYifei Jiang 
4019997cc1eSYifei Jiang static int kvm_riscv_put_regs_csr(CPUState *cs)
4029997cc1eSYifei Jiang {
4039997cc1eSYifei Jiang     int ret = 0;
4049997cc1eSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
4059997cc1eSYifei Jiang 
4069997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sstatus, env->mstatus);
4079997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sie, env->mie);
4089997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, stvec, env->stvec);
4099997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sscratch, env->sscratch);
4109997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sepc, env->sepc);
4119997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, scause, env->scause);
4129997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, stval, env->stval);
4139997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sip, env->mip);
4149997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, satp, env->satp);
4159997cc1eSYifei Jiang 
4169997cc1eSYifei Jiang     return ret;
4179997cc1eSYifei Jiang }
4189997cc1eSYifei Jiang 
419937f0b45SYifei Jiang static int kvm_riscv_get_regs_fp(CPUState *cs)
420937f0b45SYifei Jiang {
421937f0b45SYifei Jiang     int ret = 0;
422937f0b45SYifei Jiang     int i;
423937f0b45SYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
424937f0b45SYifei Jiang 
425937f0b45SYifei Jiang     if (riscv_has_ext(env, RVD)) {
426937f0b45SYifei Jiang         uint64_t reg;
427937f0b45SYifei Jiang         for (i = 0; i < 32; i++) {
428937f0b45SYifei Jiang             ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(env, i), &reg);
429937f0b45SYifei Jiang             if (ret) {
430937f0b45SYifei Jiang                 return ret;
431937f0b45SYifei Jiang             }
432937f0b45SYifei Jiang             env->fpr[i] = reg;
433937f0b45SYifei Jiang         }
434937f0b45SYifei Jiang         return ret;
435937f0b45SYifei Jiang     }
436937f0b45SYifei Jiang 
437937f0b45SYifei Jiang     if (riscv_has_ext(env, RVF)) {
438937f0b45SYifei Jiang         uint32_t reg;
439937f0b45SYifei Jiang         for (i = 0; i < 32; i++) {
440937f0b45SYifei Jiang             ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(env, i), &reg);
441937f0b45SYifei Jiang             if (ret) {
442937f0b45SYifei Jiang                 return ret;
443937f0b45SYifei Jiang             }
444937f0b45SYifei Jiang             env->fpr[i] = reg;
445937f0b45SYifei Jiang         }
446937f0b45SYifei Jiang         return ret;
447937f0b45SYifei Jiang     }
448937f0b45SYifei Jiang 
449937f0b45SYifei Jiang     return ret;
450937f0b45SYifei Jiang }
451937f0b45SYifei Jiang 
4529997cc1eSYifei Jiang static int kvm_riscv_put_regs_fp(CPUState *cs)
4539997cc1eSYifei Jiang {
4549997cc1eSYifei Jiang     int ret = 0;
4559997cc1eSYifei Jiang     int i;
4569997cc1eSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
4579997cc1eSYifei Jiang 
4589997cc1eSYifei Jiang     if (riscv_has_ext(env, RVD)) {
4599997cc1eSYifei Jiang         uint64_t reg;
4609997cc1eSYifei Jiang         for (i = 0; i < 32; i++) {
4619997cc1eSYifei Jiang             reg = env->fpr[i];
4629997cc1eSYifei Jiang             ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(env, i), &reg);
4639997cc1eSYifei Jiang             if (ret) {
4649997cc1eSYifei Jiang                 return ret;
4659997cc1eSYifei Jiang             }
4669997cc1eSYifei Jiang         }
4679997cc1eSYifei Jiang         return ret;
4689997cc1eSYifei Jiang     }
4699997cc1eSYifei Jiang 
4709997cc1eSYifei Jiang     if (riscv_has_ext(env, RVF)) {
4719997cc1eSYifei Jiang         uint32_t reg;
4729997cc1eSYifei Jiang         for (i = 0; i < 32; i++) {
4739997cc1eSYifei Jiang             reg = env->fpr[i];
4749997cc1eSYifei Jiang             ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(env, i), &reg);
4759997cc1eSYifei Jiang             if (ret) {
4769997cc1eSYifei Jiang                 return ret;
4779997cc1eSYifei Jiang             }
4789997cc1eSYifei Jiang         }
4799997cc1eSYifei Jiang         return ret;
4809997cc1eSYifei Jiang     }
4819997cc1eSYifei Jiang 
4829997cc1eSYifei Jiang     return ret;
4839997cc1eSYifei Jiang }
4849997cc1eSYifei Jiang 
48527abe66fSYifei Jiang static void kvm_riscv_get_regs_timer(CPUState *cs)
48627abe66fSYifei Jiang {
48727abe66fSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
48827abe66fSYifei Jiang 
48927abe66fSYifei Jiang     if (env->kvm_timer_dirty) {
49027abe66fSYifei Jiang         return;
49127abe66fSYifei Jiang     }
49227abe66fSYifei Jiang 
49327abe66fSYifei Jiang     KVM_RISCV_GET_TIMER(cs, env, time, env->kvm_timer_time);
49427abe66fSYifei Jiang     KVM_RISCV_GET_TIMER(cs, env, compare, env->kvm_timer_compare);
49527abe66fSYifei Jiang     KVM_RISCV_GET_TIMER(cs, env, state, env->kvm_timer_state);
49627abe66fSYifei Jiang     KVM_RISCV_GET_TIMER(cs, env, frequency, env->kvm_timer_frequency);
49727abe66fSYifei Jiang 
49827abe66fSYifei Jiang     env->kvm_timer_dirty = true;
49927abe66fSYifei Jiang }
50027abe66fSYifei Jiang 
50127abe66fSYifei Jiang static void kvm_riscv_put_regs_timer(CPUState *cs)
50227abe66fSYifei Jiang {
50327abe66fSYifei Jiang     uint64_t reg;
50427abe66fSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
50527abe66fSYifei Jiang 
50627abe66fSYifei Jiang     if (!env->kvm_timer_dirty) {
50727abe66fSYifei Jiang         return;
50827abe66fSYifei Jiang     }
50927abe66fSYifei Jiang 
51027abe66fSYifei Jiang     KVM_RISCV_SET_TIMER(cs, env, time, env->kvm_timer_time);
51127abe66fSYifei Jiang     KVM_RISCV_SET_TIMER(cs, env, compare, env->kvm_timer_compare);
51227abe66fSYifei Jiang 
51327abe66fSYifei Jiang     /*
51427abe66fSYifei Jiang      * To set register of RISCV_TIMER_REG(state) will occur a error from KVM
51527abe66fSYifei Jiang      * on env->kvm_timer_state == 0, It's better to adapt in KVM, but it
51627abe66fSYifei Jiang      * doesn't matter that adaping in QEMU now.
51727abe66fSYifei Jiang      * TODO If KVM changes, adapt here.
51827abe66fSYifei Jiang      */
51927abe66fSYifei Jiang     if (env->kvm_timer_state) {
52027abe66fSYifei Jiang         KVM_RISCV_SET_TIMER(cs, env, state, env->kvm_timer_state);
52127abe66fSYifei Jiang     }
52227abe66fSYifei Jiang 
52327abe66fSYifei Jiang     /*
52427abe66fSYifei Jiang      * For now, migration will not work between Hosts with different timer
52527abe66fSYifei Jiang      * frequency. Therefore, we should check whether they are the same here
52627abe66fSYifei Jiang      * during the migration.
52727abe66fSYifei Jiang      */
52827abe66fSYifei Jiang     if (migration_is_running(migrate_get_current()->state)) {
52927abe66fSYifei Jiang         KVM_RISCV_GET_TIMER(cs, env, frequency, reg);
53027abe66fSYifei Jiang         if (reg != env->kvm_timer_frequency) {
53127abe66fSYifei Jiang             error_report("Dst Hosts timer frequency != Src Hosts");
53227abe66fSYifei Jiang         }
53327abe66fSYifei Jiang     }
53427abe66fSYifei Jiang 
53527abe66fSYifei Jiang     env->kvm_timer_dirty = false;
53627abe66fSYifei Jiang }
5379997cc1eSYifei Jiang 
538492265aeSDaniel Henrique Barboza typedef struct KVMScratchCPU {
539492265aeSDaniel Henrique Barboza     int kvmfd;
540492265aeSDaniel Henrique Barboza     int vmfd;
541492265aeSDaniel Henrique Barboza     int cpufd;
542492265aeSDaniel Henrique Barboza } KVMScratchCPU;
543492265aeSDaniel Henrique Barboza 
544492265aeSDaniel Henrique Barboza /*
545492265aeSDaniel Henrique Barboza  * Heavily inspired by kvm_arm_create_scratch_host_vcpu()
546492265aeSDaniel Henrique Barboza  * from target/arm/kvm.c.
547492265aeSDaniel Henrique Barboza  */
548492265aeSDaniel Henrique Barboza static bool kvm_riscv_create_scratch_vcpu(KVMScratchCPU *scratch)
549492265aeSDaniel Henrique Barboza {
550492265aeSDaniel Henrique Barboza     int kvmfd = -1, vmfd = -1, cpufd = -1;
551492265aeSDaniel Henrique Barboza 
552492265aeSDaniel Henrique Barboza     kvmfd = qemu_open_old("/dev/kvm", O_RDWR);
553492265aeSDaniel Henrique Barboza     if (kvmfd < 0) {
554492265aeSDaniel Henrique Barboza         goto err;
555492265aeSDaniel Henrique Barboza     }
556492265aeSDaniel Henrique Barboza     do {
557492265aeSDaniel Henrique Barboza         vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);
558492265aeSDaniel Henrique Barboza     } while (vmfd == -1 && errno == EINTR);
559492265aeSDaniel Henrique Barboza     if (vmfd < 0) {
560492265aeSDaniel Henrique Barboza         goto err;
561492265aeSDaniel Henrique Barboza     }
562492265aeSDaniel Henrique Barboza     cpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);
563492265aeSDaniel Henrique Barboza     if (cpufd < 0) {
564492265aeSDaniel Henrique Barboza         goto err;
565492265aeSDaniel Henrique Barboza     }
566492265aeSDaniel Henrique Barboza 
567492265aeSDaniel Henrique Barboza     scratch->kvmfd =  kvmfd;
568492265aeSDaniel Henrique Barboza     scratch->vmfd = vmfd;
569492265aeSDaniel Henrique Barboza     scratch->cpufd = cpufd;
570492265aeSDaniel Henrique Barboza 
571492265aeSDaniel Henrique Barboza     return true;
572492265aeSDaniel Henrique Barboza 
573492265aeSDaniel Henrique Barboza  err:
574492265aeSDaniel Henrique Barboza     if (cpufd >= 0) {
575492265aeSDaniel Henrique Barboza         close(cpufd);
576492265aeSDaniel Henrique Barboza     }
577492265aeSDaniel Henrique Barboza     if (vmfd >= 0) {
578492265aeSDaniel Henrique Barboza         close(vmfd);
579492265aeSDaniel Henrique Barboza     }
580492265aeSDaniel Henrique Barboza     if (kvmfd >= 0) {
581492265aeSDaniel Henrique Barboza         close(kvmfd);
582492265aeSDaniel Henrique Barboza     }
583492265aeSDaniel Henrique Barboza 
584492265aeSDaniel Henrique Barboza     return false;
585492265aeSDaniel Henrique Barboza }
586492265aeSDaniel Henrique Barboza 
587492265aeSDaniel Henrique Barboza static void kvm_riscv_destroy_scratch_vcpu(KVMScratchCPU *scratch)
588492265aeSDaniel Henrique Barboza {
589492265aeSDaniel Henrique Barboza     close(scratch->cpufd);
590492265aeSDaniel Henrique Barboza     close(scratch->vmfd);
591492265aeSDaniel Henrique Barboza     close(scratch->kvmfd);
592492265aeSDaniel Henrique Barboza }
593492265aeSDaniel Henrique Barboza 
594492265aeSDaniel Henrique Barboza static void kvm_riscv_init_machine_ids(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
595492265aeSDaniel Henrique Barboza {
596492265aeSDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
597492265aeSDaniel Henrique Barboza     struct kvm_one_reg reg;
598492265aeSDaniel Henrique Barboza     int ret;
599492265aeSDaniel Henrique Barboza 
600492265aeSDaniel Henrique Barboza     reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
601492265aeSDaniel Henrique Barboza                               KVM_REG_RISCV_CONFIG_REG(mvendorid));
602492265aeSDaniel Henrique Barboza     reg.addr = (uint64_t)&cpu->cfg.mvendorid;
603492265aeSDaniel Henrique Barboza     ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
604492265aeSDaniel Henrique Barboza     if (ret != 0) {
605492265aeSDaniel Henrique Barboza         error_report("Unable to retrieve mvendorid from host, error %d", ret);
606492265aeSDaniel Henrique Barboza     }
607d758f884SDaniel Henrique Barboza 
608d758f884SDaniel Henrique Barboza     reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
609d758f884SDaniel Henrique Barboza                               KVM_REG_RISCV_CONFIG_REG(marchid));
610d758f884SDaniel Henrique Barboza     reg.addr = (uint64_t)&cpu->cfg.marchid;
611d758f884SDaniel Henrique Barboza     ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
612d758f884SDaniel Henrique Barboza     if (ret != 0) {
613d758f884SDaniel Henrique Barboza         error_report("Unable to retrieve marchid from host, error %d", ret);
614d758f884SDaniel Henrique Barboza     }
615d758f884SDaniel Henrique Barboza 
616d758f884SDaniel Henrique Barboza     reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
617d758f884SDaniel Henrique Barboza                               KVM_REG_RISCV_CONFIG_REG(mimpid));
618d758f884SDaniel Henrique Barboza     reg.addr = (uint64_t)&cpu->cfg.mimpid;
619d758f884SDaniel Henrique Barboza     ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
620d758f884SDaniel Henrique Barboza     if (ret != 0) {
621d758f884SDaniel Henrique Barboza         error_report("Unable to retrieve mimpid from host, error %d", ret);
622d758f884SDaniel Henrique Barboza     }
623492265aeSDaniel Henrique Barboza }
624492265aeSDaniel Henrique Barboza 
625e28b9c49SDaniel Henrique Barboza static void kvm_riscv_init_misa_ext_mask(RISCVCPU *cpu,
626e28b9c49SDaniel Henrique Barboza                                          KVMScratchCPU *kvmcpu)
627e28b9c49SDaniel Henrique Barboza {
628e28b9c49SDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
629e28b9c49SDaniel Henrique Barboza     struct kvm_one_reg reg;
630e28b9c49SDaniel Henrique Barboza     int ret;
631e28b9c49SDaniel Henrique Barboza 
632e28b9c49SDaniel Henrique Barboza     reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
633e28b9c49SDaniel Henrique Barboza                               KVM_REG_RISCV_CONFIG_REG(isa));
634e28b9c49SDaniel Henrique Barboza     reg.addr = (uint64_t)&env->misa_ext_mask;
635e28b9c49SDaniel Henrique Barboza     ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
636e28b9c49SDaniel Henrique Barboza 
637e28b9c49SDaniel Henrique Barboza     if (ret) {
638e28b9c49SDaniel Henrique Barboza         error_report("Unable to fetch ISA register from KVM, "
639e28b9c49SDaniel Henrique Barboza                      "error %d", ret);
640e28b9c49SDaniel Henrique Barboza         kvm_riscv_destroy_scratch_vcpu(kvmcpu);
641e28b9c49SDaniel Henrique Barboza         exit(EXIT_FAILURE);
642e28b9c49SDaniel Henrique Barboza     }
643e28b9c49SDaniel Henrique Barboza 
644e28b9c49SDaniel Henrique Barboza     env->misa_ext = env->misa_ext_mask;
645e28b9c49SDaniel Henrique Barboza }
646e28b9c49SDaniel Henrique Barboza 
647f7a69fa6SDaniel Henrique Barboza static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
648f7a69fa6SDaniel Henrique Barboza {
649f7a69fa6SDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
650f7a69fa6SDaniel Henrique Barboza     uint64_t val;
651f7a69fa6SDaniel Henrique Barboza     int i, ret;
652f7a69fa6SDaniel Henrique Barboza 
653f7a69fa6SDaniel Henrique Barboza     for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) {
654f7a69fa6SDaniel Henrique Barboza         KVMCPUConfig *multi_ext_cfg = &kvm_multi_ext_cfgs[i];
655f7a69fa6SDaniel Henrique Barboza         struct kvm_one_reg reg;
656f7a69fa6SDaniel Henrique Barboza 
657f7a69fa6SDaniel Henrique Barboza         reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_ISA_EXT,
658f7a69fa6SDaniel Henrique Barboza                                   multi_ext_cfg->kvm_reg_id);
659f7a69fa6SDaniel Henrique Barboza         reg.addr = (uint64_t)&val;
660f7a69fa6SDaniel Henrique Barboza         ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
661f7a69fa6SDaniel Henrique Barboza         if (ret != 0) {
662f7a69fa6SDaniel Henrique Barboza             if (errno == EINVAL) {
663f7a69fa6SDaniel Henrique Barboza                 /* Silently default to 'false' if KVM does not support it. */
664f7a69fa6SDaniel Henrique Barboza                 multi_ext_cfg->supported = false;
665f7a69fa6SDaniel Henrique Barboza                 val = false;
666f7a69fa6SDaniel Henrique Barboza             } else {
667f7a69fa6SDaniel Henrique Barboza                 error_report("Unable to read ISA_EXT KVM register %s, "
668f7a69fa6SDaniel Henrique Barboza                              "error %d", multi_ext_cfg->name, ret);
669f7a69fa6SDaniel Henrique Barboza                 kvm_riscv_destroy_scratch_vcpu(kvmcpu);
670f7a69fa6SDaniel Henrique Barboza                 exit(EXIT_FAILURE);
671f7a69fa6SDaniel Henrique Barboza             }
672f7a69fa6SDaniel Henrique Barboza         } else {
673f7a69fa6SDaniel Henrique Barboza             multi_ext_cfg->supported = true;
674f7a69fa6SDaniel Henrique Barboza         }
675f7a69fa6SDaniel Henrique Barboza 
676f7a69fa6SDaniel Henrique Barboza         kvm_cpu_cfg_set(cpu, multi_ext_cfg, val);
677f7a69fa6SDaniel Henrique Barboza     }
678f7a69fa6SDaniel Henrique Barboza }
679f7a69fa6SDaniel Henrique Barboza 
680492265aeSDaniel Henrique Barboza void kvm_riscv_init_user_properties(Object *cpu_obj)
681492265aeSDaniel Henrique Barboza {
682492265aeSDaniel Henrique Barboza     RISCVCPU *cpu = RISCV_CPU(cpu_obj);
683492265aeSDaniel Henrique Barboza     KVMScratchCPU kvmcpu;
684492265aeSDaniel Henrique Barboza 
685492265aeSDaniel Henrique Barboza     if (!kvm_riscv_create_scratch_vcpu(&kvmcpu)) {
686492265aeSDaniel Henrique Barboza         return;
687492265aeSDaniel Henrique Barboza     }
688492265aeSDaniel Henrique Barboza 
68992becce5SDaniel Henrique Barboza     kvm_riscv_add_cpu_user_properties(cpu_obj);
690492265aeSDaniel Henrique Barboza     kvm_riscv_init_machine_ids(cpu, &kvmcpu);
691e28b9c49SDaniel Henrique Barboza     kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu);
692f7a69fa6SDaniel Henrique Barboza     kvm_riscv_init_multiext_cfg(cpu, &kvmcpu);
693492265aeSDaniel Henrique Barboza 
694492265aeSDaniel Henrique Barboza     kvm_riscv_destroy_scratch_vcpu(&kvmcpu);
695492265aeSDaniel Henrique Barboza }
696492265aeSDaniel Henrique Barboza 
69791654e61SYifei Jiang const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
69891654e61SYifei Jiang     KVM_CAP_LAST_INFO
69991654e61SYifei Jiang };
70091654e61SYifei Jiang 
70191654e61SYifei Jiang int kvm_arch_get_registers(CPUState *cs)
70291654e61SYifei Jiang {
703937f0b45SYifei Jiang     int ret = 0;
704937f0b45SYifei Jiang 
705937f0b45SYifei Jiang     ret = kvm_riscv_get_regs_core(cs);
706937f0b45SYifei Jiang     if (ret) {
707937f0b45SYifei Jiang         return ret;
708937f0b45SYifei Jiang     }
709937f0b45SYifei Jiang 
710937f0b45SYifei Jiang     ret = kvm_riscv_get_regs_csr(cs);
711937f0b45SYifei Jiang     if (ret) {
712937f0b45SYifei Jiang         return ret;
713937f0b45SYifei Jiang     }
714937f0b45SYifei Jiang 
715937f0b45SYifei Jiang     ret = kvm_riscv_get_regs_fp(cs);
716937f0b45SYifei Jiang     if (ret) {
717937f0b45SYifei Jiang         return ret;
718937f0b45SYifei Jiang     }
719937f0b45SYifei Jiang 
720937f0b45SYifei Jiang     return ret;
72191654e61SYifei Jiang }
72291654e61SYifei Jiang 
72391654e61SYifei Jiang int kvm_arch_put_registers(CPUState *cs, int level)
72491654e61SYifei Jiang {
7259997cc1eSYifei Jiang     int ret = 0;
7269997cc1eSYifei Jiang 
7279997cc1eSYifei Jiang     ret = kvm_riscv_put_regs_core(cs);
7289997cc1eSYifei Jiang     if (ret) {
7299997cc1eSYifei Jiang         return ret;
7309997cc1eSYifei Jiang     }
7319997cc1eSYifei Jiang 
7329997cc1eSYifei Jiang     ret = kvm_riscv_put_regs_csr(cs);
7339997cc1eSYifei Jiang     if (ret) {
7349997cc1eSYifei Jiang         return ret;
7359997cc1eSYifei Jiang     }
7369997cc1eSYifei Jiang 
7379997cc1eSYifei Jiang     ret = kvm_riscv_put_regs_fp(cs);
7389997cc1eSYifei Jiang     if (ret) {
7399997cc1eSYifei Jiang         return ret;
7409997cc1eSYifei Jiang     }
7419997cc1eSYifei Jiang 
7429997cc1eSYifei Jiang     return ret;
74391654e61SYifei Jiang }
74491654e61SYifei Jiang 
74591654e61SYifei Jiang int kvm_arch_release_virq_post(int virq)
74691654e61SYifei Jiang {
74791654e61SYifei Jiang     return 0;
74891654e61SYifei Jiang }
74991654e61SYifei Jiang 
75091654e61SYifei Jiang int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
75191654e61SYifei Jiang                              uint64_t address, uint32_t data, PCIDevice *dev)
75291654e61SYifei Jiang {
75391654e61SYifei Jiang     return 0;
75491654e61SYifei Jiang }
75591654e61SYifei Jiang 
75691654e61SYifei Jiang int kvm_arch_destroy_vcpu(CPUState *cs)
75791654e61SYifei Jiang {
75891654e61SYifei Jiang     return 0;
75991654e61SYifei Jiang }
76091654e61SYifei Jiang 
76191654e61SYifei Jiang unsigned long kvm_arch_vcpu_id(CPUState *cpu)
76291654e61SYifei Jiang {
76391654e61SYifei Jiang     return cpu->cpu_index;
76491654e61SYifei Jiang }
76591654e61SYifei Jiang 
7669ad3e016SYifei Jiang static void kvm_riscv_vm_state_change(void *opaque, bool running,
7679ad3e016SYifei Jiang                                       RunState state)
7689ad3e016SYifei Jiang {
7699ad3e016SYifei Jiang     CPUState *cs = opaque;
7709ad3e016SYifei Jiang 
7719ad3e016SYifei Jiang     if (running) {
7729ad3e016SYifei Jiang         kvm_riscv_put_regs_timer(cs);
7739ad3e016SYifei Jiang     } else {
7749ad3e016SYifei Jiang         kvm_riscv_get_regs_timer(cs);
7759ad3e016SYifei Jiang     }
7769ad3e016SYifei Jiang }
7779ad3e016SYifei Jiang 
77891654e61SYifei Jiang void kvm_arch_init_irq_routing(KVMState *s)
77991654e61SYifei Jiang {
78091654e61SYifei Jiang }
78191654e61SYifei Jiang 
7821fb5a622SDaniel Henrique Barboza static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs)
7831fb5a622SDaniel Henrique Barboza {
7841fb5a622SDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
7851fb5a622SDaniel Henrique Barboza     uint64_t id;
7861fb5a622SDaniel Henrique Barboza     int ret;
7871fb5a622SDaniel Henrique Barboza 
7881fb5a622SDaniel Henrique Barboza     id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
7891fb5a622SDaniel Henrique Barboza                           KVM_REG_RISCV_CONFIG_REG(mvendorid));
7901fb5a622SDaniel Henrique Barboza     ret = kvm_set_one_reg(cs, id, &cpu->cfg.mvendorid);
7911fb5a622SDaniel Henrique Barboza     if (ret != 0) {
7921fb5a622SDaniel Henrique Barboza         return ret;
7931fb5a622SDaniel Henrique Barboza     }
7941fb5a622SDaniel Henrique Barboza 
7951fb5a622SDaniel Henrique Barboza     id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
7961fb5a622SDaniel Henrique Barboza                           KVM_REG_RISCV_CONFIG_REG(marchid));
7971fb5a622SDaniel Henrique Barboza     ret = kvm_set_one_reg(cs, id, &cpu->cfg.marchid);
7981fb5a622SDaniel Henrique Barboza     if (ret != 0) {
7991fb5a622SDaniel Henrique Barboza         return ret;
8001fb5a622SDaniel Henrique Barboza     }
8011fb5a622SDaniel Henrique Barboza 
8021fb5a622SDaniel Henrique Barboza     id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
8031fb5a622SDaniel Henrique Barboza                           KVM_REG_RISCV_CONFIG_REG(mimpid));
8041fb5a622SDaniel Henrique Barboza     ret = kvm_set_one_reg(cs, id, &cpu->cfg.mimpid);
8051fb5a622SDaniel Henrique Barboza 
8061fb5a622SDaniel Henrique Barboza     return ret;
8071fb5a622SDaniel Henrique Barboza }
8081fb5a622SDaniel Henrique Barboza 
80991654e61SYifei Jiang int kvm_arch_init_vcpu(CPUState *cs)
81091654e61SYifei Jiang {
8110a312b85SYifei Jiang     int ret = 0;
8120a312b85SYifei Jiang     RISCVCPU *cpu = RISCV_CPU(cs);
8130a312b85SYifei Jiang 
8149ad3e016SYifei Jiang     qemu_add_vm_change_state_handler(kvm_riscv_vm_state_change, cs);
8159ad3e016SYifei Jiang 
8161fb5a622SDaniel Henrique Barboza     if (!object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_CPU_HOST)) {
8171fb5a622SDaniel Henrique Barboza         ret = kvm_vcpu_set_machine_ids(cpu, cs);
8187313fffbSDaniel Henrique Barboza         if (ret != 0) {
8197313fffbSDaniel Henrique Barboza             return ret;
8201fb5a622SDaniel Henrique Barboza         }
8217313fffbSDaniel Henrique Barboza     }
8227313fffbSDaniel Henrique Barboza 
8237313fffbSDaniel Henrique Barboza     kvm_riscv_update_cpu_misa_ext(cpu, cs);
824df817297SDaniel Henrique Barboza     kvm_riscv_update_cpu_cfg_isa_ext(cpu, cs);
8251fb5a622SDaniel Henrique Barboza 
8260a312b85SYifei Jiang     return ret;
82791654e61SYifei Jiang }
82891654e61SYifei Jiang 
82991654e61SYifei Jiang int kvm_arch_msi_data_to_gsi(uint32_t data)
83091654e61SYifei Jiang {
83191654e61SYifei Jiang     abort();
83291654e61SYifei Jiang }
83391654e61SYifei Jiang 
83491654e61SYifei Jiang int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
83591654e61SYifei Jiang                                 int vector, PCIDevice *dev)
83691654e61SYifei Jiang {
83791654e61SYifei Jiang     return 0;
83891654e61SYifei Jiang }
83991654e61SYifei Jiang 
84091654e61SYifei Jiang int kvm_arch_init(MachineState *ms, KVMState *s)
84191654e61SYifei Jiang {
84291654e61SYifei Jiang     return 0;
84391654e61SYifei Jiang }
84491654e61SYifei Jiang 
84591654e61SYifei Jiang int kvm_arch_irqchip_create(KVMState *s)
84691654e61SYifei Jiang {
84791654e61SYifei Jiang     return 0;
84891654e61SYifei Jiang }
84991654e61SYifei Jiang 
85091654e61SYifei Jiang int kvm_arch_process_async_events(CPUState *cs)
85191654e61SYifei Jiang {
85291654e61SYifei Jiang     return 0;
85391654e61SYifei Jiang }
85491654e61SYifei Jiang 
85591654e61SYifei Jiang void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
85691654e61SYifei Jiang {
85791654e61SYifei Jiang }
85891654e61SYifei Jiang 
85991654e61SYifei Jiang MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
86091654e61SYifei Jiang {
86191654e61SYifei Jiang     return MEMTXATTRS_UNSPECIFIED;
86291654e61SYifei Jiang }
86391654e61SYifei Jiang 
86491654e61SYifei Jiang bool kvm_arch_stop_on_emulation_error(CPUState *cs)
86591654e61SYifei Jiang {
86691654e61SYifei Jiang     return true;
86791654e61SYifei Jiang }
86891654e61SYifei Jiang 
8694eb47125SYifei Jiang static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run)
8704eb47125SYifei Jiang {
8714eb47125SYifei Jiang     int ret = 0;
8724eb47125SYifei Jiang     unsigned char ch;
8734eb47125SYifei Jiang     switch (run->riscv_sbi.extension_id) {
8744eb47125SYifei Jiang     case SBI_EXT_0_1_CONSOLE_PUTCHAR:
8754eb47125SYifei Jiang         ch = run->riscv_sbi.args[0];
8764eb47125SYifei Jiang         qemu_chr_fe_write(serial_hd(0)->be, &ch, sizeof(ch));
8774eb47125SYifei Jiang         break;
8784eb47125SYifei Jiang     case SBI_EXT_0_1_CONSOLE_GETCHAR:
8794eb47125SYifei Jiang         ret = qemu_chr_fe_read_all(serial_hd(0)->be, &ch, sizeof(ch));
8804eb47125SYifei Jiang         if (ret == sizeof(ch)) {
881947bf7feSVladimir Isaev             run->riscv_sbi.ret[0] = ch;
8824eb47125SYifei Jiang         } else {
883947bf7feSVladimir Isaev             run->riscv_sbi.ret[0] = -1;
8844eb47125SYifei Jiang         }
885947bf7feSVladimir Isaev         ret = 0;
8864eb47125SYifei Jiang         break;
8874eb47125SYifei Jiang     default:
8884eb47125SYifei Jiang         qemu_log_mask(LOG_UNIMP,
8894eb47125SYifei Jiang                       "%s: un-handled SBI EXIT, specific reasons is %lu\n",
8904eb47125SYifei Jiang                       __func__, run->riscv_sbi.extension_id);
8914eb47125SYifei Jiang         ret = -1;
8924eb47125SYifei Jiang         break;
8934eb47125SYifei Jiang     }
8944eb47125SYifei Jiang     return ret;
8954eb47125SYifei Jiang }
8964eb47125SYifei Jiang 
89791654e61SYifei Jiang int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
89891654e61SYifei Jiang {
8994eb47125SYifei Jiang     int ret = 0;
9004eb47125SYifei Jiang     switch (run->exit_reason) {
9014eb47125SYifei Jiang     case KVM_EXIT_RISCV_SBI:
9024eb47125SYifei Jiang         ret = kvm_riscv_handle_sbi(cs, run);
9034eb47125SYifei Jiang         break;
9044eb47125SYifei Jiang     default:
9054eb47125SYifei Jiang         qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
9064eb47125SYifei Jiang                       __func__, run->exit_reason);
9074eb47125SYifei Jiang         ret = -1;
9084eb47125SYifei Jiang         break;
9094eb47125SYifei Jiang     }
9104eb47125SYifei Jiang     return ret;
91191654e61SYifei Jiang }
91291654e61SYifei Jiang 
913ad40be27SYifei Jiang void kvm_riscv_reset_vcpu(RISCVCPU *cpu)
914ad40be27SYifei Jiang {
915ad40be27SYifei Jiang     CPURISCVState *env = &cpu->env;
916ad40be27SYifei Jiang 
917ad40be27SYifei Jiang     if (!kvm_enabled()) {
918ad40be27SYifei Jiang         return;
919ad40be27SYifei Jiang     }
920ad40be27SYifei Jiang     env->pc = cpu->env.kernel_addr;
921ad40be27SYifei Jiang     env->gpr[10] = kvm_arch_vcpu_id(CPU(cpu)); /* a0 */
922ad40be27SYifei Jiang     env->gpr[11] = cpu->env.fdt_addr;          /* a1 */
923ad40be27SYifei Jiang     env->satp = 0;
924ad40be27SYifei Jiang }
925ad40be27SYifei Jiang 
9262b650fbbSYifei Jiang void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level)
9272b650fbbSYifei Jiang {
9282b650fbbSYifei Jiang     int ret;
9292b650fbbSYifei Jiang     unsigned virq = level ? KVM_INTERRUPT_SET : KVM_INTERRUPT_UNSET;
9302b650fbbSYifei Jiang 
9312b650fbbSYifei Jiang     if (irq != IRQ_S_EXT) {
9322b650fbbSYifei Jiang         perror("kvm riscv set irq != IRQ_S_EXT\n");
9332b650fbbSYifei Jiang         abort();
9342b650fbbSYifei Jiang     }
9352b650fbbSYifei Jiang 
9362b650fbbSYifei Jiang     ret = kvm_vcpu_ioctl(CPU(cpu), KVM_INTERRUPT, &virq);
9372b650fbbSYifei Jiang     if (ret < 0) {
9382b650fbbSYifei Jiang         perror("Set irq failed");
9392b650fbbSYifei Jiang         abort();
9402b650fbbSYifei Jiang     }
9412b650fbbSYifei Jiang }
9422b650fbbSYifei Jiang 
94391654e61SYifei Jiang bool kvm_arch_cpu_check_are_resettable(void)
94491654e61SYifei Jiang {
94591654e61SYifei Jiang     return true;
94691654e61SYifei Jiang }
9473dba0a33SPaolo Bonzini 
9483dba0a33SPaolo Bonzini void kvm_arch_accel_class_init(ObjectClass *oc)
9493dba0a33SPaolo Bonzini {
9503dba0a33SPaolo Bonzini }
951