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
