diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 81d27f935e..bc8074fec8 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -70,6 +70,7 @@ char *riscv_plic_hart_config_string(int hart_count) void riscv_boot_info_init(RISCVBootInfo *info, RISCVHartArrayState *harts) { info->kernel_size = 0; + info->initrd_size = 0; info->is_32bit = riscv_is_32bit(harts); } @@ -213,6 +214,9 @@ static void riscv_load_initrd(MachineState *machine, RISCVBootInfo *info) } } + info->initrd_start = start; + info->initrd_size = size; + /* Some RISC-V machines (e.g. opentitan) don't have a fdt. */ if (fdt) { end = start + size; @@ -309,6 +313,7 @@ uint64_t riscv_compute_fdt_addr(hwaddr dram_base, hwaddr dram_size, int ret = fdt_pack(ms->fdt); hwaddr dram_end, temp; int fdtsize; + uint64_t dtb_start, dtb_start_limit; /* Should only fail if we've built a corrupted tree */ g_assert(ret == 0); @@ -319,6 +324,17 @@ uint64_t riscv_compute_fdt_addr(hwaddr dram_base, hwaddr dram_size, exit(1); } + if (info->initrd_size) { + /* If initrd is successfully loaded, place DTB after it. */ + dtb_start_limit = info->initrd_start + info->initrd_size; + } else if (info->kernel_size) { + /* If only kernel is successfully loaded, place DTB after it. */ + dtb_start_limit = info->image_high_addr; + } else { + /* Otherwise, do not check DTB overlapping */ + dtb_start_limit = 0; + } + /* * A dram_size == 0, usually from a MemMapEntry[].size element, * means that the DRAM block goes all the way to ms->ram_size. @@ -338,7 +354,14 @@ uint64_t riscv_compute_fdt_addr(hwaddr dram_base, hwaddr dram_size, temp = (dram_base < 3072 * MiB) ? MIN(dram_end, 3072 * MiB) : dram_end; } - return QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB); + dtb_start = QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB); + + if (dtb_start_limit && (dtb_start < dtb_start_limit)) { + error_report("No enough memory to place DTB after kernel/initrd"); + exit(1); + } + + return dtb_start; } /* diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index 06b51ed086..7d59b2e6c6 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -32,6 +32,9 @@ typedef struct RISCVBootInfo { hwaddr image_low_addr; hwaddr image_high_addr; + hwaddr initrd_start; + ssize_t initrd_size; + bool is_32bit; } RISCVBootInfo;