'How does QEMU risc-v put FDT address in register a1?
From RISC-V OpenSBI's source code and documents, in OpenSBI firmware a1
preserves FDT address from the prior booting stage, which I guess is QEMU if the following command is used to boot OpenSBI firmware:
qemu-system-riscv64 -M virt -m 256M -nographic -bios build/platform/generic/firmware/fw_payload.bin
and OpenSBI firmware is built with
make PLATFORM=generic CROSS_COMPILE=riscv64-linux-gnu-
fw_base.S
in OpenSBI's source code will use the value of a1
to invoke fw_platform_init
, which assumes a1
contains the FDT address.
My question is when and how a1
is set before fw_base.S
?
Solution 1:[1]
a1
is set by function riscv_setup_rom_reset_vec(...)
which in qemu/hw/riscv/boot.c
inserts some instructions to set FDT address:
/* reset vector */
uint32_t reset_vec[10] = {
0x00000297, /* 1: auipc t0, %pcrel_hi(fw_dyn) */
0x02828613, /* addi a2, t0, %pcrel_lo(1b) */
0xf1402573, /* csrr a0, mhartid */
0,
0,
0x00028067, /* jr t0 */
start_addr, /* start: .dword */
start_addr_hi32,
fdt_load_addr, /* fdt_laddr: .dword */
0x00000000,
/* fw_dyn: */
};
if (riscv_is_32bit(harts)) {
reset_vec[3] = 0x0202a583; /* lw a1, 32(t0) */
reset_vec[4] = 0x0182a283; /* lw t0, 24(t0) */
} else {
reset_vec[3] = 0x0202b583; /* ld a1, 32(t0) */
reset_vec[4] = 0x0182b283; /* ld t0, 24(t0) */
}
When qemu runs, it will first jump to 0x1000
to execute these instructions and then jump to _start
.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Xujie Shen |