qemu-riscv 如何将设备树 Blob 传递给客户内核?

How does qemu-riscv pass the Device Tree Blob to the guest kernel?

qemu-system-riscv 中的默认 bios (OpenSBI) 如何将设备树 Blob 传递给来宾?

我可以从 qemu-system-arm 'virt' 平台的 documentation 看到 QEMU 在使用 Linux 引导协议,或在裸机客户内核的硬编码地址。 QEMU 存储库中 hw/riscv/virt.c 中的源代码显示为 RISC-V 'virt' 平台生成了设备树 Blob(通过 create_fdt 函数),但是 none我能找到的文档描述了如何将其传递给来宾。感谢任何帮助。

How does the default bios (OpenSBI) in qemu-system-riscv pass the Device Tree Blob to a guest?

没有。该机制类似于所有 qemu“virt”机器。在这种特殊情况下,qemu 负责生成和加载已编译的 dtb。

实际上你只能依赖 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 期望通过“a1”传递的 fdt 地址,除非您使用 dtb 内置编译 OpenSBI FW_FDT_PATH,请参阅:

opensbi/docs/firmware/fw.md

opensbi/docs/firmware/fw_payload.md

目前在编译时无法直接设置fdt地址(OpenSBI v0.9)。

传递给下一个模式的 fdt 地址可以用 FW_PAYLOAD_FDT_ADDR.

改变

所以FW_FDT_PATHFW_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();

最后看到 https://www.sifive.com/blog/all-aboard-part-6-booting-a-risc-v-linux-kernel 的 RISC-V 内核启动过程:

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

并且 OpenSBI 使用 FW_OPTIONS=0x2:

编译
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