This series adds both riscv32 and riscv64 kvm support, It is based on https://gitee.com/openeuler/kernel/tree/kernel-5.5/.
Several steps to use this: 1. Build emulation $ ./configure --target-list=riscv64-softmmu $ make -j$(nproc)
2. Build kernel https://gitee.com/openeuler/kernel/tree/kernel-5.5/
3. Build QEMU VM cross built in riscv toolchain. $ PKG_CONFIG_LIBDIR=<toolchain pkgconfig path> $ export PKG_CONFIG_SYSROOT_DIR=<toolchain sysroot path> $ ./configure --target-list=riscv64-softmmu --enable-kvm \ --cross-prefix=riscv64-linux-gnu- --disable-libiscsi --disable-glusterfs \ --disable-libusb --disable-usb-redir --audio-drv-list= --disable-opengl \ --disable-libxml2 $ make -j$(nproc)
4. Start emulation $ ./qemu-system-riscv64 -M virt -m 4096M -cpu rv64,x-h=true -nographic \ -name guest=riscv-hyp,debug-threads=on \ -smp 4 \ -bios ./fw_jump.bin \ -kernel ./Image \ -drive file=./hyp.img,format=raw,id=hd0 \ -device virtio-blk-device,drive=hd0 \ -append "root=/dev/vda rw console=ttyS0 earlycon=sbi"
5. Start kvm-acceled QEMU VM in emulation $ ./qemu-system-riscv64 -M virt,accel=kvm -m 1024M -cpu host -nographic \ -name guest=riscv-guset \ -smp 2 \ -bios none \ -kernel ./Image \ -drive file=./guest.img,format=raw,id=hd0 \ -device virtio-blk-device,drive=hd0 \ -append "root=/dev/vda rw console=ttyS0 earlycon=sbi"
Yifei Jiang (9): linux-header: Update linux/kvm.h target/riscv: Add target/riscv/kvm.c to place the public kvm interface target/riscv: Implement function kvm_arch_init_vcpu target/riscv: Implement kvm_arch_get_registers target/riscv: Implement kvm_arch_put_registers target/riscv: Support start kernel directly by KVM hw/riscv: PLIC update external interrupt by KVM when kvm enabled target/riscv: Handler KVM_EXIT_RISCV_SBI exit target/riscv: add host cpu type
configure | 1 + hw/riscv/sifive_plic.c | 31 +- hw/riscv/virt.c | 15 +- linux-headers/linux/kvm.h | 8 + target/riscv/Makefile.objs | 1 + target/riscv/cpu.c | 10 + target/riscv/cpu.h | 4 + target/riscv/kvm.c | 501 +++++++++++++++++++++++++++++ target/riscv/kvm_riscv.h | 25 ++ target/riscv/sbi_ecall_interface.h | 72 +++++ 10 files changed, 657 insertions(+), 11 deletions(-) create mode 100644 target/riscv/kvm.c create mode 100644 target/riscv/kvm_riscv.h create mode 100644 target/riscv/sbi_ecall_interface.h
Update linux/kvm.h on https://gitee.com/openeuler/kernel/tree/kernel-5.5/ Only use this header file, so do not update all linux headers.
Signed-off-by: Yifei Jiang jiangyifei@huawei.com Signed-off-by: Yipeng Yin yinyipeng1@huawei.com --- linux-headers/linux/kvm.h | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 9804495a4..ff6fb2ff5 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -236,6 +236,7 @@ struct kvm_hyperv_exit { #define KVM_EXIT_IOAPIC_EOI 26 #define KVM_EXIT_HYPERV 27 #define KVM_EXIT_ARM_NISV 28 +#define KVM_EXIT_RISCV_SBI 28
/* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -400,6 +401,13 @@ struct kvm_run { __u64 esr_iss; __u64 fault_ipa; } arm_nisv; + /* KVM_EXIT_RISCV_SBI */ + struct { + unsigned long extension_id; + unsigned long function_id; + unsigned long args[6]; + unsigned long ret[2]; + } riscv_sbi; /* Fix the size of the union. */ char padding[256]; };
Add target/riscv/kvm.c to place kvm_arch_* function needed by kvm/kvm-all.c. Meanwhile, add kvm support in configure file.
Signed-off-by: Yifei Jiang jiangyifei@huawei.com Signed-off-by: Yipeng Yin yinyipeng1@huawei.com --- configure | 1 + target/riscv/Makefile.objs | 1 + target/riscv/kvm.c | 128 +++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 target/riscv/kvm.c
diff --git a/configure b/configure index b969dee67..10565e588 100755 --- a/configure +++ b/configure @@ -200,6 +200,7 @@ supported_kvm_target() { x86_64:i386 | x86_64:x86_64 | x86_64:x32 | \ mips:mips | mipsel:mips | \ ppc:ppc | ppc64:ppc | ppc:ppc64 | ppc64:ppc64 | ppc64:ppc64le | \ + riscv32:riscv32 | riscv64:riscv64 | \ s390x:s390x) return 0 ;; diff --git a/target/riscv/Makefile.objs b/target/riscv/Makefile.objs index ff651f69f..7ea8f4c3d 100644 --- a/target/riscv/Makefile.objs +++ b/target/riscv/Makefile.objs @@ -1,5 +1,6 @@ obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o obj-$(CONFIG_SOFTMMU) += pmp.o +obj-$(CONFIG_KVM) += kvm.o
ifeq ($(CONFIG_SOFTMMU),y) obj-y += monitor.o diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c new file mode 100644 index 000000000..8c386d9ac --- /dev/null +++ b/target/riscv/kvm.c @@ -0,0 +1,128 @@ +/* + * RISC-V implementation of KVM hooks + * + * Copyright (c) 2020 Huawei Technologies Co., Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see http://www.gnu.org/licenses/. + */ + +#include "qemu/osdep.h" +#include <sys/ioctl.h> + +#include <linux/kvm.h> + +#include "qemu-common.h" +#include "qemu/timer.h" +#include "qemu/error-report.h" +#include "qemu/main-loop.h" +#include "sysemu/sysemu.h" +#include "sysemu/kvm.h" +#include "sysemu/kvm_int.h" +#include "cpu.h" +#include "trace.h" +#include "hw/pci/pci.h" +#include "exec/memattrs.h" +#include "exec/address-spaces.h" +#include "hw/boards.h" +#include "hw/irq.h" +#include "qemu/log.h" +#include "hw/loader.h" + +const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO +}; + +int kvm_arch_get_registers(CPUState *cs) +{ + return 0; +} + +int kvm_arch_put_registers(CPUState *cs, int level) +{ + return 0; +} + +int kvm_arch_release_virq_post(int virq) +{ + return 0; +} + +int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, + uint64_t address, uint32_t data, PCIDevice *dev) +{ + return 0; +} + +int kvm_arch_destroy_vcpu(CPUState *cs) +{ + return 0; +} + +unsigned long kvm_arch_vcpu_id(CPUState *cpu) +{ + return cpu->cpu_index; +} + +void kvm_arch_init_irq_routing(KVMState *s) +{ +} + +int kvm_arch_init_vcpu(CPUState *cs) +{ + return 0; +} + +int kvm_arch_msi_data_to_gsi(uint32_t data) +{ + abort(); +} + +int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, + int vector, PCIDevice *dev) +{ + return 0; +} + +int kvm_arch_init(MachineState *ms, KVMState *s) +{ + return 0; +} + +int kvm_arch_irqchip_create(KVMState *s) +{ + return 0; +} + +int kvm_arch_process_async_events(CPUState *cs) +{ + return 0; +} + +void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) +{ +} + +MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) +{ + return MEMTXATTRS_UNSPECIFIED; +} + +bool kvm_arch_stop_on_emulation_error(CPUState *cs) +{ + return true; +} + +int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) +{ + return 0; +}
Get isa info from kvm while kvm init.
Signed-off-by: Yifei Jiang jiangyifei@huawei.com Signed-off-by: Yipeng Yin yinyipeng1@huawei.com --- target/riscv/kvm.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c index 8c386d9ac..7983f43f3 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -38,6 +38,18 @@ #include "qemu/log.h" #include "hw/loader.h"
+static __u64 kvm_riscv_reg_id(__u64 type, __u64 idx) +{ + __u64 id = KVM_REG_RISCV | type | idx; + +#if defined(TARGET_RISCV32) + id |= KVM_REG_SIZE_U32; +#elif defined(TARGET_RISCV64) + id |= KVM_REG_SIZE_U64; +#endif + return id; +} + const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; @@ -79,7 +91,19 @@ void kvm_arch_init_irq_routing(KVMState *s)
int kvm_arch_init_vcpu(CPUState *cs) { - return 0; + int ret = 0; + target_ulong isa; + RISCVCPU *cpu = RISCV_CPU(cs); + __u64 id; + + id = kvm_riscv_reg_id(KVM_REG_RISCV_CONFIG, KVM_REG_RISCV_CONFIG_REG(isa)); + ret = kvm_get_one_reg(cs, id, &isa); + if (ret) { + return ret; + } + cpu->env.misa = isa; + + return ret; }
int kvm_arch_msi_data_to_gsi(uint32_t data)
Get GPR CSR and FP registers from kvm by KVM_GET_ONE_REG ioctl.
Signed-off-by: Yifei Jiang jiangyifei@huawei.com Signed-off-by: Yipeng Yin yinyipeng1@huawei.com --- target/riscv/kvm.c | 144 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-)
diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c index 7983f43f3..3d4470727 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -50,13 +50,155 @@ static __u64 kvm_riscv_reg_id(__u64 type, __u64 idx) return id; }
+#define RISCV_CORE_REG(name) kvm_riscv_reg_id(KVM_REG_RISCV_CORE, \ + KVM_REG_RISCV_CORE_REG(name)) + +#define RISCV_CSR_REG(name) kvm_riscv_reg_id(KVM_REG_RISCV_CSR, \ + KVM_REG_RISCV_CSR_REG(name)) + +#define RISCV_FP_F_REG(idx) kvm_riscv_reg_id(KVM_REG_RISCV_FP_F, idx) + +#define RISCV_FP_D_REG(idx) kvm_riscv_reg_id(KVM_REG_RISCV_FP_D, idx) + +static int kvm_riscv_get_regs_core(CPUState *cs) +{ + int ret = 0; + int i; + target_ulong reg; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + ret = kvm_get_one_reg(cs, RISCV_CORE_REG(regs.pc), ®); + if (ret) { + return ret; + } + env->pc = reg; + + for (i = 1; i < 32; i++) { + __u64 id = kvm_riscv_reg_id(KVM_REG_RISCV_CORE, i); + ret = kvm_get_one_reg(cs, id, ®); + if (ret) { + return ret; + } + env->gpr[i] = reg; + } + + return ret; +} + +static int kvm_riscv_get_regs_csr(CPUState *cs) +{ + int ret = 0; + target_ulong reg; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + ret = kvm_get_one_reg(cs, RISCV_CSR_REG(sstatus), ®); + if (ret) { + return ret; + } + env->mstatus = reg; + + ret = kvm_get_one_reg(cs, RISCV_CSR_REG(sie), ®); + if (ret) { + return ret; + } + env->mie = reg; + + ret = kvm_get_one_reg(cs, RISCV_CSR_REG(stvec), ®); + if (ret) { + return ret; + } + env->stvec = reg; + + ret = kvm_get_one_reg(cs, RISCV_CSR_REG(sscratch), ®); + if (ret) { + return ret; + } + env->sscratch = reg; + + ret = kvm_get_one_reg(cs, RISCV_CSR_REG(sepc), ®); + if (ret) { + return ret; + } + env->sepc = reg; + + ret = kvm_get_one_reg(cs, RISCV_CSR_REG(scause), ®); + if (ret) { + return ret; + } + env->scause = reg; + + ret = kvm_get_one_reg(cs, RISCV_CSR_REG(sip), ®); + if (ret) { + return ret; + } + env->mip = reg; + + ret = kvm_get_one_reg(cs, RISCV_CSR_REG(satp), ®); + if (ret) { + return ret; + } + env->satp = reg; + + return ret; +} + +static int kvm_riscv_get_regs_fp(CPUState *cs) +{ + int ret = 0; + int i; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + if (riscv_has_ext(env, RVD)) { + uint64_t reg; + for (i = 0; i < 32; i++) { + ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(i), ®); + if (ret) { + return ret; + } + env->fpr[i] = reg; + } + return ret; + } + + if (riscv_has_ext(env, RVF)) { + uint32_t reg; + for (i = 0; i < 32; i++) { + ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(i), ®); + if (ret) { + return ret; + } + env->fpr[i] = reg; + } + return ret; + } + + return ret; +} + const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO };
int kvm_arch_get_registers(CPUState *cs) { - return 0; + int ret = 0; + + ret = kvm_riscv_get_regs_core(cs); + if (ret) { + return ret; + } + + ret = kvm_riscv_get_regs_csr(cs); + if (ret) { + return ret; + } + + ret = kvm_riscv_get_regs_fp(cs); + if (ret) { + return ret; + } + + return ret; }
int kvm_arch_put_registers(CPUState *cs, int level)
Put GPR CSR and FP registers to kvm by KVM_SET_ONE_REG ioctl
Signed-off-by: Yifei Jiang jiangyifei@huawei.com Signed-off-by: Yipeng Yin yinyipeng1@huawei.com --- target/riscv/kvm.c | 136 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 135 insertions(+), 1 deletion(-)
diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c index 3d4470727..f153523dc 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -85,6 +85,31 @@ static int kvm_riscv_get_regs_core(CPUState *cs) return ret; }
+static int kvm_riscv_put_regs_core(CPUState *cs) +{ + int ret = 0; + int i; + target_ulong reg; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + reg = env->pc; + ret = kvm_set_one_reg(cs, RISCV_CORE_REG(regs.pc), ®); + if (ret) { + return ret; + } + + for (i = 1; i < 32; i++) { + __u64 id = kvm_riscv_reg_id(KVM_REG_RISCV_CORE, i); + reg = env->gpr[i]; + ret = kvm_set_one_reg(cs, id, ®); + if (ret) { + return ret; + } + } + + return ret; +} + static int kvm_riscv_get_regs_csr(CPUState *cs) { int ret = 0; @@ -142,6 +167,64 @@ static int kvm_riscv_get_regs_csr(CPUState *cs) return ret; }
+static int kvm_riscv_put_regs_csr(CPUState *cs) +{ + int ret = 0; + target_ulong reg; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + reg = env->mstatus; + ret = kvm_set_one_reg(cs, RISCV_CSR_REG(sstatus), ®); + if (ret) { + return ret; + } + + reg = env->mie; + ret = kvm_set_one_reg(cs, RISCV_CSR_REG(sie), ®); + if (ret) { + return ret; + } + + reg = env->stvec; + ret = kvm_set_one_reg(cs, RISCV_CSR_REG(stvec), ®); + if (ret) { + return ret; + } + + reg = env->sscratch; + ret = kvm_set_one_reg(cs, RISCV_CSR_REG(sscratch), ®); + if (ret) { + return ret; + } + + reg = env->sepc; + ret = kvm_set_one_reg(cs, RISCV_CSR_REG(sepc), ®); + if (ret) { + return ret; + } + + reg = env->scause; + ret = kvm_set_one_reg(cs, RISCV_CSR_REG(scause), ®); + if (ret) { + return ret; + } + + reg = env->mip; + ret = kvm_set_one_reg(cs, RISCV_CSR_REG(sip), ®); + if (ret) { + return ret; + } + + reg = env->satp; + ret = kvm_set_one_reg(cs, RISCV_CSR_REG(satp), ®); + if (ret) { + return ret; + } + + return ret; +} + + static int kvm_riscv_get_regs_fp(CPUState *cs) { int ret = 0; @@ -175,6 +258,40 @@ static int kvm_riscv_get_regs_fp(CPUState *cs) return ret; }
+static int kvm_riscv_put_regs_fp(CPUState *cs) +{ + int ret = 0; + int i; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + if (riscv_has_ext(env, RVD)) { + uint64_t reg; + for (i = 0; i < 32; i++) { + reg = env->fpr[i]; + ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(i), ®); + if (ret) { + return ret; + } + } + return ret; + } + + if (riscv_has_ext(env, RVF)) { + uint32_t reg; + for (i = 0; i < 32; i++) { + reg = env->fpr[i]; + ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(i), ®); + if (ret) { + return ret; + } + } + return ret; + } + + return ret; +} + + const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; @@ -203,7 +320,24 @@ int kvm_arch_get_registers(CPUState *cs)
int kvm_arch_put_registers(CPUState *cs, int level) { - return 0; + int ret = 0; + + ret = kvm_riscv_put_regs_core(cs); + if (ret) { + return ret; + } + + ret = kvm_riscv_put_regs_csr(cs); + if (ret) { + return ret; + } + + ret = kvm_riscv_put_regs_fp(cs); + if (ret) { + return ret; + } + + return ret; }
int kvm_arch_release_virq_post(int virq)
Get kernel and fdt start address in virt.c, and pass them to KVM when cpu reset. In addition, add kvm_riscv.h to place riscv specific interface.
Signed-off-by: Yifei Jiang jiangyifei@huawei.com Signed-off-by: Yipeng Yin yinyipeng1@huawei.com --- hw/riscv/virt.c | 15 +++++++++++++-- target/riscv/cpu.c | 4 ++++ target/riscv/cpu.h | 3 +++ target/riscv/kvm.c | 14 ++++++++++++++ target/riscv/kvm_riscv.h | 24 ++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 target/riscv/kvm_riscv.h
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index e01925ff3..270c4a887 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -43,6 +43,7 @@ #include "exec/address-spaces.h" #include "hw/pci/pci.h" #include "hw/pci-host/gpex.h" +#include "sysemu/kvm.h"
#include <libfdt.h>
@@ -498,6 +499,9 @@ static void riscv_virt_board_init(MachineState *machine) target_ulong start_addr = memmap[VIRT_DRAM].base; DeviceState *mmio_plic, *virtio_plic, *pcie_plic; int i, j, base_hartid, hart_count; + uint64_t kernel_entry = 0; + hwaddr start_fdt; + CPUState *cs;
/* Check socket count limit */ if (VIRT_SOCKETS_MAX < riscv_socket_count(machine)) { @@ -607,7 +611,7 @@ static void riscv_virt_board_init(MachineState *machine) memmap[VIRT_DRAM].base, NULL);
if (machine->kernel_filename) { - uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename, + kernel_entry = riscv_load_kernel(machine->kernel_filename, NULL);
if (machine->initrd_filename) { @@ -661,10 +665,17 @@ static void riscv_virt_board_init(MachineState *machine) exit(1); } qemu_fdt_dumpdtb(s->fdt, fdt_totalsize(s->fdt)); + start_fdt = memmap[VIRT_MROM].base + sizeof(reset_vec); rom_add_blob_fixed_as("mrom.fdt", s->fdt, fdt_totalsize(s->fdt), - memmap[VIRT_MROM].base + sizeof(reset_vec), + start_fdt, &address_space_memory);
+ for (cs = first_cpu; cs; cs = CPU_NEXT(cs)) { + RISCVCPU *riscv_cpu = RISCV_CPU(cs); + riscv_cpu->env.loader_start = kernel_entry; + riscv_cpu->env.fdt_start = start_fdt; + } + /* SiFive Test MMIO device */ sifive_test_create(memmap[VIRT_TEST].base);
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index eeb91f851..73af94efb 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -28,6 +28,7 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "fpu/softfloat-helpers.h" +#include "kvm_riscv.h"
/* RISC-V CPU definitions */
@@ -336,6 +337,9 @@ static void riscv_cpu_reset(DeviceState *dev) cs->exception_index = EXCP_NONE; env->load_res = -1; set_default_nan_mode(1, &env->fp_status); +#ifdef CONFIG_KVM + kvm_riscv_reset_vcpu(cpu); +#endif }
static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 1bb527151..df6d95b16 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -206,6 +206,9 @@ struct CPURISCVState {
/* Fields from here on are preserved across CPU reset. */ QEMUTimer *timer; /* Internal timer */ + + hwaddr loader_start; + hwaddr fdt_start; };
#define RISCV_CPU_CLASS(klass) \ diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c index f153523dc..23b463ab5 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -37,6 +37,7 @@ #include "hw/irq.h" #include "qemu/log.h" #include "hw/loader.h" +#include "kvm_riscv.h"
static __u64 kvm_riscv_reg_id(__u64 type, __u64 idx) { @@ -426,3 +427,16 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { return 0; } + +void kvm_riscv_reset_vcpu(RISCVCPU *cpu) +{ + CPURISCVState *env = &cpu->env; + + if (!kvm_enabled()) { + return; + } + env->pc = cpu->env.loader_start; + env->gpr[10] = kvm_arch_vcpu_id(CPU(cpu)); /* a0 */ + env->gpr[11] = cpu->env.fdt_start; /* a1 */ +} + diff --git a/target/riscv/kvm_riscv.h b/target/riscv/kvm_riscv.h new file mode 100644 index 000000000..f38c82bf5 --- /dev/null +++ b/target/riscv/kvm_riscv.h @@ -0,0 +1,24 @@ +/* + * QEMU KVM support -- RISC-V specific functions. + * + * Copyright (c) 2020 Huawei Technologies Co., Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see http://www.gnu.org/licenses/. + */ + +#ifndef QEMU_KVM_RISCV_H +#define QEMU_KVM_RISCV_H + +void kvm_riscv_reset_vcpu(RISCVCPU *cpu); + +#endif
Only support supervisor external interrupt currently.
Signed-off-by: Yifei Jiang jiangyifei@huawei.com Signed-off-by: Yipeng Yin yinyipeng1@huawei.com --- hw/riscv/sifive_plic.c | 31 ++++++++++++++++++++++--------- target/riscv/kvm.c | 19 +++++++++++++++++++ target/riscv/kvm_riscv.h | 1 + 3 files changed, 42 insertions(+), 9 deletions(-)
diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c index f88bb4805..be2fb0706 100644 --- a/hw/riscv/sifive_plic.c +++ b/hw/riscv/sifive_plic.c @@ -29,6 +29,8 @@ #include "target/riscv/cpu.h" #include "sysemu/sysemu.h" #include "hw/riscv/sifive_plic.h" +#include "sysemu/kvm.h" +#include "kvm_riscv.h"
#define RISCV_DEBUG_PLIC 0
@@ -145,15 +147,26 @@ static void sifive_plic_update(SiFivePLICState *plic) continue; } int level = sifive_plic_irqs_pending(plic, addrid); - switch (mode) { - case PLICMode_M: - riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, BOOL_TO_MASK(level)); - break; - case PLICMode_S: - riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_SEIP, BOOL_TO_MASK(level)); - break; - default: - break; + if (kvm_enabled()) { + if (mode == PLICMode_M) { + continue; + } +#ifdef CONFIG_KVM + kvm_riscv_set_irq(RISCV_CPU(cpu), IRQ_S_EXT, level); +#endif + } else { + switch (mode) { + case PLICMode_M: + riscv_cpu_update_mip(RISCV_CPU(cpu), + MIP_MEIP, BOOL_TO_MASK(level)); + break; + case PLICMode_S: + riscv_cpu_update_mip(RISCV_CPU(cpu), + MIP_SEIP, BOOL_TO_MASK(level)); + break; + default: + break; + } } }
diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c index 23b463ab5..2864da65a 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -440,3 +440,22 @@ void kvm_riscv_reset_vcpu(RISCVCPU *cpu) env->gpr[11] = cpu->env.fdt_start; /* a1 */ }
+void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level) +{ + int ret; + unsigned virq = level ? KVM_INTERRUPT_SET : KVM_INTERRUPT_UNSET; + + if (irq != IRQ_S_EXT) { + return; + } + + if (!kvm_enabled()) { + return; + } + + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_INTERRUPT, &virq); + if (ret < 0) { + perror("Set irq failed"); + abort(); + } +} diff --git a/target/riscv/kvm_riscv.h b/target/riscv/kvm_riscv.h index f38c82bf5..ed281bdce 100644 --- a/target/riscv/kvm_riscv.h +++ b/target/riscv/kvm_riscv.h @@ -20,5 +20,6 @@ #define QEMU_KVM_RISCV_H
void kvm_riscv_reset_vcpu(RISCVCPU *cpu); +void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level);
#endif
Use char-fe handler console sbi call, which implement early console io while apply 'earlycon=sbi' into kernel parameters.
The common SBI interface sbi_ecall_interface.h is introduced from https://github.com/riscv/opensbi/blob/master/include/sbi/sbi_ecall_interface....
Signed-off-by: Yifei Jiang jiangyifei@huawei.com Signed-off-by: Yipeng Yin yinyipeng1@huawei.com --- target/riscv/kvm.c | 42 ++++++++++++++++- target/riscv/sbi_ecall_interface.h | 72 ++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 target/riscv/sbi_ecall_interface.h
diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c index 2864da65a..f1504c0f1 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -38,6 +38,8 @@ #include "qemu/log.h" #include "hw/loader.h" #include "kvm_riscv.h" +#include "sbi_ecall_interface.h" +#include "chardev/char-fe.h"
static __u64 kvm_riscv_reg_id(__u64 type, __u64 idx) { @@ -423,9 +425,47 @@ bool kvm_arch_stop_on_emulation_error(CPUState *cs) return true; }
+static int kvm_riscv_handle_sbi(struct kvm_run *run) +{ + int ret = 0; + unsigned char ch; + switch (run->riscv_sbi.extension_id) { + case SBI_EXT_0_1_CONSOLE_PUTCHAR: + ch = run->riscv_sbi.args[0]; + qemu_chr_fe_write(serial_hd(0)->be, &ch, sizeof(ch)); + break; + case SBI_EXT_0_1_CONSOLE_GETCHAR: + ret = qemu_chr_fe_read_all(serial_hd(0)->be, &ch, sizeof(ch)); + if (ret == sizeof(ch)) { + run->riscv_sbi.args[0] = ch; + } else { + run->riscv_sbi.args[0] = -1; + } + break; + default: + qemu_log_mask(LOG_UNIMP, + "%s: un-handled SBI EXIT, specific reasons is %lu\n", + __func__, run->riscv_sbi.extension_id); + ret = -1; + break; + } + return ret; +} + int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { - return 0; + int ret = 0; + switch (run->exit_reason) { + case KVM_EXIT_RISCV_SBI: + ret = kvm_riscv_handle_sbi(run); + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n", + __func__, run->exit_reason); + ret = -1; + break; + } + return ret; }
void kvm_riscv_reset_vcpu(RISCVCPU *cpu) diff --git a/target/riscv/sbi_ecall_interface.h b/target/riscv/sbi_ecall_interface.h new file mode 100644 index 000000000..fb1a3fa8f --- /dev/null +++ b/target/riscv/sbi_ecall_interface.h @@ -0,0 +1,72 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel anup.patel@wdc.com + */ + +#ifndef __SBI_ECALL_INTERFACE_H__ +#define __SBI_ECALL_INTERFACE_H__ + +/* clang-format off */ + +/* SBI Extension IDs */ +#define SBI_EXT_0_1_SET_TIMER 0x0 +#define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1 +#define SBI_EXT_0_1_CONSOLE_GETCHAR 0x2 +#define SBI_EXT_0_1_CLEAR_IPI 0x3 +#define SBI_EXT_0_1_SEND_IPI 0x4 +#define SBI_EXT_0_1_REMOTE_FENCE_I 0x5 +#define SBI_EXT_0_1_REMOTE_SFENCE_VMA 0x6 +#define SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID 0x7 +#define SBI_EXT_0_1_SHUTDOWN 0x8 +#define SBI_EXT_BASE 0x10 +#define SBI_EXT_TIME 0x54494D45 +#define SBI_EXT_IPI 0x735049 +#define SBI_EXT_RFENCE 0x52464E43 +#define SBI_EXT_HSM 0x48534D + +/* SBI function IDs for BASE extension*/ +#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0 +#define SBI_EXT_BASE_GET_IMP_ID 0x1 +#define SBI_EXT_BASE_GET_IMP_VERSION 0x2 +#define SBI_EXT_BASE_PROBE_EXT 0x3 +#define SBI_EXT_BASE_GET_MVENDORID 0x4 +#define SBI_EXT_BASE_GET_MARCHID 0x5 +#define SBI_EXT_BASE_GET_MIMPID 0x6 + +/* SBI function IDs for TIME extension*/ +#define SBI_EXT_TIME_SET_TIMER 0x0 + +/* SBI function IDs for IPI extension*/ +#define SBI_EXT_IPI_SEND_IPI 0x0 + +/* SBI function IDs for RFENCE extension*/ +#define SBI_EXT_RFENCE_REMOTE_FENCE_I 0x0 +#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA 0x1 +#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID 0x2 +#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x3 +#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x4 +#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x5 +#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x6 + +/* SBI function IDs for HSM extension */ +#define SBI_EXT_HSM_HART_START 0x0 +#define SBI_EXT_HSM_HART_STOP 0x1 +#define SBI_EXT_HSM_HART_GET_STATUS 0x2 + +#define SBI_HSM_HART_STATUS_STARTED 0x0 +#define SBI_HSM_HART_STATUS_STOPPED 0x1 +#define SBI_HSM_HART_STATUS_START_PENDING 0x2 +#define SBI_HSM_HART_STATUS_STOP_PENDING 0x3 + +#define SBI_SPEC_VERSION_MAJOR_OFFSET 24 +#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f +#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff +#define SBI_EXT_VENDOR_START 0x09000000 +#define SBI_EXT_VENDOR_END 0x09FFFFFF +/* clang-format on */ + +#endif
Currently, host cpu is inherited simply.
Signed-off-by: Yifei Jiang jiangyifei@huawei.com Signed-off-by: Yipeng Yin yinyipeng1@huawei.com --- target/riscv/cpu.c | 6 ++++++ target/riscv/cpu.h | 1 + 2 files changed, 7 insertions(+)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 73af94efb..b7de444fb 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -192,6 +192,10 @@ static void rv64imacu_nommu_cpu_init(Object *obj) set_feature(env, RISCV_FEATURE_PMP); }
+static void riscv_host_cpu_init(Object *obj) +{ +} + #endif
static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model) @@ -603,10 +607,12 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32imafcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_HOST, riscv_host_cpu_init), #elif defined(TARGET_RISCV64) DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base64_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64gcsu_priv1_10_0_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_HOST, riscv_host_cpu_init), #endif };
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index df6d95b16..f69f38df7 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -40,6 +40,7 @@ #define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51") #define TYPE_RISCV_CPU_SIFIVE_U34 RISCV_CPU_TYPE_NAME("sifive-u34") #define TYPE_RISCV_CPU_SIFIVE_U54 RISCV_CPU_TYPE_NAME("sifive-u54") +#define TYPE_RISCV_CPU_HOST RISCV_CPU_TYPE_NAME("host")
#define RV32 ((target_ulong)1 << (TARGET_LONG_BITS - 2)) #define RV64 ((target_ulong)2 << (TARGET_LONG_BITS - 2))