191654e61SYifei Jiang /* 291654e61SYifei Jiang * RISC-V implementation of KVM hooks 391654e61SYifei Jiang * 491654e61SYifei Jiang * Copyright (c) 2020 Huawei Technologies Co., Ltd 591654e61SYifei Jiang * 691654e61SYifei Jiang * This program is free software; you can redistribute it and/or modify it 791654e61SYifei Jiang * under the terms and conditions of the GNU General Public License, 891654e61SYifei Jiang * version 2 or later, as published by the Free Software Foundation. 991654e61SYifei Jiang * 1091654e61SYifei Jiang * This program is distributed in the hope it will be useful, but WITHOUT 1191654e61SYifei Jiang * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1291654e61SYifei Jiang * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1391654e61SYifei Jiang * more details. 1491654e61SYifei Jiang * 1591654e61SYifei Jiang * You should have received a copy of the GNU General Public License along with 1691654e61SYifei Jiang * this program. If not, see <http://www.gnu.org/licenses/>. 1791654e61SYifei Jiang */ 1891654e61SYifei Jiang 1991654e61SYifei Jiang #include "qemu/osdep.h" 2091654e61SYifei Jiang #include <sys/ioctl.h> 2191654e61SYifei Jiang 2291654e61SYifei Jiang #include <linux/kvm.h> 2391654e61SYifei Jiang 2491654e61SYifei Jiang #include "qemu/timer.h" 2592becce5SDaniel Henrique Barboza #include "qapi/error.h" 2691654e61SYifei Jiang #include "qemu/error-report.h" 2791654e61SYifei Jiang #include "qemu/main-loop.h" 2892becce5SDaniel Henrique Barboza #include "qapi/visitor.h" 2991654e61SYifei Jiang #include "sysemu/sysemu.h" 3091654e61SYifei Jiang #include "sysemu/kvm.h" 3191654e61SYifei Jiang #include "sysemu/kvm_int.h" 3291654e61SYifei Jiang #include "cpu.h" 3391654e61SYifei Jiang #include "trace.h" 3491654e61SYifei Jiang #include "hw/pci/pci.h" 3591654e61SYifei Jiang #include "exec/memattrs.h" 3691654e61SYifei Jiang #include "exec/address-spaces.h" 3791654e61SYifei Jiang #include "hw/boards.h" 3891654e61SYifei Jiang #include "hw/irq.h" 3991654e61SYifei Jiang #include "qemu/log.h" 4091654e61SYifei Jiang #include "hw/loader.h" 41ad40be27SYifei Jiang #include "kvm_riscv.h" 424eb47125SYifei Jiang #include "sbi_ecall_interface.h" 434eb47125SYifei Jiang #include "chardev/char-fe.h" 4427abe66fSYifei Jiang #include "migration/migration.h" 459ad3e016SYifei Jiang #include "sysemu/runstate.h" 4691654e61SYifei Jiang 470a312b85SYifei Jiang static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type, 480a312b85SYifei Jiang uint64_t idx) 490a312b85SYifei Jiang { 500a312b85SYifei Jiang uint64_t id = KVM_REG_RISCV | type | idx; 510a312b85SYifei Jiang 520a312b85SYifei Jiang switch (riscv_cpu_mxl(env)) { 530a312b85SYifei Jiang case MXL_RV32: 540a312b85SYifei Jiang id |= KVM_REG_SIZE_U32; 550a312b85SYifei Jiang break; 560a312b85SYifei Jiang case MXL_RV64: 570a312b85SYifei Jiang id |= KVM_REG_SIZE_U64; 580a312b85SYifei Jiang break; 590a312b85SYifei Jiang default: 600a312b85SYifei Jiang g_assert_not_reached(); 610a312b85SYifei Jiang } 620a312b85SYifei Jiang return id; 630a312b85SYifei Jiang } 640a312b85SYifei Jiang 65937f0b45SYifei Jiang #define RISCV_CORE_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, \ 66937f0b45SYifei Jiang KVM_REG_RISCV_CORE_REG(name)) 67937f0b45SYifei Jiang 68937f0b45SYifei Jiang #define RISCV_CSR_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CSR, \ 69937f0b45SYifei Jiang KVM_REG_RISCV_CSR_REG(name)) 70937f0b45SYifei Jiang 7127abe66fSYifei Jiang #define RISCV_TIMER_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_TIMER, \ 7227abe66fSYifei Jiang KVM_REG_RISCV_TIMER_REG(name)) 7327abe66fSYifei Jiang 74937f0b45SYifei Jiang #define RISCV_FP_F_REG(env, idx) kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_F, idx) 75937f0b45SYifei Jiang 76937f0b45SYifei Jiang #define RISCV_FP_D_REG(env, idx) kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_D, idx) 77937f0b45SYifei Jiang 78937f0b45SYifei Jiang #define KVM_RISCV_GET_CSR(cs, env, csr, reg) \ 79937f0b45SYifei Jiang do { \ 80937f0b45SYifei Jiang int ret = kvm_get_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \ 81937f0b45SYifei Jiang if (ret) { \ 82937f0b45SYifei Jiang return ret; \ 83937f0b45SYifei Jiang } \ 84937f0b45SYifei Jiang } while (0) 85937f0b45SYifei Jiang 869997cc1eSYifei Jiang #define KVM_RISCV_SET_CSR(cs, env, csr, reg) \ 879997cc1eSYifei Jiang do { \ 889997cc1eSYifei Jiang int ret = kvm_set_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \ 899997cc1eSYifei Jiang if (ret) { \ 909997cc1eSYifei Jiang return ret; \ 919997cc1eSYifei Jiang } \ 929997cc1eSYifei Jiang } while (0) 939997cc1eSYifei Jiang 9427abe66fSYifei Jiang #define KVM_RISCV_GET_TIMER(cs, env, name, reg) \ 9527abe66fSYifei Jiang do { \ 9627abe66fSYifei Jiang int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(env, name), ®); \ 9727abe66fSYifei Jiang if (ret) { \ 9827abe66fSYifei Jiang abort(); \ 9927abe66fSYifei Jiang } \ 10027abe66fSYifei Jiang } while (0) 10127abe66fSYifei Jiang 10227abe66fSYifei Jiang #define KVM_RISCV_SET_TIMER(cs, env, name, reg) \ 10327abe66fSYifei Jiang do { \ 104c5cc248bSyang.zhang int ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(env, name), ®); \ 10527abe66fSYifei Jiang if (ret) { \ 10627abe66fSYifei Jiang abort(); \ 10727abe66fSYifei Jiang } \ 10827abe66fSYifei Jiang } while (0) 10927abe66fSYifei Jiang 11092becce5SDaniel Henrique Barboza typedef struct KVMCPUConfig { 11192becce5SDaniel Henrique Barboza const char *name; 11292becce5SDaniel Henrique Barboza const char *description; 11392becce5SDaniel Henrique Barboza target_ulong offset; 11492becce5SDaniel Henrique Barboza int kvm_reg_id; 11592becce5SDaniel Henrique Barboza bool user_set; 11692becce5SDaniel Henrique Barboza } KVMCPUConfig; 11792becce5SDaniel Henrique Barboza 11892becce5SDaniel Henrique Barboza #define KVM_MISA_CFG(_bit, _reg_id) \ 11992becce5SDaniel Henrique Barboza {.offset = _bit, .kvm_reg_id = _reg_id} 12092becce5SDaniel Henrique Barboza 12192becce5SDaniel Henrique Barboza /* KVM ISA extensions */ 12292becce5SDaniel Henrique Barboza static KVMCPUConfig kvm_misa_ext_cfgs[] = { 12392becce5SDaniel Henrique Barboza KVM_MISA_CFG(RVA, KVM_RISCV_ISA_EXT_A), 12492becce5SDaniel Henrique Barboza KVM_MISA_CFG(RVC, KVM_RISCV_ISA_EXT_C), 12592becce5SDaniel Henrique Barboza KVM_MISA_CFG(RVD, KVM_RISCV_ISA_EXT_D), 12692becce5SDaniel Henrique Barboza KVM_MISA_CFG(RVF, KVM_RISCV_ISA_EXT_F), 12792becce5SDaniel Henrique Barboza KVM_MISA_CFG(RVH, KVM_RISCV_ISA_EXT_H), 12892becce5SDaniel Henrique Barboza KVM_MISA_CFG(RVI, KVM_RISCV_ISA_EXT_I), 12992becce5SDaniel Henrique Barboza KVM_MISA_CFG(RVM, KVM_RISCV_ISA_EXT_M), 13092becce5SDaniel Henrique Barboza }; 13192becce5SDaniel Henrique Barboza 13292becce5SDaniel Henrique Barboza static void kvm_cpu_set_misa_ext_cfg(Object *obj, Visitor *v, 13392becce5SDaniel Henrique Barboza const char *name, 13492becce5SDaniel Henrique Barboza void *opaque, Error **errp) 13592becce5SDaniel Henrique Barboza { 13692becce5SDaniel Henrique Barboza KVMCPUConfig *misa_ext_cfg = opaque; 13792becce5SDaniel Henrique Barboza target_ulong misa_bit = misa_ext_cfg->offset; 13892becce5SDaniel Henrique Barboza RISCVCPU *cpu = RISCV_CPU(obj); 13992becce5SDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 14092becce5SDaniel Henrique Barboza bool value, host_bit; 14192becce5SDaniel Henrique Barboza 14292becce5SDaniel Henrique Barboza if (!visit_type_bool(v, name, &value, errp)) { 14392becce5SDaniel Henrique Barboza return; 14492becce5SDaniel Henrique Barboza } 14592becce5SDaniel Henrique Barboza 14692becce5SDaniel Henrique Barboza host_bit = env->misa_ext_mask & misa_bit; 14792becce5SDaniel Henrique Barboza 14892becce5SDaniel Henrique Barboza if (value == host_bit) { 14992becce5SDaniel Henrique Barboza return; 15092becce5SDaniel Henrique Barboza } 15192becce5SDaniel Henrique Barboza 15292becce5SDaniel Henrique Barboza if (!value) { 15392becce5SDaniel Henrique Barboza misa_ext_cfg->user_set = true; 15492becce5SDaniel Henrique Barboza return; 15592becce5SDaniel Henrique Barboza } 15692becce5SDaniel Henrique Barboza 15792becce5SDaniel Henrique Barboza /* 15892becce5SDaniel Henrique Barboza * Forbid users to enable extensions that aren't 15992becce5SDaniel Henrique Barboza * available in the hart. 16092becce5SDaniel Henrique Barboza */ 16192becce5SDaniel Henrique Barboza error_setg(errp, "Enabling MISA bit '%s' is not allowed: it's not " 16292becce5SDaniel Henrique Barboza "enabled in the host", misa_ext_cfg->name); 16392becce5SDaniel Henrique Barboza } 16492becce5SDaniel Henrique Barboza 165*7313fffbSDaniel Henrique Barboza static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs) 166*7313fffbSDaniel Henrique Barboza { 167*7313fffbSDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 168*7313fffbSDaniel Henrique Barboza uint64_t id, reg; 169*7313fffbSDaniel Henrique Barboza int i, ret; 170*7313fffbSDaniel Henrique Barboza 171*7313fffbSDaniel Henrique Barboza for (i = 0; i < ARRAY_SIZE(kvm_misa_ext_cfgs); i++) { 172*7313fffbSDaniel Henrique Barboza KVMCPUConfig *misa_cfg = &kvm_misa_ext_cfgs[i]; 173*7313fffbSDaniel Henrique Barboza target_ulong misa_bit = misa_cfg->offset; 174*7313fffbSDaniel Henrique Barboza 175*7313fffbSDaniel Henrique Barboza if (!misa_cfg->user_set) { 176*7313fffbSDaniel Henrique Barboza continue; 177*7313fffbSDaniel Henrique Barboza } 178*7313fffbSDaniel Henrique Barboza 179*7313fffbSDaniel Henrique Barboza /* If we're here we're going to disable the MISA bit */ 180*7313fffbSDaniel Henrique Barboza reg = 0; 181*7313fffbSDaniel Henrique Barboza id = kvm_riscv_reg_id(env, KVM_REG_RISCV_ISA_EXT, 182*7313fffbSDaniel Henrique Barboza misa_cfg->kvm_reg_id); 183*7313fffbSDaniel Henrique Barboza ret = kvm_set_one_reg(cs, id, ®); 184*7313fffbSDaniel Henrique Barboza if (ret != 0) { 185*7313fffbSDaniel Henrique Barboza /* 186*7313fffbSDaniel Henrique Barboza * We're not checking for -EINVAL because if the bit is about 187*7313fffbSDaniel Henrique Barboza * to be disabled, it means that it was already enabled by 188*7313fffbSDaniel Henrique Barboza * KVM. We determined that by fetching the 'isa' register 189*7313fffbSDaniel Henrique Barboza * during init() time. Any error at this point is worth 190*7313fffbSDaniel Henrique Barboza * aborting. 191*7313fffbSDaniel Henrique Barboza */ 192*7313fffbSDaniel Henrique Barboza error_report("Unable to set KVM reg %s, error %d", 193*7313fffbSDaniel Henrique Barboza misa_cfg->name, ret); 194*7313fffbSDaniel Henrique Barboza exit(EXIT_FAILURE); 195*7313fffbSDaniel Henrique Barboza } 196*7313fffbSDaniel Henrique Barboza env->misa_ext &= ~misa_bit; 197*7313fffbSDaniel Henrique Barboza } 198*7313fffbSDaniel Henrique Barboza } 199*7313fffbSDaniel Henrique Barboza 20092becce5SDaniel Henrique Barboza static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj) 20192becce5SDaniel Henrique Barboza { 20292becce5SDaniel Henrique Barboza int i; 20392becce5SDaniel Henrique Barboza 20492becce5SDaniel Henrique Barboza for (i = 0; i < ARRAY_SIZE(kvm_misa_ext_cfgs); i++) { 20592becce5SDaniel Henrique Barboza KVMCPUConfig *misa_cfg = &kvm_misa_ext_cfgs[i]; 20692becce5SDaniel Henrique Barboza int bit = misa_cfg->offset; 20792becce5SDaniel Henrique Barboza 20892becce5SDaniel Henrique Barboza misa_cfg->name = riscv_get_misa_ext_name(bit); 20992becce5SDaniel Henrique Barboza misa_cfg->description = riscv_get_misa_ext_description(bit); 21092becce5SDaniel Henrique Barboza 21192becce5SDaniel Henrique Barboza object_property_add(cpu_obj, misa_cfg->name, "bool", 21292becce5SDaniel Henrique Barboza NULL, 21392becce5SDaniel Henrique Barboza kvm_cpu_set_misa_ext_cfg, 21492becce5SDaniel Henrique Barboza NULL, misa_cfg); 21592becce5SDaniel Henrique Barboza object_property_set_description(cpu_obj, misa_cfg->name, 21692becce5SDaniel Henrique Barboza misa_cfg->description); 21792becce5SDaniel Henrique Barboza } 21892becce5SDaniel Henrique Barboza } 21992becce5SDaniel Henrique Barboza 220937f0b45SYifei Jiang static int kvm_riscv_get_regs_core(CPUState *cs) 221937f0b45SYifei Jiang { 222937f0b45SYifei Jiang int ret = 0; 223937f0b45SYifei Jiang int i; 224937f0b45SYifei Jiang target_ulong reg; 225937f0b45SYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 226937f0b45SYifei Jiang 227937f0b45SYifei Jiang ret = kvm_get_one_reg(cs, RISCV_CORE_REG(env, regs.pc), ®); 228937f0b45SYifei Jiang if (ret) { 229937f0b45SYifei Jiang return ret; 230937f0b45SYifei Jiang } 231937f0b45SYifei Jiang env->pc = reg; 232937f0b45SYifei Jiang 233937f0b45SYifei Jiang for (i = 1; i < 32; i++) { 234937f0b45SYifei Jiang uint64_t id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, i); 235937f0b45SYifei Jiang ret = kvm_get_one_reg(cs, id, ®); 236937f0b45SYifei Jiang if (ret) { 237937f0b45SYifei Jiang return ret; 238937f0b45SYifei Jiang } 239937f0b45SYifei Jiang env->gpr[i] = reg; 240937f0b45SYifei Jiang } 241937f0b45SYifei Jiang 242937f0b45SYifei Jiang return ret; 243937f0b45SYifei Jiang } 244937f0b45SYifei Jiang 2459997cc1eSYifei Jiang static int kvm_riscv_put_regs_core(CPUState *cs) 2469997cc1eSYifei Jiang { 2479997cc1eSYifei Jiang int ret = 0; 2489997cc1eSYifei Jiang int i; 2499997cc1eSYifei Jiang target_ulong reg; 2509997cc1eSYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 2519997cc1eSYifei Jiang 2529997cc1eSYifei Jiang reg = env->pc; 2539997cc1eSYifei Jiang ret = kvm_set_one_reg(cs, RISCV_CORE_REG(env, regs.pc), ®); 2549997cc1eSYifei Jiang if (ret) { 2559997cc1eSYifei Jiang return ret; 2569997cc1eSYifei Jiang } 2579997cc1eSYifei Jiang 2589997cc1eSYifei Jiang for (i = 1; i < 32; i++) { 2599997cc1eSYifei Jiang uint64_t id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, i); 2609997cc1eSYifei Jiang reg = env->gpr[i]; 2619997cc1eSYifei Jiang ret = kvm_set_one_reg(cs, id, ®); 2629997cc1eSYifei Jiang if (ret) { 2639997cc1eSYifei Jiang return ret; 2649997cc1eSYifei Jiang } 2659997cc1eSYifei Jiang } 2669997cc1eSYifei Jiang 2679997cc1eSYifei Jiang return ret; 2689997cc1eSYifei Jiang } 2699997cc1eSYifei Jiang 270937f0b45SYifei Jiang static int kvm_riscv_get_regs_csr(CPUState *cs) 271937f0b45SYifei Jiang { 272937f0b45SYifei Jiang int ret = 0; 273937f0b45SYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 274937f0b45SYifei Jiang 275937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, sstatus, env->mstatus); 276937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, sie, env->mie); 277937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, stvec, env->stvec); 278937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, sscratch, env->sscratch); 279937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, sepc, env->sepc); 280937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, scause, env->scause); 281937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, stval, env->stval); 282937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, sip, env->mip); 283937f0b45SYifei Jiang KVM_RISCV_GET_CSR(cs, env, satp, env->satp); 284937f0b45SYifei Jiang return ret; 285937f0b45SYifei Jiang } 286937f0b45SYifei Jiang 2879997cc1eSYifei Jiang static int kvm_riscv_put_regs_csr(CPUState *cs) 2889997cc1eSYifei Jiang { 2899997cc1eSYifei Jiang int ret = 0; 2909997cc1eSYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 2919997cc1eSYifei Jiang 2929997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, sstatus, env->mstatus); 2939997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, sie, env->mie); 2949997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, stvec, env->stvec); 2959997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, sscratch, env->sscratch); 2969997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, sepc, env->sepc); 2979997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, scause, env->scause); 2989997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, stval, env->stval); 2999997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, sip, env->mip); 3009997cc1eSYifei Jiang KVM_RISCV_SET_CSR(cs, env, satp, env->satp); 3019997cc1eSYifei Jiang 3029997cc1eSYifei Jiang return ret; 3039997cc1eSYifei Jiang } 3049997cc1eSYifei Jiang 305937f0b45SYifei Jiang static int kvm_riscv_get_regs_fp(CPUState *cs) 306937f0b45SYifei Jiang { 307937f0b45SYifei Jiang int ret = 0; 308937f0b45SYifei Jiang int i; 309937f0b45SYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 310937f0b45SYifei Jiang 311937f0b45SYifei Jiang if (riscv_has_ext(env, RVD)) { 312937f0b45SYifei Jiang uint64_t reg; 313937f0b45SYifei Jiang for (i = 0; i < 32; i++) { 314937f0b45SYifei Jiang ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(env, i), ®); 315937f0b45SYifei Jiang if (ret) { 316937f0b45SYifei Jiang return ret; 317937f0b45SYifei Jiang } 318937f0b45SYifei Jiang env->fpr[i] = reg; 319937f0b45SYifei Jiang } 320937f0b45SYifei Jiang return ret; 321937f0b45SYifei Jiang } 322937f0b45SYifei Jiang 323937f0b45SYifei Jiang if (riscv_has_ext(env, RVF)) { 324937f0b45SYifei Jiang uint32_t reg; 325937f0b45SYifei Jiang for (i = 0; i < 32; i++) { 326937f0b45SYifei Jiang ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(env, i), ®); 327937f0b45SYifei Jiang if (ret) { 328937f0b45SYifei Jiang return ret; 329937f0b45SYifei Jiang } 330937f0b45SYifei Jiang env->fpr[i] = reg; 331937f0b45SYifei Jiang } 332937f0b45SYifei Jiang return ret; 333937f0b45SYifei Jiang } 334937f0b45SYifei Jiang 335937f0b45SYifei Jiang return ret; 336937f0b45SYifei Jiang } 337937f0b45SYifei Jiang 3389997cc1eSYifei Jiang static int kvm_riscv_put_regs_fp(CPUState *cs) 3399997cc1eSYifei Jiang { 3409997cc1eSYifei Jiang int ret = 0; 3419997cc1eSYifei Jiang int i; 3429997cc1eSYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 3439997cc1eSYifei Jiang 3449997cc1eSYifei Jiang if (riscv_has_ext(env, RVD)) { 3459997cc1eSYifei Jiang uint64_t reg; 3469997cc1eSYifei Jiang for (i = 0; i < 32; i++) { 3479997cc1eSYifei Jiang reg = env->fpr[i]; 3489997cc1eSYifei Jiang ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(env, i), ®); 3499997cc1eSYifei Jiang if (ret) { 3509997cc1eSYifei Jiang return ret; 3519997cc1eSYifei Jiang } 3529997cc1eSYifei Jiang } 3539997cc1eSYifei Jiang return ret; 3549997cc1eSYifei Jiang } 3559997cc1eSYifei Jiang 3569997cc1eSYifei Jiang if (riscv_has_ext(env, RVF)) { 3579997cc1eSYifei Jiang uint32_t reg; 3589997cc1eSYifei Jiang for (i = 0; i < 32; i++) { 3599997cc1eSYifei Jiang reg = env->fpr[i]; 3609997cc1eSYifei Jiang ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(env, i), ®); 3619997cc1eSYifei Jiang if (ret) { 3629997cc1eSYifei Jiang return ret; 3639997cc1eSYifei Jiang } 3649997cc1eSYifei Jiang } 3659997cc1eSYifei Jiang return ret; 3669997cc1eSYifei Jiang } 3679997cc1eSYifei Jiang 3689997cc1eSYifei Jiang return ret; 3699997cc1eSYifei Jiang } 3709997cc1eSYifei Jiang 37127abe66fSYifei Jiang static void kvm_riscv_get_regs_timer(CPUState *cs) 37227abe66fSYifei Jiang { 37327abe66fSYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 37427abe66fSYifei Jiang 37527abe66fSYifei Jiang if (env->kvm_timer_dirty) { 37627abe66fSYifei Jiang return; 37727abe66fSYifei Jiang } 37827abe66fSYifei Jiang 37927abe66fSYifei Jiang KVM_RISCV_GET_TIMER(cs, env, time, env->kvm_timer_time); 38027abe66fSYifei Jiang KVM_RISCV_GET_TIMER(cs, env, compare, env->kvm_timer_compare); 38127abe66fSYifei Jiang KVM_RISCV_GET_TIMER(cs, env, state, env->kvm_timer_state); 38227abe66fSYifei Jiang KVM_RISCV_GET_TIMER(cs, env, frequency, env->kvm_timer_frequency); 38327abe66fSYifei Jiang 38427abe66fSYifei Jiang env->kvm_timer_dirty = true; 38527abe66fSYifei Jiang } 38627abe66fSYifei Jiang 38727abe66fSYifei Jiang static void kvm_riscv_put_regs_timer(CPUState *cs) 38827abe66fSYifei Jiang { 38927abe66fSYifei Jiang uint64_t reg; 39027abe66fSYifei Jiang CPURISCVState *env = &RISCV_CPU(cs)->env; 39127abe66fSYifei Jiang 39227abe66fSYifei Jiang if (!env->kvm_timer_dirty) { 39327abe66fSYifei Jiang return; 39427abe66fSYifei Jiang } 39527abe66fSYifei Jiang 39627abe66fSYifei Jiang KVM_RISCV_SET_TIMER(cs, env, time, env->kvm_timer_time); 39727abe66fSYifei Jiang KVM_RISCV_SET_TIMER(cs, env, compare, env->kvm_timer_compare); 39827abe66fSYifei Jiang 39927abe66fSYifei Jiang /* 40027abe66fSYifei Jiang * To set register of RISCV_TIMER_REG(state) will occur a error from KVM 40127abe66fSYifei Jiang * on env->kvm_timer_state == 0, It's better to adapt in KVM, but it 40227abe66fSYifei Jiang * doesn't matter that adaping in QEMU now. 40327abe66fSYifei Jiang * TODO If KVM changes, adapt here. 40427abe66fSYifei Jiang */ 40527abe66fSYifei Jiang if (env->kvm_timer_state) { 40627abe66fSYifei Jiang KVM_RISCV_SET_TIMER(cs, env, state, env->kvm_timer_state); 40727abe66fSYifei Jiang } 40827abe66fSYifei Jiang 40927abe66fSYifei Jiang /* 41027abe66fSYifei Jiang * For now, migration will not work between Hosts with different timer 41127abe66fSYifei Jiang * frequency. Therefore, we should check whether they are the same here 41227abe66fSYifei Jiang * during the migration. 41327abe66fSYifei Jiang */ 41427abe66fSYifei Jiang if (migration_is_running(migrate_get_current()->state)) { 41527abe66fSYifei Jiang KVM_RISCV_GET_TIMER(cs, env, frequency, reg); 41627abe66fSYifei Jiang if (reg != env->kvm_timer_frequency) { 41727abe66fSYifei Jiang error_report("Dst Hosts timer frequency != Src Hosts"); 41827abe66fSYifei Jiang } 41927abe66fSYifei Jiang } 42027abe66fSYifei Jiang 42127abe66fSYifei Jiang env->kvm_timer_dirty = false; 42227abe66fSYifei Jiang } 4239997cc1eSYifei Jiang 424492265aeSDaniel Henrique Barboza typedef struct KVMScratchCPU { 425492265aeSDaniel Henrique Barboza int kvmfd; 426492265aeSDaniel Henrique Barboza int vmfd; 427492265aeSDaniel Henrique Barboza int cpufd; 428492265aeSDaniel Henrique Barboza } KVMScratchCPU; 429492265aeSDaniel Henrique Barboza 430492265aeSDaniel Henrique Barboza /* 431492265aeSDaniel Henrique Barboza * Heavily inspired by kvm_arm_create_scratch_host_vcpu() 432492265aeSDaniel Henrique Barboza * from target/arm/kvm.c. 433492265aeSDaniel Henrique Barboza */ 434492265aeSDaniel Henrique Barboza static bool kvm_riscv_create_scratch_vcpu(KVMScratchCPU *scratch) 435492265aeSDaniel Henrique Barboza { 436492265aeSDaniel Henrique Barboza int kvmfd = -1, vmfd = -1, cpufd = -1; 437492265aeSDaniel Henrique Barboza 438492265aeSDaniel Henrique Barboza kvmfd = qemu_open_old("/dev/kvm", O_RDWR); 439492265aeSDaniel Henrique Barboza if (kvmfd < 0) { 440492265aeSDaniel Henrique Barboza goto err; 441492265aeSDaniel Henrique Barboza } 442492265aeSDaniel Henrique Barboza do { 443492265aeSDaniel Henrique Barboza vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0); 444492265aeSDaniel Henrique Barboza } while (vmfd == -1 && errno == EINTR); 445492265aeSDaniel Henrique Barboza if (vmfd < 0) { 446492265aeSDaniel Henrique Barboza goto err; 447492265aeSDaniel Henrique Barboza } 448492265aeSDaniel Henrique Barboza cpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0); 449492265aeSDaniel Henrique Barboza if (cpufd < 0) { 450492265aeSDaniel Henrique Barboza goto err; 451492265aeSDaniel Henrique Barboza } 452492265aeSDaniel Henrique Barboza 453492265aeSDaniel Henrique Barboza scratch->kvmfd = kvmfd; 454492265aeSDaniel Henrique Barboza scratch->vmfd = vmfd; 455492265aeSDaniel Henrique Barboza scratch->cpufd = cpufd; 456492265aeSDaniel Henrique Barboza 457492265aeSDaniel Henrique Barboza return true; 458492265aeSDaniel Henrique Barboza 459492265aeSDaniel Henrique Barboza err: 460492265aeSDaniel Henrique Barboza if (cpufd >= 0) { 461492265aeSDaniel Henrique Barboza close(cpufd); 462492265aeSDaniel Henrique Barboza } 463492265aeSDaniel Henrique Barboza if (vmfd >= 0) { 464492265aeSDaniel Henrique Barboza close(vmfd); 465492265aeSDaniel Henrique Barboza } 466492265aeSDaniel Henrique Barboza if (kvmfd >= 0) { 467492265aeSDaniel Henrique Barboza close(kvmfd); 468492265aeSDaniel Henrique Barboza } 469492265aeSDaniel Henrique Barboza 470492265aeSDaniel Henrique Barboza return false; 471492265aeSDaniel Henrique Barboza } 472492265aeSDaniel Henrique Barboza 473492265aeSDaniel Henrique Barboza static void kvm_riscv_destroy_scratch_vcpu(KVMScratchCPU *scratch) 474492265aeSDaniel Henrique Barboza { 475492265aeSDaniel Henrique Barboza close(scratch->cpufd); 476492265aeSDaniel Henrique Barboza close(scratch->vmfd); 477492265aeSDaniel Henrique Barboza close(scratch->kvmfd); 478492265aeSDaniel Henrique Barboza } 479492265aeSDaniel Henrique Barboza 480492265aeSDaniel Henrique Barboza static void kvm_riscv_init_machine_ids(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) 481492265aeSDaniel Henrique Barboza { 482492265aeSDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 483492265aeSDaniel Henrique Barboza struct kvm_one_reg reg; 484492265aeSDaniel Henrique Barboza int ret; 485492265aeSDaniel Henrique Barboza 486492265aeSDaniel Henrique Barboza reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, 487492265aeSDaniel Henrique Barboza KVM_REG_RISCV_CONFIG_REG(mvendorid)); 488492265aeSDaniel Henrique Barboza reg.addr = (uint64_t)&cpu->cfg.mvendorid; 489492265aeSDaniel Henrique Barboza ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); 490492265aeSDaniel Henrique Barboza if (ret != 0) { 491492265aeSDaniel Henrique Barboza error_report("Unable to retrieve mvendorid from host, error %d", ret); 492492265aeSDaniel Henrique Barboza } 493d758f884SDaniel Henrique Barboza 494d758f884SDaniel Henrique Barboza reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, 495d758f884SDaniel Henrique Barboza KVM_REG_RISCV_CONFIG_REG(marchid)); 496d758f884SDaniel Henrique Barboza reg.addr = (uint64_t)&cpu->cfg.marchid; 497d758f884SDaniel Henrique Barboza ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); 498d758f884SDaniel Henrique Barboza if (ret != 0) { 499d758f884SDaniel Henrique Barboza error_report("Unable to retrieve marchid from host, error %d", ret); 500d758f884SDaniel Henrique Barboza } 501d758f884SDaniel Henrique Barboza 502d758f884SDaniel Henrique Barboza reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, 503d758f884SDaniel Henrique Barboza KVM_REG_RISCV_CONFIG_REG(mimpid)); 504d758f884SDaniel Henrique Barboza reg.addr = (uint64_t)&cpu->cfg.mimpid; 505d758f884SDaniel Henrique Barboza ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); 506d758f884SDaniel Henrique Barboza if (ret != 0) { 507d758f884SDaniel Henrique Barboza error_report("Unable to retrieve mimpid from host, error %d", ret); 508d758f884SDaniel Henrique Barboza } 509492265aeSDaniel Henrique Barboza } 510492265aeSDaniel Henrique Barboza 511e28b9c49SDaniel Henrique Barboza static void kvm_riscv_init_misa_ext_mask(RISCVCPU *cpu, 512e28b9c49SDaniel Henrique Barboza KVMScratchCPU *kvmcpu) 513e28b9c49SDaniel Henrique Barboza { 514e28b9c49SDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 515e28b9c49SDaniel Henrique Barboza struct kvm_one_reg reg; 516e28b9c49SDaniel Henrique Barboza int ret; 517e28b9c49SDaniel Henrique Barboza 518e28b9c49SDaniel Henrique Barboza reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, 519e28b9c49SDaniel Henrique Barboza KVM_REG_RISCV_CONFIG_REG(isa)); 520e28b9c49SDaniel Henrique Barboza reg.addr = (uint64_t)&env->misa_ext_mask; 521e28b9c49SDaniel Henrique Barboza ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); 522e28b9c49SDaniel Henrique Barboza 523e28b9c49SDaniel Henrique Barboza if (ret) { 524e28b9c49SDaniel Henrique Barboza error_report("Unable to fetch ISA register from KVM, " 525e28b9c49SDaniel Henrique Barboza "error %d", ret); 526e28b9c49SDaniel Henrique Barboza kvm_riscv_destroy_scratch_vcpu(kvmcpu); 527e28b9c49SDaniel Henrique Barboza exit(EXIT_FAILURE); 528e28b9c49SDaniel Henrique Barboza } 529e28b9c49SDaniel Henrique Barboza 530e28b9c49SDaniel Henrique Barboza env->misa_ext = env->misa_ext_mask; 531e28b9c49SDaniel Henrique Barboza } 532e28b9c49SDaniel Henrique Barboza 533492265aeSDaniel Henrique Barboza void kvm_riscv_init_user_properties(Object *cpu_obj) 534492265aeSDaniel Henrique Barboza { 535492265aeSDaniel Henrique Barboza RISCVCPU *cpu = RISCV_CPU(cpu_obj); 536492265aeSDaniel Henrique Barboza KVMScratchCPU kvmcpu; 537492265aeSDaniel Henrique Barboza 538492265aeSDaniel Henrique Barboza if (!kvm_riscv_create_scratch_vcpu(&kvmcpu)) { 539492265aeSDaniel Henrique Barboza return; 540492265aeSDaniel Henrique Barboza } 541492265aeSDaniel Henrique Barboza 54292becce5SDaniel Henrique Barboza kvm_riscv_add_cpu_user_properties(cpu_obj); 543492265aeSDaniel Henrique Barboza kvm_riscv_init_machine_ids(cpu, &kvmcpu); 544e28b9c49SDaniel Henrique Barboza kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu); 545492265aeSDaniel Henrique Barboza 546492265aeSDaniel Henrique Barboza kvm_riscv_destroy_scratch_vcpu(&kvmcpu); 547492265aeSDaniel Henrique Barboza } 548492265aeSDaniel Henrique Barboza 54991654e61SYifei Jiang const KVMCapabilityInfo kvm_arch_required_capabilities[] = { 55091654e61SYifei Jiang KVM_CAP_LAST_INFO 55191654e61SYifei Jiang }; 55291654e61SYifei Jiang 55391654e61SYifei Jiang int kvm_arch_get_registers(CPUState *cs) 55491654e61SYifei Jiang { 555937f0b45SYifei Jiang int ret = 0; 556937f0b45SYifei Jiang 557937f0b45SYifei Jiang ret = kvm_riscv_get_regs_core(cs); 558937f0b45SYifei Jiang if (ret) { 559937f0b45SYifei Jiang return ret; 560937f0b45SYifei Jiang } 561937f0b45SYifei Jiang 562937f0b45SYifei Jiang ret = kvm_riscv_get_regs_csr(cs); 563937f0b45SYifei Jiang if (ret) { 564937f0b45SYifei Jiang return ret; 565937f0b45SYifei Jiang } 566937f0b45SYifei Jiang 567937f0b45SYifei Jiang ret = kvm_riscv_get_regs_fp(cs); 568937f0b45SYifei Jiang if (ret) { 569937f0b45SYifei Jiang return ret; 570937f0b45SYifei Jiang } 571937f0b45SYifei Jiang 572937f0b45SYifei Jiang return ret; 57391654e61SYifei Jiang } 57491654e61SYifei Jiang 57591654e61SYifei Jiang int kvm_arch_put_registers(CPUState *cs, int level) 57691654e61SYifei Jiang { 5779997cc1eSYifei Jiang int ret = 0; 5789997cc1eSYifei Jiang 5799997cc1eSYifei Jiang ret = kvm_riscv_put_regs_core(cs); 5809997cc1eSYifei Jiang if (ret) { 5819997cc1eSYifei Jiang return ret; 5829997cc1eSYifei Jiang } 5839997cc1eSYifei Jiang 5849997cc1eSYifei Jiang ret = kvm_riscv_put_regs_csr(cs); 5859997cc1eSYifei Jiang if (ret) { 5869997cc1eSYifei Jiang return ret; 5879997cc1eSYifei Jiang } 5889997cc1eSYifei Jiang 5899997cc1eSYifei Jiang ret = kvm_riscv_put_regs_fp(cs); 5909997cc1eSYifei Jiang if (ret) { 5919997cc1eSYifei Jiang return ret; 5929997cc1eSYifei Jiang } 5939997cc1eSYifei Jiang 5949997cc1eSYifei Jiang return ret; 59591654e61SYifei Jiang } 59691654e61SYifei Jiang 59791654e61SYifei Jiang int kvm_arch_release_virq_post(int virq) 59891654e61SYifei Jiang { 59991654e61SYifei Jiang return 0; 60091654e61SYifei Jiang } 60191654e61SYifei Jiang 60291654e61SYifei Jiang int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, 60391654e61SYifei Jiang uint64_t address, uint32_t data, PCIDevice *dev) 60491654e61SYifei Jiang { 60591654e61SYifei Jiang return 0; 60691654e61SYifei Jiang } 60791654e61SYifei Jiang 60891654e61SYifei Jiang int kvm_arch_destroy_vcpu(CPUState *cs) 60991654e61SYifei Jiang { 61091654e61SYifei Jiang return 0; 61191654e61SYifei Jiang } 61291654e61SYifei Jiang 61391654e61SYifei Jiang unsigned long kvm_arch_vcpu_id(CPUState *cpu) 61491654e61SYifei Jiang { 61591654e61SYifei Jiang return cpu->cpu_index; 61691654e61SYifei Jiang } 61791654e61SYifei Jiang 6189ad3e016SYifei Jiang static void kvm_riscv_vm_state_change(void *opaque, bool running, 6199ad3e016SYifei Jiang RunState state) 6209ad3e016SYifei Jiang { 6219ad3e016SYifei Jiang CPUState *cs = opaque; 6229ad3e016SYifei Jiang 6239ad3e016SYifei Jiang if (running) { 6249ad3e016SYifei Jiang kvm_riscv_put_regs_timer(cs); 6259ad3e016SYifei Jiang } else { 6269ad3e016SYifei Jiang kvm_riscv_get_regs_timer(cs); 6279ad3e016SYifei Jiang } 6289ad3e016SYifei Jiang } 6299ad3e016SYifei Jiang 63091654e61SYifei Jiang void kvm_arch_init_irq_routing(KVMState *s) 63191654e61SYifei Jiang { 63291654e61SYifei Jiang } 63391654e61SYifei Jiang 6341fb5a622SDaniel Henrique Barboza static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs) 6351fb5a622SDaniel Henrique Barboza { 6361fb5a622SDaniel Henrique Barboza CPURISCVState *env = &cpu->env; 6371fb5a622SDaniel Henrique Barboza uint64_t id; 6381fb5a622SDaniel Henrique Barboza int ret; 6391fb5a622SDaniel Henrique Barboza 6401fb5a622SDaniel Henrique Barboza id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, 6411fb5a622SDaniel Henrique Barboza KVM_REG_RISCV_CONFIG_REG(mvendorid)); 6421fb5a622SDaniel Henrique Barboza ret = kvm_set_one_reg(cs, id, &cpu->cfg.mvendorid); 6431fb5a622SDaniel Henrique Barboza if (ret != 0) { 6441fb5a622SDaniel Henrique Barboza return ret; 6451fb5a622SDaniel Henrique Barboza } 6461fb5a622SDaniel Henrique Barboza 6471fb5a622SDaniel Henrique Barboza id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, 6481fb5a622SDaniel Henrique Barboza KVM_REG_RISCV_CONFIG_REG(marchid)); 6491fb5a622SDaniel Henrique Barboza ret = kvm_set_one_reg(cs, id, &cpu->cfg.marchid); 6501fb5a622SDaniel Henrique Barboza if (ret != 0) { 6511fb5a622SDaniel Henrique Barboza return ret; 6521fb5a622SDaniel Henrique Barboza } 6531fb5a622SDaniel Henrique Barboza 6541fb5a622SDaniel Henrique Barboza id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, 6551fb5a622SDaniel Henrique Barboza KVM_REG_RISCV_CONFIG_REG(mimpid)); 6561fb5a622SDaniel Henrique Barboza ret = kvm_set_one_reg(cs, id, &cpu->cfg.mimpid); 6571fb5a622SDaniel Henrique Barboza 6581fb5a622SDaniel Henrique Barboza return ret; 6591fb5a622SDaniel Henrique Barboza } 6601fb5a622SDaniel Henrique Barboza 66191654e61SYifei Jiang int kvm_arch_init_vcpu(CPUState *cs) 66291654e61SYifei Jiang { 6630a312b85SYifei Jiang int ret = 0; 6640a312b85SYifei Jiang RISCVCPU *cpu = RISCV_CPU(cs); 6650a312b85SYifei Jiang 6669ad3e016SYifei Jiang qemu_add_vm_change_state_handler(kvm_riscv_vm_state_change, cs); 6679ad3e016SYifei Jiang 6681fb5a622SDaniel Henrique Barboza if (!object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_CPU_HOST)) { 6691fb5a622SDaniel Henrique Barboza ret = kvm_vcpu_set_machine_ids(cpu, cs); 670*7313fffbSDaniel Henrique Barboza if (ret != 0) { 671*7313fffbSDaniel Henrique Barboza return ret; 6721fb5a622SDaniel Henrique Barboza } 673*7313fffbSDaniel Henrique Barboza } 674*7313fffbSDaniel Henrique Barboza 675*7313fffbSDaniel Henrique Barboza kvm_riscv_update_cpu_misa_ext(cpu, cs); 6761fb5a622SDaniel Henrique Barboza 6770a312b85SYifei Jiang return ret; 67891654e61SYifei Jiang } 67991654e61SYifei Jiang 68091654e61SYifei Jiang int kvm_arch_msi_data_to_gsi(uint32_t data) 68191654e61SYifei Jiang { 68291654e61SYifei Jiang abort(); 68391654e61SYifei Jiang } 68491654e61SYifei Jiang 68591654e61SYifei Jiang int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, 68691654e61SYifei Jiang int vector, PCIDevice *dev) 68791654e61SYifei Jiang { 68891654e61SYifei Jiang return 0; 68991654e61SYifei Jiang } 69091654e61SYifei Jiang 69191654e61SYifei Jiang int kvm_arch_init(MachineState *ms, KVMState *s) 69291654e61SYifei Jiang { 69391654e61SYifei Jiang return 0; 69491654e61SYifei Jiang } 69591654e61SYifei Jiang 69691654e61SYifei Jiang int kvm_arch_irqchip_create(KVMState *s) 69791654e61SYifei Jiang { 69891654e61SYifei Jiang return 0; 69991654e61SYifei Jiang } 70091654e61SYifei Jiang 70191654e61SYifei Jiang int kvm_arch_process_async_events(CPUState *cs) 70291654e61SYifei Jiang { 70391654e61SYifei Jiang return 0; 70491654e61SYifei Jiang } 70591654e61SYifei Jiang 70691654e61SYifei Jiang void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) 70791654e61SYifei Jiang { 70891654e61SYifei Jiang } 70991654e61SYifei Jiang 71091654e61SYifei Jiang MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) 71191654e61SYifei Jiang { 71291654e61SYifei Jiang return MEMTXATTRS_UNSPECIFIED; 71391654e61SYifei Jiang } 71491654e61SYifei Jiang 71591654e61SYifei Jiang bool kvm_arch_stop_on_emulation_error(CPUState *cs) 71691654e61SYifei Jiang { 71791654e61SYifei Jiang return true; 71891654e61SYifei Jiang } 71991654e61SYifei Jiang 7204eb47125SYifei Jiang static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run) 7214eb47125SYifei Jiang { 7224eb47125SYifei Jiang int ret = 0; 7234eb47125SYifei Jiang unsigned char ch; 7244eb47125SYifei Jiang switch (run->riscv_sbi.extension_id) { 7254eb47125SYifei Jiang case SBI_EXT_0_1_CONSOLE_PUTCHAR: 7264eb47125SYifei Jiang ch = run->riscv_sbi.args[0]; 7274eb47125SYifei Jiang qemu_chr_fe_write(serial_hd(0)->be, &ch, sizeof(ch)); 7284eb47125SYifei Jiang break; 7294eb47125SYifei Jiang case SBI_EXT_0_1_CONSOLE_GETCHAR: 7304eb47125SYifei Jiang ret = qemu_chr_fe_read_all(serial_hd(0)->be, &ch, sizeof(ch)); 7314eb47125SYifei Jiang if (ret == sizeof(ch)) { 732947bf7feSVladimir Isaev run->riscv_sbi.ret[0] = ch; 7334eb47125SYifei Jiang } else { 734947bf7feSVladimir Isaev run->riscv_sbi.ret[0] = -1; 7354eb47125SYifei Jiang } 736947bf7feSVladimir Isaev ret = 0; 7374eb47125SYifei Jiang break; 7384eb47125SYifei Jiang default: 7394eb47125SYifei Jiang qemu_log_mask(LOG_UNIMP, 7404eb47125SYifei Jiang "%s: un-handled SBI EXIT, specific reasons is %lu\n", 7414eb47125SYifei Jiang __func__, run->riscv_sbi.extension_id); 7424eb47125SYifei Jiang ret = -1; 7434eb47125SYifei Jiang break; 7444eb47125SYifei Jiang } 7454eb47125SYifei Jiang return ret; 7464eb47125SYifei Jiang } 7474eb47125SYifei Jiang 74891654e61SYifei Jiang int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) 74991654e61SYifei Jiang { 7504eb47125SYifei Jiang int ret = 0; 7514eb47125SYifei Jiang switch (run->exit_reason) { 7524eb47125SYifei Jiang case KVM_EXIT_RISCV_SBI: 7534eb47125SYifei Jiang ret = kvm_riscv_handle_sbi(cs, run); 7544eb47125SYifei Jiang break; 7554eb47125SYifei Jiang default: 7564eb47125SYifei Jiang qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n", 7574eb47125SYifei Jiang __func__, run->exit_reason); 7584eb47125SYifei Jiang ret = -1; 7594eb47125SYifei Jiang break; 7604eb47125SYifei Jiang } 7614eb47125SYifei Jiang return ret; 76291654e61SYifei Jiang } 76391654e61SYifei Jiang 764ad40be27SYifei Jiang void kvm_riscv_reset_vcpu(RISCVCPU *cpu) 765ad40be27SYifei Jiang { 766ad40be27SYifei Jiang CPURISCVState *env = &cpu->env; 767ad40be27SYifei Jiang 768ad40be27SYifei Jiang if (!kvm_enabled()) { 769ad40be27SYifei Jiang return; 770ad40be27SYifei Jiang } 771ad40be27SYifei Jiang env->pc = cpu->env.kernel_addr; 772ad40be27SYifei Jiang env->gpr[10] = kvm_arch_vcpu_id(CPU(cpu)); /* a0 */ 773ad40be27SYifei Jiang env->gpr[11] = cpu->env.fdt_addr; /* a1 */ 774ad40be27SYifei Jiang env->satp = 0; 775ad40be27SYifei Jiang } 776ad40be27SYifei Jiang 7772b650fbbSYifei Jiang void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level) 7782b650fbbSYifei Jiang { 7792b650fbbSYifei Jiang int ret; 7802b650fbbSYifei Jiang unsigned virq = level ? KVM_INTERRUPT_SET : KVM_INTERRUPT_UNSET; 7812b650fbbSYifei Jiang 7822b650fbbSYifei Jiang if (irq != IRQ_S_EXT) { 7832b650fbbSYifei Jiang perror("kvm riscv set irq != IRQ_S_EXT\n"); 7842b650fbbSYifei Jiang abort(); 7852b650fbbSYifei Jiang } 7862b650fbbSYifei Jiang 7872b650fbbSYifei Jiang ret = kvm_vcpu_ioctl(CPU(cpu), KVM_INTERRUPT, &virq); 7882b650fbbSYifei Jiang if (ret < 0) { 7892b650fbbSYifei Jiang perror("Set irq failed"); 7902b650fbbSYifei Jiang abort(); 7912b650fbbSYifei Jiang } 7922b650fbbSYifei Jiang } 7932b650fbbSYifei Jiang 79491654e61SYifei Jiang bool kvm_arch_cpu_check_are_resettable(void) 79591654e61SYifei Jiang { 79691654e61SYifei Jiang return true; 79791654e61SYifei Jiang } 7983dba0a33SPaolo Bonzini 7993dba0a33SPaolo Bonzini void kvm_arch_accel_class_init(ObjectClass *oc) 8003dba0a33SPaolo Bonzini { 8013dba0a33SPaolo Bonzini } 802