Hi, qemu
As I know, brom will pass 3 parameters to the next stage bootloader, ex:
openSBI.
a0 will pass hartid, a2 will pass fw_dynamic_info start address.
although a1 doesn't use directly in openSBI.
a1 read value is determined in compile time rather than read from the
original a1 that passes from brom.
In qemu/hw/riscv/boot.c
both 32bit and 64bit machines read 4byte that offset 32byte from the
brom start address.
for 64 bits machine: a1 read low 32bit data member magic of fw_dynamic_info,
the value will same as FW_DYNAMIC_INFO_MAGIC_VALUE because risc-v is
little endian.
for 32bits machine: each data member of fw_dynamic_info is 4 bytes, so
a1 will read the version rather than magic.
Do the 32bit and 64bit pass different parameters are expected?
If it is not expected, I guess the original version is 64bit machine,
and then supports 32bit but misses this detail, I hope I can have an
opportunity to fix this problem.
If it is expected, why they must be done?
Thanks,
Eric Chan
qemu/include/hw/riscv/boot_opensbi.h
#define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f
qemu/hw/riscv/boot.c
void riscv_setup_rom_reset_vec(MachineState *machine,
RISCVHartArrayState *harts,
hwaddr start_addr,
hwaddr rom_base, hwaddr rom_size,
uint64_t kernel_entry,
uint64_t fdt_load_addr)
{
int i;
uint32_t start_addr_hi32 = 0x00000000;
uint32_t fdt_load_addr_hi32 = 0x00000000;
if (!riscv_is_32bit(harts)) {
start_addr_hi32 = start_addr >> 32;
fdt_load_addr_hi32 = fdt_load_addr >> 32;
}
/* 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 */
fdt_load_addr_hi32,
/* 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) */
}
/* copy in the reset vector in little_endian byte order */
for (i = 0; i < ARRAY_SIZE(reset_vec); i++) {
reset_vec[i] = cpu_to_le32(reset_vec[i]);
}
rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
rom_base, &address_space_memory);
riscv_rom_copy_firmware_info(machine, rom_base, rom_size, sizeof(reset_vec),
kernel_entry);
}
opensbi/firmware/fw_dynamic.S
fw_boot_hart:
/* Sanity checks */
li a1, FW_DYNAMIC_INFO_MAGIC_VALUE
REG_L a0, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
bne a0, a1, _bad_dynamic_info
li a1, FW_DYNAMIC_INFO_VERSION_MAX
REG_L a0, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
bgt a0, a1, _bad_dynamic_info
/* Read boot HART id */
li a1, FW_DYNAMIC_INFO_VERSION_2
blt a0, a1, 2f
REG_L a0, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
ret
2: li a0, -1
ret