当前成果:
git clone -b nuclei_gd32vf103 https://gitee.com/gevico/qemu.git
下面记录关键 patch 解决的问题:
[patch] 修复 dts 编译警告问题
commit c48d9d247e6bf30153b8e5e91dab4f63ac847a80
Author: 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 8b0a11489cb4c7d796e545fb4bb59a0ada6ed09d
Author: 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.h
index 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 aa5224ecb03957825982f52579dae0dc02a93c98
Author: 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 72a1f9a351d5b3adf2dd8dbcbb1505e9f3824ec6
Author: zevorn <[email protected]t>
Date: Thu Jul 25 00:05:12 2024 +0800
hw/riscv: Add the intc device to gdv32vf103 cpu
commit ac3c55d0e19cb03bb31bd8f580ec24f18eb18590
Author: 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 7df1ce25dd9ea24fe1c4e9a4bc0ed41d933495e2
Author: 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.c
index 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 cpu
commit 5969602dcb461db5cba548ba83c29069be097dd8
Author: zevorn <[email protected]t>
Date: Sun Jul 28 17:16:39 2024 +0800
hw/gpio: Add the nuclei_gpio device
commit 60d9091f591599635af9ef49625962c25e50c2dc
Author: zevorn <[email protected]t>
Date: Sun Jul 28 17:04:20 2024 +0800
hw/riscv: Add the rcu device to gdv32vf103 cpu
commit e0af6cbaf0307ebd727ae5bdf471920733557f08
Author: 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 qemu
qemu-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 的异常来处理,这样非常方便通过客户程序的指令流或者函数调用流,来定位出错的地方。