xref: /qemu/target/riscv/kvm/kvm-cpu.c (revision 1fb5a622f7ef0cfd65b39decd768983e1d0ba1c2)
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 
399492265aeSDaniel Henrique Barboza void kvm_riscv_init_user_properties(Object *cpu_obj)
400492265aeSDaniel Henrique Barboza {
401492265aeSDaniel Henrique Barboza     RISCVCPU *cpu = RISCV_CPU(cpu_obj);
402492265aeSDaniel Henrique Barboza     KVMScratchCPU kvmcpu;
403492265aeSDaniel Henrique Barboza 
404492265aeSDaniel Henrique Barboza     if (!kvm_riscv_create_scratch_vcpu(&kvmcpu)) {
405492265aeSDaniel Henrique Barboza         return;
406492265aeSDaniel Henrique Barboza     }
407492265aeSDaniel Henrique Barboza 
408492265aeSDaniel Henrique Barboza     kvm_riscv_init_machine_ids(cpu, &kvmcpu);
409492265aeSDaniel Henrique Barboza 
410492265aeSDaniel Henrique Barboza     kvm_riscv_destroy_scratch_vcpu(&kvmcpu);
411492265aeSDaniel Henrique Barboza }
412492265aeSDaniel Henrique Barboza 
41391654e61SYifei Jiang const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
41491654e61SYifei Jiang     KVM_CAP_LAST_INFO
41591654e61SYifei Jiang };
41691654e61SYifei Jiang 
41791654e61SYifei Jiang int kvm_arch_get_registers(CPUState *cs)
41891654e61SYifei Jiang {
419937f0b45SYifei Jiang     int ret = 0;
420937f0b45SYifei Jiang 
421937f0b45SYifei Jiang     ret = kvm_riscv_get_regs_core(cs);
422937f0b45SYifei Jiang     if (ret) {
423937f0b45SYifei Jiang         return ret;
424937f0b45SYifei Jiang     }
425937f0b45SYifei Jiang 
426937f0b45SYifei Jiang     ret = kvm_riscv_get_regs_csr(cs);
427937f0b45SYifei Jiang     if (ret) {
428937f0b45SYifei Jiang         return ret;
429937f0b45SYifei Jiang     }
430937f0b45SYifei Jiang 
431937f0b45SYifei Jiang     ret = kvm_riscv_get_regs_fp(cs);
432937f0b45SYifei Jiang     if (ret) {
433937f0b45SYifei Jiang         return ret;
434937f0b45SYifei Jiang     }
435937f0b45SYifei Jiang 
436937f0b45SYifei Jiang     return ret;
43791654e61SYifei Jiang }
43891654e61SYifei Jiang 
43991654e61SYifei Jiang int kvm_arch_put_registers(CPUState *cs, int level)
44091654e61SYifei Jiang {
4419997cc1eSYifei Jiang     int ret = 0;
4429997cc1eSYifei Jiang 
4439997cc1eSYifei Jiang     ret = kvm_riscv_put_regs_core(cs);
4449997cc1eSYifei Jiang     if (ret) {
4459997cc1eSYifei Jiang         return ret;
4469997cc1eSYifei Jiang     }
4479997cc1eSYifei Jiang 
4489997cc1eSYifei Jiang     ret = kvm_riscv_put_regs_csr(cs);
4499997cc1eSYifei Jiang     if (ret) {
4509997cc1eSYifei Jiang         return ret;
4519997cc1eSYifei Jiang     }
4529997cc1eSYifei Jiang 
4539997cc1eSYifei Jiang     ret = kvm_riscv_put_regs_fp(cs);
4549997cc1eSYifei Jiang     if (ret) {
4559997cc1eSYifei Jiang         return ret;
4569997cc1eSYifei Jiang     }
4579997cc1eSYifei Jiang 
4589997cc1eSYifei Jiang     return ret;
45991654e61SYifei Jiang }
46091654e61SYifei Jiang 
46191654e61SYifei Jiang int kvm_arch_release_virq_post(int virq)
46291654e61SYifei Jiang {
46391654e61SYifei Jiang     return 0;
46491654e61SYifei Jiang }
46591654e61SYifei Jiang 
46691654e61SYifei Jiang int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
46791654e61SYifei Jiang                              uint64_t address, uint32_t data, PCIDevice *dev)
46891654e61SYifei Jiang {
46991654e61SYifei Jiang     return 0;
47091654e61SYifei Jiang }
47191654e61SYifei Jiang 
47291654e61SYifei Jiang int kvm_arch_destroy_vcpu(CPUState *cs)
47391654e61SYifei Jiang {
47491654e61SYifei Jiang     return 0;
47591654e61SYifei Jiang }
47691654e61SYifei Jiang 
47791654e61SYifei Jiang unsigned long kvm_arch_vcpu_id(CPUState *cpu)
47891654e61SYifei Jiang {
47991654e61SYifei Jiang     return cpu->cpu_index;
48091654e61SYifei Jiang }
48191654e61SYifei Jiang 
4829ad3e016SYifei Jiang static void kvm_riscv_vm_state_change(void *opaque, bool running,
4839ad3e016SYifei Jiang                                       RunState state)
4849ad3e016SYifei Jiang {
4859ad3e016SYifei Jiang     CPUState *cs = opaque;
4869ad3e016SYifei Jiang 
4879ad3e016SYifei Jiang     if (running) {
4889ad3e016SYifei Jiang         kvm_riscv_put_regs_timer(cs);
4899ad3e016SYifei Jiang     } else {
4909ad3e016SYifei Jiang         kvm_riscv_get_regs_timer(cs);
4919ad3e016SYifei Jiang     }
4929ad3e016SYifei Jiang }
4939ad3e016SYifei Jiang 
49491654e61SYifei Jiang void kvm_arch_init_irq_routing(KVMState *s)
49591654e61SYifei Jiang {
49691654e61SYifei Jiang }
49791654e61SYifei Jiang 
498*1fb5a622SDaniel Henrique Barboza static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs)
499*1fb5a622SDaniel Henrique Barboza {
500*1fb5a622SDaniel Henrique Barboza     CPURISCVState *env = &cpu->env;
501*1fb5a622SDaniel Henrique Barboza     uint64_t id;
502*1fb5a622SDaniel Henrique Barboza     int ret;
503*1fb5a622SDaniel Henrique Barboza 
504*1fb5a622SDaniel Henrique Barboza     id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
505*1fb5a622SDaniel Henrique Barboza                           KVM_REG_RISCV_CONFIG_REG(mvendorid));
506*1fb5a622SDaniel Henrique Barboza     ret = kvm_set_one_reg(cs, id, &cpu->cfg.mvendorid);
507*1fb5a622SDaniel Henrique Barboza     if (ret != 0) {
508*1fb5a622SDaniel Henrique Barboza         return ret;
509*1fb5a622SDaniel Henrique Barboza     }
510*1fb5a622SDaniel Henrique Barboza 
511*1fb5a622SDaniel Henrique Barboza     id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
512*1fb5a622SDaniel Henrique Barboza                           KVM_REG_RISCV_CONFIG_REG(marchid));
513*1fb5a622SDaniel Henrique Barboza     ret = kvm_set_one_reg(cs, id, &cpu->cfg.marchid);
514*1fb5a622SDaniel Henrique Barboza     if (ret != 0) {
515*1fb5a622SDaniel Henrique Barboza         return ret;
516*1fb5a622SDaniel Henrique Barboza     }
517*1fb5a622SDaniel Henrique Barboza 
518*1fb5a622SDaniel Henrique Barboza     id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
519*1fb5a622SDaniel Henrique Barboza                           KVM_REG_RISCV_CONFIG_REG(mimpid));
520*1fb5a622SDaniel Henrique Barboza     ret = kvm_set_one_reg(cs, id, &cpu->cfg.mimpid);
521*1fb5a622SDaniel Henrique Barboza 
522*1fb5a622SDaniel Henrique Barboza     return ret;
523*1fb5a622SDaniel Henrique Barboza }
524*1fb5a622SDaniel Henrique Barboza 
52591654e61SYifei Jiang int kvm_arch_init_vcpu(CPUState *cs)
52691654e61SYifei Jiang {
5270a312b85SYifei Jiang     int ret = 0;
5280a312b85SYifei Jiang     target_ulong isa;
5290a312b85SYifei Jiang     RISCVCPU *cpu = RISCV_CPU(cs);
5300a312b85SYifei Jiang     CPURISCVState *env = &cpu->env;
5310a312b85SYifei Jiang     uint64_t id;
5320a312b85SYifei Jiang 
5339ad3e016SYifei Jiang     qemu_add_vm_change_state_handler(kvm_riscv_vm_state_change, cs);
5349ad3e016SYifei Jiang 
5350a312b85SYifei Jiang     id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
5360a312b85SYifei Jiang                           KVM_REG_RISCV_CONFIG_REG(isa));
5370a312b85SYifei Jiang     ret = kvm_get_one_reg(cs, id, &isa);
5380a312b85SYifei Jiang     if (ret) {
5390a312b85SYifei Jiang         return ret;
5400a312b85SYifei Jiang     }
5410a312b85SYifei Jiang     env->misa_ext = isa;
5420a312b85SYifei Jiang 
543*1fb5a622SDaniel Henrique Barboza     if (!object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_CPU_HOST)) {
544*1fb5a622SDaniel Henrique Barboza         ret = kvm_vcpu_set_machine_ids(cpu, cs);
545*1fb5a622SDaniel Henrique Barboza     }
546*1fb5a622SDaniel Henrique Barboza 
5470a312b85SYifei Jiang     return ret;
54891654e61SYifei Jiang }
54991654e61SYifei Jiang 
55091654e61SYifei Jiang int kvm_arch_msi_data_to_gsi(uint32_t data)
55191654e61SYifei Jiang {
55291654e61SYifei Jiang     abort();
55391654e61SYifei Jiang }
55491654e61SYifei Jiang 
55591654e61SYifei Jiang int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
55691654e61SYifei Jiang                                 int vector, PCIDevice *dev)
55791654e61SYifei Jiang {
55891654e61SYifei Jiang     return 0;
55991654e61SYifei Jiang }
56091654e61SYifei Jiang 
56191654e61SYifei Jiang int kvm_arch_init(MachineState *ms, KVMState *s)
56291654e61SYifei Jiang {
56391654e61SYifei Jiang     return 0;
56491654e61SYifei Jiang }
56591654e61SYifei Jiang 
56691654e61SYifei Jiang int kvm_arch_irqchip_create(KVMState *s)
56791654e61SYifei Jiang {
56891654e61SYifei Jiang     return 0;
56991654e61SYifei Jiang }
57091654e61SYifei Jiang 
57191654e61SYifei Jiang int kvm_arch_process_async_events(CPUState *cs)
57291654e61SYifei Jiang {
57391654e61SYifei Jiang     return 0;
57491654e61SYifei Jiang }
57591654e61SYifei Jiang 
57691654e61SYifei Jiang void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
57791654e61SYifei Jiang {
57891654e61SYifei Jiang }
57991654e61SYifei Jiang 
58091654e61SYifei Jiang MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
58191654e61SYifei Jiang {
58291654e61SYifei Jiang     return MEMTXATTRS_UNSPECIFIED;
58391654e61SYifei Jiang }
58491654e61SYifei Jiang 
58591654e61SYifei Jiang bool kvm_arch_stop_on_emulation_error(CPUState *cs)
58691654e61SYifei Jiang {
58791654e61SYifei Jiang     return true;
58891654e61SYifei Jiang }
58991654e61SYifei Jiang 
5904eb47125SYifei Jiang static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run)
5914eb47125SYifei Jiang {
5924eb47125SYifei Jiang     int ret = 0;
5934eb47125SYifei Jiang     unsigned char ch;
5944eb47125SYifei Jiang     switch (run->riscv_sbi.extension_id) {
5954eb47125SYifei Jiang     case SBI_EXT_0_1_CONSOLE_PUTCHAR:
5964eb47125SYifei Jiang         ch = run->riscv_sbi.args[0];
5974eb47125SYifei Jiang         qemu_chr_fe_write(serial_hd(0)->be, &ch, sizeof(ch));
5984eb47125SYifei Jiang         break;
5994eb47125SYifei Jiang     case SBI_EXT_0_1_CONSOLE_GETCHAR:
6004eb47125SYifei Jiang         ret = qemu_chr_fe_read_all(serial_hd(0)->be, &ch, sizeof(ch));
6014eb47125SYifei Jiang         if (ret == sizeof(ch)) {
602947bf7feSVladimir Isaev             run->riscv_sbi.ret[0] = ch;
6034eb47125SYifei Jiang         } else {
604947bf7feSVladimir Isaev             run->riscv_sbi.ret[0] = -1;
6054eb47125SYifei Jiang         }
606947bf7feSVladimir Isaev         ret = 0;
6074eb47125SYifei Jiang         break;
6084eb47125SYifei Jiang     default:
6094eb47125SYifei Jiang         qemu_log_mask(LOG_UNIMP,
6104eb47125SYifei Jiang                       "%s: un-handled SBI EXIT, specific reasons is %lu\n",
6114eb47125SYifei Jiang                       __func__, run->riscv_sbi.extension_id);
6124eb47125SYifei Jiang         ret = -1;
6134eb47125SYifei Jiang         break;
6144eb47125SYifei Jiang     }
6154eb47125SYifei Jiang     return ret;
6164eb47125SYifei Jiang }
6174eb47125SYifei Jiang 
61891654e61SYifei Jiang int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
61991654e61SYifei Jiang {
6204eb47125SYifei Jiang     int ret = 0;
6214eb47125SYifei Jiang     switch (run->exit_reason) {
6224eb47125SYifei Jiang     case KVM_EXIT_RISCV_SBI:
6234eb47125SYifei Jiang         ret = kvm_riscv_handle_sbi(cs, run);
6244eb47125SYifei Jiang         break;
6254eb47125SYifei Jiang     default:
6264eb47125SYifei Jiang         qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
6274eb47125SYifei Jiang                       __func__, run->exit_reason);
6284eb47125SYifei Jiang         ret = -1;
6294eb47125SYifei Jiang         break;
6304eb47125SYifei Jiang     }
6314eb47125SYifei Jiang     return ret;
63291654e61SYifei Jiang }
63391654e61SYifei Jiang 
634ad40be27SYifei Jiang void kvm_riscv_reset_vcpu(RISCVCPU *cpu)
635ad40be27SYifei Jiang {
636ad40be27SYifei Jiang     CPURISCVState *env = &cpu->env;
637ad40be27SYifei Jiang 
638ad40be27SYifei Jiang     if (!kvm_enabled()) {
639ad40be27SYifei Jiang         return;
640ad40be27SYifei Jiang     }
641ad40be27SYifei Jiang     env->pc = cpu->env.kernel_addr;
642ad40be27SYifei Jiang     env->gpr[10] = kvm_arch_vcpu_id(CPU(cpu)); /* a0 */
643ad40be27SYifei Jiang     env->gpr[11] = cpu->env.fdt_addr;          /* a1 */
644ad40be27SYifei Jiang     env->satp = 0;
645ad40be27SYifei Jiang }
646ad40be27SYifei Jiang 
6472b650fbbSYifei Jiang void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level)
6482b650fbbSYifei Jiang {
6492b650fbbSYifei Jiang     int ret;
6502b650fbbSYifei Jiang     unsigned virq = level ? KVM_INTERRUPT_SET : KVM_INTERRUPT_UNSET;
6512b650fbbSYifei Jiang 
6522b650fbbSYifei Jiang     if (irq != IRQ_S_EXT) {
6532b650fbbSYifei Jiang         perror("kvm riscv set irq != IRQ_S_EXT\n");
6542b650fbbSYifei Jiang         abort();
6552b650fbbSYifei Jiang     }
6562b650fbbSYifei Jiang 
6572b650fbbSYifei Jiang     ret = kvm_vcpu_ioctl(CPU(cpu), KVM_INTERRUPT, &virq);
6582b650fbbSYifei Jiang     if (ret < 0) {
6592b650fbbSYifei Jiang         perror("Set irq failed");
6602b650fbbSYifei Jiang         abort();
6612b650fbbSYifei Jiang     }
6622b650fbbSYifei Jiang }
6632b650fbbSYifei Jiang 
66491654e61SYifei Jiang bool kvm_arch_cpu_check_are_resettable(void)
66591654e61SYifei Jiang {
66691654e61SYifei Jiang     return true;
66791654e61SYifei Jiang }
6683dba0a33SPaolo Bonzini 
6693dba0a33SPaolo Bonzini void kvm_arch_accel_class_init(ObjectClass *oc)
6703dba0a33SPaolo Bonzini {
6713dba0a33SPaolo Bonzini }
672