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> 210d71f0a3SDaniel Henrique Barboza #include <sys/prctl.h> 2291654e61SYifei Jiang 2391654e61SYifei Jiang #include <linux/kvm.h> 2491654e61SYifei Jiang 2591654e61SYifei Jiang #include "qemu/timer.h" 2692becce5SDaniel Henrique Barboza #include "qapi/error.h" 2791654e61SYifei Jiang #include "qemu/error-report.h" 2891654e61SYifei Jiang #include "qemu/main-loop.h" 2992becce5SDaniel Henrique Barboza #include "qapi/visitor.h" 3091654e61SYifei Jiang #include "sysemu/sysemu.h" 3191654e61SYifei Jiang #include "sysemu/kvm.h" 3291654e61SYifei Jiang #include "sysemu/kvm_int.h" 3391654e61SYifei Jiang #include "cpu.h" 3491654e61SYifei Jiang #include "trace.h" 35d86c25b2SDaniel Henrique Barboza #include "hw/core/accel-cpu.h" 3691654e61SYifei Jiang #include "hw/pci/pci.h" 3791654e61SYifei Jiang #include "exec/memattrs.h" 3891654e61SYifei Jiang #include "exec/address-spaces.h" 3991654e61SYifei Jiang #include "hw/boards.h" 4091654e61SYifei Jiang #include "hw/irq.h" 419634ef7eSYong-Xuan Wang #include "hw/intc/riscv_imsic.h" 4291654e61SYifei Jiang #include "qemu/log.h" 4391654e61SYifei Jiang #include "hw/loader.h" 44ad40be27SYifei Jiang #include "kvm_riscv.h" 454eb47125SYifei Jiang #include "sbi_ecall_interface.h" 464eb47125SYifei Jiang #include "chardev/char-fe.h" 4727abe66fSYifei Jiang #include "migration/migration.h" 489ad3e016SYifei Jiang #include "sysemu/runstate.h" 499634ef7eSYong-Xuan Wang #include "hw/riscv/numa.h" 5091654e61SYifei Jiang 510d71f0a3SDaniel Henrique Barboza #define PR_RISCV_V_SET_CONTROL 69 520d71f0a3SDaniel Henrique Barboza #define PR_RISCV_V_VSTATE_CTRL_ON 2 530d71f0a3SDaniel Henrique Barboza 54b8156640SDaniel Henrique Barboza void riscv_kvm_aplic_request(void *opaque, int irq, int level) 55b8156640SDaniel Henrique Barboza { 56b8156640SDaniel Henrique Barboza kvm_set_irq(kvm_state, irq, !!level); 57b8156640SDaniel Henrique Barboza } 58b8156640SDaniel Henrique Barboza 5986339515Sliguang.zhang static bool cap_has_mp_state; 6086339515Sliguang.zhang 61da14fc74SDaniel Henrique Barboza static uint64_t kvm_riscv_reg_id_ulong(CPURISCVState *env, uint64_t type, 620a312b85SYifei Jiang uint64_t idx) 630a312b85SYifei Jiang { 640a312b85SYifei Jiang uint64_t id = KVM_REG_RISCV | type | idx; 650a312b85SYifei Jiang 660a312b85SYifei Jiang switch (riscv_cpu_mxl(env)) { 670a312b85SYifei Jiang case MXL_RV32: 680a312b85SYifei Jiang id |= KVM_REG_SIZE_U32; 690a312b85SYifei Jiang break; 700a312b85SYifei Jiang case MXL_RV64: 710a312b85SYifei Jiang id |= KVM_REG_SIZE_U64; 720a312b85SYifei Jiang break; 730a312b85SYifei Jiang default: 740a312b85SYifei Jiang g_assert_not_reached(); 750a312b85SYifei Jiang } 760a312b85SYifei Jiang return id; 770a312b85SYifei Jiang } 780a312b85SYifei Jiang 7949c211ffSDaniel Henrique Barboza static uint64_t kvm_riscv_reg_id_u32(uint64_t type, uint64_t idx) 8049c211ffSDaniel Henrique Barboza { 8149c211ffSDaniel Henrique Barboza return KVM_REG_RISCV | KVM_REG_SIZE_U32 | type | idx; 8249c211ffSDaniel Henrique Barboza } 8349c211ffSDaniel Henrique Barboza 84450bd661SDaniel Henrique Barboza static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx) 85450bd661SDaniel Henrique Barboza { 86450bd661SDaniel Henrique Barboza return KVM_REG_RISCV | KVM_REG_SIZE_U64 | type | idx; 87450bd661SDaniel Henrique Barboza } 88450bd661SDaniel Henrique Barboza 89*6f4a6248SDaniel Henrique Barboza static uint64_t kvm_encode_reg_size_id(uint64_t id, size_t size_b) 90*6f4a6248SDaniel Henrique Barboza { 91*6f4a6248SDaniel Henrique Barboza uint64_t size_ctz = __builtin_ctz(size_b); 92*6f4a6248SDaniel Henrique Barboza 93*6f4a6248SDaniel Henrique Barboza return id | (size_ctz << KVM_REG_SIZE_SHIFT); 94*6f4a6248SDaniel Henrique Barboza } 95*6f4a6248SDaniel Henrique Barboza 96*6f4a6248SDaniel Henrique Barboza static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu, 97*6f4a6248SDaniel Henrique Barboza uint64_t idx) 98*6f4a6248SDaniel Henrique Barboza { 99*6f4a6248SDaniel Henrique Barboza uint64_t id; 100*6f4a6248SDaniel Henrique Barboza size_t size_b; 101*6f4a6248SDaniel Henrique Barboza 102*6f4a6248SDaniel Henrique Barboza g_assert(idx < 32); 103*6f4a6248SDaniel Henrique Barboza 104*6f4a6248SDaniel Henrique Barboza id = KVM_REG_RISCV | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_REG(idx); 105*6f4a6248SDaniel Henrique Barboza size_b = cpu->cfg.vlenb; 106*6f4a6248SDaniel Henrique Barboza 107*6f4a6248SDaniel Henrique Barboza return kvm_encode_reg_size_id(id, size_b); 108*6f4a6248SDaniel Henrique Barboza } 109*6f4a6248SDaniel Henrique Barboza 110da14fc74SDaniel Henrique Barboza #define RISCV_CORE_REG(env, name) \ 111da14fc74SDaniel Henrique Barboza kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, \ 112937f0b45SYifei Jiang KVM_REG_RISCV_CORE_REG(name)) 113937f0b45SYifei Jiang 114da14fc74SDaniel Henrique Barboza #define RISCV_CSR_REG(env, name) \ 115da14fc74SDaniel Henrique Barboza kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CSR, \ 116937f0b45SYifei Jiang KVM_REG_RISCV_CSR_REG(name)) 117937f0b45SYifei Jiang 118f25974f4SDaniel Henrique Barboza #define RISCV_CONFIG_REG(env, name) \ 119da14fc74SDaniel Henrique Barboza kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, \ 120f25974f4SDaniel Henrique Barboza KVM_REG_RISCV_CONFIG_REG(name)) 121f25974f4SDaniel Henrique Barboza 12210f86d1bSDaniel Henrique Barboza #define RISCV_TIMER_REG(name) kvm_riscv_reg_id_u64(KVM_REG_RISCV_TIMER, \ 12327abe66fSYifei Jiang KVM_REG_RISCV_TIMER_REG(name)) 12427abe66fSYifei Jiang 12549c211ffSDaniel Henrique Barboza #define RISCV_FP_F_REG(idx) kvm_riscv_reg_id_u32(KVM_REG_RISCV_FP_F, idx) 126937f0b45SYifei Jiang 127450bd661SDaniel Henrique Barboza #define RISCV_FP_D_REG(idx) kvm_riscv_reg_id_u64(KVM_REG_RISCV_FP_D, idx) 128937f0b45SYifei Jiang 1293ca78c06SDaniel Henrique Barboza #define RISCV_VECTOR_CSR_REG(env, name) \ 1303ca78c06SDaniel Henrique Barboza kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_VECTOR, \ 1313ca78c06SDaniel Henrique Barboza KVM_REG_RISCV_VECTOR_CSR_REG(name)) 1323ca78c06SDaniel Henrique Barboza 133937f0b45SYifei Jiang #define KVM_RISCV_GET_CSR(cs, env, csr, reg) \ 134937f0b45SYifei Jiang do { \ 135560b8e1dSDaniel Henrique Barboza int _ret = kvm_get_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \ 136560b8e1dSDaniel Henrique Barboza if (_ret) { \ 137560b8e1dSDaniel Henrique Barboza return _ret; \ 138937f0b45SYifei Jiang } \ 139937f0b45SYifei Jiang } while (0) 140937f0b45SYifei Jiang 1419997cc1eSYifei Jiang #define KVM_RISCV_SET_CSR(cs, env, csr, reg) \ 1429997cc1eSYifei Jiang do { \ 143560b8e1dSDaniel Henrique Barboza int _ret = kvm_set_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \ 144560b8e1dSDaniel Henrique Barboza if (_ret) { \ 145560b8e1dSDaniel Henrique Barboza return _ret; \ 1469997cc1eSYifei Jiang } \ 1479997cc1eSYifei Jiang } while (0) 1489997cc1eSYifei Jiang 14910f86d1bSDaniel Henrique Barboza #define KVM_RISCV_GET_TIMER(cs, name, reg) \ 15027abe66fSYifei Jiang do { \ 15110f86d1bSDaniel Henrique Barboza int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(name), ®); \ 15227abe66fSYifei Jiang if (ret) { \ 15327abe66fSYifei Jiang abort(); \ 15427abe66fSYifei Jiang } \ 15527abe66fSYifei Jiang } while (0) 15627abe66fSYifei Jiang 15710f86d1bSDaniel Henrique Barboza #define KVM_RISCV_SET_TIMER(cs, name, reg) \ 15827abe66fSYifei Jiang do { \ 15910f86d1bSDaniel Henrique Barboza int ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(name), ®); \ 16027abe66fSYifei Jiang if (ret) { \ 16127abe66fSYifei Jiang abort(); \ 16227abe66fSYifei Jiang } \ 16327abe66fSYifei Jiang } while (0) 16427abe66fSYifei Jiang 16592becce5SDaniel Henrique Barboza typedef struct KVMCPUConfig { 16692becce5SDaniel Henrique Barboza const char *name; 16792becce5SDaniel Henrique Barboza const char *description; 16892becce5SDaniel Henrique Barboza target_ulong offset; 169fafb0dc4SDaniel Henrique Barboza uint64_t kvm_reg_id; 17092becce5SDaniel Henrique Barboza bool user_set; 171f7a69fa6SDaniel Henrique Barboza bool supported; 17292becce5SDaniel Henrique Barboza } KVMCPUConfig; 17392becce5SDaniel Henrique Barboza 17492becce5SDaniel Henrique Barboza #define KVM_MISA_CFG(_bit, _reg_id) \ 17592becce5SDaniel Henrique Barboza {.offset = _bit, .kvm_reg_id = _reg_id} 17692becce5SDaniel Henrique Barboza 17792becce5SDaniel Henrique Barboza /* KVM ISA extensions */ 17892becce5SDaniel Henrique Barboza static KVMCPUConfig kvm_misa_ext_cfgs[] = { 17992becce5SDaniel Henrique Barboza KVM_MISA_CFG(RVA, KVM_RISCV_ISA_EXT_A), 18092becce5SDaniel Henrique Barboza KVM_MISA_CFG(RVC, KVM_RISCV_ISA_EXT_C), 18192becce5SDaniel Henrique Barboza KVM_MISA_CFG(RVD, KVM_RISCV_ISA_EXT_D), 18292becce5SDaniel Henrique Barboza KVM_MISA_CFG(RVF, KVM_RISCV_ISA_EXT_F), 18392becce5SDaniel Henrique Barboza KVM_MISA_CFG(RVH, KVM_RISCV_ISA_EXT_H), 18492becce5SDaniel Henrique Barboza KVM_MISA_CFG(RVI, KVM_RISCV_ISA_EXT_I), 18592becce5SDaniel Henrique Barboza KVM_MISA_CFG(RVM, KVM_RISCV_ISA_EXT_M), 1863ca78c06SDaniel Henrique Barboza KVM_MISA_CFG(RVV, KVM_RISCV_ISA_EXT_V), 18792becce5SDaniel Henrique Barboza }; 18892becce5SDaniel Henrique Barboza 189456a6554SDaniel Henrique Barboza static void kvm_cpu_get_misa_ext_cfg(Object *obj, Visitor *v, 190456a6554SDaniel Henrique Barboza const char *name, 191456a6554SDaniel Henrique Barboza void *opaque, Error **errp) 192456a6554SDaniel Henrique Barboza { 193456a6554SDaniel Henrique Barboza KVMCPUConfig *misa_ext_cfg = opaque; 194456a6554SDaniel Henrique Barboza target_ulong misa_bit = misa_ext_cfg->offset; 195456a6554SDaniel Henrique Barboza RISCVCPU *cpu = RISCV_CPU(obj); 196456a6554SDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 197456a6554SDaniel Henrique Barboza bool value = env->misa_ext_mask & misa_bit; 198456a6554SDaniel Henrique Barboza 199456a6554SDaniel Henrique Barboza visit_type_bool(v, name, &value, errp); 200456a6554SDaniel Henrique Barboza } 201456a6554SDaniel Henrique Barboza 20292becce5SDaniel Henrique Barboza static void kvm_cpu_set_misa_ext_cfg(Object *obj, Visitor *v, 20392becce5SDaniel Henrique Barboza const char *name, 20492becce5SDaniel Henrique Barboza void *opaque, Error **errp) 20592becce5SDaniel Henrique Barboza { 20692becce5SDaniel Henrique Barboza KVMCPUConfig *misa_ext_cfg = opaque; 20792becce5SDaniel Henrique Barboza target_ulong misa_bit = misa_ext_cfg->offset; 20892becce5SDaniel Henrique Barboza RISCVCPU *cpu = RISCV_CPU(obj); 20992becce5SDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 21092becce5SDaniel Henrique Barboza bool value, host_bit; 21192becce5SDaniel Henrique Barboza 21292becce5SDaniel Henrique Barboza if (!visit_type_bool(v, name, &value, errp)) { 21392becce5SDaniel Henrique Barboza return; 21492becce5SDaniel Henrique Barboza } 21592becce5SDaniel Henrique Barboza 21692becce5SDaniel Henrique Barboza host_bit = env->misa_ext_mask & misa_bit; 21792becce5SDaniel Henrique Barboza 21892becce5SDaniel Henrique Barboza if (value == host_bit) { 21992becce5SDaniel Henrique Barboza return; 22092becce5SDaniel Henrique Barboza } 22192becce5SDaniel Henrique Barboza 22292becce5SDaniel Henrique Barboza if (!value) { 22392becce5SDaniel Henrique Barboza misa_ext_cfg->user_set = true; 22492becce5SDaniel Henrique Barboza return; 22592becce5SDaniel Henrique Barboza } 22692becce5SDaniel Henrique Barboza 22792becce5SDaniel Henrique Barboza /* 22892becce5SDaniel Henrique Barboza * Forbid users to enable extensions that aren't 22992becce5SDaniel Henrique Barboza * available in the hart. 23092becce5SDaniel Henrique Barboza */ 23192becce5SDaniel Henrique Barboza error_setg(errp, "Enabling MISA bit '%s' is not allowed: it's not " 23292becce5SDaniel Henrique Barboza "enabled in the host", misa_ext_cfg->name); 23392becce5SDaniel Henrique Barboza } 23492becce5SDaniel Henrique Barboza 2357313fffbSDaniel Henrique Barboza static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs) 2367313fffbSDaniel Henrique Barboza { 2377313fffbSDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 2387313fffbSDaniel Henrique Barboza uint64_t id, reg; 2397313fffbSDaniel Henrique Barboza int i, ret; 2407313fffbSDaniel Henrique Barboza 2417313fffbSDaniel Henrique Barboza for (i = 0; i < ARRAY_SIZE(kvm_misa_ext_cfgs); i++) { 2427313fffbSDaniel Henrique Barboza KVMCPUConfig *misa_cfg = &kvm_misa_ext_cfgs[i]; 2437313fffbSDaniel Henrique Barboza target_ulong misa_bit = misa_cfg->offset; 2447313fffbSDaniel Henrique Barboza 2457313fffbSDaniel Henrique Barboza if (!misa_cfg->user_set) { 2467313fffbSDaniel Henrique Barboza continue; 2477313fffbSDaniel Henrique Barboza } 2487313fffbSDaniel Henrique Barboza 2497313fffbSDaniel Henrique Barboza /* If we're here we're going to disable the MISA bit */ 2507313fffbSDaniel Henrique Barboza reg = 0; 251da14fc74SDaniel Henrique Barboza id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT, 2527313fffbSDaniel Henrique Barboza misa_cfg->kvm_reg_id); 2537313fffbSDaniel Henrique Barboza ret = kvm_set_one_reg(cs, id, ®); 2547313fffbSDaniel Henrique Barboza if (ret != 0) { 2557313fffbSDaniel Henrique Barboza /* 2567313fffbSDaniel Henrique Barboza * We're not checking for -EINVAL because if the bit is about 2577313fffbSDaniel Henrique Barboza * to be disabled, it means that it was already enabled by 2587313fffbSDaniel Henrique Barboza * KVM. We determined that by fetching the 'isa' register 2597313fffbSDaniel Henrique Barboza * during init() time. Any error at this point is worth 2607313fffbSDaniel Henrique Barboza * aborting. 2617313fffbSDaniel Henrique Barboza */ 2627313fffbSDaniel Henrique Barboza error_report("Unable to set KVM reg %s, error %d", 2637313fffbSDaniel Henrique Barboza misa_cfg->name, ret); 2647313fffbSDaniel Henrique Barboza exit(EXIT_FAILURE); 2657313fffbSDaniel Henrique Barboza } 2667313fffbSDaniel Henrique Barboza env->misa_ext &= ~misa_bit; 2677313fffbSDaniel Henrique Barboza } 2687313fffbSDaniel Henrique Barboza } 2697313fffbSDaniel Henrique Barboza 270f7a69fa6SDaniel Henrique Barboza #define KVM_EXT_CFG(_name, _prop, _reg_id) \ 271238fd586SDaniel Henrique Barboza {.name = _name, .offset = CPU_CFG_OFFSET(_prop), \ 272f7a69fa6SDaniel Henrique Barboza .kvm_reg_id = _reg_id} 273f7a69fa6SDaniel Henrique Barboza 274f7a69fa6SDaniel Henrique Barboza static KVMCPUConfig kvm_multi_ext_cfgs[] = { 275a326a2b0SDaniel Henrique Barboza KVM_EXT_CFG("zicbom", ext_zicbom, KVM_RISCV_ISA_EXT_ZICBOM), 276e57039ddSDaniel Henrique Barboza KVM_EXT_CFG("zicboz", ext_zicboz, KVM_RISCV_ISA_EXT_ZICBOZ), 277b31dee8aSDaniel Henrique Barboza KVM_EXT_CFG("zicntr", ext_zicntr, KVM_RISCV_ISA_EXT_ZICNTR), 278672ec606SDaniel Henrique Barboza KVM_EXT_CFG("zicsr", ext_zicsr, KVM_RISCV_ISA_EXT_ZICSR), 279672ec606SDaniel Henrique Barboza KVM_EXT_CFG("zifencei", ext_zifencei, KVM_RISCV_ISA_EXT_ZIFENCEI), 280f7a69fa6SDaniel Henrique Barboza KVM_EXT_CFG("zihintpause", ext_zihintpause, KVM_RISCV_ISA_EXT_ZIHINTPAUSE), 281b4ceb3f2SDaniel Henrique Barboza KVM_EXT_CFG("zihpm", ext_zihpm, KVM_RISCV_ISA_EXT_ZIHPM), 282672ec606SDaniel Henrique Barboza KVM_EXT_CFG("zba", ext_zba, KVM_RISCV_ISA_EXT_ZBA), 283f7a69fa6SDaniel Henrique Barboza KVM_EXT_CFG("zbb", ext_zbb, KVM_RISCV_ISA_EXT_ZBB), 284672ec606SDaniel Henrique Barboza KVM_EXT_CFG("zbs", ext_zbs, KVM_RISCV_ISA_EXT_ZBS), 285f7a69fa6SDaniel Henrique Barboza KVM_EXT_CFG("ssaia", ext_ssaia, KVM_RISCV_ISA_EXT_SSAIA), 286f7a69fa6SDaniel Henrique Barboza KVM_EXT_CFG("sstc", ext_sstc, KVM_RISCV_ISA_EXT_SSTC), 287f7a69fa6SDaniel Henrique Barboza KVM_EXT_CFG("svinval", ext_svinval, KVM_RISCV_ISA_EXT_SVINVAL), 288672ec606SDaniel Henrique Barboza KVM_EXT_CFG("svnapot", ext_svnapot, KVM_RISCV_ISA_EXT_SVNAPOT), 289f7a69fa6SDaniel Henrique Barboza KVM_EXT_CFG("svpbmt", ext_svpbmt, KVM_RISCV_ISA_EXT_SVPBMT), 290f7a69fa6SDaniel Henrique Barboza }; 291f7a69fa6SDaniel Henrique Barboza 292a1be1d9aSDaniel Henrique Barboza static void *kvmconfig_get_cfg_addr(RISCVCPU *cpu, KVMCPUConfig *kvmcfg) 293a1be1d9aSDaniel Henrique Barboza { 294a1be1d9aSDaniel Henrique Barboza return (void *)&cpu->cfg + kvmcfg->offset; 295a1be1d9aSDaniel Henrique Barboza } 296a1be1d9aSDaniel Henrique Barboza 297f7a69fa6SDaniel Henrique Barboza static void kvm_cpu_cfg_set(RISCVCPU *cpu, KVMCPUConfig *multi_ext, 298f7a69fa6SDaniel Henrique Barboza uint32_t val) 299f7a69fa6SDaniel Henrique Barboza { 300a1be1d9aSDaniel Henrique Barboza bool *ext_enabled = kvmconfig_get_cfg_addr(cpu, multi_ext); 301f7a69fa6SDaniel Henrique Barboza 302f7a69fa6SDaniel Henrique Barboza *ext_enabled = val; 303f7a69fa6SDaniel Henrique Barboza } 304f7a69fa6SDaniel Henrique Barboza 305f7a69fa6SDaniel Henrique Barboza static uint32_t kvm_cpu_cfg_get(RISCVCPU *cpu, 306f7a69fa6SDaniel Henrique Barboza KVMCPUConfig *multi_ext) 307f7a69fa6SDaniel Henrique Barboza { 308a1be1d9aSDaniel Henrique Barboza bool *ext_enabled = kvmconfig_get_cfg_addr(cpu, multi_ext); 309f7a69fa6SDaniel Henrique Barboza 310f7a69fa6SDaniel Henrique Barboza return *ext_enabled; 311f7a69fa6SDaniel Henrique Barboza } 312f7a69fa6SDaniel Henrique Barboza 313456a6554SDaniel Henrique Barboza static void kvm_cpu_get_multi_ext_cfg(Object *obj, Visitor *v, 314456a6554SDaniel Henrique Barboza const char *name, 315456a6554SDaniel Henrique Barboza void *opaque, Error **errp) 316456a6554SDaniel Henrique Barboza { 317456a6554SDaniel Henrique Barboza KVMCPUConfig *multi_ext_cfg = opaque; 318456a6554SDaniel Henrique Barboza RISCVCPU *cpu = RISCV_CPU(obj); 319456a6554SDaniel Henrique Barboza bool value = kvm_cpu_cfg_get(cpu, multi_ext_cfg); 320456a6554SDaniel Henrique Barboza 321456a6554SDaniel Henrique Barboza visit_type_bool(v, name, &value, errp); 322456a6554SDaniel Henrique Barboza } 323456a6554SDaniel Henrique Barboza 324f7a69fa6SDaniel Henrique Barboza static void kvm_cpu_set_multi_ext_cfg(Object *obj, Visitor *v, 325f7a69fa6SDaniel Henrique Barboza const char *name, 326f7a69fa6SDaniel Henrique Barboza void *opaque, Error **errp) 327f7a69fa6SDaniel Henrique Barboza { 328f7a69fa6SDaniel Henrique Barboza KVMCPUConfig *multi_ext_cfg = opaque; 329f7a69fa6SDaniel Henrique Barboza RISCVCPU *cpu = RISCV_CPU(obj); 330f7a69fa6SDaniel Henrique Barboza bool value, host_val; 331f7a69fa6SDaniel Henrique Barboza 332f7a69fa6SDaniel Henrique Barboza if (!visit_type_bool(v, name, &value, errp)) { 333f7a69fa6SDaniel Henrique Barboza return; 334f7a69fa6SDaniel Henrique Barboza } 335f7a69fa6SDaniel Henrique Barboza 336f7a69fa6SDaniel Henrique Barboza host_val = kvm_cpu_cfg_get(cpu, multi_ext_cfg); 337f7a69fa6SDaniel Henrique Barboza 338f7a69fa6SDaniel Henrique Barboza /* 339f7a69fa6SDaniel Henrique Barboza * Ignore if the user is setting the same value 340f7a69fa6SDaniel Henrique Barboza * as the host. 341f7a69fa6SDaniel Henrique Barboza */ 342f7a69fa6SDaniel Henrique Barboza if (value == host_val) { 343f7a69fa6SDaniel Henrique Barboza return; 344f7a69fa6SDaniel Henrique Barboza } 345f7a69fa6SDaniel Henrique Barboza 346f7a69fa6SDaniel Henrique Barboza if (!multi_ext_cfg->supported) { 347f7a69fa6SDaniel Henrique Barboza /* 348f7a69fa6SDaniel Henrique Barboza * Error out if the user is trying to enable an 349f7a69fa6SDaniel Henrique Barboza * extension that KVM doesn't support. Ignore 350f7a69fa6SDaniel Henrique Barboza * option otherwise. 351f7a69fa6SDaniel Henrique Barboza */ 352f7a69fa6SDaniel Henrique Barboza if (value) { 353f7a69fa6SDaniel Henrique Barboza error_setg(errp, "KVM does not support disabling extension %s", 354f7a69fa6SDaniel Henrique Barboza multi_ext_cfg->name); 355f7a69fa6SDaniel Henrique Barboza } 356f7a69fa6SDaniel Henrique Barboza 357f7a69fa6SDaniel Henrique Barboza return; 358f7a69fa6SDaniel Henrique Barboza } 359f7a69fa6SDaniel Henrique Barboza 360f7a69fa6SDaniel Henrique Barboza multi_ext_cfg->user_set = true; 361f7a69fa6SDaniel Henrique Barboza kvm_cpu_cfg_set(cpu, multi_ext_cfg, value); 362f7a69fa6SDaniel Henrique Barboza } 363f7a69fa6SDaniel Henrique Barboza 364b9f82221SDaniel Henrique Barboza static KVMCPUConfig kvm_cbom_blocksize = { 365b9f82221SDaniel Henrique Barboza .name = "cbom_blocksize", 366238fd586SDaniel Henrique Barboza .offset = CPU_CFG_OFFSET(cbom_blocksize), 367b9f82221SDaniel Henrique Barboza .kvm_reg_id = KVM_REG_RISCV_CONFIG_REG(zicbom_block_size) 368b9f82221SDaniel Henrique Barboza }; 369b9f82221SDaniel Henrique Barboza 370b9f82221SDaniel Henrique Barboza static KVMCPUConfig kvm_cboz_blocksize = { 371b9f82221SDaniel Henrique Barboza .name = "cboz_blocksize", 372238fd586SDaniel Henrique Barboza .offset = CPU_CFG_OFFSET(cboz_blocksize), 373b9f82221SDaniel Henrique Barboza .kvm_reg_id = KVM_REG_RISCV_CONFIG_REG(zicboz_block_size) 374b9f82221SDaniel Henrique Barboza }; 375b9f82221SDaniel Henrique Barboza 376d4ff3da8SDaniel Henrique Barboza static KVMCPUConfig kvm_v_vlenb = { 377d4ff3da8SDaniel Henrique Barboza .name = "vlenb", 378d4ff3da8SDaniel Henrique Barboza .offset = CPU_CFG_OFFSET(vlenb), 379d4ff3da8SDaniel Henrique Barboza .kvm_reg_id = KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_VECTOR | 380d4ff3da8SDaniel Henrique Barboza KVM_REG_RISCV_VECTOR_CSR_REG(vlenb) 381d4ff3da8SDaniel Henrique Barboza }; 382d4ff3da8SDaniel Henrique Barboza 383df817297SDaniel Henrique Barboza static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs) 384df817297SDaniel Henrique Barboza { 385df817297SDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 386df817297SDaniel Henrique Barboza uint64_t id, reg; 387df817297SDaniel Henrique Barboza int i, ret; 388df817297SDaniel Henrique Barboza 389df817297SDaniel Henrique Barboza for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) { 390df817297SDaniel Henrique Barboza KVMCPUConfig *multi_ext_cfg = &kvm_multi_ext_cfgs[i]; 391df817297SDaniel Henrique Barboza 392df817297SDaniel Henrique Barboza if (!multi_ext_cfg->user_set) { 393df817297SDaniel Henrique Barboza continue; 394df817297SDaniel Henrique Barboza } 395df817297SDaniel Henrique Barboza 396da14fc74SDaniel Henrique Barboza id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT, 397df817297SDaniel Henrique Barboza multi_ext_cfg->kvm_reg_id); 398df817297SDaniel Henrique Barboza reg = kvm_cpu_cfg_get(cpu, multi_ext_cfg); 399df817297SDaniel Henrique Barboza ret = kvm_set_one_reg(cs, id, ®); 400df817297SDaniel Henrique Barboza if (ret != 0) { 401df817297SDaniel Henrique Barboza error_report("Unable to %s extension %s in KVM, error %d", 402df817297SDaniel Henrique Barboza reg ? "enable" : "disable", 403df817297SDaniel Henrique Barboza multi_ext_cfg->name, ret); 404df817297SDaniel Henrique Barboza exit(EXIT_FAILURE); 405df817297SDaniel Henrique Barboza } 406df817297SDaniel Henrique Barboza } 407df817297SDaniel Henrique Barboza } 408df817297SDaniel Henrique Barboza 409456a6554SDaniel Henrique Barboza static void cpu_get_cfg_unavailable(Object *obj, Visitor *v, 410456a6554SDaniel Henrique Barboza const char *name, 411456a6554SDaniel Henrique Barboza void *opaque, Error **errp) 412456a6554SDaniel Henrique Barboza { 413456a6554SDaniel Henrique Barboza bool value = false; 414456a6554SDaniel Henrique Barboza 415456a6554SDaniel Henrique Barboza visit_type_bool(v, name, &value, errp); 416456a6554SDaniel Henrique Barboza } 417456a6554SDaniel Henrique Barboza 41832fa1776SDaniel Henrique Barboza static void cpu_set_cfg_unavailable(Object *obj, Visitor *v, 41932fa1776SDaniel Henrique Barboza const char *name, 42032fa1776SDaniel Henrique Barboza void *opaque, Error **errp) 42132fa1776SDaniel Henrique Barboza { 42232fa1776SDaniel Henrique Barboza const char *propname = opaque; 42332fa1776SDaniel Henrique Barboza bool value; 42432fa1776SDaniel Henrique Barboza 42532fa1776SDaniel Henrique Barboza if (!visit_type_bool(v, name, &value, errp)) { 42632fa1776SDaniel Henrique Barboza return; 42732fa1776SDaniel Henrique Barboza } 42832fa1776SDaniel Henrique Barboza 42932fa1776SDaniel Henrique Barboza if (value) { 4301a567c5cSDaniel Henrique Barboza error_setg(errp, "'%s' is not available with KVM", 43132fa1776SDaniel Henrique Barboza propname); 43232fa1776SDaniel Henrique Barboza } 43332fa1776SDaniel Henrique Barboza } 43432fa1776SDaniel Henrique Barboza 43532fa1776SDaniel Henrique Barboza static void riscv_cpu_add_kvm_unavail_prop(Object *obj, const char *prop_name) 43632fa1776SDaniel Henrique Barboza { 43732fa1776SDaniel Henrique Barboza /* Check if KVM created the property already */ 43832fa1776SDaniel Henrique Barboza if (object_property_find(obj, prop_name)) { 43932fa1776SDaniel Henrique Barboza return; 44032fa1776SDaniel Henrique Barboza } 44132fa1776SDaniel Henrique Barboza 44232fa1776SDaniel Henrique Barboza /* 44332fa1776SDaniel Henrique Barboza * Set the default to disabled for every extension 44432fa1776SDaniel Henrique Barboza * unknown to KVM and error out if the user attempts 44532fa1776SDaniel Henrique Barboza * to enable any of them. 44632fa1776SDaniel Henrique Barboza */ 44732fa1776SDaniel Henrique Barboza object_property_add(obj, prop_name, "bool", 448456a6554SDaniel Henrique Barboza cpu_get_cfg_unavailable, 449456a6554SDaniel Henrique Barboza cpu_set_cfg_unavailable, 45032fa1776SDaniel Henrique Barboza NULL, (void *)prop_name); 45132fa1776SDaniel Henrique Barboza } 45232fa1776SDaniel Henrique Barboza 45332fa1776SDaniel Henrique Barboza static void riscv_cpu_add_kvm_unavail_prop_array(Object *obj, 45432fa1776SDaniel Henrique Barboza const RISCVCPUMultiExtConfig *array) 45532fa1776SDaniel Henrique Barboza { 45632fa1776SDaniel Henrique Barboza const RISCVCPUMultiExtConfig *prop; 45732fa1776SDaniel Henrique Barboza 45832fa1776SDaniel Henrique Barboza g_assert(array); 45932fa1776SDaniel Henrique Barboza 46032fa1776SDaniel Henrique Barboza for (prop = array; prop && prop->name; prop++) { 46132fa1776SDaniel Henrique Barboza riscv_cpu_add_kvm_unavail_prop(obj, prop->name); 46232fa1776SDaniel Henrique Barboza } 46332fa1776SDaniel Henrique Barboza } 46432fa1776SDaniel Henrique Barboza 46592becce5SDaniel Henrique Barboza static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj) 46692becce5SDaniel Henrique Barboza { 46792becce5SDaniel Henrique Barboza int i; 46892becce5SDaniel Henrique Barboza 469efa365b7SDaniel Henrique Barboza riscv_add_satp_mode_properties(cpu_obj); 470efa365b7SDaniel Henrique Barboza 47192becce5SDaniel Henrique Barboza for (i = 0; i < ARRAY_SIZE(kvm_misa_ext_cfgs); i++) { 47292becce5SDaniel Henrique Barboza KVMCPUConfig *misa_cfg = &kvm_misa_ext_cfgs[i]; 47392becce5SDaniel Henrique Barboza int bit = misa_cfg->offset; 47492becce5SDaniel Henrique Barboza 47592becce5SDaniel Henrique Barboza misa_cfg->name = riscv_get_misa_ext_name(bit); 47692becce5SDaniel Henrique Barboza misa_cfg->description = riscv_get_misa_ext_description(bit); 47792becce5SDaniel Henrique Barboza 47892becce5SDaniel Henrique Barboza object_property_add(cpu_obj, misa_cfg->name, "bool", 479456a6554SDaniel Henrique Barboza kvm_cpu_get_misa_ext_cfg, 48092becce5SDaniel Henrique Barboza kvm_cpu_set_misa_ext_cfg, 48192becce5SDaniel Henrique Barboza NULL, misa_cfg); 48292becce5SDaniel Henrique Barboza object_property_set_description(cpu_obj, misa_cfg->name, 48392becce5SDaniel Henrique Barboza misa_cfg->description); 48492becce5SDaniel Henrique Barboza } 485f7a69fa6SDaniel Henrique Barboza 486efa365b7SDaniel Henrique Barboza for (i = 0; misa_bits[i] != 0; i++) { 487efa365b7SDaniel Henrique Barboza const char *ext_name = riscv_get_misa_ext_name(misa_bits[i]); 488efa365b7SDaniel Henrique Barboza riscv_cpu_add_kvm_unavail_prop(cpu_obj, ext_name); 489efa365b7SDaniel Henrique Barboza } 490efa365b7SDaniel Henrique Barboza 491f7a69fa6SDaniel Henrique Barboza for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) { 492f7a69fa6SDaniel Henrique Barboza KVMCPUConfig *multi_cfg = &kvm_multi_ext_cfgs[i]; 493f7a69fa6SDaniel Henrique Barboza 494f7a69fa6SDaniel Henrique Barboza object_property_add(cpu_obj, multi_cfg->name, "bool", 495456a6554SDaniel Henrique Barboza kvm_cpu_get_multi_ext_cfg, 496f7a69fa6SDaniel Henrique Barboza kvm_cpu_set_multi_ext_cfg, 497f7a69fa6SDaniel Henrique Barboza NULL, multi_cfg); 498f7a69fa6SDaniel Henrique Barboza } 499b9f82221SDaniel Henrique Barboza 500efa365b7SDaniel Henrique Barboza riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_extensions); 501efa365b7SDaniel Henrique Barboza riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_vendor_exts); 502efa365b7SDaniel Henrique Barboza riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_experimental_exts); 5031a567c5cSDaniel Henrique Barboza 5041a567c5cSDaniel Henrique Barboza /* We don't have the needed KVM support for profiles */ 5051a567c5cSDaniel Henrique Barboza for (i = 0; riscv_profiles[i] != NULL; i++) { 5061a567c5cSDaniel Henrique Barboza riscv_cpu_add_kvm_unavail_prop(cpu_obj, riscv_profiles[i]->name); 5071a567c5cSDaniel Henrique Barboza } 50892becce5SDaniel Henrique Barboza } 50992becce5SDaniel Henrique Barboza 510937f0b45SYifei Jiang static int kvm_riscv_get_regs_core(CPUState *cs) 511937f0b45SYifei Jiang { 512937f0b45SYifei Jiang int ret = 0; 513937f0b45SYifei Jiang int i; 514937f0b45SYifei Jiang target_ulong reg; 515937f0b45SYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 516937f0b45SYifei Jiang 517937f0b45SYifei Jiang ret = kvm_get_one_reg(cs, RISCV_CORE_REG(env, regs.pc), ®); 518937f0b45SYifei Jiang if (ret) { 519937f0b45SYifei Jiang return ret; 520937f0b45SYifei Jiang } 521937f0b45SYifei Jiang env->pc = reg; 522937f0b45SYifei Jiang 523937f0b45SYifei Jiang for (i = 1; i < 32; i++) { 524da14fc74SDaniel Henrique Barboza uint64_t id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, i); 525937f0b45SYifei Jiang ret = kvm_get_one_reg(cs, id, ®); 526937f0b45SYifei Jiang if (ret) { 527937f0b45SYifei Jiang return ret; 528937f0b45SYifei Jiang } 529937f0b45SYifei Jiang env->gpr[i] = reg; 530937f0b45SYifei Jiang } 531937f0b45SYifei Jiang 532937f0b45SYifei Jiang return ret; 533937f0b45SYifei Jiang } 534937f0b45SYifei Jiang 5359997cc1eSYifei Jiang static int kvm_riscv_put_regs_core(CPUState *cs) 5369997cc1eSYifei Jiang { 5379997cc1eSYifei Jiang int ret = 0; 5389997cc1eSYifei Jiang int i; 5399997cc1eSYifei Jiang target_ulong reg; 5409997cc1eSYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 5419997cc1eSYifei Jiang 5429997cc1eSYifei Jiang reg = env->pc; 5439997cc1eSYifei Jiang ret = kvm_set_one_reg(cs, RISCV_CORE_REG(env, regs.pc), ®); 5449997cc1eSYifei Jiang if (ret) { 5459997cc1eSYifei Jiang return ret; 5469997cc1eSYifei Jiang } 5479997cc1eSYifei Jiang 5489997cc1eSYifei Jiang for (i = 1; i < 32; i++) { 549da14fc74SDaniel Henrique Barboza uint64_t id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, i); 5509997cc1eSYifei Jiang reg = env->gpr[i]; 5519997cc1eSYifei Jiang ret = kvm_set_one_reg(cs, id, ®); 5529997cc1eSYifei Jiang if (ret) { 5539997cc1eSYifei Jiang return ret; 5549997cc1eSYifei Jiang } 5559997cc1eSYifei Jiang } 5569997cc1eSYifei Jiang 5579997cc1eSYifei Jiang return ret; 5589997cc1eSYifei Jiang } 5599997cc1eSYifei Jiang 560937f0b45SYifei Jiang static int kvm_riscv_get_regs_csr(CPUState *cs) 561937f0b45SYifei Jiang { 562937f0b45SYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 563937f0b45SYifei Jiang 564937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, sstatus, env->mstatus); 565937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, sie, env->mie); 566937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, stvec, env->stvec); 567937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, sscratch, env->sscratch); 568937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, sepc, env->sepc); 569937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, scause, env->scause); 570937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, stval, env->stval); 571937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, sip, env->mip); 572937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, satp, env->satp); 573560b8e1dSDaniel Henrique Barboza 574560b8e1dSDaniel Henrique Barboza return 0; 575937f0b45SYifei Jiang } 576937f0b45SYifei Jiang 5779997cc1eSYifei Jiang static int kvm_riscv_put_regs_csr(CPUState *cs) 5789997cc1eSYifei Jiang { 5799997cc1eSYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 5809997cc1eSYifei Jiang 5819997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, sstatus, env->mstatus); 5829997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, sie, env->mie); 5839997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, stvec, env->stvec); 5849997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, sscratch, env->sscratch); 5859997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, sepc, env->sepc); 5869997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, scause, env->scause); 5879997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, stval, env->stval); 5889997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, sip, env->mip); 5899997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, satp, env->satp); 5909997cc1eSYifei Jiang 591560b8e1dSDaniel Henrique Barboza return 0; 5929997cc1eSYifei Jiang } 5939997cc1eSYifei Jiang 594937f0b45SYifei Jiang static int kvm_riscv_get_regs_fp(CPUState *cs) 595937f0b45SYifei Jiang { 596937f0b45SYifei Jiang int ret = 0; 597937f0b45SYifei Jiang int i; 598937f0b45SYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 599937f0b45SYifei Jiang 600937f0b45SYifei Jiang if (riscv_has_ext(env, RVD)) { 601937f0b45SYifei Jiang uint64_t reg; 602937f0b45SYifei Jiang for (i = 0; i < 32; i++) { 603450bd661SDaniel Henrique Barboza ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(i), ®); 604937f0b45SYifei Jiang if (ret) { 605937f0b45SYifei Jiang return ret; 606937f0b45SYifei Jiang } 607937f0b45SYifei Jiang env->fpr[i] = reg; 608937f0b45SYifei Jiang } 609937f0b45SYifei Jiang return ret; 610937f0b45SYifei Jiang } 611937f0b45SYifei Jiang 612937f0b45SYifei Jiang if (riscv_has_ext(env, RVF)) { 613937f0b45SYifei Jiang uint32_t reg; 614937f0b45SYifei Jiang for (i = 0; i < 32; i++) { 61549c211ffSDaniel Henrique Barboza ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(i), ®); 616937f0b45SYifei Jiang if (ret) { 617937f0b45SYifei Jiang return ret; 618937f0b45SYifei Jiang } 619937f0b45SYifei Jiang env->fpr[i] = reg; 620937f0b45SYifei Jiang } 621937f0b45SYifei Jiang return ret; 622937f0b45SYifei Jiang } 623937f0b45SYifei Jiang 624937f0b45SYifei Jiang return ret; 625937f0b45SYifei Jiang } 626937f0b45SYifei Jiang 6279997cc1eSYifei Jiang static int kvm_riscv_put_regs_fp(CPUState *cs) 6289997cc1eSYifei Jiang { 6299997cc1eSYifei Jiang int ret = 0; 6309997cc1eSYifei Jiang int i; 6319997cc1eSYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 6329997cc1eSYifei Jiang 6339997cc1eSYifei Jiang if (riscv_has_ext(env, RVD)) { 6349997cc1eSYifei Jiang uint64_t reg; 6359997cc1eSYifei Jiang for (i = 0; i < 32; i++) { 6369997cc1eSYifei Jiang reg = env->fpr[i]; 637450bd661SDaniel Henrique Barboza ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(i), ®); 6389997cc1eSYifei Jiang if (ret) { 6399997cc1eSYifei Jiang return ret; 6409997cc1eSYifei Jiang } 6419997cc1eSYifei Jiang } 6429997cc1eSYifei Jiang return ret; 6439997cc1eSYifei Jiang } 6449997cc1eSYifei Jiang 6459997cc1eSYifei Jiang if (riscv_has_ext(env, RVF)) { 6469997cc1eSYifei Jiang uint32_t reg; 6479997cc1eSYifei Jiang for (i = 0; i < 32; i++) { 6489997cc1eSYifei Jiang reg = env->fpr[i]; 64949c211ffSDaniel Henrique Barboza ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(i), ®); 6509997cc1eSYifei Jiang if (ret) { 6519997cc1eSYifei Jiang return ret; 6529997cc1eSYifei Jiang } 6539997cc1eSYifei Jiang } 6549997cc1eSYifei Jiang return ret; 6559997cc1eSYifei Jiang } 6569997cc1eSYifei Jiang 6579997cc1eSYifei Jiang return ret; 6589997cc1eSYifei Jiang } 6599997cc1eSYifei Jiang 66027abe66fSYifei Jiang static void kvm_riscv_get_regs_timer(CPUState *cs) 66127abe66fSYifei Jiang { 66227abe66fSYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 66327abe66fSYifei Jiang 66427abe66fSYifei Jiang if (env->kvm_timer_dirty) { 66527abe66fSYifei Jiang return; 66627abe66fSYifei Jiang } 66727abe66fSYifei Jiang 66810f86d1bSDaniel Henrique Barboza KVM_RISCV_GET_TIMER(cs, time, env->kvm_timer_time); 66910f86d1bSDaniel Henrique Barboza KVM_RISCV_GET_TIMER(cs, compare, env->kvm_timer_compare); 67010f86d1bSDaniel Henrique Barboza KVM_RISCV_GET_TIMER(cs, state, env->kvm_timer_state); 67110f86d1bSDaniel Henrique Barboza KVM_RISCV_GET_TIMER(cs, frequency, env->kvm_timer_frequency); 67227abe66fSYifei Jiang 67327abe66fSYifei Jiang env->kvm_timer_dirty = true; 67427abe66fSYifei Jiang } 67527abe66fSYifei Jiang 67627abe66fSYifei Jiang static void kvm_riscv_put_regs_timer(CPUState *cs) 67727abe66fSYifei Jiang { 67827abe66fSYifei Jiang uint64_t reg; 67927abe66fSYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 68027abe66fSYifei Jiang 68127abe66fSYifei Jiang if (!env->kvm_timer_dirty) { 68227abe66fSYifei Jiang return; 68327abe66fSYifei Jiang } 68427abe66fSYifei Jiang 68510f86d1bSDaniel Henrique Barboza KVM_RISCV_SET_TIMER(cs, time, env->kvm_timer_time); 68610f86d1bSDaniel Henrique Barboza KVM_RISCV_SET_TIMER(cs, compare, env->kvm_timer_compare); 68727abe66fSYifei Jiang 68827abe66fSYifei Jiang /* 68927abe66fSYifei Jiang * To set register of RISCV_TIMER_REG(state) will occur a error from KVM 69027abe66fSYifei Jiang * on env->kvm_timer_state == 0, It's better to adapt in KVM, but it 69127abe66fSYifei Jiang * doesn't matter that adaping in QEMU now. 69227abe66fSYifei Jiang * TODO If KVM changes, adapt here. 69327abe66fSYifei Jiang */ 69427abe66fSYifei Jiang if (env->kvm_timer_state) { 69510f86d1bSDaniel Henrique Barboza KVM_RISCV_SET_TIMER(cs, state, env->kvm_timer_state); 69627abe66fSYifei Jiang } 69727abe66fSYifei Jiang 69827abe66fSYifei Jiang /* 69927abe66fSYifei Jiang * For now, migration will not work between Hosts with different timer 70027abe66fSYifei Jiang * frequency. Therefore, we should check whether they are the same here 70127abe66fSYifei Jiang * during the migration. 70227abe66fSYifei Jiang */ 70327abe66fSYifei Jiang if (migration_is_running(migrate_get_current()->state)) { 70410f86d1bSDaniel Henrique Barboza KVM_RISCV_GET_TIMER(cs, frequency, reg); 70527abe66fSYifei Jiang if (reg != env->kvm_timer_frequency) { 70627abe66fSYifei Jiang error_report("Dst Hosts timer frequency != Src Hosts"); 70727abe66fSYifei Jiang } 70827abe66fSYifei Jiang } 70927abe66fSYifei Jiang 71027abe66fSYifei Jiang env->kvm_timer_dirty = false; 71127abe66fSYifei Jiang } 7129997cc1eSYifei Jiang 7133ca78c06SDaniel Henrique Barboza static int kvm_riscv_get_regs_vector(CPUState *cs) 7143ca78c06SDaniel Henrique Barboza { 715d4ff3da8SDaniel Henrique Barboza RISCVCPU *cpu = RISCV_CPU(cs); 716d4ff3da8SDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 7173ca78c06SDaniel Henrique Barboza target_ulong reg; 718*6f4a6248SDaniel Henrique Barboza uint64_t vreg_id; 719*6f4a6248SDaniel Henrique Barboza int vreg_idx, ret = 0; 7203ca78c06SDaniel Henrique Barboza 7213ca78c06SDaniel Henrique Barboza if (!riscv_has_ext(env, RVV)) { 7223ca78c06SDaniel Henrique Barboza return 0; 7233ca78c06SDaniel Henrique Barboza } 7243ca78c06SDaniel Henrique Barboza 7253ca78c06SDaniel Henrique Barboza ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vstart), ®); 7263ca78c06SDaniel Henrique Barboza if (ret) { 7273ca78c06SDaniel Henrique Barboza return ret; 7283ca78c06SDaniel Henrique Barboza } 7293ca78c06SDaniel Henrique Barboza env->vstart = reg; 7303ca78c06SDaniel Henrique Barboza 7313ca78c06SDaniel Henrique Barboza ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vl), ®); 7323ca78c06SDaniel Henrique Barboza if (ret) { 7333ca78c06SDaniel Henrique Barboza return ret; 7343ca78c06SDaniel Henrique Barboza } 7353ca78c06SDaniel Henrique Barboza env->vl = reg; 7363ca78c06SDaniel Henrique Barboza 7373ca78c06SDaniel Henrique Barboza ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), ®); 7383ca78c06SDaniel Henrique Barboza if (ret) { 7393ca78c06SDaniel Henrique Barboza return ret; 7403ca78c06SDaniel Henrique Barboza } 7413ca78c06SDaniel Henrique Barboza env->vtype = reg; 7423ca78c06SDaniel Henrique Barboza 743d4ff3da8SDaniel Henrique Barboza if (kvm_v_vlenb.supported) { 744d4ff3da8SDaniel Henrique Barboza ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vlenb), ®); 745d4ff3da8SDaniel Henrique Barboza if (ret) { 746d4ff3da8SDaniel Henrique Barboza return ret; 747d4ff3da8SDaniel Henrique Barboza } 748d4ff3da8SDaniel Henrique Barboza cpu->cfg.vlenb = reg; 749*6f4a6248SDaniel Henrique Barboza 750*6f4a6248SDaniel Henrique Barboza for (int i = 0; i < 32; i++) { 751*6f4a6248SDaniel Henrique Barboza /* 752*6f4a6248SDaniel Henrique Barboza * vreg[] is statically allocated using RV_VLEN_MAX. 753*6f4a6248SDaniel Henrique Barboza * Use it instead of vlenb to calculate vreg_idx for 754*6f4a6248SDaniel Henrique Barboza * simplicity. 755*6f4a6248SDaniel Henrique Barboza */ 756*6f4a6248SDaniel Henrique Barboza vreg_idx = i * RV_VLEN_MAX / 64; 757*6f4a6248SDaniel Henrique Barboza vreg_id = kvm_riscv_vector_reg_id(cpu, i); 758*6f4a6248SDaniel Henrique Barboza 759*6f4a6248SDaniel Henrique Barboza ret = kvm_get_one_reg(cs, vreg_id, &env->vreg[vreg_idx]); 760*6f4a6248SDaniel Henrique Barboza if (ret) { 761*6f4a6248SDaniel Henrique Barboza return ret; 762*6f4a6248SDaniel Henrique Barboza } 763*6f4a6248SDaniel Henrique Barboza } 764d4ff3da8SDaniel Henrique Barboza } 765d4ff3da8SDaniel Henrique Barboza 7663ca78c06SDaniel Henrique Barboza return 0; 7673ca78c06SDaniel Henrique Barboza } 7683ca78c06SDaniel Henrique Barboza 7693ca78c06SDaniel Henrique Barboza static int kvm_riscv_put_regs_vector(CPUState *cs) 7703ca78c06SDaniel Henrique Barboza { 771d4ff3da8SDaniel Henrique Barboza RISCVCPU *cpu = RISCV_CPU(cs); 772d4ff3da8SDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 7733ca78c06SDaniel Henrique Barboza target_ulong reg; 774*6f4a6248SDaniel Henrique Barboza uint64_t vreg_id; 775*6f4a6248SDaniel Henrique Barboza int vreg_idx, ret = 0; 7763ca78c06SDaniel Henrique Barboza 7773ca78c06SDaniel Henrique Barboza if (!riscv_has_ext(env, RVV)) { 7783ca78c06SDaniel Henrique Barboza return 0; 7793ca78c06SDaniel Henrique Barboza } 7803ca78c06SDaniel Henrique Barboza 7813ca78c06SDaniel Henrique Barboza reg = env->vstart; 7823ca78c06SDaniel Henrique Barboza ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vstart), ®); 7833ca78c06SDaniel Henrique Barboza if (ret) { 7843ca78c06SDaniel Henrique Barboza return ret; 7853ca78c06SDaniel Henrique Barboza } 7863ca78c06SDaniel Henrique Barboza 7873ca78c06SDaniel Henrique Barboza reg = env->vl; 7883ca78c06SDaniel Henrique Barboza ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vl), ®); 7893ca78c06SDaniel Henrique Barboza if (ret) { 7903ca78c06SDaniel Henrique Barboza return ret; 7913ca78c06SDaniel Henrique Barboza } 7923ca78c06SDaniel Henrique Barboza 7933ca78c06SDaniel Henrique Barboza reg = env->vtype; 7943ca78c06SDaniel Henrique Barboza ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), ®); 795d4ff3da8SDaniel Henrique Barboza if (ret) { 796d4ff3da8SDaniel Henrique Barboza return ret; 797d4ff3da8SDaniel Henrique Barboza } 798d4ff3da8SDaniel Henrique Barboza 799d4ff3da8SDaniel Henrique Barboza if (kvm_v_vlenb.supported) { 800d4ff3da8SDaniel Henrique Barboza reg = cpu->cfg.vlenb; 801d4ff3da8SDaniel Henrique Barboza ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vlenb), ®); 802*6f4a6248SDaniel Henrique Barboza 803*6f4a6248SDaniel Henrique Barboza for (int i = 0; i < 32; i++) { 804*6f4a6248SDaniel Henrique Barboza /* 805*6f4a6248SDaniel Henrique Barboza * vreg[] is statically allocated using RV_VLEN_MAX. 806*6f4a6248SDaniel Henrique Barboza * Use it instead of vlenb to calculate vreg_idx for 807*6f4a6248SDaniel Henrique Barboza * simplicity. 808*6f4a6248SDaniel Henrique Barboza */ 809*6f4a6248SDaniel Henrique Barboza vreg_idx = i * RV_VLEN_MAX / 64; 810*6f4a6248SDaniel Henrique Barboza vreg_id = kvm_riscv_vector_reg_id(cpu, i); 811*6f4a6248SDaniel Henrique Barboza 812*6f4a6248SDaniel Henrique Barboza ret = kvm_set_one_reg(cs, vreg_id, &env->vreg[vreg_idx]); 813*6f4a6248SDaniel Henrique Barboza if (ret) { 814*6f4a6248SDaniel Henrique Barboza return ret; 815*6f4a6248SDaniel Henrique Barboza } 816*6f4a6248SDaniel Henrique Barboza } 817d4ff3da8SDaniel Henrique Barboza } 8183ca78c06SDaniel Henrique Barboza 8193ca78c06SDaniel Henrique Barboza return ret; 8203ca78c06SDaniel Henrique Barboza } 8213ca78c06SDaniel Henrique Barboza 822492265aeSDaniel Henrique Barboza typedef struct KVMScratchCPU { 823492265aeSDaniel Henrique Barboza int kvmfd; 824492265aeSDaniel Henrique Barboza int vmfd; 825492265aeSDaniel Henrique Barboza int cpufd; 826492265aeSDaniel Henrique Barboza } KVMScratchCPU; 827492265aeSDaniel Henrique Barboza 828492265aeSDaniel Henrique Barboza /* 829492265aeSDaniel Henrique Barboza * Heavily inspired by kvm_arm_create_scratch_host_vcpu() 830492265aeSDaniel Henrique Barboza * from target/arm/kvm.c. 831492265aeSDaniel Henrique Barboza */ 832492265aeSDaniel Henrique Barboza static bool kvm_riscv_create_scratch_vcpu(KVMScratchCPU *scratch) 833492265aeSDaniel Henrique Barboza { 834492265aeSDaniel Henrique Barboza int kvmfd = -1, vmfd = -1, cpufd = -1; 835492265aeSDaniel Henrique Barboza 836492265aeSDaniel Henrique Barboza kvmfd = qemu_open_old("/dev/kvm", O_RDWR); 837492265aeSDaniel Henrique Barboza if (kvmfd < 0) { 838492265aeSDaniel Henrique Barboza goto err; 839492265aeSDaniel Henrique Barboza } 840492265aeSDaniel Henrique Barboza do { 841492265aeSDaniel Henrique Barboza vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0); 842492265aeSDaniel Henrique Barboza } while (vmfd == -1 && errno == EINTR); 843492265aeSDaniel Henrique Barboza if (vmfd < 0) { 844492265aeSDaniel Henrique Barboza goto err; 845492265aeSDaniel Henrique Barboza } 846492265aeSDaniel Henrique Barboza cpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0); 847492265aeSDaniel Henrique Barboza if (cpufd < 0) { 848492265aeSDaniel Henrique Barboza goto err; 849492265aeSDaniel Henrique Barboza } 850492265aeSDaniel Henrique Barboza 851492265aeSDaniel Henrique Barboza scratch->kvmfd = kvmfd; 852492265aeSDaniel Henrique Barboza scratch->vmfd = vmfd; 853492265aeSDaniel Henrique Barboza scratch->cpufd = cpufd; 854492265aeSDaniel Henrique Barboza 855492265aeSDaniel Henrique Barboza return true; 856492265aeSDaniel Henrique Barboza 857492265aeSDaniel Henrique Barboza err: 858492265aeSDaniel Henrique Barboza if (cpufd >= 0) { 859492265aeSDaniel Henrique Barboza close(cpufd); 860492265aeSDaniel Henrique Barboza } 861492265aeSDaniel Henrique Barboza if (vmfd >= 0) { 862492265aeSDaniel Henrique Barboza close(vmfd); 863492265aeSDaniel Henrique Barboza } 864492265aeSDaniel Henrique Barboza if (kvmfd >= 0) { 865492265aeSDaniel Henrique Barboza close(kvmfd); 866492265aeSDaniel Henrique Barboza } 867492265aeSDaniel Henrique Barboza 868492265aeSDaniel Henrique Barboza return false; 869492265aeSDaniel Henrique Barboza } 870492265aeSDaniel Henrique Barboza 871492265aeSDaniel Henrique Barboza static void kvm_riscv_destroy_scratch_vcpu(KVMScratchCPU *scratch) 872492265aeSDaniel Henrique Barboza { 873492265aeSDaniel Henrique Barboza close(scratch->cpufd); 874492265aeSDaniel Henrique Barboza close(scratch->vmfd); 875492265aeSDaniel Henrique Barboza close(scratch->kvmfd); 876492265aeSDaniel Henrique Barboza } 877492265aeSDaniel Henrique Barboza 878492265aeSDaniel Henrique Barboza static void kvm_riscv_init_machine_ids(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) 879492265aeSDaniel Henrique Barboza { 880492265aeSDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 881492265aeSDaniel Henrique Barboza struct kvm_one_reg reg; 882492265aeSDaniel Henrique Barboza int ret; 883492265aeSDaniel Henrique Barboza 884f25974f4SDaniel Henrique Barboza reg.id = RISCV_CONFIG_REG(env, mvendorid); 885492265aeSDaniel Henrique Barboza reg.addr = (uint64_t)&cpu->cfg.mvendorid; 886492265aeSDaniel Henrique Barboza ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); 887492265aeSDaniel Henrique Barboza if (ret != 0) { 888492265aeSDaniel Henrique Barboza error_report("Unable to retrieve mvendorid from host, error %d", ret); 889492265aeSDaniel Henrique Barboza } 890d758f884SDaniel Henrique Barboza 891f25974f4SDaniel Henrique Barboza reg.id = RISCV_CONFIG_REG(env, marchid); 892d758f884SDaniel Henrique Barboza reg.addr = (uint64_t)&cpu->cfg.marchid; 893d758f884SDaniel Henrique Barboza ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); 894d758f884SDaniel Henrique Barboza if (ret != 0) { 895d758f884SDaniel Henrique Barboza error_report("Unable to retrieve marchid from host, error %d", ret); 896d758f884SDaniel Henrique Barboza } 897d758f884SDaniel Henrique Barboza 898f25974f4SDaniel Henrique Barboza reg.id = RISCV_CONFIG_REG(env, mimpid); 899d758f884SDaniel Henrique Barboza reg.addr = (uint64_t)&cpu->cfg.mimpid; 900d758f884SDaniel Henrique Barboza ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); 901d758f884SDaniel Henrique Barboza if (ret != 0) { 902d758f884SDaniel Henrique Barboza error_report("Unable to retrieve mimpid from host, error %d", ret); 903d758f884SDaniel Henrique Barboza } 904492265aeSDaniel Henrique Barboza } 905492265aeSDaniel Henrique Barboza 906e28b9c49SDaniel Henrique Barboza static void kvm_riscv_init_misa_ext_mask(RISCVCPU *cpu, 907e28b9c49SDaniel Henrique Barboza KVMScratchCPU *kvmcpu) 908e28b9c49SDaniel Henrique Barboza { 909e28b9c49SDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 910e28b9c49SDaniel Henrique Barboza struct kvm_one_reg reg; 911e28b9c49SDaniel Henrique Barboza int ret; 912e28b9c49SDaniel Henrique Barboza 913f25974f4SDaniel Henrique Barboza reg.id = RISCV_CONFIG_REG(env, isa); 914e28b9c49SDaniel Henrique Barboza reg.addr = (uint64_t)&env->misa_ext_mask; 915e28b9c49SDaniel Henrique Barboza ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); 916e28b9c49SDaniel Henrique Barboza 917e28b9c49SDaniel Henrique Barboza if (ret) { 918e28b9c49SDaniel Henrique Barboza error_report("Unable to fetch ISA register from KVM, " 919e28b9c49SDaniel Henrique Barboza "error %d", ret); 920e28b9c49SDaniel Henrique Barboza kvm_riscv_destroy_scratch_vcpu(kvmcpu); 921e28b9c49SDaniel Henrique Barboza exit(EXIT_FAILURE); 922e28b9c49SDaniel Henrique Barboza } 923e28b9c49SDaniel Henrique Barboza 924e28b9c49SDaniel Henrique Barboza env->misa_ext = env->misa_ext_mask; 925e28b9c49SDaniel Henrique Barboza } 926e28b9c49SDaniel Henrique Barboza 927b9f82221SDaniel Henrique Barboza static void kvm_riscv_read_cbomz_blksize(RISCVCPU *cpu, KVMScratchCPU *kvmcpu, 928b9f82221SDaniel Henrique Barboza KVMCPUConfig *cbomz_cfg) 929b9f82221SDaniel Henrique Barboza { 930b9f82221SDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 931b9f82221SDaniel Henrique Barboza struct kvm_one_reg reg; 932b9f82221SDaniel Henrique Barboza int ret; 933b9f82221SDaniel Henrique Barboza 934da14fc74SDaniel Henrique Barboza reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, 935b9f82221SDaniel Henrique Barboza cbomz_cfg->kvm_reg_id); 936b9f82221SDaniel Henrique Barboza reg.addr = (uint64_t)kvmconfig_get_cfg_addr(cpu, cbomz_cfg); 937b9f82221SDaniel Henrique Barboza ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); 938b9f82221SDaniel Henrique Barboza if (ret != 0) { 939b9f82221SDaniel Henrique Barboza error_report("Unable to read KVM reg %s, error %d", 940b9f82221SDaniel Henrique Barboza cbomz_cfg->name, ret); 941b9f82221SDaniel Henrique Barboza exit(EXIT_FAILURE); 942b9f82221SDaniel Henrique Barboza } 943b9f82221SDaniel Henrique Barboza } 944b9f82221SDaniel Henrique Barboza 945608bdebbSDaniel Henrique Barboza static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu, 946608bdebbSDaniel Henrique Barboza KVMScratchCPU *kvmcpu) 947f7a69fa6SDaniel Henrique Barboza { 948f7a69fa6SDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 949f7a69fa6SDaniel Henrique Barboza uint64_t val; 950f7a69fa6SDaniel Henrique Barboza int i, ret; 951f7a69fa6SDaniel Henrique Barboza 952f7a69fa6SDaniel Henrique Barboza for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) { 953f7a69fa6SDaniel Henrique Barboza KVMCPUConfig *multi_ext_cfg = &kvm_multi_ext_cfgs[i]; 954f7a69fa6SDaniel Henrique Barboza struct kvm_one_reg reg; 955f7a69fa6SDaniel Henrique Barboza 956da14fc74SDaniel Henrique Barboza reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT, 957f7a69fa6SDaniel Henrique Barboza multi_ext_cfg->kvm_reg_id); 958f7a69fa6SDaniel Henrique Barboza reg.addr = (uint64_t)&val; 959f7a69fa6SDaniel Henrique Barboza ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); 960f7a69fa6SDaniel Henrique Barboza if (ret != 0) { 961f7a69fa6SDaniel Henrique Barboza if (errno == EINVAL) { 962f7a69fa6SDaniel Henrique Barboza /* Silently default to 'false' if KVM does not support it. */ 963f7a69fa6SDaniel Henrique Barboza multi_ext_cfg->supported = false; 964f7a69fa6SDaniel Henrique Barboza val = false; 965f7a69fa6SDaniel Henrique Barboza } else { 966d424db23SNatanael Copa error_report("Unable to read ISA_EXT KVM register %s: %s", 967d424db23SNatanael Copa multi_ext_cfg->name, strerror(errno)); 968f7a69fa6SDaniel Henrique Barboza exit(EXIT_FAILURE); 969f7a69fa6SDaniel Henrique Barboza } 970f7a69fa6SDaniel Henrique Barboza } else { 971f7a69fa6SDaniel Henrique Barboza multi_ext_cfg->supported = true; 972f7a69fa6SDaniel Henrique Barboza } 973f7a69fa6SDaniel Henrique Barboza 974f7a69fa6SDaniel Henrique Barboza kvm_cpu_cfg_set(cpu, multi_ext_cfg, val); 975f7a69fa6SDaniel Henrique Barboza } 976b9f82221SDaniel Henrique Barboza 977a326a2b0SDaniel Henrique Barboza if (cpu->cfg.ext_zicbom) { 978b9f82221SDaniel Henrique Barboza kvm_riscv_read_cbomz_blksize(cpu, kvmcpu, &kvm_cbom_blocksize); 979b9f82221SDaniel Henrique Barboza } 980b9f82221SDaniel Henrique Barboza 981e57039ddSDaniel Henrique Barboza if (cpu->cfg.ext_zicboz) { 982b9f82221SDaniel Henrique Barboza kvm_riscv_read_cbomz_blksize(cpu, kvmcpu, &kvm_cboz_blocksize); 983b9f82221SDaniel Henrique Barboza } 984f7a69fa6SDaniel Henrique Barboza } 985f7a69fa6SDaniel Henrique Barboza 986608bdebbSDaniel Henrique Barboza static int uint64_cmp(const void *a, const void *b) 987608bdebbSDaniel Henrique Barboza { 988608bdebbSDaniel Henrique Barboza uint64_t val1 = *(const uint64_t *)a; 989608bdebbSDaniel Henrique Barboza uint64_t val2 = *(const uint64_t *)b; 990608bdebbSDaniel Henrique Barboza 991608bdebbSDaniel Henrique Barboza if (val1 < val2) { 992608bdebbSDaniel Henrique Barboza return -1; 993608bdebbSDaniel Henrique Barboza } 994608bdebbSDaniel Henrique Barboza 995608bdebbSDaniel Henrique Barboza if (val1 > val2) { 996608bdebbSDaniel Henrique Barboza return 1; 997608bdebbSDaniel Henrique Barboza } 998608bdebbSDaniel Henrique Barboza 999608bdebbSDaniel Henrique Barboza return 0; 1000608bdebbSDaniel Henrique Barboza } 1001608bdebbSDaniel Henrique Barboza 1002d4ff3da8SDaniel Henrique Barboza static void kvm_riscv_read_vlenb(RISCVCPU *cpu, KVMScratchCPU *kvmcpu, 1003d4ff3da8SDaniel Henrique Barboza struct kvm_reg_list *reglist) 1004d4ff3da8SDaniel Henrique Barboza { 1005d4ff3da8SDaniel Henrique Barboza struct kvm_one_reg reg; 1006d4ff3da8SDaniel Henrique Barboza struct kvm_reg_list *reg_search; 1007d4ff3da8SDaniel Henrique Barboza uint64_t val; 1008d4ff3da8SDaniel Henrique Barboza int ret; 1009d4ff3da8SDaniel Henrique Barboza 1010d4ff3da8SDaniel Henrique Barboza reg_search = bsearch(&kvm_v_vlenb.kvm_reg_id, reglist->reg, reglist->n, 1011d4ff3da8SDaniel Henrique Barboza sizeof(uint64_t), uint64_cmp); 1012d4ff3da8SDaniel Henrique Barboza 1013d4ff3da8SDaniel Henrique Barboza if (reg_search) { 1014d4ff3da8SDaniel Henrique Barboza reg.id = kvm_v_vlenb.kvm_reg_id; 1015d4ff3da8SDaniel Henrique Barboza reg.addr = (uint64_t)&val; 1016d4ff3da8SDaniel Henrique Barboza 1017d4ff3da8SDaniel Henrique Barboza ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); 1018d4ff3da8SDaniel Henrique Barboza if (ret != 0) { 1019d4ff3da8SDaniel Henrique Barboza error_report("Unable to read vlenb register, error code: %s", 1020d4ff3da8SDaniel Henrique Barboza strerrorname_np(errno)); 1021d4ff3da8SDaniel Henrique Barboza exit(EXIT_FAILURE); 1022d4ff3da8SDaniel Henrique Barboza } 1023d4ff3da8SDaniel Henrique Barboza 1024d4ff3da8SDaniel Henrique Barboza kvm_v_vlenb.supported = true; 1025d4ff3da8SDaniel Henrique Barboza cpu->cfg.vlenb = val; 1026d4ff3da8SDaniel Henrique Barboza } 1027d4ff3da8SDaniel Henrique Barboza } 1028d4ff3da8SDaniel Henrique Barboza 1029608bdebbSDaniel Henrique Barboza static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) 1030608bdebbSDaniel Henrique Barboza { 1031608bdebbSDaniel Henrique Barboza KVMCPUConfig *multi_ext_cfg; 1032608bdebbSDaniel Henrique Barboza struct kvm_one_reg reg; 1033608bdebbSDaniel Henrique Barboza struct kvm_reg_list rl_struct; 1034608bdebbSDaniel Henrique Barboza struct kvm_reg_list *reglist; 1035608bdebbSDaniel Henrique Barboza uint64_t val, reg_id, *reg_search; 1036608bdebbSDaniel Henrique Barboza int i, ret; 1037608bdebbSDaniel Henrique Barboza 1038608bdebbSDaniel Henrique Barboza rl_struct.n = 0; 1039608bdebbSDaniel Henrique Barboza ret = ioctl(kvmcpu->cpufd, KVM_GET_REG_LIST, &rl_struct); 1040608bdebbSDaniel Henrique Barboza 1041608bdebbSDaniel Henrique Barboza /* 1042608bdebbSDaniel Henrique Barboza * If KVM_GET_REG_LIST isn't supported we'll get errno 22 1043608bdebbSDaniel Henrique Barboza * (EINVAL). Use read_legacy() in this case. 1044608bdebbSDaniel Henrique Barboza */ 1045608bdebbSDaniel Henrique Barboza if (errno == EINVAL) { 1046608bdebbSDaniel Henrique Barboza return kvm_riscv_read_multiext_legacy(cpu, kvmcpu); 1047608bdebbSDaniel Henrique Barboza } else if (errno != E2BIG) { 1048608bdebbSDaniel Henrique Barboza /* 1049608bdebbSDaniel Henrique Barboza * E2BIG is an expected error message for the API since we 1050608bdebbSDaniel Henrique Barboza * don't know the number of registers. The right amount will 1051608bdebbSDaniel Henrique Barboza * be written in rl_struct.n. 1052608bdebbSDaniel Henrique Barboza * 1053608bdebbSDaniel Henrique Barboza * Error out if we get any other errno. 1054608bdebbSDaniel Henrique Barboza */ 1055d424db23SNatanael Copa error_report("Error when accessing get-reg-list: %s", 1056d424db23SNatanael Copa strerror(errno)); 1057608bdebbSDaniel Henrique Barboza exit(EXIT_FAILURE); 1058608bdebbSDaniel Henrique Barboza } 1059608bdebbSDaniel Henrique Barboza 1060608bdebbSDaniel Henrique Barboza reglist = g_malloc(sizeof(struct kvm_reg_list) + 1061608bdebbSDaniel Henrique Barboza rl_struct.n * sizeof(uint64_t)); 1062608bdebbSDaniel Henrique Barboza reglist->n = rl_struct.n; 1063608bdebbSDaniel Henrique Barboza ret = ioctl(kvmcpu->cpufd, KVM_GET_REG_LIST, reglist); 1064608bdebbSDaniel Henrique Barboza if (ret) { 1065d424db23SNatanael Copa error_report("Error when reading KVM_GET_REG_LIST: %s", 1066d424db23SNatanael Copa strerror(errno)); 1067608bdebbSDaniel Henrique Barboza exit(EXIT_FAILURE); 1068608bdebbSDaniel Henrique Barboza } 1069608bdebbSDaniel Henrique Barboza 1070608bdebbSDaniel Henrique Barboza /* sort reglist to use bsearch() */ 1071608bdebbSDaniel Henrique Barboza qsort(®list->reg, reglist->n, sizeof(uint64_t), uint64_cmp); 1072608bdebbSDaniel Henrique Barboza 1073608bdebbSDaniel Henrique Barboza for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) { 1074608bdebbSDaniel Henrique Barboza multi_ext_cfg = &kvm_multi_ext_cfgs[i]; 1075da14fc74SDaniel Henrique Barboza reg_id = kvm_riscv_reg_id_ulong(&cpu->env, KVM_REG_RISCV_ISA_EXT, 1076608bdebbSDaniel Henrique Barboza multi_ext_cfg->kvm_reg_id); 1077608bdebbSDaniel Henrique Barboza reg_search = bsearch(®_id, reglist->reg, reglist->n, 1078608bdebbSDaniel Henrique Barboza sizeof(uint64_t), uint64_cmp); 1079608bdebbSDaniel Henrique Barboza if (!reg_search) { 1080608bdebbSDaniel Henrique Barboza continue; 1081608bdebbSDaniel Henrique Barboza } 1082608bdebbSDaniel Henrique Barboza 1083608bdebbSDaniel Henrique Barboza reg.id = reg_id; 1084608bdebbSDaniel Henrique Barboza reg.addr = (uint64_t)&val; 1085608bdebbSDaniel Henrique Barboza ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); 1086608bdebbSDaniel Henrique Barboza if (ret != 0) { 1087d424db23SNatanael Copa error_report("Unable to read ISA_EXT KVM register %s: %s", 1088d424db23SNatanael Copa multi_ext_cfg->name, strerror(errno)); 1089608bdebbSDaniel Henrique Barboza exit(EXIT_FAILURE); 1090608bdebbSDaniel Henrique Barboza } 1091608bdebbSDaniel Henrique Barboza 1092608bdebbSDaniel Henrique Barboza multi_ext_cfg->supported = true; 1093608bdebbSDaniel Henrique Barboza kvm_cpu_cfg_set(cpu, multi_ext_cfg, val); 1094608bdebbSDaniel Henrique Barboza } 1095608bdebbSDaniel Henrique Barboza 1096a326a2b0SDaniel Henrique Barboza if (cpu->cfg.ext_zicbom) { 1097608bdebbSDaniel Henrique Barboza kvm_riscv_read_cbomz_blksize(cpu, kvmcpu, &kvm_cbom_blocksize); 1098608bdebbSDaniel Henrique Barboza } 1099608bdebbSDaniel Henrique Barboza 1100e57039ddSDaniel Henrique Barboza if (cpu->cfg.ext_zicboz) { 1101608bdebbSDaniel Henrique Barboza kvm_riscv_read_cbomz_blksize(cpu, kvmcpu, &kvm_cboz_blocksize); 1102608bdebbSDaniel Henrique Barboza } 1103d4ff3da8SDaniel Henrique Barboza 1104d4ff3da8SDaniel Henrique Barboza if (riscv_has_ext(&cpu->env, RVV)) { 1105d4ff3da8SDaniel Henrique Barboza kvm_riscv_read_vlenb(cpu, kvmcpu, reglist); 1106d4ff3da8SDaniel Henrique Barboza } 1107608bdebbSDaniel Henrique Barboza } 1108608bdebbSDaniel Henrique Barboza 1109efa365b7SDaniel Henrique Barboza static void riscv_init_kvm_registers(Object *cpu_obj) 1110492265aeSDaniel Henrique Barboza { 1111492265aeSDaniel Henrique Barboza RISCVCPU *cpu = RISCV_CPU(cpu_obj); 1112492265aeSDaniel Henrique Barboza KVMScratchCPU kvmcpu; 1113492265aeSDaniel Henrique Barboza 1114492265aeSDaniel Henrique Barboza if (!kvm_riscv_create_scratch_vcpu(&kvmcpu)) { 1115492265aeSDaniel Henrique Barboza return; 1116492265aeSDaniel Henrique Barboza } 1117492265aeSDaniel Henrique Barboza 1118492265aeSDaniel Henrique Barboza kvm_riscv_init_machine_ids(cpu, &kvmcpu); 1119e28b9c49SDaniel Henrique Barboza kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu); 1120f7a69fa6SDaniel Henrique Barboza kvm_riscv_init_multiext_cfg(cpu, &kvmcpu); 1121492265aeSDaniel Henrique Barboza 1122492265aeSDaniel Henrique Barboza kvm_riscv_destroy_scratch_vcpu(&kvmcpu); 1123492265aeSDaniel Henrique Barboza } 1124492265aeSDaniel Henrique Barboza 112591654e61SYifei Jiang const KVMCapabilityInfo kvm_arch_required_capabilities[] = { 112691654e61SYifei Jiang KVM_CAP_LAST_INFO 112791654e61SYifei Jiang }; 112891654e61SYifei Jiang 112991654e61SYifei Jiang int kvm_arch_get_registers(CPUState *cs) 113091654e61SYifei Jiang { 1131937f0b45SYifei Jiang int ret = 0; 1132937f0b45SYifei Jiang 1133937f0b45SYifei Jiang ret = kvm_riscv_get_regs_core(cs); 1134937f0b45SYifei Jiang if (ret) { 1135937f0b45SYifei Jiang return ret; 1136937f0b45SYifei Jiang } 1137937f0b45SYifei Jiang 1138937f0b45SYifei Jiang ret = kvm_riscv_get_regs_csr(cs); 1139937f0b45SYifei Jiang if (ret) { 1140937f0b45SYifei Jiang return ret; 1141937f0b45SYifei Jiang } 1142937f0b45SYifei Jiang 1143937f0b45SYifei Jiang ret = kvm_riscv_get_regs_fp(cs); 1144937f0b45SYifei Jiang if (ret) { 1145937f0b45SYifei Jiang return ret; 1146937f0b45SYifei Jiang } 1147937f0b45SYifei Jiang 11483ca78c06SDaniel Henrique Barboza ret = kvm_riscv_get_regs_vector(cs); 11493ca78c06SDaniel Henrique Barboza if (ret) { 11503ca78c06SDaniel Henrique Barboza return ret; 11513ca78c06SDaniel Henrique Barboza } 11523ca78c06SDaniel Henrique Barboza 1153937f0b45SYifei Jiang return ret; 115491654e61SYifei Jiang } 115591654e61SYifei Jiang 115686339515Sliguang.zhang int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state) 115786339515Sliguang.zhang { 115886339515Sliguang.zhang if (cap_has_mp_state) { 115986339515Sliguang.zhang struct kvm_mp_state mp_state = { 116086339515Sliguang.zhang .mp_state = state 116186339515Sliguang.zhang }; 116286339515Sliguang.zhang 116386339515Sliguang.zhang int ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MP_STATE, &mp_state); 116486339515Sliguang.zhang if (ret) { 116586339515Sliguang.zhang fprintf(stderr, "%s: failed to sync MP_STATE %d/%s\n", 116686339515Sliguang.zhang __func__, ret, strerror(-ret)); 116786339515Sliguang.zhang return -1; 116886339515Sliguang.zhang } 116986339515Sliguang.zhang } 117086339515Sliguang.zhang 117186339515Sliguang.zhang return 0; 117286339515Sliguang.zhang } 117386339515Sliguang.zhang 117491654e61SYifei Jiang int kvm_arch_put_registers(CPUState *cs, int level) 117591654e61SYifei Jiang { 11769997cc1eSYifei Jiang int ret = 0; 11779997cc1eSYifei Jiang 11789997cc1eSYifei Jiang ret = kvm_riscv_put_regs_core(cs); 11799997cc1eSYifei Jiang if (ret) { 11809997cc1eSYifei Jiang return ret; 11819997cc1eSYifei Jiang } 11829997cc1eSYifei Jiang 11839997cc1eSYifei Jiang ret = kvm_riscv_put_regs_csr(cs); 11849997cc1eSYifei Jiang if (ret) { 11859997cc1eSYifei Jiang return ret; 11869997cc1eSYifei Jiang } 11879997cc1eSYifei Jiang 11889997cc1eSYifei Jiang ret = kvm_riscv_put_regs_fp(cs); 11899997cc1eSYifei Jiang if (ret) { 11909997cc1eSYifei Jiang return ret; 11919997cc1eSYifei Jiang } 11929997cc1eSYifei Jiang 11933ca78c06SDaniel Henrique Barboza ret = kvm_riscv_put_regs_vector(cs); 11943ca78c06SDaniel Henrique Barboza if (ret) { 11953ca78c06SDaniel Henrique Barboza return ret; 11963ca78c06SDaniel Henrique Barboza } 11973ca78c06SDaniel Henrique Barboza 119886339515Sliguang.zhang if (KVM_PUT_RESET_STATE == level) { 119986339515Sliguang.zhang RISCVCPU *cpu = RISCV_CPU(cs); 120086339515Sliguang.zhang if (cs->cpu_index == 0) { 120186339515Sliguang.zhang ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_RUNNABLE); 120286339515Sliguang.zhang } else { 120386339515Sliguang.zhang ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_STOPPED); 120486339515Sliguang.zhang } 120586339515Sliguang.zhang if (ret) { 120686339515Sliguang.zhang return ret; 120786339515Sliguang.zhang } 120886339515Sliguang.zhang } 120986339515Sliguang.zhang 12109997cc1eSYifei Jiang return ret; 121191654e61SYifei Jiang } 121291654e61SYifei Jiang 121391654e61SYifei Jiang int kvm_arch_release_virq_post(int virq) 121491654e61SYifei Jiang { 121591654e61SYifei Jiang return 0; 121691654e61SYifei Jiang } 121791654e61SYifei Jiang 121891654e61SYifei Jiang int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, 121991654e61SYifei Jiang uint64_t address, uint32_t data, PCIDevice *dev) 122091654e61SYifei Jiang { 122191654e61SYifei Jiang return 0; 122291654e61SYifei Jiang } 122391654e61SYifei Jiang 122491654e61SYifei Jiang int kvm_arch_destroy_vcpu(CPUState *cs) 122591654e61SYifei Jiang { 122691654e61SYifei Jiang return 0; 122791654e61SYifei Jiang } 122891654e61SYifei Jiang 122991654e61SYifei Jiang unsigned long kvm_arch_vcpu_id(CPUState *cpu) 123091654e61SYifei Jiang { 123191654e61SYifei Jiang return cpu->cpu_index; 123291654e61SYifei Jiang } 123391654e61SYifei Jiang 12349ad3e016SYifei Jiang static void kvm_riscv_vm_state_change(void *opaque, bool running, 12359ad3e016SYifei Jiang RunState state) 12369ad3e016SYifei Jiang { 12379ad3e016SYifei Jiang CPUState *cs = opaque; 12389ad3e016SYifei Jiang 12399ad3e016SYifei Jiang if (running) { 12409ad3e016SYifei Jiang kvm_riscv_put_regs_timer(cs); 12419ad3e016SYifei Jiang } else { 12429ad3e016SYifei Jiang kvm_riscv_get_regs_timer(cs); 12439ad3e016SYifei Jiang } 12449ad3e016SYifei Jiang } 12459ad3e016SYifei Jiang 124691654e61SYifei Jiang void kvm_arch_init_irq_routing(KVMState *s) 124791654e61SYifei Jiang { 124891654e61SYifei Jiang } 124991654e61SYifei Jiang 12501fb5a622SDaniel Henrique Barboza static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs) 12511fb5a622SDaniel Henrique Barboza { 12521fb5a622SDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 1253136cb9ccSDaniel Henrique Barboza target_ulong reg; 12541fb5a622SDaniel Henrique Barboza uint64_t id; 12551fb5a622SDaniel Henrique Barboza int ret; 12561fb5a622SDaniel Henrique Barboza 1257f25974f4SDaniel Henrique Barboza id = RISCV_CONFIG_REG(env, mvendorid); 1258136cb9ccSDaniel Henrique Barboza /* 1259136cb9ccSDaniel Henrique Barboza * cfg.mvendorid is an uint32 but a target_ulong will 1260136cb9ccSDaniel Henrique Barboza * be written. Assign it to a target_ulong var to avoid 1261136cb9ccSDaniel Henrique Barboza * writing pieces of other cpu->cfg fields in the reg. 1262136cb9ccSDaniel Henrique Barboza */ 1263136cb9ccSDaniel Henrique Barboza reg = cpu->cfg.mvendorid; 1264136cb9ccSDaniel Henrique Barboza ret = kvm_set_one_reg(cs, id, ®); 12651fb5a622SDaniel Henrique Barboza if (ret != 0) { 12661fb5a622SDaniel Henrique Barboza return ret; 12671fb5a622SDaniel Henrique Barboza } 12681fb5a622SDaniel Henrique Barboza 1269f25974f4SDaniel Henrique Barboza id = RISCV_CONFIG_REG(env, marchid); 12701fb5a622SDaniel Henrique Barboza ret = kvm_set_one_reg(cs, id, &cpu->cfg.marchid); 12711fb5a622SDaniel Henrique Barboza if (ret != 0) { 12721fb5a622SDaniel Henrique Barboza return ret; 12731fb5a622SDaniel Henrique Barboza } 12741fb5a622SDaniel Henrique Barboza 1275f25974f4SDaniel Henrique Barboza id = RISCV_CONFIG_REG(env, mimpid); 12761fb5a622SDaniel Henrique Barboza ret = kvm_set_one_reg(cs, id, &cpu->cfg.mimpid); 12771fb5a622SDaniel Henrique Barboza 12781fb5a622SDaniel Henrique Barboza return ret; 12791fb5a622SDaniel Henrique Barboza } 12801fb5a622SDaniel Henrique Barboza 128191654e61SYifei Jiang int kvm_arch_init_vcpu(CPUState *cs) 128291654e61SYifei Jiang { 12830a312b85SYifei Jiang int ret = 0; 12840a312b85SYifei Jiang RISCVCPU *cpu = RISCV_CPU(cs); 12850a312b85SYifei Jiang 12869ad3e016SYifei Jiang qemu_add_vm_change_state_handler(kvm_riscv_vm_state_change, cs); 12879ad3e016SYifei Jiang 12881fb5a622SDaniel Henrique Barboza if (!object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_CPU_HOST)) { 12891fb5a622SDaniel Henrique Barboza ret = kvm_vcpu_set_machine_ids(cpu, cs); 12907313fffbSDaniel Henrique Barboza if (ret != 0) { 12917313fffbSDaniel Henrique Barboza return ret; 12921fb5a622SDaniel Henrique Barboza } 12937313fffbSDaniel Henrique Barboza } 12947313fffbSDaniel Henrique Barboza 12957313fffbSDaniel Henrique Barboza kvm_riscv_update_cpu_misa_ext(cpu, cs); 1296df817297SDaniel Henrique Barboza kvm_riscv_update_cpu_cfg_isa_ext(cpu, cs); 12971fb5a622SDaniel Henrique Barboza 12980a312b85SYifei Jiang return ret; 129991654e61SYifei Jiang } 130091654e61SYifei Jiang 130191654e61SYifei Jiang int kvm_arch_msi_data_to_gsi(uint32_t data) 130291654e61SYifei Jiang { 130391654e61SYifei Jiang abort(); 130491654e61SYifei Jiang } 130591654e61SYifei Jiang 130691654e61SYifei Jiang int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, 130791654e61SYifei Jiang int vector, PCIDevice *dev) 130891654e61SYifei Jiang { 130991654e61SYifei Jiang return 0; 131091654e61SYifei Jiang } 131191654e61SYifei Jiang 13125e0d6590SAkihiko Odaki int kvm_arch_get_default_type(MachineState *ms) 13135e0d6590SAkihiko Odaki { 13145e0d6590SAkihiko Odaki return 0; 13155e0d6590SAkihiko Odaki } 13165e0d6590SAkihiko Odaki 131791654e61SYifei Jiang int kvm_arch_init(MachineState *ms, KVMState *s) 131891654e61SYifei Jiang { 131986339515Sliguang.zhang cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE); 132091654e61SYifei Jiang return 0; 132191654e61SYifei Jiang } 132291654e61SYifei Jiang 132391654e61SYifei Jiang int kvm_arch_irqchip_create(KVMState *s) 132491654e61SYifei Jiang { 132597b9f5efSYong-Xuan Wang if (kvm_kernel_irqchip_split()) { 132697b9f5efSYong-Xuan Wang error_report("-machine kernel_irqchip=split is not supported on RISC-V."); 132797b9f5efSYong-Xuan Wang exit(1); 132897b9f5efSYong-Xuan Wang } 132997b9f5efSYong-Xuan Wang 133097b9f5efSYong-Xuan Wang /* 133197b9f5efSYong-Xuan Wang * We can create the VAIA using the newer device control API. 133297b9f5efSYong-Xuan Wang */ 133397b9f5efSYong-Xuan Wang return kvm_check_extension(s, KVM_CAP_DEVICE_CTRL); 133491654e61SYifei Jiang } 133591654e61SYifei Jiang 133691654e61SYifei Jiang int kvm_arch_process_async_events(CPUState *cs) 133791654e61SYifei Jiang { 133891654e61SYifei Jiang return 0; 133991654e61SYifei Jiang } 134091654e61SYifei Jiang 134191654e61SYifei Jiang void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) 134291654e61SYifei Jiang { 134391654e61SYifei Jiang } 134491654e61SYifei Jiang 134591654e61SYifei Jiang MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) 134691654e61SYifei Jiang { 134791654e61SYifei Jiang return MEMTXATTRS_UNSPECIFIED; 134891654e61SYifei Jiang } 134991654e61SYifei Jiang 135091654e61SYifei Jiang bool kvm_arch_stop_on_emulation_error(CPUState *cs) 135191654e61SYifei Jiang { 135291654e61SYifei Jiang return true; 135391654e61SYifei Jiang } 135491654e61SYifei Jiang 13554eb47125SYifei Jiang static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run) 13564eb47125SYifei Jiang { 13574eb47125SYifei Jiang int ret = 0; 13584eb47125SYifei Jiang unsigned char ch; 13594eb47125SYifei Jiang switch (run->riscv_sbi.extension_id) { 13604eb47125SYifei Jiang case SBI_EXT_0_1_CONSOLE_PUTCHAR: 13614eb47125SYifei Jiang ch = run->riscv_sbi.args[0]; 13624eb47125SYifei Jiang qemu_chr_fe_write(serial_hd(0)->be, &ch, sizeof(ch)); 13634eb47125SYifei Jiang break; 13644eb47125SYifei Jiang case SBI_EXT_0_1_CONSOLE_GETCHAR: 13654eb47125SYifei Jiang ret = qemu_chr_fe_read_all(serial_hd(0)->be, &ch, sizeof(ch)); 13664eb47125SYifei Jiang if (ret == sizeof(ch)) { 1367947bf7feSVladimir Isaev run->riscv_sbi.ret[0] = ch; 13684eb47125SYifei Jiang } else { 1369947bf7feSVladimir Isaev run->riscv_sbi.ret[0] = -1; 13704eb47125SYifei Jiang } 1371947bf7feSVladimir Isaev ret = 0; 13724eb47125SYifei Jiang break; 13734eb47125SYifei Jiang default: 13744eb47125SYifei Jiang qemu_log_mask(LOG_UNIMP, 13754eb47125SYifei Jiang "%s: un-handled SBI EXIT, specific reasons is %lu\n", 13764eb47125SYifei Jiang __func__, run->riscv_sbi.extension_id); 13774eb47125SYifei Jiang ret = -1; 13784eb47125SYifei Jiang break; 13794eb47125SYifei Jiang } 13804eb47125SYifei Jiang return ret; 13814eb47125SYifei Jiang } 13824eb47125SYifei Jiang 138391654e61SYifei Jiang int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) 138491654e61SYifei Jiang { 13854eb47125SYifei Jiang int ret = 0; 13864eb47125SYifei Jiang switch (run->exit_reason) { 13874eb47125SYifei Jiang case KVM_EXIT_RISCV_SBI: 13884eb47125SYifei Jiang ret = kvm_riscv_handle_sbi(cs, run); 13894eb47125SYifei Jiang break; 13904eb47125SYifei Jiang default: 13914eb47125SYifei Jiang qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n", 13924eb47125SYifei Jiang __func__, run->exit_reason); 13934eb47125SYifei Jiang ret = -1; 13944eb47125SYifei Jiang break; 13954eb47125SYifei Jiang } 13964eb47125SYifei Jiang return ret; 139791654e61SYifei Jiang } 139891654e61SYifei Jiang 1399ad40be27SYifei Jiang void kvm_riscv_reset_vcpu(RISCVCPU *cpu) 1400ad40be27SYifei Jiang { 1401ad40be27SYifei Jiang CPURISCVState *env = &cpu->env; 140286339515Sliguang.zhang int i; 1403ad40be27SYifei Jiang 1404ad40be27SYifei Jiang if (!kvm_enabled()) { 1405ad40be27SYifei Jiang return; 1406ad40be27SYifei Jiang } 140786339515Sliguang.zhang for (i = 0; i < 32; i++) { 140886339515Sliguang.zhang env->gpr[i] = 0; 140986339515Sliguang.zhang } 1410ad40be27SYifei Jiang env->pc = cpu->env.kernel_addr; 1411ad40be27SYifei Jiang env->gpr[10] = kvm_arch_vcpu_id(CPU(cpu)); /* a0 */ 1412ad40be27SYifei Jiang env->gpr[11] = cpu->env.fdt_addr; /* a1 */ 1413ad40be27SYifei Jiang env->satp = 0; 141486339515Sliguang.zhang env->mie = 0; 141586339515Sliguang.zhang env->stvec = 0; 141686339515Sliguang.zhang env->sscratch = 0; 141786339515Sliguang.zhang env->sepc = 0; 141886339515Sliguang.zhang env->scause = 0; 141986339515Sliguang.zhang env->stval = 0; 142086339515Sliguang.zhang env->mip = 0; 1421ad40be27SYifei Jiang } 1422ad40be27SYifei Jiang 14232b650fbbSYifei Jiang void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level) 14242b650fbbSYifei Jiang { 14252b650fbbSYifei Jiang int ret; 14262b650fbbSYifei Jiang unsigned virq = level ? KVM_INTERRUPT_SET : KVM_INTERRUPT_UNSET; 14272b650fbbSYifei Jiang 14282b650fbbSYifei Jiang if (irq != IRQ_S_EXT) { 14292b650fbbSYifei Jiang perror("kvm riscv set irq != IRQ_S_EXT\n"); 14302b650fbbSYifei Jiang abort(); 14312b650fbbSYifei Jiang } 14322b650fbbSYifei Jiang 14332b650fbbSYifei Jiang ret = kvm_vcpu_ioctl(CPU(cpu), KVM_INTERRUPT, &virq); 14342b650fbbSYifei Jiang if (ret < 0) { 14352b650fbbSYifei Jiang perror("Set irq failed"); 14362b650fbbSYifei Jiang abort(); 14372b650fbbSYifei Jiang } 14382b650fbbSYifei Jiang } 14392b650fbbSYifei Jiang 144091654e61SYifei Jiang bool kvm_arch_cpu_check_are_resettable(void) 144191654e61SYifei Jiang { 144291654e61SYifei Jiang return true; 144391654e61SYifei Jiang } 14443dba0a33SPaolo Bonzini 14459634ef7eSYong-Xuan Wang static int aia_mode; 14469634ef7eSYong-Xuan Wang 14479634ef7eSYong-Xuan Wang static const char *kvm_aia_mode_str(uint64_t mode) 14489634ef7eSYong-Xuan Wang { 14499634ef7eSYong-Xuan Wang switch (mode) { 14509634ef7eSYong-Xuan Wang case KVM_DEV_RISCV_AIA_MODE_EMUL: 14519634ef7eSYong-Xuan Wang return "emul"; 14529634ef7eSYong-Xuan Wang case KVM_DEV_RISCV_AIA_MODE_HWACCEL: 14539634ef7eSYong-Xuan Wang return "hwaccel"; 14549634ef7eSYong-Xuan Wang case KVM_DEV_RISCV_AIA_MODE_AUTO: 14559634ef7eSYong-Xuan Wang default: 14569634ef7eSYong-Xuan Wang return "auto"; 14579634ef7eSYong-Xuan Wang }; 14589634ef7eSYong-Xuan Wang } 14599634ef7eSYong-Xuan Wang 14609634ef7eSYong-Xuan Wang static char *riscv_get_kvm_aia(Object *obj, Error **errp) 14619634ef7eSYong-Xuan Wang { 14629634ef7eSYong-Xuan Wang return g_strdup(kvm_aia_mode_str(aia_mode)); 14639634ef7eSYong-Xuan Wang } 14649634ef7eSYong-Xuan Wang 14659634ef7eSYong-Xuan Wang static void riscv_set_kvm_aia(Object *obj, const char *val, Error **errp) 14669634ef7eSYong-Xuan Wang { 14679634ef7eSYong-Xuan Wang if (!strcmp(val, "emul")) { 14689634ef7eSYong-Xuan Wang aia_mode = KVM_DEV_RISCV_AIA_MODE_EMUL; 14699634ef7eSYong-Xuan Wang } else if (!strcmp(val, "hwaccel")) { 14709634ef7eSYong-Xuan Wang aia_mode = KVM_DEV_RISCV_AIA_MODE_HWACCEL; 14719634ef7eSYong-Xuan Wang } else if (!strcmp(val, "auto")) { 14729634ef7eSYong-Xuan Wang aia_mode = KVM_DEV_RISCV_AIA_MODE_AUTO; 14739634ef7eSYong-Xuan Wang } else { 14749634ef7eSYong-Xuan Wang error_setg(errp, "Invalid KVM AIA mode"); 14759634ef7eSYong-Xuan Wang error_append_hint(errp, "Valid values are emul, hwaccel, and auto.\n"); 14769634ef7eSYong-Xuan Wang } 14779634ef7eSYong-Xuan Wang } 14789634ef7eSYong-Xuan Wang 14793dba0a33SPaolo Bonzini void kvm_arch_accel_class_init(ObjectClass *oc) 14803dba0a33SPaolo Bonzini { 14819634ef7eSYong-Xuan Wang object_class_property_add_str(oc, "riscv-aia", riscv_get_kvm_aia, 14829634ef7eSYong-Xuan Wang riscv_set_kvm_aia); 14839634ef7eSYong-Xuan Wang object_class_property_set_description(oc, "riscv-aia", 14849634ef7eSYong-Xuan Wang "Set KVM AIA mode. Valid values are " 14859634ef7eSYong-Xuan Wang "emul, hwaccel, and auto. Default " 14869634ef7eSYong-Xuan Wang "is auto."); 14879634ef7eSYong-Xuan Wang object_property_set_default_str(object_class_property_find(oc, "riscv-aia"), 14889634ef7eSYong-Xuan Wang "auto"); 14899634ef7eSYong-Xuan Wang } 14909634ef7eSYong-Xuan Wang 14919634ef7eSYong-Xuan Wang void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, 14929634ef7eSYong-Xuan Wang uint64_t aia_irq_num, uint64_t aia_msi_num, 14939634ef7eSYong-Xuan Wang uint64_t aplic_base, uint64_t imsic_base, 14949634ef7eSYong-Xuan Wang uint64_t guest_num) 14959634ef7eSYong-Xuan Wang { 14969634ef7eSYong-Xuan Wang int ret, i; 14979634ef7eSYong-Xuan Wang int aia_fd = -1; 14989634ef7eSYong-Xuan Wang uint64_t default_aia_mode; 14999634ef7eSYong-Xuan Wang uint64_t socket_count = riscv_socket_count(machine); 15009634ef7eSYong-Xuan Wang uint64_t max_hart_per_socket = 0; 15019634ef7eSYong-Xuan Wang uint64_t socket, base_hart, hart_count, socket_imsic_base, imsic_addr; 15029634ef7eSYong-Xuan Wang uint64_t socket_bits, hart_bits, guest_bits; 15039634ef7eSYong-Xuan Wang 15049634ef7eSYong-Xuan Wang aia_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_RISCV_AIA, false); 15059634ef7eSYong-Xuan Wang 15069634ef7eSYong-Xuan Wang if (aia_fd < 0) { 15079634ef7eSYong-Xuan Wang error_report("Unable to create in-kernel irqchip"); 15089634ef7eSYong-Xuan Wang exit(1); 15099634ef7eSYong-Xuan Wang } 15109634ef7eSYong-Xuan Wang 15119634ef7eSYong-Xuan Wang ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, 15129634ef7eSYong-Xuan Wang KVM_DEV_RISCV_AIA_CONFIG_MODE, 15139634ef7eSYong-Xuan Wang &default_aia_mode, false, NULL); 15149634ef7eSYong-Xuan Wang if (ret < 0) { 15159634ef7eSYong-Xuan Wang error_report("KVM AIA: failed to get current KVM AIA mode"); 15169634ef7eSYong-Xuan Wang exit(1); 15179634ef7eSYong-Xuan Wang } 15189634ef7eSYong-Xuan Wang qemu_log("KVM AIA: default mode is %s\n", 15199634ef7eSYong-Xuan Wang kvm_aia_mode_str(default_aia_mode)); 15209634ef7eSYong-Xuan Wang 15219634ef7eSYong-Xuan Wang if (default_aia_mode != aia_mode) { 15229634ef7eSYong-Xuan Wang ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, 15239634ef7eSYong-Xuan Wang KVM_DEV_RISCV_AIA_CONFIG_MODE, 15249634ef7eSYong-Xuan Wang &aia_mode, true, NULL); 15259634ef7eSYong-Xuan Wang if (ret < 0) 15269634ef7eSYong-Xuan Wang warn_report("KVM AIA: failed to set KVM AIA mode"); 15279634ef7eSYong-Xuan Wang else 15289634ef7eSYong-Xuan Wang qemu_log("KVM AIA: set current mode to %s\n", 15299634ef7eSYong-Xuan Wang kvm_aia_mode_str(aia_mode)); 15309634ef7eSYong-Xuan Wang } 15319634ef7eSYong-Xuan Wang 15329634ef7eSYong-Xuan Wang ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, 15339634ef7eSYong-Xuan Wang KVM_DEV_RISCV_AIA_CONFIG_SRCS, 15349634ef7eSYong-Xuan Wang &aia_irq_num, true, NULL); 15359634ef7eSYong-Xuan Wang if (ret < 0) { 15369634ef7eSYong-Xuan Wang error_report("KVM AIA: failed to set number of input irq lines"); 15379634ef7eSYong-Xuan Wang exit(1); 15389634ef7eSYong-Xuan Wang } 15399634ef7eSYong-Xuan Wang 15409634ef7eSYong-Xuan Wang ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, 15419634ef7eSYong-Xuan Wang KVM_DEV_RISCV_AIA_CONFIG_IDS, 15429634ef7eSYong-Xuan Wang &aia_msi_num, true, NULL); 15439634ef7eSYong-Xuan Wang if (ret < 0) { 15449634ef7eSYong-Xuan Wang error_report("KVM AIA: failed to set number of msi"); 15459634ef7eSYong-Xuan Wang exit(1); 15469634ef7eSYong-Xuan Wang } 15479634ef7eSYong-Xuan Wang 1548871dad3aSYong-Xuan Wang 1549871dad3aSYong-Xuan Wang if (socket_count > 1) { 15509634ef7eSYong-Xuan Wang socket_bits = find_last_bit(&socket_count, BITS_PER_LONG) + 1; 15519634ef7eSYong-Xuan Wang ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, 15529634ef7eSYong-Xuan Wang KVM_DEV_RISCV_AIA_CONFIG_GROUP_BITS, 15539634ef7eSYong-Xuan Wang &socket_bits, true, NULL); 15549634ef7eSYong-Xuan Wang if (ret < 0) { 15559634ef7eSYong-Xuan Wang error_report("KVM AIA: failed to set group_bits"); 15569634ef7eSYong-Xuan Wang exit(1); 15579634ef7eSYong-Xuan Wang } 15589634ef7eSYong-Xuan Wang 15599634ef7eSYong-Xuan Wang ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, 15609634ef7eSYong-Xuan Wang KVM_DEV_RISCV_AIA_CONFIG_GROUP_SHIFT, 15619634ef7eSYong-Xuan Wang &group_shift, true, NULL); 15629634ef7eSYong-Xuan Wang if (ret < 0) { 15639634ef7eSYong-Xuan Wang error_report("KVM AIA: failed to set group_shift"); 15649634ef7eSYong-Xuan Wang exit(1); 15659634ef7eSYong-Xuan Wang } 1566871dad3aSYong-Xuan Wang } 15679634ef7eSYong-Xuan Wang 15689634ef7eSYong-Xuan Wang guest_bits = guest_num == 0 ? 0 : 15699634ef7eSYong-Xuan Wang find_last_bit(&guest_num, BITS_PER_LONG) + 1; 15709634ef7eSYong-Xuan Wang ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, 15719634ef7eSYong-Xuan Wang KVM_DEV_RISCV_AIA_CONFIG_GUEST_BITS, 15729634ef7eSYong-Xuan Wang &guest_bits, true, NULL); 15739634ef7eSYong-Xuan Wang if (ret < 0) { 15749634ef7eSYong-Xuan Wang error_report("KVM AIA: failed to set guest_bits"); 15759634ef7eSYong-Xuan Wang exit(1); 15769634ef7eSYong-Xuan Wang } 15779634ef7eSYong-Xuan Wang 15789634ef7eSYong-Xuan Wang ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_ADDR, 15799634ef7eSYong-Xuan Wang KVM_DEV_RISCV_AIA_ADDR_APLIC, 15809634ef7eSYong-Xuan Wang &aplic_base, true, NULL); 15819634ef7eSYong-Xuan Wang if (ret < 0) { 15829634ef7eSYong-Xuan Wang error_report("KVM AIA: failed to set the base address of APLIC"); 15839634ef7eSYong-Xuan Wang exit(1); 15849634ef7eSYong-Xuan Wang } 15859634ef7eSYong-Xuan Wang 15869634ef7eSYong-Xuan Wang for (socket = 0; socket < socket_count; socket++) { 15879634ef7eSYong-Xuan Wang socket_imsic_base = imsic_base + socket * (1U << group_shift); 15889634ef7eSYong-Xuan Wang hart_count = riscv_socket_hart_count(machine, socket); 15899634ef7eSYong-Xuan Wang base_hart = riscv_socket_first_hartid(machine, socket); 15909634ef7eSYong-Xuan Wang 15919634ef7eSYong-Xuan Wang if (max_hart_per_socket < hart_count) { 15929634ef7eSYong-Xuan Wang max_hart_per_socket = hart_count; 15939634ef7eSYong-Xuan Wang } 15949634ef7eSYong-Xuan Wang 15959634ef7eSYong-Xuan Wang for (i = 0; i < hart_count; i++) { 15969634ef7eSYong-Xuan Wang imsic_addr = socket_imsic_base + i * IMSIC_HART_SIZE(guest_bits); 15979634ef7eSYong-Xuan Wang ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_ADDR, 15989634ef7eSYong-Xuan Wang KVM_DEV_RISCV_AIA_ADDR_IMSIC(i + base_hart), 15999634ef7eSYong-Xuan Wang &imsic_addr, true, NULL); 16009634ef7eSYong-Xuan Wang if (ret < 0) { 16019634ef7eSYong-Xuan Wang error_report("KVM AIA: failed to set the IMSIC address for hart %d", i); 16029634ef7eSYong-Xuan Wang exit(1); 16039634ef7eSYong-Xuan Wang } 16049634ef7eSYong-Xuan Wang } 16059634ef7eSYong-Xuan Wang } 16069634ef7eSYong-Xuan Wang 16079634ef7eSYong-Xuan Wang hart_bits = find_last_bit(&max_hart_per_socket, BITS_PER_LONG) + 1; 16089634ef7eSYong-Xuan Wang ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, 16099634ef7eSYong-Xuan Wang KVM_DEV_RISCV_AIA_CONFIG_HART_BITS, 16109634ef7eSYong-Xuan Wang &hart_bits, true, NULL); 16119634ef7eSYong-Xuan Wang if (ret < 0) { 16129634ef7eSYong-Xuan Wang error_report("KVM AIA: failed to set hart_bits"); 16139634ef7eSYong-Xuan Wang exit(1); 16149634ef7eSYong-Xuan Wang } 16159634ef7eSYong-Xuan Wang 16169634ef7eSYong-Xuan Wang if (kvm_has_gsi_routing()) { 16179634ef7eSYong-Xuan Wang for (uint64_t idx = 0; idx < aia_irq_num + 1; ++idx) { 16189634ef7eSYong-Xuan Wang /* KVM AIA only has one APLIC instance */ 16199634ef7eSYong-Xuan Wang kvm_irqchip_add_irq_route(kvm_state, idx, 0, idx); 16209634ef7eSYong-Xuan Wang } 16219634ef7eSYong-Xuan Wang kvm_gsi_routing_allowed = true; 16229634ef7eSYong-Xuan Wang kvm_irqchip_commit_routes(kvm_state); 16239634ef7eSYong-Xuan Wang } 16249634ef7eSYong-Xuan Wang 16259634ef7eSYong-Xuan Wang ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CTRL, 16269634ef7eSYong-Xuan Wang KVM_DEV_RISCV_AIA_CTRL_INIT, 16279634ef7eSYong-Xuan Wang NULL, true, NULL); 16289634ef7eSYong-Xuan Wang if (ret < 0) { 16299634ef7eSYong-Xuan Wang error_report("KVM AIA: initialized fail"); 16309634ef7eSYong-Xuan Wang exit(1); 16319634ef7eSYong-Xuan Wang } 16329634ef7eSYong-Xuan Wang 1633a788260bSPaolo Bonzini kvm_msi_via_irqfd_allowed = true; 16343dba0a33SPaolo Bonzini } 1635a7e87cd7SDaniel Henrique Barboza 1636d86c25b2SDaniel Henrique Barboza static void kvm_cpu_instance_init(CPUState *cs) 163732fa1776SDaniel Henrique Barboza { 1638d86c25b2SDaniel Henrique Barboza Object *obj = OBJECT(RISCV_CPU(cs)); 163932fa1776SDaniel Henrique Barboza 1640efa365b7SDaniel Henrique Barboza riscv_init_kvm_registers(obj); 164132fa1776SDaniel Henrique Barboza 1642efa365b7SDaniel Henrique Barboza kvm_riscv_add_cpu_user_properties(obj); 164332fa1776SDaniel Henrique Barboza } 164432fa1776SDaniel Henrique Barboza 16450d71f0a3SDaniel Henrique Barboza /* 16460d71f0a3SDaniel Henrique Barboza * We'll get here via the following path: 16470d71f0a3SDaniel Henrique Barboza * 16480d71f0a3SDaniel Henrique Barboza * riscv_cpu_realize() 16490d71f0a3SDaniel Henrique Barboza * -> cpu_exec_realizefn() 16500d71f0a3SDaniel Henrique Barboza * -> kvm_cpu_realize() (via accel_cpu_common_realize()) 16510d71f0a3SDaniel Henrique Barboza */ 16520d71f0a3SDaniel Henrique Barboza static bool kvm_cpu_realize(CPUState *cs, Error **errp) 16530d71f0a3SDaniel Henrique Barboza { 16540d71f0a3SDaniel Henrique Barboza RISCVCPU *cpu = RISCV_CPU(cs); 16550d71f0a3SDaniel Henrique Barboza int ret; 16560d71f0a3SDaniel Henrique Barboza 16570d71f0a3SDaniel Henrique Barboza if (riscv_has_ext(&cpu->env, RVV)) { 16580d71f0a3SDaniel Henrique Barboza ret = prctl(PR_RISCV_V_SET_CONTROL, PR_RISCV_V_VSTATE_CTRL_ON); 16590d71f0a3SDaniel Henrique Barboza if (ret) { 16600d71f0a3SDaniel Henrique Barboza error_setg(errp, "Error in prctl PR_RISCV_V_SET_CONTROL, code: %s", 16610d71f0a3SDaniel Henrique Barboza strerrorname_np(errno)); 16620d71f0a3SDaniel Henrique Barboza return false; 16630d71f0a3SDaniel Henrique Barboza } 16640d71f0a3SDaniel Henrique Barboza } 16650d71f0a3SDaniel Henrique Barboza 16660d71f0a3SDaniel Henrique Barboza return true; 16670d71f0a3SDaniel Henrique Barboza } 16680d71f0a3SDaniel Henrique Barboza 1669bbef9140SDaniel Henrique Barboza void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp) 1670bbef9140SDaniel Henrique Barboza { 1671bbef9140SDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 1672bbef9140SDaniel Henrique Barboza KVMScratchCPU kvmcpu; 1673bbef9140SDaniel Henrique Barboza struct kvm_one_reg reg; 1674bbef9140SDaniel Henrique Barboza uint64_t val; 1675bbef9140SDaniel Henrique Barboza int ret; 1676bbef9140SDaniel Henrique Barboza 1677bbef9140SDaniel Henrique Barboza /* short-circuit without spinning the scratch CPU */ 1678d4ff3da8SDaniel Henrique Barboza if (!cpu->cfg.ext_zicbom && !cpu->cfg.ext_zicboz && 1679d4ff3da8SDaniel Henrique Barboza !riscv_has_ext(env, RVV)) { 1680bbef9140SDaniel Henrique Barboza return; 1681bbef9140SDaniel Henrique Barboza } 1682bbef9140SDaniel Henrique Barboza 1683bbef9140SDaniel Henrique Barboza if (!kvm_riscv_create_scratch_vcpu(&kvmcpu)) { 1684bbef9140SDaniel Henrique Barboza error_setg(errp, "Unable to create scratch KVM cpu"); 1685bbef9140SDaniel Henrique Barboza return; 1686bbef9140SDaniel Henrique Barboza } 1687bbef9140SDaniel Henrique Barboza 1688bbef9140SDaniel Henrique Barboza if (cpu->cfg.ext_zicbom && 1689bbef9140SDaniel Henrique Barboza riscv_cpu_option_set(kvm_cbom_blocksize.name)) { 1690bbef9140SDaniel Henrique Barboza 1691bbef9140SDaniel Henrique Barboza reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, 1692bbef9140SDaniel Henrique Barboza kvm_cbom_blocksize.kvm_reg_id); 1693bbef9140SDaniel Henrique Barboza reg.addr = (uint64_t)&val; 1694bbef9140SDaniel Henrique Barboza ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, ®); 1695bbef9140SDaniel Henrique Barboza if (ret != 0) { 1696bbef9140SDaniel Henrique Barboza error_setg(errp, "Unable to read cbom_blocksize, error %d", errno); 1697bbef9140SDaniel Henrique Barboza return; 1698bbef9140SDaniel Henrique Barboza } 1699bbef9140SDaniel Henrique Barboza 1700bbef9140SDaniel Henrique Barboza if (cpu->cfg.cbom_blocksize != val) { 1701bbef9140SDaniel Henrique Barboza error_setg(errp, "Unable to set cbom_blocksize to a different " 1702bbef9140SDaniel Henrique Barboza "value than the host (%lu)", val); 1703bbef9140SDaniel Henrique Barboza return; 1704bbef9140SDaniel Henrique Barboza } 1705bbef9140SDaniel Henrique Barboza } 1706bbef9140SDaniel Henrique Barboza 1707bbef9140SDaniel Henrique Barboza if (cpu->cfg.ext_zicboz && 1708bbef9140SDaniel Henrique Barboza riscv_cpu_option_set(kvm_cboz_blocksize.name)) { 1709bbef9140SDaniel Henrique Barboza 1710bbef9140SDaniel Henrique Barboza reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, 1711bbef9140SDaniel Henrique Barboza kvm_cboz_blocksize.kvm_reg_id); 1712bbef9140SDaniel Henrique Barboza reg.addr = (uint64_t)&val; 1713bbef9140SDaniel Henrique Barboza ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, ®); 1714bbef9140SDaniel Henrique Barboza if (ret != 0) { 1715bbef9140SDaniel Henrique Barboza error_setg(errp, "Unable to read cboz_blocksize, error %d", errno); 1716bbef9140SDaniel Henrique Barboza return; 1717bbef9140SDaniel Henrique Barboza } 1718bbef9140SDaniel Henrique Barboza 1719bbef9140SDaniel Henrique Barboza if (cpu->cfg.cboz_blocksize != val) { 1720bbef9140SDaniel Henrique Barboza error_setg(errp, "Unable to set cboz_blocksize to a different " 1721bbef9140SDaniel Henrique Barboza "value than the host (%lu)", val); 1722bbef9140SDaniel Henrique Barboza return; 1723bbef9140SDaniel Henrique Barboza } 1724bbef9140SDaniel Henrique Barboza } 1725bbef9140SDaniel Henrique Barboza 1726d4ff3da8SDaniel Henrique Barboza /* Users are setting vlen, not vlenb */ 1727d4ff3da8SDaniel Henrique Barboza if (riscv_has_ext(env, RVV) && riscv_cpu_option_set("vlen")) { 1728d4ff3da8SDaniel Henrique Barboza if (!kvm_v_vlenb.supported) { 1729d4ff3da8SDaniel Henrique Barboza error_setg(errp, "Unable to set 'vlenb': register not supported"); 1730d4ff3da8SDaniel Henrique Barboza return; 1731d4ff3da8SDaniel Henrique Barboza } 1732d4ff3da8SDaniel Henrique Barboza 1733d4ff3da8SDaniel Henrique Barboza reg.id = kvm_v_vlenb.kvm_reg_id; 1734d4ff3da8SDaniel Henrique Barboza reg.addr = (uint64_t)&val; 1735d4ff3da8SDaniel Henrique Barboza ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, ®); 1736d4ff3da8SDaniel Henrique Barboza if (ret != 0) { 1737d4ff3da8SDaniel Henrique Barboza error_setg(errp, "Unable to read vlenb register, error %d", errno); 1738d4ff3da8SDaniel Henrique Barboza return; 1739d4ff3da8SDaniel Henrique Barboza } 1740d4ff3da8SDaniel Henrique Barboza 1741d4ff3da8SDaniel Henrique Barboza if (cpu->cfg.vlenb != val) { 1742d4ff3da8SDaniel Henrique Barboza error_setg(errp, "Unable to set 'vlen' to a different " 1743d4ff3da8SDaniel Henrique Barboza "value than the host (%lu)", val * 8); 1744d4ff3da8SDaniel Henrique Barboza return; 1745d4ff3da8SDaniel Henrique Barboza } 1746d4ff3da8SDaniel Henrique Barboza } 1747d4ff3da8SDaniel Henrique Barboza 1748bbef9140SDaniel Henrique Barboza kvm_riscv_destroy_scratch_vcpu(&kvmcpu); 1749bbef9140SDaniel Henrique Barboza } 1750bbef9140SDaniel Henrique Barboza 1751d86c25b2SDaniel Henrique Barboza static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data) 1752d86c25b2SDaniel Henrique Barboza { 1753d86c25b2SDaniel Henrique Barboza AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); 1754d86c25b2SDaniel Henrique Barboza 1755d86c25b2SDaniel Henrique Barboza acc->cpu_instance_init = kvm_cpu_instance_init; 17560d71f0a3SDaniel Henrique Barboza acc->cpu_target_realize = kvm_cpu_realize; 1757d86c25b2SDaniel Henrique Barboza } 1758d86c25b2SDaniel Henrique Barboza 1759d86c25b2SDaniel Henrique Barboza static const TypeInfo kvm_cpu_accel_type_info = { 1760d86c25b2SDaniel Henrique Barboza .name = ACCEL_CPU_NAME("kvm"), 1761d86c25b2SDaniel Henrique Barboza 1762d86c25b2SDaniel Henrique Barboza .parent = TYPE_ACCEL_CPU, 1763d86c25b2SDaniel Henrique Barboza .class_init = kvm_cpu_accel_class_init, 1764d86c25b2SDaniel Henrique Barboza .abstract = true, 1765d86c25b2SDaniel Henrique Barboza }; 1766d86c25b2SDaniel Henrique Barboza static void kvm_cpu_accel_register_types(void) 1767d86c25b2SDaniel Henrique Barboza { 1768d86c25b2SDaniel Henrique Barboza type_register_static(&kvm_cpu_accel_type_info); 1769d86c25b2SDaniel Henrique Barboza } 1770d86c25b2SDaniel Henrique Barboza type_init(kvm_cpu_accel_register_types); 1771d86c25b2SDaniel Henrique Barboza 1772a7e87cd7SDaniel Henrique Barboza static void riscv_host_cpu_init(Object *obj) 1773a7e87cd7SDaniel Henrique Barboza { 1774a7e87cd7SDaniel Henrique Barboza CPURISCVState *env = &RISCV_CPU(obj)->env; 1775a7e87cd7SDaniel Henrique Barboza 1776a7e87cd7SDaniel Henrique Barboza #if defined(TARGET_RISCV32) 1777a7e87cd7SDaniel Henrique Barboza env->misa_mxl_max = env->misa_mxl = MXL_RV32; 1778a7e87cd7SDaniel Henrique Barboza #elif defined(TARGET_RISCV64) 1779a7e87cd7SDaniel Henrique Barboza env->misa_mxl_max = env->misa_mxl = MXL_RV64; 1780a7e87cd7SDaniel Henrique Barboza #endif 1781a7e87cd7SDaniel Henrique Barboza } 1782a7e87cd7SDaniel Henrique Barboza 1783a7e87cd7SDaniel Henrique Barboza static const TypeInfo riscv_kvm_cpu_type_infos[] = { 1784a7e87cd7SDaniel Henrique Barboza { 1785a7e87cd7SDaniel Henrique Barboza .name = TYPE_RISCV_CPU_HOST, 1786a7e87cd7SDaniel Henrique Barboza .parent = TYPE_RISCV_CPU, 1787a7e87cd7SDaniel Henrique Barboza .instance_init = riscv_host_cpu_init, 1788a7e87cd7SDaniel Henrique Barboza } 1789a7e87cd7SDaniel Henrique Barboza }; 1790a7e87cd7SDaniel Henrique Barboza 1791a7e87cd7SDaniel Henrique Barboza DEFINE_TYPES(riscv_kvm_cpu_type_infos) 1792