From: Michalis Pappas Date: Fri, 23 Jun 2023 09:30:58 +0000 (+0200) Subject: plat/common: Populate the initrd bootinfo memreg from dtb X-Git-Tag: RELEASE-0.14.0~37 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=92f2b5ff41eb96cf73fbc693649df956b1c87f17;p=unikraft%2Funikraft.git plat/common: Populate the initrd bootinfo memreg from dtb Linux arm64 systems obtain the initrd address from the "linux,initrd-start" and "linux,initrd-end" properties of the "chosen" node in the fdt as: chosen { linux,initrd-start = <0x0 0x80000000>; linux,initrd-end = <0x0 0x80002000>; } Populate the initrd bootinfo region when these nodes are available in the dtb. Signed-off-by: Michalis Pappas Reviewed-by: Sergiu Moga Approved-by: Razvan Deaconescu Tested-by: Unikraft CI GitHub-Closes: #988 --- diff --git a/plat/common/bootinfo_fdt.c b/plat/common/bootinfo_fdt.c index 1435bb149..957cb53a6 100644 --- a/plat/common/bootinfo_fdt.c +++ b/plat/common/bootinfo_fdt.c @@ -115,6 +115,50 @@ static void fdt_bootinfo_cmdl_mrd(struct ukplat_bootinfo *bi, void *fdtp) bi->cmdline_len = (__u64)cmdl_len; } +/* Ideally the initrd nodes would use #address-cells, yet these nodes are not + * defined by the device-tree spec, and as such there is no formal requirement + * that they do so. In fact, QEMU virt uses a 32-bit address here, despite + * defining 2 address cells. To handle such cases, use the property length to + * determine the correct address. + */ +#define initrd_addr(val, len) \ + (len == 4 ? fdt32_to_cpu(val) : fdt64_to_cpu(val)) + +static void fdt_bootinfo_initrd_mrd(struct ukplat_bootinfo *bi, void *fdtp) +{ + struct ukplat_memregion_desc mrd = {0}; + const __u64 *fdt_initrd_start; + const __u64 *fdt_initrd_end; + int start_len, end_len; + int nchosen; + int rc; + + nchosen = fdt_path_offset(fdtp, "/chosen"); + if (unlikely(!nchosen)) + return; + + fdt_initrd_start = fdt_getprop(fdtp, nchosen, "linux,initrd-start", + &start_len); + if (unlikely(!fdt_initrd_start || start_len <= 0)) + return; + + fdt_initrd_end = fdt_getprop(fdtp, nchosen, "linux,initrd-end", + &end_len); + if (unlikely(!fdt_initrd_end || end_len <= 0)) + return; + + mrd.vbase = initrd_addr(fdt_initrd_start[0], start_len); + mrd.pbase = initrd_addr(fdt_initrd_start[0], start_len); + mrd.len = initrd_addr(fdt_initrd_end[0], end_len) - + initrd_addr(fdt_initrd_start[0], start_len); + mrd.type = UKPLAT_MEMRT_INITRD; + mrd.flags = UKPLAT_MEMRF_READ | UKPLAT_MEMRF_MAP; + + rc = ukplat_memregion_list_insert(&bi->mrds, &mrd); + if (unlikely(rc < 0)) + ukplat_bootinfo_crash("Could not add initrd memory descriptor"); +} + static void fdt_bootinfo_fdt_mrd(struct ukplat_bootinfo *bi, void *fdtp) { struct ukplat_memregion_desc mrd = {0}; @@ -144,6 +188,7 @@ void ukplat_bootinfo_fdt_setup(void *fdtp) fdt_bootinfo_fdt_mrd(bi, fdtp); fdt_bootinfo_mem_mrd(bi, fdtp); + fdt_bootinfo_initrd_mrd(bi, fdtp); ukplat_memregion_list_coalesce(&bi->mrds); /* We use this after coalescing/sorted because this calls