xref: /qemu/target/riscv/kvm/kvm-cpu.c (revision e28b9c497428f9efccc7b7f5fc69e7c6524b41a0)
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"
2591654e61SYifei Jiang #include "qemu/error-report.h"
2691654e61SYifei Jiang #include "qemu/main-loop.h"
2791654e61SYifei Jiang #include "sysemu/sysemu.h"
2891654e61SYifei Jiang #include "sysemu/kvm.h"
2991654e61SYifei Jiang #include "sysemu/kvm_int.h"
3091654e61SYifei Jiang #include "cpu.h"
3191654e61SYifei Jiang #include "trace.h"
3291654e61SYifei Jiang #include "hw/pci/pci.h"
3391654e61SYifei Jiang #include "exec/memattrs.h"
3491654e61SYifei Jiang #include "exec/address-spaces.h"
3591654e61SYifei Jiang #include "hw/boards.h"
3691654e61SYifei Jiang #include "hw/irq.h"
3791654e61SYifei Jiang #include "qemu/log.h"
3891654e61SYifei Jiang #include "hw/loader.h"
39ad40be27SYifei Jiang #include "kvm_riscv.h"
404eb47125SYifei Jiang #include "sbi_ecall_interface.h"
414eb47125SYifei Jiang #include "chardev/char-fe.h"
4227abe66fSYifei Jiang #include "migration/migration.h"
439ad3e016SYifei Jiang #include "sysemu/runstate.h"
4491654e61SYifei Jiang 
450a312b85SYifei Jiang static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type,
460a312b85SYifei Jiang                                  uint64_t idx)
470a312b85SYifei Jiang {
480a312b85SYifei Jiang     uint64_t id = KVM_REG_RISCV | type | idx;
490a312b85SYifei Jiang 
500a312b85SYifei Jiang     switch (riscv_cpu_mxl(env)) {
510a312b85SYifei Jiang     case MXL_RV32:
520a312b85SYifei Jiang         id |= KVM_REG_SIZE_U32;
530a312b85SYifei Jiang         break;
540a312b85SYifei Jiang     case MXL_RV64:
550a312b85SYifei Jiang         id |= KVM_REG_SIZE_U64;
560a312b85SYifei Jiang         break;
570a312b85SYifei Jiang     default:
580a312b85SYifei Jiang         g_assert_not_reached();
590a312b85SYifei Jiang     }
600a312b85SYifei Jiang     return id;
610a312b85SYifei Jiang }
620a312b85SYifei Jiang 
63937f0b45SYifei Jiang #define RISCV_CORE_REG(env, name)  kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, \
64937f0b45SYifei Jiang                  KVM_REG_RISCV_CORE_REG(name))
65937f0b45SYifei Jiang 
66937f0b45SYifei Jiang #define RISCV_CSR_REG(env, name)  kvm_riscv_reg_id(env, KVM_REG_RISCV_CSR, \
67937f0b45SYifei Jiang                  KVM_REG_RISCV_CSR_REG(name))
68937f0b45SYifei Jiang 
6927abe66fSYifei Jiang #define RISCV_TIMER_REG(env, name)  kvm_riscv_reg_id(env, KVM_REG_RISCV_TIMER, \
7027abe66fSYifei Jiang                  KVM_REG_RISCV_TIMER_REG(name))
7127abe66fSYifei Jiang 
72937f0b45SYifei Jiang #define RISCV_FP_F_REG(env, idx)  kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_F, idx)
73937f0b45SYifei Jiang 
74937f0b45SYifei Jiang #define RISCV_FP_D_REG(env, idx)  kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_D, idx)
75937f0b45SYifei Jiang 
76937f0b45SYifei Jiang #define KVM_RISCV_GET_CSR(cs, env, csr, reg) \
77937f0b45SYifei Jiang     do { \
78937f0b45SYifei Jiang         int ret = kvm_get_one_reg(cs, RISCV_CSR_REG(env, csr), &reg); \
79937f0b45SYifei Jiang         if (ret) { \
80937f0b45SYifei Jiang             return ret; \
81937f0b45SYifei Jiang         } \
82937f0b45SYifei Jiang     } while (0)
83937f0b45SYifei Jiang 
849997cc1eSYifei Jiang #define KVM_RISCV_SET_CSR(cs, env, csr, reg) \
859997cc1eSYifei Jiang     do { \
869997cc1eSYifei Jiang         int ret = kvm_set_one_reg(cs, RISCV_CSR_REG(env, csr), &reg); \
879997cc1eSYifei Jiang         if (ret) { \
889997cc1eSYifei Jiang             return ret; \
899997cc1eSYifei Jiang         } \
909997cc1eSYifei Jiang     } while (0)
919997cc1eSYifei Jiang 
9227abe66fSYifei Jiang #define KVM_RISCV_GET_TIMER(cs, env, name, reg) \
9327abe66fSYifei Jiang     do { \
9427abe66fSYifei Jiang         int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(env, name), &reg); \
9527abe66fSYifei Jiang         if (ret) { \
9627abe66fSYifei Jiang             abort(); \
9727abe66fSYifei Jiang         } \
9827abe66fSYifei Jiang     } while (0)
9927abe66fSYifei Jiang 
10027abe66fSYifei Jiang #define KVM_RISCV_SET_TIMER(cs, env, name, reg) \
10127abe66fSYifei Jiang     do { \
102c5cc248bSyang.zhang         int ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(env, name), &reg); \
10327abe66fSYifei Jiang         if (ret) { \
10427abe66fSYifei Jiang             abort(); \
10527abe66fSYifei Jiang         } \
10627abe66fSYifei Jiang     } while (0)
10727abe66fSYifei Jiang 
108937f0b45SYifei Jiang static int kvm_riscv_get_regs_core(CPUState *cs)
109937f0b45SYifei Jiang {
110937f0b45SYifei Jiang     int ret = 0;
111937f0b45SYifei Jiang     int i;
112937f0b45SYifei Jiang     target_ulong reg;
113937f0b45SYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
114937f0b45SYifei Jiang 
115937f0b45SYifei Jiang     ret = kvm_get_one_reg(cs, RISCV_CORE_REG(env, regs.pc), &reg);
116937f0b45SYifei Jiang     if (ret) {
117937f0b45SYifei Jiang         return ret;
118937f0b45SYifei Jiang     }
119937f0b45SYifei Jiang     env->pc = reg;
120937f0b45SYifei Jiang 
121937f0b45SYifei Jiang     for (i = 1; i < 32; i++) {
122937f0b45SYifei Jiang         uint64_t id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, i);
123937f0b45SYifei Jiang         ret = kvm_get_one_reg(cs, id, &reg);
124937f0b45SYifei Jiang         if (ret) {
125937f0b45SYifei Jiang             return ret;
126937f0b45SYifei Jiang         }
127937f0b45SYifei Jiang         env->gpr[i] = reg;
128937f0b45SYifei Jiang     }
129937f0b45SYifei Jiang 
130937f0b45SYifei Jiang     return ret;
131937f0b45SYifei Jiang }
132937f0b45SYifei Jiang 
1339997cc1eSYifei Jiang static int kvm_riscv_put_regs_core(CPUState *cs)
1349997cc1eSYifei Jiang {
1359997cc1eSYifei Jiang     int ret = 0;
1369997cc1eSYifei Jiang     int i;
1379997cc1eSYifei Jiang     target_ulong reg;
1389997cc1eSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
1399997cc1eSYifei Jiang 
1409997cc1eSYifei Jiang     reg = env->pc;
1419997cc1eSYifei Jiang     ret = kvm_set_one_reg(cs, RISCV_CORE_REG(env, regs.pc), &reg);
1429997cc1eSYifei Jiang     if (ret) {
1439997cc1eSYifei Jiang         return ret;
1449997cc1eSYifei Jiang     }
1459997cc1eSYifei Jiang 
1469997cc1eSYifei Jiang     for (i = 1; i < 32; i++) {
1479997cc1eSYifei Jiang         uint64_t id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, i);
1489997cc1eSYifei Jiang         reg = env->gpr[i];
1499997cc1eSYifei Jiang         ret = kvm_set_one_reg(cs, id, &reg);
1509997cc1eSYifei Jiang         if (ret) {
1519997cc1eSYifei Jiang             return ret;
1529997cc1eSYifei Jiang         }
1539997cc1eSYifei Jiang     }
1549997cc1eSYifei Jiang 
1559997cc1eSYifei Jiang     return ret;
1569997cc1eSYifei Jiang }
1579997cc1eSYifei Jiang 
158937f0b45SYifei Jiang static int kvm_riscv_get_regs_csr(CPUState *cs)
159937f0b45SYifei Jiang {
160937f0b45SYifei Jiang     int ret = 0;
161937f0b45SYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
162937f0b45SYifei Jiang 
163937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sstatus, env->mstatus);
164937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sie, env->mie);
165937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, stvec, env->stvec);
166937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sscratch, env->sscratch);
167937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sepc, env->sepc);
168937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, scause, env->scause);
169937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, stval, env->stval);
170937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, sip, env->mip);
171937f0b45SYifei Jiang     KVM_RISCV_GET_CSR(cs, env, satp, env->satp);
172937f0b45SYifei Jiang     return ret;
173937f0b45SYifei Jiang }
174937f0b45SYifei Jiang 
1759997cc1eSYifei Jiang static int kvm_riscv_put_regs_csr(CPUState *cs)
1769997cc1eSYifei Jiang {
1779997cc1eSYifei Jiang     int ret = 0;
1789997cc1eSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
1799997cc1eSYifei Jiang 
1809997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sstatus, env->mstatus);
1819997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sie, env->mie);
1829997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, stvec, env->stvec);
1839997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sscratch, env->sscratch);
1849997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sepc, env->sepc);
1859997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, scause, env->scause);
1869997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, stval, env->stval);
1879997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, sip, env->mip);
1889997cc1eSYifei Jiang     KVM_RISCV_SET_CSR(cs, env, satp, env->satp);
1899997cc1eSYifei Jiang 
1909997cc1eSYifei Jiang     return ret;
1919997cc1eSYifei Jiang }
1929997cc1eSYifei Jiang 
193937f0b45SYifei Jiang static int kvm_riscv_get_regs_fp(CPUState *cs)
194937f0b45SYifei Jiang {
195937f0b45SYifei Jiang     int ret = 0;
196937f0b45SYifei Jiang     int i;
197937f0b45SYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
198937f0b45SYifei Jiang 
199937f0b45SYifei Jiang     if (riscv_has_ext(env, RVD)) {
200937f0b45SYifei Jiang         uint64_t reg;
201937f0b45SYifei Jiang         for (i = 0; i < 32; i++) {
202937f0b45SYifei Jiang             ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(env, i), &reg);
203937f0b45SYifei Jiang             if (ret) {
204937f0b45SYifei Jiang                 return ret;
205937f0b45SYifei Jiang             }
206937f0b45SYifei Jiang             env->fpr[i] = reg;
207937f0b45SYifei Jiang         }
208937f0b45SYifei Jiang         return ret;
209937f0b45SYifei Jiang     }
210937f0b45SYifei Jiang 
211937f0b45SYifei Jiang     if (riscv_has_ext(env, RVF)) {
212937f0b45SYifei Jiang         uint32_t reg;
213937f0b45SYifei Jiang         for (i = 0; i < 32; i++) {
214937f0b45SYifei Jiang             ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(env, i), &reg);
215937f0b45SYifei Jiang             if (ret) {
216937f0b45SYifei Jiang                 return ret;
217937f0b45SYifei Jiang             }
218937f0b45SYifei Jiang             env->fpr[i] = reg;
219937f0b45SYifei Jiang         }
220937f0b45SYifei Jiang         return ret;
221937f0b45SYifei Jiang     }
222937f0b45SYifei Jiang 
223937f0b45SYifei Jiang     return ret;
224937f0b45SYifei Jiang }
225937f0b45SYifei Jiang 
2269997cc1eSYifei Jiang static int kvm_riscv_put_regs_fp(CPUState *cs)
2279997cc1eSYifei Jiang {
2289997cc1eSYifei Jiang     int ret = 0;
2299997cc1eSYifei Jiang     int i;
2309997cc1eSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
2319997cc1eSYifei Jiang 
2329997cc1eSYifei Jiang     if (riscv_has_ext(env, RVD)) {
2339997cc1eSYifei Jiang         uint64_t reg;
2349997cc1eSYifei Jiang         for (i = 0; i < 32; i++) {
2359997cc1eSYifei Jiang             reg = env->fpr[i];
2369997cc1eSYifei Jiang             ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(env, i), &reg);
2379997cc1eSYifei Jiang             if (ret) {
2389997cc1eSYifei Jiang                 return ret;
2399997cc1eSYifei Jiang             }
2409997cc1eSYifei Jiang         }
2419997cc1eSYifei Jiang         return ret;
2429997cc1eSYifei Jiang     }
2439997cc1eSYifei Jiang 
2449997cc1eSYifei Jiang     if (riscv_has_ext(env, RVF)) {
2459997cc1eSYifei Jiang         uint32_t reg;
2469997cc1eSYifei Jiang         for (i = 0; i < 32; i++) {
2479997cc1eSYifei Jiang             reg = env->fpr[i];
2489997cc1eSYifei Jiang             ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(env, i), &reg);
2499997cc1eSYifei Jiang             if (ret) {
2509997cc1eSYifei Jiang                 return ret;
2519997cc1eSYifei Jiang             }
2529997cc1eSYifei Jiang         }
2539997cc1eSYifei Jiang         return ret;
2549997cc1eSYifei Jiang     }
2559997cc1eSYifei Jiang 
2569997cc1eSYifei Jiang     return ret;
2579997cc1eSYifei Jiang }
2589997cc1eSYifei Jiang 
25927abe66fSYifei Jiang static void kvm_riscv_get_regs_timer(CPUState *cs)
26027abe66fSYifei Jiang {
26127abe66fSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
26227abe66fSYifei Jiang 
26327abe66fSYifei Jiang     if (env->kvm_timer_dirty) {
26427abe66fSYifei Jiang         return;
26527abe66fSYifei Jiang     }
26627abe66fSYifei Jiang 
26727abe66fSYifei Jiang     KVM_RISCV_GET_TIMER(cs, env, time, env->kvm_timer_time);
26827abe66fSYifei Jiang     KVM_RISCV_GET_TIMER(cs, env, compare, env->kvm_timer_compare);
26927abe66fSYifei Jiang     KVM_RISCV_GET_TIMER(cs, env, state, env->kvm_timer_state);
27027abe66fSYifei Jiang     KVM_RISCV_GET_TIMER(cs, env, frequency, env->kvm_timer_frequency);
27127abe66fSYifei Jiang 
27227abe66fSYifei Jiang     env->kvm_timer_dirty = true;
27327abe66fSYifei Jiang }
27427abe66fSYifei Jiang 
27527abe66fSYifei Jiang static void kvm_riscv_put_regs_timer(CPUState *cs)
27627abe66fSYifei Jiang {
27727abe66fSYifei Jiang     uint64_t reg;
27827abe66fSYifei Jiang     CPURISCVState *env = &RISCV_CPU(cs)->env;
27927abe66fSYifei Jiang 
28027abe66fSYifei Jiang     if (!env->kvm_timer_dirty) {
28127abe66fSYifei Jiang         return;
28227abe66fSYifei Jiang     }
28327abe66fSYifei Jiang 
28427abe66fSYifei Jiang     KVM_RISCV_SET_TIMER(cs, env, time, env->kvm_timer_time);
28527abe66fSYifei Jiang     KVM_RISCV_SET_TIMER(cs, env, compare, env->kvm_timer_compare);
28627abe66fSYifei Jiang 
28727abe66fSYifei Jiang     /*
28827abe66fSYifei Jiang      * To set register of RISCV_TIMER_REG(state) will occur a error from KVM
28927abe66fSYifei Jiang      * on env->kvm_timer_state == 0, It's better to adapt in KVM, but it
29027abe66fSYifei Jiang      * doesn't matter that adaping in QEMU now.
29127abe66fSYifei Jiang      * TODO If KVM changes, adapt here.
29227abe66fSYifei Jiang      */
29327abe66fSYifei Jiang     if (env->kvm_timer_state) {
29427abe66fSYifei Jiang         KVM_RISCV_SET_TIMER(cs, env, state, env->kvm_timer_state);
29527abe66fSYifei Jiang     }
29627abe66fSYifei Jiang 
29727abe66fSYifei Jiang     /*
29827abe66fSYifei Jiang      * For now, migration will not work between Hosts with different timer
29927abe66fSYifei Jiang      * frequency. Therefore, we should check whether they are the same here
30027abe66fSYifei Jiang      * during the migration.
30127abe66fSYifei Jiang      */
30227abe66fSYifei Jiang     if (migration_is_running(migrate_get_current()->state)) {
30327abe66fSYifei Jiang         KVM_RISCV_GET_TIMER(cs, env, frequency, reg);
30427abe66fSYifei Jiang         if (reg != env->kvm_timer_frequency) {
30527abe66fSYifei Jiang             error_report("Dst Hosts timer frequency != Src Hosts");
30627abe66fSYifei Jiang         }
30727abe66fSYifei Jiang     }
30827abe66fSYifei Jiang 
30927abe66fSYifei Jiang     env->kvm_timer_dirty = false;
31027abe66fSYifei Jiang }
3119997cc1eSYifei Jiang 
312492265aeSDaniel Henrique Barboza typedef struct KVMScratchCPU {
313492265aeSDaniel Henrique Barboza     int kvmfd;
314492265aeSDaniel Henrique Barboza     int vmfd;
315492265aeSDaniel Henrique Barboza     int cpufd;
316492265aeSDaniel Henrique Barboza } KVMScratchCPU;
317492265aeSDaniel Henrique Barboza 
318492265aeSDaniel Henrique Barboza /*
319492265aeSDaniel Henrique Barboza  * Heavily inspired by kvm_arm_create_scratch_host_vcpu()
320492265aeSDaniel Henrique Barboza  * from target/arm/kvm.c.
321492265aeSDaniel Henrique Barboza  */
322492265aeSDaniel Henrique Barboza static bool kvm_riscv_create_scratch_vcpu(KVMScratchCPU *scratch)
323492265aeSDaniel Henrique Barboza {
324492265aeSDaniel Henrique Barboza     int kvmfd = -1, vmfd = -1, cpufd = -1;
325492265aeSDaniel Henrique Barboza 
326492265aeSDaniel Henrique Barboza     kvmfd = qemu_open_old("/dev/kvm", O_RDWR);
327492265aeSDaniel Henrique Barboza     if (kvmfd < 0) {
328492265aeSDaniel Henrique Barboza         goto err;
329492265aeSDaniel Henrique Barboza     }
330492265aeSDaniel Henrique Barboza     do {
331492265aeSDaniel Henrique Barboza         vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);
332492265aeSDaniel Henrique Barboza     } while (vmfd == -1 && errno == EINTR);
333492265aeSDaniel Henrique Barboza     if (vmfd < 0) {
334492265aeSDaniel Henrique Barboza         goto err;
335492265aeSDaniel Henrique Barboza     }
336492265aeSDaniel Henrique Barboza     cpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);
337492265aeSDaniel Henrique Barboza     if (cpufd < 0) {
338492265aeSDaniel Henrique Barboza         goto err;
339492265aeSDaniel Henrique Barboza     }
340492265aeSDaniel Henrique Barboza 
341492265aeSDaniel Henrique Barboza     scratch->kvmfd =  kvmfd;
342492265aeSDaniel Henrique Barboza     scratch->vmfd = vmfd;
343492265aeSDaniel Henrique Barboza     scratch->cpufd = cpufd;
344492265aeSDaniel Henrique Barboza 
345492265aeSDaniel Henrique Barboza     return true;
346492265aeSDaniel Henrique Barboza 
347492265aeSDaniel Henrique Barboza  err:
348492265aeSDaniel Henrique Barboza     if (cpufd >= 0) {
349492265aeSDaniel Henrique Barboza         close(cpufd);
350492265aeSDaniel Henrique Barboza     }
351492265aeSDaniel Henrique Barboza     if (vmfd >= 0) {
352492265aeSDaniel Henrique Barboza         close(vmfd);
353492265aeSDaniel Henrique Barboza     }
354492265aeSDaniel Henrique Barboza     if (kvmfd >= 0) {
355492265aeSDaniel Henrique Barboza         close(kvmfd);
356492265aeSDaniel Henrique Barboza     }
357492265aeSDaniel Henrique Barboza 
358492265aeSDaniel Henrique Barboza     return false;
359492265aeSDaniel Henrique Barboza }
360492265aeSDaniel Henrique Barboza 
361492265aeSDaniel Henrique Barboza static void kvm_riscv_destroy_scratch_vcpu(KVMScratchCPU *scratch)
362492265aeSDaniel Henrique Barboza {
363492265aeSDaniel Henrique Barboza     close(scratch->cpufd);
364492265aeSDaniel Henrique Barboza     close(scratch->vmfd);
365492265aeSDaniel Henrique Barboza     close(scratch->kvmfd);
366492265aeSDaniel Henrique Barboza }
367492265aeSDaniel Henrique Barboza 
368492265aeSDaniel Henrique Barboza static void kvm_riscv_init_machine_ids(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
369492265aeSDaniel Henrique Barboza {
370492265aeSDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
371492265aeSDaniel Henrique Barboza     struct kvm_one_reg reg;
372492265aeSDaniel Henrique Barboza     int ret;
373492265aeSDaniel Henrique Barboza 
374492265aeSDaniel Henrique Barboza     reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
375492265aeSDaniel Henrique Barboza                               KVM_REG_RISCV_CONFIG_REG(mvendorid));
376492265aeSDaniel Henrique Barboza     reg.addr = (uint64_t)&cpu->cfg.mvendorid;
377492265aeSDaniel Henrique Barboza     ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
378492265aeSDaniel Henrique Barboza     if (ret != 0) {
379492265aeSDaniel Henrique Barboza         error_report("Unable to retrieve mvendorid from host, error %d", ret);
380492265aeSDaniel Henrique Barboza     }
381d758f884SDaniel Henrique Barboza 
382d758f884SDaniel Henrique Barboza     reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
383d758f884SDaniel Henrique Barboza                               KVM_REG_RISCV_CONFIG_REG(marchid));
384d758f884SDaniel Henrique Barboza     reg.addr = (uint64_t)&cpu->cfg.marchid;
385d758f884SDaniel Henrique Barboza     ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
386d758f884SDaniel Henrique Barboza     if (ret != 0) {
387d758f884SDaniel Henrique Barboza         error_report("Unable to retrieve marchid from host, error %d", ret);
388d758f884SDaniel Henrique Barboza     }
389d758f884SDaniel Henrique Barboza 
390d758f884SDaniel Henrique Barboza     reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
391d758f884SDaniel Henrique Barboza                               KVM_REG_RISCV_CONFIG_REG(mimpid));
392d758f884SDaniel Henrique Barboza     reg.addr = (uint64_t)&cpu->cfg.mimpid;
393d758f884SDaniel Henrique Barboza     ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
394d758f884SDaniel Henrique Barboza     if (ret != 0) {
395d758f884SDaniel Henrique Barboza         error_report("Unable to retrieve mimpid from host, error %d", ret);
396d758f884SDaniel Henrique Barboza     }
397492265aeSDaniel Henrique Barboza }
398492265aeSDaniel Henrique Barboza 
399*e28b9c49SDaniel Henrique Barboza static void kvm_riscv_init_misa_ext_mask(RISCVCPU *cpu,
400*e28b9c49SDaniel Henrique Barboza                                          KVMScratchCPU *kvmcpu)
401*e28b9c49SDaniel Henrique Barboza {
402*e28b9c49SDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
403*e28b9c49SDaniel Henrique Barboza     struct kvm_one_reg reg;
404*e28b9c49SDaniel Henrique Barboza     int ret;
405*e28b9c49SDaniel Henrique Barboza 
406*e28b9c49SDaniel Henrique Barboza     reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
407*e28b9c49SDaniel Henrique Barboza                               KVM_REG_RISCV_CONFIG_REG(isa));
408*e28b9c49SDaniel Henrique Barboza     reg.addr = (uint64_t)&env->misa_ext_mask;
409*e28b9c49SDaniel Henrique Barboza     ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
410*e28b9c49SDaniel Henrique Barboza 
411*e28b9c49SDaniel Henrique Barboza     if (ret) {
412*e28b9c49SDaniel Henrique Barboza         error_report("Unable to fetch ISA register from KVM, "
413*e28b9c49SDaniel Henrique Barboza                      "error %d", ret);
414*e28b9c49SDaniel Henrique Barboza         kvm_riscv_destroy_scratch_vcpu(kvmcpu);
415*e28b9c49SDaniel Henrique Barboza         exit(EXIT_FAILURE);
416*e28b9c49SDaniel Henrique Barboza     }
417*e28b9c49SDaniel Henrique Barboza 
418*e28b9c49SDaniel Henrique Barboza     env->misa_ext = env->misa_ext_mask;
419*e28b9c49SDaniel Henrique Barboza }
420*e28b9c49SDaniel Henrique Barboza 
421492265aeSDaniel Henrique Barboza void kvm_riscv_init_user_properties(Object *cpu_obj)
422492265aeSDaniel Henrique Barboza {
423492265aeSDaniel Henrique Barboza     RISCVCPU *cpu = RISCV_CPU(cpu_obj);
424492265aeSDaniel Henrique Barboza     KVMScratchCPU kvmcpu;
425492265aeSDaniel Henrique Barboza 
426492265aeSDaniel Henrique Barboza     if (!kvm_riscv_create_scratch_vcpu(&kvmcpu)) {
427492265aeSDaniel Henrique Barboza         return;
428492265aeSDaniel Henrique Barboza     }
429492265aeSDaniel Henrique Barboza 
430492265aeSDaniel Henrique Barboza     kvm_riscv_init_machine_ids(cpu, &kvmcpu);
431*e28b9c49SDaniel Henrique Barboza     kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu);
432492265aeSDaniel Henrique Barboza 
433492265aeSDaniel Henrique Barboza     kvm_riscv_destroy_scratch_vcpu(&kvmcpu);
434492265aeSDaniel Henrique Barboza }
435492265aeSDaniel Henrique Barboza 
43691654e61SYifei Jiang const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
43791654e61SYifei Jiang     KVM_CAP_LAST_INFO
43891654e61SYifei Jiang };
43991654e61SYifei Jiang 
44091654e61SYifei Jiang int kvm_arch_get_registers(CPUState *cs)
44191654e61SYifei Jiang {
442937f0b45SYifei Jiang     int ret = 0;
443937f0b45SYifei Jiang 
444937f0b45SYifei Jiang     ret = kvm_riscv_get_regs_core(cs);
445937f0b45SYifei Jiang     if (ret) {
446937f0b45SYifei Jiang         return ret;
447937f0b45SYifei Jiang     }
448937f0b45SYifei Jiang 
449937f0b45SYifei Jiang     ret = kvm_riscv_get_regs_csr(cs);
450937f0b45SYifei Jiang     if (ret) {
451937f0b45SYifei Jiang         return ret;
452937f0b45SYifei Jiang     }
453937f0b45SYifei Jiang 
454937f0b45SYifei Jiang     ret = kvm_riscv_get_regs_fp(cs);
455937f0b45SYifei Jiang     if (ret) {
456937f0b45SYifei Jiang         return ret;
457937f0b45SYifei Jiang     }
458937f0b45SYifei Jiang 
459937f0b45SYifei Jiang     return ret;
46091654e61SYifei Jiang }
46191654e61SYifei Jiang 
46291654e61SYifei Jiang int kvm_arch_put_registers(CPUState *cs, int level)
46391654e61SYifei Jiang {
4649997cc1eSYifei Jiang     int ret = 0;
4659997cc1eSYifei Jiang 
4669997cc1eSYifei Jiang     ret = kvm_riscv_put_regs_core(cs);
4679997cc1eSYifei Jiang     if (ret) {
4689997cc1eSYifei Jiang         return ret;
4699997cc1eSYifei Jiang     }
4709997cc1eSYifei Jiang 
4719997cc1eSYifei Jiang     ret = kvm_riscv_put_regs_csr(cs);
4729997cc1eSYifei Jiang     if (ret) {
4739997cc1eSYifei Jiang         return ret;
4749997cc1eSYifei Jiang     }
4759997cc1eSYifei Jiang 
4769997cc1eSYifei Jiang     ret = kvm_riscv_put_regs_fp(cs);
4779997cc1eSYifei Jiang     if (ret) {
4789997cc1eSYifei Jiang         return ret;
4799997cc1eSYifei Jiang     }
4809997cc1eSYifei Jiang 
4819997cc1eSYifei Jiang     return ret;
48291654e61SYifei Jiang }
48391654e61SYifei Jiang 
48491654e61SYifei Jiang int kvm_arch_release_virq_post(int virq)
48591654e61SYifei Jiang {
48691654e61SYifei Jiang     return 0;
48791654e61SYifei Jiang }
48891654e61SYifei Jiang 
48991654e61SYifei Jiang int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
49091654e61SYifei Jiang                              uint64_t address, uint32_t data, PCIDevice *dev)
49191654e61SYifei Jiang {
49291654e61SYifei Jiang     return 0;
49391654e61SYifei Jiang }
49491654e61SYifei Jiang 
49591654e61SYifei Jiang int kvm_arch_destroy_vcpu(CPUState *cs)
49691654e61SYifei Jiang {
49791654e61SYifei Jiang     return 0;
49891654e61SYifei Jiang }
49991654e61SYifei Jiang 
50091654e61SYifei Jiang unsigned long kvm_arch_vcpu_id(CPUState *cpu)
50191654e61SYifei Jiang {
50291654e61SYifei Jiang     return cpu->cpu_index;
50391654e61SYifei Jiang }
50491654e61SYifei Jiang 
5059ad3e016SYifei Jiang static void kvm_riscv_vm_state_change(void *opaque, bool running,
5069ad3e016SYifei Jiang                                       RunState state)
5079ad3e016SYifei Jiang {
5089ad3e016SYifei Jiang     CPUState *cs = opaque;
5099ad3e016SYifei Jiang 
5109ad3e016SYifei Jiang     if (running) {
5119ad3e016SYifei Jiang         kvm_riscv_put_regs_timer(cs);
5129ad3e016SYifei Jiang     } else {
5139ad3e016SYifei Jiang         kvm_riscv_get_regs_timer(cs);
5149ad3e016SYifei Jiang     }
5159ad3e016SYifei Jiang }
5169ad3e016SYifei Jiang 
51791654e61SYifei Jiang void kvm_arch_init_irq_routing(KVMState *s)
51891654e61SYifei Jiang {
51991654e61SYifei Jiang }
52091654e61SYifei Jiang 
5211fb5a622SDaniel Henrique Barboza static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs)
5221fb5a622SDaniel Henrique Barboza {
5231fb5a622SDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
5241fb5a622SDaniel Henrique Barboza     uint64_t id;
5251fb5a622SDaniel Henrique Barboza     int ret;
5261fb5a622SDaniel Henrique Barboza 
5271fb5a622SDaniel Henrique Barboza     id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
5281fb5a622SDaniel Henrique Barboza                           KVM_REG_RISCV_CONFIG_REG(mvendorid));
5291fb5a622SDaniel Henrique Barboza     ret = kvm_set_one_reg(cs, id, &cpu->cfg.mvendorid);
5301fb5a622SDaniel Henrique Barboza     if (ret != 0) {
5311fb5a622SDaniel Henrique Barboza         return ret;
5321fb5a622SDaniel Henrique Barboza     }
5331fb5a622SDaniel Henrique Barboza 
5341fb5a622SDaniel Henrique Barboza     id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
5351fb5a622SDaniel Henrique Barboza                           KVM_REG_RISCV_CONFIG_REG(marchid));
5361fb5a622SDaniel Henrique Barboza     ret = kvm_set_one_reg(cs, id, &cpu->cfg.marchid);
5371fb5a622SDaniel Henrique Barboza     if (ret != 0) {
5381fb5a622SDaniel Henrique Barboza         return ret;
5391fb5a622SDaniel Henrique Barboza     }
5401fb5a622SDaniel Henrique Barboza 
5411fb5a622SDaniel Henrique Barboza     id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
5421fb5a622SDaniel Henrique Barboza                           KVM_REG_RISCV_CONFIG_REG(mimpid));
5431fb5a622SDaniel Henrique Barboza     ret = kvm_set_one_reg(cs, id, &cpu->cfg.mimpid);
5441fb5a622SDaniel Henrique Barboza 
5451fb5a622SDaniel Henrique Barboza     return ret;
5461fb5a622SDaniel Henrique Barboza }
5471fb5a622SDaniel Henrique Barboza 
54891654e61SYifei Jiang int kvm_arch_init_vcpu(CPUState *cs)
54991654e61SYifei Jiang {
5500a312b85SYifei Jiang     int ret = 0;
5510a312b85SYifei Jiang     RISCVCPU *cpu = RISCV_CPU(cs);
5520a312b85SYifei Jiang 
5539ad3e016SYifei Jiang     qemu_add_vm_change_state_handler(kvm_riscv_vm_state_change, cs);
5549ad3e016SYifei Jiang 
5551fb5a622SDaniel Henrique Barboza     if (!object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_CPU_HOST)) {
5561fb5a622SDaniel Henrique Barboza         ret = kvm_vcpu_set_machine_ids(cpu, cs);
5571fb5a622SDaniel Henrique Barboza     }
5581fb5a622SDaniel Henrique Barboza 
5590a312b85SYifei Jiang     return ret;
56091654e61SYifei Jiang }
56191654e61SYifei Jiang 
56291654e61SYifei Jiang int kvm_arch_msi_data_to_gsi(uint32_t data)
56391654e61SYifei Jiang {
56491654e61SYifei Jiang     abort();
56591654e61SYifei Jiang }
56691654e61SYifei Jiang 
56791654e61SYifei Jiang int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
56891654e61SYifei Jiang                                 int vector, PCIDevice *dev)
56991654e61SYifei Jiang {
57091654e61SYifei Jiang     return 0;
57191654e61SYifei Jiang }
57291654e61SYifei Jiang 
57391654e61SYifei Jiang int kvm_arch_init(MachineState *ms, KVMState *s)
57491654e61SYifei Jiang {
57591654e61SYifei Jiang     return 0;
57691654e61SYifei Jiang }
57791654e61SYifei Jiang 
57891654e61SYifei Jiang int kvm_arch_irqchip_create(KVMState *s)
57991654e61SYifei Jiang {
58091654e61SYifei Jiang     return 0;
58191654e61SYifei Jiang }
58291654e61SYifei Jiang 
58391654e61SYifei Jiang int kvm_arch_process_async_events(CPUState *cs)
58491654e61SYifei Jiang {
58591654e61SYifei Jiang     return 0;
58691654e61SYifei Jiang }
58791654e61SYifei Jiang 
58891654e61SYifei Jiang void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
58991654e61SYifei Jiang {
59091654e61SYifei Jiang }
59191654e61SYifei Jiang 
59291654e61SYifei Jiang MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
59391654e61SYifei Jiang {
59491654e61SYifei Jiang     return MEMTXATTRS_UNSPECIFIED;
59591654e61SYifei Jiang }
59691654e61SYifei Jiang 
59791654e61SYifei Jiang bool kvm_arch_stop_on_emulation_error(CPUState *cs)
59891654e61SYifei Jiang {
59991654e61SYifei Jiang     return true;
60091654e61SYifei Jiang }
60191654e61SYifei Jiang 
6024eb47125SYifei Jiang static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run)
6034eb47125SYifei Jiang {
6044eb47125SYifei Jiang     int ret = 0;
6054eb47125SYifei Jiang     unsigned char ch;
6064eb47125SYifei Jiang     switch (run->riscv_sbi.extension_id) {
6074eb47125SYifei Jiang     case SBI_EXT_0_1_CONSOLE_PUTCHAR:
6084eb47125SYifei Jiang         ch = run->riscv_sbi.args[0];
6094eb47125SYifei Jiang         qemu_chr_fe_write(serial_hd(0)->be, &ch, sizeof(ch));
6104eb47125SYifei Jiang         break;
6114eb47125SYifei Jiang     case SBI_EXT_0_1_CONSOLE_GETCHAR:
6124eb47125SYifei Jiang         ret = qemu_chr_fe_read_all(serial_hd(0)->be, &ch, sizeof(ch));
6134eb47125SYifei Jiang         if (ret == sizeof(ch)) {
614947bf7feSVladimir Isaev             run->riscv_sbi.ret[0] = ch;
6154eb47125SYifei Jiang         } else {
616947bf7feSVladimir Isaev             run->riscv_sbi.ret[0] = -1;
6174eb47125SYifei Jiang         }
618947bf7feSVladimir Isaev         ret = 0;
6194eb47125SYifei Jiang         break;
6204eb47125SYifei Jiang     default:
6214eb47125SYifei Jiang         qemu_log_mask(LOG_UNIMP,
6224eb47125SYifei Jiang                       "%s: un-handled SBI EXIT, specific reasons is %lu\n",
6234eb47125SYifei Jiang                       __func__, run->riscv_sbi.extension_id);
6244eb47125SYifei Jiang         ret = -1;
6254eb47125SYifei Jiang         break;
6264eb47125SYifei Jiang     }
6274eb47125SYifei Jiang     return ret;
6284eb47125SYifei Jiang }
6294eb47125SYifei Jiang 
63091654e61SYifei Jiang int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
63191654e61SYifei Jiang {
6324eb47125SYifei Jiang     int ret = 0;
6334eb47125SYifei Jiang     switch (run->exit_reason) {
6344eb47125SYifei Jiang     case KVM_EXIT_RISCV_SBI:
6354eb47125SYifei Jiang         ret = kvm_riscv_handle_sbi(cs, run);
6364eb47125SYifei Jiang         break;
6374eb47125SYifei Jiang     default:
6384eb47125SYifei Jiang         qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
6394eb47125SYifei Jiang                       __func__, run->exit_reason);
6404eb47125SYifei Jiang         ret = -1;
6414eb47125SYifei Jiang         break;
6424eb47125SYifei Jiang     }
6434eb47125SYifei Jiang     return ret;
64491654e61SYifei Jiang }
64591654e61SYifei Jiang 
646ad40be27SYifei Jiang void kvm_riscv_reset_vcpu(RISCVCPU *cpu)
647ad40be27SYifei Jiang {
648ad40be27SYifei Jiang     CPURISCVState *env = &cpu->env;
649ad40be27SYifei Jiang 
650ad40be27SYifei Jiang     if (!kvm_enabled()) {
651ad40be27SYifei Jiang         return;
652ad40be27SYifei Jiang     }
653ad40be27SYifei Jiang     env->pc = cpu->env.kernel_addr;
654ad40be27SYifei Jiang     env->gpr[10] = kvm_arch_vcpu_id(CPU(cpu)); /* a0 */
655ad40be27SYifei Jiang     env->gpr[11] = cpu->env.fdt_addr;          /* a1 */
656ad40be27SYifei Jiang     env->satp = 0;
657ad40be27SYifei Jiang }
658ad40be27SYifei Jiang 
6592b650fbbSYifei Jiang void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level)
6602b650fbbSYifei Jiang {
6612b650fbbSYifei Jiang     int ret;
6622b650fbbSYifei Jiang     unsigned virq = level ? KVM_INTERRUPT_SET : KVM_INTERRUPT_UNSET;
6632b650fbbSYifei Jiang 
6642b650fbbSYifei Jiang     if (irq != IRQ_S_EXT) {
6652b650fbbSYifei Jiang         perror("kvm riscv set irq != IRQ_S_EXT\n");
6662b650fbbSYifei Jiang         abort();
6672b650fbbSYifei Jiang     }
6682b650fbbSYifei Jiang 
6692b650fbbSYifei Jiang     ret = kvm_vcpu_ioctl(CPU(cpu), KVM_INTERRUPT, &virq);
6702b650fbbSYifei Jiang     if (ret < 0) {
6712b650fbbSYifei Jiang         perror("Set irq failed");
6722b650fbbSYifei Jiang         abort();
6732b650fbbSYifei Jiang     }
6742b650fbbSYifei Jiang }
6752b650fbbSYifei Jiang 
67691654e61SYifei Jiang bool kvm_arch_cpu_check_are_resettable(void)
67791654e61SYifei Jiang {
67891654e61SYifei Jiang     return true;
67991654e61SYifei Jiang }
6803dba0a33SPaolo Bonzini 
6813dba0a33SPaolo Bonzini void kvm_arch_accel_class_init(ObjectClass *oc)
6823dba0a33SPaolo Bonzini {
6833dba0a33SPaolo Bonzini }
684