:: commit 45e036275af9867471e141444f7d07db97f5d0e9

mintsuki <mintsuki@protonmail.com> — 2024-06-27 22:43

parents: ddfd654602

dtb: Optionally reallocate and expand DTB memory as needed

diff --git a/common/lib/misc.c b/common/lib/misc.c
index e34f039d..62394da0 100644
--- a/common/lib/misc.c
+++ b/common/lib/misc.c
@@ -8,6 +8,7 @@
 #include <lib/real.h>
 #include <fs/file.h>
 #include <mm/pmm.h>
+#include <libfdt/libfdt.h>
 
 #if defined (UEFI)
 EFI_SYSTEM_TABLE *gST;
@@ -110,16 +111,48 @@ uint32_t hex2bin(uint8_t *str, uint32_t size) {
 
 #if defined (UEFI)
 
-void *get_device_tree_blob(void) {
+void *get_device_tree_blob(size_t extra_size) {
     EFI_GUID dtb_guid = EFI_DTB_TABLE_GUID;
     for (size_t i = 0; i < gST->NumberOfTableEntries; i++) {
         EFI_CONFIGURATION_TABLE *cur_table = &gST->ConfigurationTable[i];
         if (memcmp(&cur_table->VendorGuid, &dtb_guid, sizeof(EFI_GUID)))
             continue;
-        printv("efi: found dtb at %p\n", cur_table->VendorTable);
-        return cur_table->VendorTable;
+
+        size_t s = fdt_totalsize(cur_table->VendorTable);
+
+        printv("efi: found dtb at %p, size %x\n", cur_table->VendorTable, s);
+
+        void *new_tab = ext_mem_alloc(s + extra_size);
+
+        fdt_resize(cur_table->VendorTable, new_tab, s + extra_size);
+
+        return new_tab;
     }
-    return NULL;
+
+    if (extra_size == (size_t)-1) {
+        return NULL;
+    }
+
+    void *dtb = ext_mem_alloc(extra_size);
+
+    int ret;
+
+    ret = fdt_create_empty_tree(dtb, extra_size);
+    if (ret < 0) {
+        panic(true, "dtb: failed to create a device tree blob: '%s'", fdt_strerror(ret));
+    }
+
+    ret = fdt_setprop_u32(dtb, 0, "#address-cells", 2);
+    if (ret < 0) {
+        panic(true, "dtb: failed to set #address-cells: '%s'", fdt_strerror(ret));
+    }
+
+    ret = fdt_setprop_u32(dtb, 0, "#size-cells", 1);
+    if (ret < 0) {
+        panic(true, "dtb: failed to set #size-cells: '%s'", fdt_strerror(ret));
+    }
+
+    return dtb;
 }
 
 #if defined (__riscv)
diff --git a/common/lib/misc.h b/common/lib/misc.h
index 7b3851c4..612423c0 100644
--- a/common/lib/misc.h
+++ b/common/lib/misc.h
@@ -27,7 +27,7 @@ extern UINT32 efi_desc_ver;
 extern bool efi_boot_services_exited;
 bool efi_exit_boot_services(void);
 
-void *get_device_tree_blob(void);
+void *get_device_tree_blob(size_t extra_size);
 #endif
 
 extern struct volume *boot_volume;
diff --git a/common/protos/linux_risc.c b/common/protos/linux_risc.c
index da466a00..95f6e05a 100644
--- a/common/protos/linux_risc.c
+++ b/common/protos/linux_risc.c
@@ -47,32 +47,10 @@ struct linux_header {
 #endif
 
 void *prepare_device_tree_blob(char *config, char *cmdline) {
-    void *dtb = get_device_tree_blob();
+    // Hopefully 4K should be enough (mainly depends on the length of cmdline).
+    void *dtb = get_device_tree_blob(0x1000);
     int ret;
 
-    if (!dtb) {
-        // Hopefully 4K should be enough (mainly depends on the length of cmdline).
-        dtb = ext_mem_alloc_type(0x1000, MEMMAP_KERNEL_AND_MODULES);
-        if (!dtb) {
-            panic(true, "linux: failed to allocate memory for a device tree blob");
-        }
-
-        ret = fdt_create_empty_tree(dtb, 0x1000);
-        if (ret < 0) {
-            panic(true, "linux: failed to create a device tree blob: '%s'", fdt_strerror(ret));
-        }
-
-        ret = fdt_setprop_u32(dtb, 0, "#address-cells", 2);
-        if (ret < 0) {
-            panic(true, "linux: failed to set #address-cells: '%s'", fdt_strerror(ret));
-        }
-
-        ret = fdt_setprop_u32(dtb, 0, "#size-cells", 1);
-        if (ret < 0) {
-            panic(true, "linux: failed to set #size-cells: '%s'", fdt_strerror(ret));
-        }
-    }
-
     // Delete all /memory@... nodes. Linux will use the given UEFI memory map
     // instead.
     while (true) {
diff --git a/common/sys/cpu_riscv.c b/common/sys/cpu_riscv.c
index 9de27307..f9677d91 100644
--- a/common/sys/cpu_riscv.c
+++ b/common/sys/cpu_riscv.c
@@ -225,7 +225,7 @@ static void init_riscv_fdt(const void *fdt) {
 }
 
 void init_riscv(void) {
-    void *fdt = get_device_tree_blob();
+    void *fdt = get_device_tree_blob((size_t)-1);
     if (fdt != NULL) {
         init_riscv_fdt(fdt);
     } else if (acpi_get_rsdp()) {
@@ -338,4 +338,4 @@ bool riscv_check_isa_extension_for(size_t hartid, const char *name, size_t *maj,
     return false;
 }
 
-#endif
\ No newline at end of file
+#endif
tab: 248 wrap: offon