]> xenbits.xensource.com Git - unikraft/unikraft.git/commitdiff
plat/common: Populate the initrd bootinfo memreg from dtb
authorMichalis Pappas <michalis@unikraft.io>
Fri, 23 Jun 2023 09:30:58 +0000 (11:30 +0200)
committerUnikraft <monkey@unikraft.io>
Fri, 11 Aug 2023 19:49:38 +0000 (19:49 +0000)
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 <michalis@unikraft.io>
Reviewed-by: Sergiu Moga <sergiu@unikraft.io>
Approved-by: Razvan Deaconescu <razvand@unikraft.io>
Tested-by: Unikraft CI <monkey@unikraft.io>
GitHub-Closes: #988

plat/common/bootinfo_fdt.c

index 1435bb14948b89cb562d910822ba5043c60c2ad3..957cb53a6b5d8a51a15068d7b38e13c5504d67ba 100644 (file)
@@ -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