qemu-system-riscv 中的默认 bios (OpenSBI) 如何将设备树 Blob 传递给来宾?
它没有。该机制类似于所有 qemu“virt”机器。在这种特殊情况下,生成和加载已编译的 dtb 是 qemu 的责任。
实际上你只能依赖 RAM 和 FLASH 地址,所有其他信息都应该从 Qemu 生成的 DTB 中获取。
引用自 qemu/hw/riscv/boot.c:
riscv_load_fdt
/*
* We should put fdt as far as possible to avoid kernel/initrd overwriting
* its content. But it should be addressable by 32 bit system as well.
* Thus, put it at an 16MB aligned address that less than fdt size from the
* end of dram or 3GB whichever is lesser.
*/
OpenSBI 期望 fdt addr 通过“a1”传递,除非您使用 dtb 内置 FW_FDT_PATH 编译 OpenSBI,请参阅:
opensbi/docs/firmware/fw.md
opensbi/docs/firmware/fw_payload.md
目前编译时无法直接设置fdt的地址(OpenSBI v0.9)。
不过,传递到下一个模式的 fdt 的地址可以通过 FW_PAYLOAD_FDT_ADDR 进行更改。
所以 FW_FDT_PATH 和 FW_PAYLOAD_FDT_ADDR 分别影响 fdt。
Qemu 在 riscv_setup_rom_reset_vec 和其他集合中设置重置向量 fdt_load_addr
接下来会发生什么取决于 OpenSBI 模式(dtb 可以由 OpenSBI 重新分配),但您可以查看 opensbi/sbi_hart.c 中的 sbi_hart_switch_mode:
register unsigned long a0 asm("a0") = arg0;
register unsigned long a1 asm("a1") = arg1;
__asm__ __volatile__("mret" : : "r"(a0), "r"(a1));
__builtin_unreachable();
RISC-V 内核启动过程终于看到https://www.sifive.com/blog/all-aboard-part-6-booting-a-risc-v-linux-kernel:
Early Boot in Linux
When Linux boots, it expects the system to be in the following state:
a0 contains a unique per-hart ID. We currently map these to Linux CPU IDs,
so they're expected to be contiguous and close to 0.
a1 contains a pointer to the device tree, represented as a binary flattened
device tree (DTB).
更新:
例如,您可以看到以下内容:
build-qemu/qemu-system-riscv64 -machine virt -m 2G -nographic -bios opensbi/build/platform/generic/firmware/fw_jump.bin
并且使用 FW_OPTIONS=0x2 编译的 OpenSBI:
Domain0 Name : root
Domain0 Boot HART : 0
Domain0 HARTs : 0*
Domain0 Region00 : 0x0000000002000000-0x000000000200ffff (I)
Domain0 Region01 : 0x0000000080000000-0x000000008003ffff ()
Domain0 Region02 : 0x0000000000000000-0xffffffffffffffff (R,W,X)
Domain0 Next Address : 0x0000000080200000
Domain0 Next Arg1 : 0x0000000082200000
Domain0 Next Mode : S-mode
Domain0 SysReset : yes