当前成果:
git clone -b nuclei_gd32vf103 https://gitee.com/gevico/qemu.git
下面记录关键 patch 解决的问题:
[patch] 修复 dts 编译警告问题
commit c48d9d247e6bf30153b8e5e91dab4f63ac847a80Author: zevorn <[email protected]t>Date: Tue Jul 23 00:38:22 2024 +0800 pc-bios: Fix the compilation warning when dtb was generated It is mainly related to the memory and opb nodes in bamboo.dts.
这个 patch 主要解决了编译过程中遇到的 dts 编译警告,后续主线应该会修复该问题。
[patch] 添加 nuclei n205 核心
commit 8b0a11489cb4c7d796e545fb4bb59a0ada6ed09dAuthor: zevorn <[email protected]t>Date: Mon Jul 22 22:57:21 2024 +0800 target/riscv: Add nuclei_n205 core for RISCV architecture
初始化 N205 核心的时候,用的 DEFINE_VENDOR_CPU(),可扩展厂商自定义指令集。
diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.hindex 3670cfe6d9..7351cb4b0b 100644--- a/target/riscv/cpu-qom.h+++ b/target/riscv/cpu-qom.h@@ -50,6 +50,7 @@ #define TYPE_RISCV_CPU_THEAD_C906 RISCV_CPU_TYPE_NAME("thead-c906") #define TYPE_RISCV_CPU_VEYRON_V1 RISCV_CPU_TYPE_NAME("veyron-v1") #define TYPE_RISCV_CPU_HOST RISCV_CPU_TYPE_NAME("host")+#define TYPE_RISCV_CPU_NUCLEI_N205 RISCV_CPU_TYPE_NAME("nuclei-n205")
[patch] 添加 gd32vf103 Machine
commit aa5224ecb03957825982f52579dae0dc02a93c98Author: zevorn <[email protected]t>Date: Mon Jul 22 22:58:01 2024 +0800 hw/riscv: Add gd32vf103 mcu for RISCV architecture
没有实现具体外设,只增加了一些 mr 的初始化:
static void nuclei_board_init(MachineState *machine)+{+ const struct MemmapEntry *memmap = gd32vf103_memmap;+ NucleiGDState *s = g_new0(NucleiGDState, 1);+ MemoryRegion *system_memory = get_system_memory();+ MemoryRegion *main_mem = g_new(MemoryRegion, 1);+ s->soc.sram = *main_mem;+ int i;++ /* TODO: Add qtest support */+ /* Initialize SOC */+ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_NUCLEI_GD32VF103_SOC);+ qdev_realize(DEVICE(&s->soc), NULL, &error_abort);++ memory_region_init_ram(&s->soc.main_flash, NULL, "riscv.nuclei.main_flash",+ memmap[GD32VF103_MAINFLASH].size, &error_fatal);+ memory_region_add_subregion(system_memory,+ memmap[GD32VF103_MAINFLASH].base, &s->soc.main_flash);++ memory_region_init_ram(&s->soc.boot_loader, NULL, "riscv.nuclei.boot_loader",+ memmap[GD32VF103_BL].size, &error_fatal);+ memory_region_add_subregion(system_memory,+ memmap[GD32VF103_BL].base, &s->soc.boot_loader);++ memory_region_init_ram(&s->soc.ob, NULL, "riscv.nuclei.ob",+ memmap[GD32VF103_OB].size, &error_fatal);+ memory_region_add_subregion(system_memory,+ memmap[GD32VF103_OB].base, &s->soc.ob);++ memory_region_init_ram(&s->soc.sram, NULL, "riscv.nuclei.sram",+ memmap[GD32VF103_SRAM].size, &error_fatal);+ memory_region_add_subregion(system_memory,+ memmap[GD32VF103_SRAM].base, &s->soc.sram);++ /* reset vector */+ uint32_t reset_vec[8] = {+ 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */+ 0x02028593, /* addi a1, t0, %pcrel_lo(1b) */+ 0xf1402573, /* csrr a0, mhartid */+#if defined(TARGET_RISCV32)+ 0x0182a283, /* lw t0, 24(t0) */+#elif defined(TARGET_RISCV64)+ 0x0182b283, /* ld t0, 24(t0) */+#endif+ 0x00028067, /* jr t0 */+ 0x00000000,+ memmap[GD32VF103_MAINFLASH].base, /* start: .dword */+ 0x00000000,+ /* dtb: */+ };++ /* copy in the reset vector in little_endian byte order */+ for (i = 0; i < sizeof(reset_vec) >> 2; i++)+ {+ reset_vec[i] = cpu_to_le32(reset_vec[i]);+ }+ rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),+ memmap[GD32VF103_MFOL].base + 0x1000, &address_space_memory);++ /* boot rom */+ if (machine->kernel_filename)+ {+ riscv_load_kernel(machine, &s->soc.cpus,+ memmap[GD32VF103_MAINFLASH].base,+ false, NULL);+ }+}
[patch] 增加 eclic 外设,完善中断控制流程
commit 72a1f9a351d5b3adf2dd8dbcbb1505e9f3824ec6Author: zevorn <[email protected]t>Date: Thu Jul 25 00:05:12 2024 +0800 hw/riscv: Add the intc device to gdv32vf103 cpucommit ac3c55d0e19cb03bb31bd8f580ec24f18eb18590Author: zevorn <[email protected]t>Date: Thu Jul 25 00:05:02 2024 +0800 hw/intc: Add the gdv32vf103_eclic device
这部分还没有仔细研究,直接移植的 PLCT 原本的代码,但是做了 patch 整理,代码更加清晰。
[patch] 增加 nuclei-n205 CSR 扩充的寄存器的支持
commit 7df1ce25dd9ea24fe1c4e9a4bc0ed41d933495e2Author: zevorn <[email protected]t>Date: Sun Jul 28 17:04:20 2024 +0800 hw/riscv: Add the rcu device to gdv32vf103 cpu target/riscv: Add CSR register support for nuclei N205
这个 patch 有几个关键修改。
需要将 n205 的指令集版本设置为 latest,不然不支持 CSR_MCOUNTINHIBIT 寄存器,或者运行时有警告,另外需要将 cpu->cfg.ext_zifencei 和 cpu->cfg.ext_zicsr 设置为 true,不然有些 CSR 寄存器也不支持,会导致 startup 阶段访问某些 CSR 寄存器时意外陷入异常:
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.cindex 326576fe20..1d9d36ddb2 100644--- a/target/riscv/cpu.c+++ b/target/riscv/cpu.c@@ -684,13 +684,15 @@ static void rv32imacu_nuclei_cpu_init(Object *obj) #endif riscv_cpu_set_misa_ext(env, RVI | RVM | RVA | RVC | RVU);- env->priv_ver = PRIV_VERSION_1_10_0;+ env->priv_ver = PRIV_VERSION_LATEST; // support CSR_MCOUNTINHIBIT /* inherited from parent obj via riscv_cpu_init() */ qdev_prop_set_bit(DEVICE(obj), "mmu", false); #ifndef CONFIG_USER_ONLY env->resetvec = DEFAULT_RSTVEC; #endif+ cpu->cfg.ext_zifencei = true;+ cpu->cfg.ext_zicsr = true; cpu->cfg.pmp = true; }
[patch] 增加 gd32vf103 startup 阶段需要的几个外设
commit b37aac1ef3641e4aff84c9d95f48ff1cba8b2b74 (HEAD -> nuclei_gd32vf103)Author: zevorn <[email protected]t>Date: Sun Jul 28 17:16:46 2024 +0800 hw/riscv: Add the gpio device to gdv32vf103 cpucommit 5969602dcb461db5cba548ba83c29069be097dd8Author: zevorn <[email protected]t>Date: Sun Jul 28 17:16:39 2024 +0800 hw/gpio: Add the nuclei_gpio devicecommit 60d9091f591599635af9ef49625962c25e50c2dcAuthor: zevorn <[email protected]t>Date: Sun Jul 28 17:04:20 2024 +0800 hw/riscv: Add the rcu device to gdv32vf103 cpucommit e0af6cbaf0307ebd727ae5bdf471920733557f08Author: zevorn <[email protected]t>Date: Sun Jul 28 17:04:07 2024 +0800 hw/timer: Add the nuclei_rcu device
这里使用 riscv-gdb 远程 remote 到 qemu 以后,观察异常点的函数调用栈,可以追溯是哪个外设没实现,导致的访问寄存器时触发了异常,然后将对应的外设移植过来即可。
比较简单,这里不赘述移植过程,只说一下调试的流程,命令如下:
open 一个终端,启动 qemu :
cd qemuqemu-system-riscv32 -M gd32vf103v_rvstar -cpu nuclei-n205 -icount shift=0 -nodefaults -nographic -serial stdio -kernel nuclei-sdk/application/baremetal/helloworld/helloworld.elf -gdb tcp::1234 -S
open 一个新的终端,启动 gdb 来调试客户程序:
riscv-nuclei-linux-gnu-gdb ../nuclei-sdk/application/baremetal/helloworld/helloworld.elf(gdb) target remote localhost:1234(gdb) run(gdb) ctrl + c(gdb) bt...
这里可以根据函数调用栈,来定位具体异常对应的外设,或者其他指令。
Ps:对于来自客户程序的异常行为,即使是 qemu 这边没有实现对应的指令或者外设,亦或者没有初始化一些内存区域,也是按照 Guest Machine 的异常来处理,这样非常方便通过客户程序的指令流或者函数调用流,来定位出错的地方。