diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index cf4e5d59463..4093271cb2e 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -46,15 +46,25 @@ static uint64_t kernel_translate(void *opaque, uint64_t addr) } } -hwaddr riscv_load_firmware(const char *filename) +hwaddr riscv_load_firmware(const char *filename, hwaddr ram_start, + uint64_t ram_size) { uint64_t firmware_entry, firmware_start, firmware_end; + int64_t size; if (load_elf(filename, NULL, NULL, &firmware_entry, &firmware_start, &firmware_end, 0, EM_RISCV, 1, 0) < 0) { - error_report("riscv_boot: could not load firmware '%s'", filename); - exit(1); + firmware_entry = ram_start; + firmware_start = ram_start; + + size = load_image_targphys(filename, firmware_start, ram_size); + if (size < 0) { + error_report("riscv_boot: could not load firmware '%s'", filename); + exit(1); + } + + firmware_end = firmware_start + size; } /* align kernel load address to the megapage after the firmware */ @@ -71,15 +81,31 @@ hwaddr riscv_load_firmware(const char *filename) return firmware_entry; } -hwaddr riscv_load_kernel(const char *filename, void *fdt) +hwaddr riscv_load_kernel(const char *filename, void *fdt, hwaddr ram_start, + uint64_t ram_size) { uint64_t kernel_entry, kernel_start, kernel_end; + int64_t size; if (load_elf(filename, kernel_translate, NULL, &kernel_entry, &kernel_start, &kernel_end, 0, EM_RISCV, 1, 0) < 0) { - error_report("riscv_boot: could not load kernel '%s'", filename); - exit(1); + if (kernel_offset) { + kernel_entry = kernel_offset; + kernel_start = kernel_offset; + ram_size -= kernel_offset - ram_start; + } else { + kernel_entry = ram_start; + kernel_start = ram_start; + } + + size = load_image_targphys(filename, kernel_start, ram_size); + if (size < 0) { + error_report("riscv_boot: could not load kernel '%s'", filename); + exit(1); + } + + kernel_end = kernel_start + size; } boot_debug("entry=0x" TARGET_FMT_plx " start=0x" TARGET_FMT_plx " " @@ -143,23 +169,27 @@ void riscv_load_initrd(const char *filename, uint64_t mem_size, } } -hwaddr riscv_load_firmware_kernel_initrd(MachineState *machine, void *fdt) +hwaddr riscv_load_firmware_kernel_initrd(MachineState *machine, void *fdt, + hwaddr ram_start) { hwaddr firmware_entry = 0; /* load firmware e.g. -bios bbl */ if (machine->firmware) { - firmware_entry = riscv_load_firmware(machine->firmware); + firmware_entry = riscv_load_firmware(machine->firmware, ram_start, + machine->ram_size); } /* load combined bbl+kernel or separate kernel */ if (machine->kernel_filename) { if (machine->firmware) { /* load separate bios and kernel e.g. -bios bbl -kernel vmlinux */ - riscv_load_kernel(machine->kernel_filename, fdt); + riscv_load_kernel(machine->kernel_filename, fdt, ram_start, + machine->ram_size); } else { /* load traditional combined bbl+kernel e.g. -kernel bbl_vmlimux */ - firmware_entry = riscv_load_kernel(machine->kernel_filename, NULL); + firmware_entry = riscv_load_kernel(machine->kernel_filename, NULL, + ram_start, machine->ram_size); } if (machine->initrd_filename) { /* load separate initrd */ diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 66dc4e07c3f..098605fb24a 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -266,7 +266,8 @@ static void riscv_virt_board_init(MachineState *machine) * separate firmware and kernel: -bios bbl -kernel vmlinux * firmware, kernel and ramdisk: -bios bbl -kernel vmlinux -initrd initramfs */ - firmware_entry = riscv_load_firmware_kernel_initrd(machine, fdt); + firmware_entry = riscv_load_firmware_kernel_initrd(machine, fdt, + memmap[VIRT_DRAM].base); /* reset vector */ uint32_t reset_vec[8] = { diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index aa30bf1c45b..6dc2f1ece3c 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -21,10 +21,13 @@ #ifndef HW_RISCV_BOOT_H #define HW_RISCV_BOOT_H -hwaddr riscv_load_firmware(const char *filename); -hwaddr riscv_load_kernel(const char *filename, void *fdt); +hwaddr riscv_load_firmware(const char *filename, hwaddr ram_start, + uint64_t ram_size); +hwaddr riscv_load_kernel(const char *filename, void *fdt, hwaddr ram_start, + uint64_t ram_size); void riscv_load_initrd(const char *filename, uint64_t mem_size, hwaddr firmware_entry, void *fdt); -hwaddr riscv_load_firmware_kernel_initrd(MachineState *machine, void *fdt); +hwaddr riscv_load_firmware_kernel_initrd(MachineState *machine, void *fdt, + hwaddr ram_start); #endif