Arthur Heymans has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/68719 )
Change subject: NOTFORMERGE/WIP/POC edk2 devicetree ......................................................................
NOTFORMERGE/WIP/POC edk2 devicetree
Pass information to the payload via FDT instead of coreboot tables.
Currently implemented: - usable / reserved memory - framebuffer (TODO: more formats) - Some CBMEM pointers
TODO: clean up, add more entries, remove hacks
Change-Id: Id96d4e7805855d35392e78f8d7b3a1ff911105a3 Signed-off-by: Arthur Heymans arthur@aheymans.xyz --- M payloads/external/tianocore/tools_def.txt M src/commonlib/bsd/include/commonlib/bsd/cbmem_id.h M src/include/boot/tables.h M src/include/bootmem.h M src/include/device_tree.h M src/include/fit.h M src/lib/Kconfig M src/lib/Makefile.inc M src/lib/bootmem.c M src/lib/device_tree.c A src/lib/fdt_handoff.c M src/lib/fit.c M src/lib/fit_payload.c M src/lib/hardwaremain.c M src/lib/hexdump.c M src/lib/selfboot.c M src/mainboard/emulation/qemu-q35/Kconfig M src/mainboard/emulation/qemu-q35/mainboard.c 18 files changed, 212 insertions(+), 20 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/19/68719/1
diff --git a/payloads/external/tianocore/tools_def.txt b/payloads/external/tianocore/tools_def.txt index fba9b09..5aced20 100755 --- a/payloads/external/tianocore/tools_def.txt +++ b/payloads/external/tianocore/tools_def.txt @@ -104,10 +104,10 @@ *_COREBOOT_X64_OBJCOPY_FLAGS = *_COREBOOT_X64_NASM_FLAGS = -f elf64
- DEBUG_COREBOOT_X64_CC_FLAGS = DEF(GCC5_X64_CC_FLAGS) -flto -DUSING_LTO -Os + DEBUG_COREBOOT_X64_CC_FLAGS = DEF(GCC5_X64_CC_FLAGS) -flto -DUSING_LTO -Os -Wno-dangling-pointer DEBUG_COREBOOT_X64_DLINK_FLAGS = DEF(GCC5_X64_DLINK_FLAGS) -flto -Os
-RELEASE_COREBOOT_X64_CC_FLAGS = DEF(GCC5_X64_CC_FLAGS) -flto -DUSING_LTO -Os -Wno-unused-but-set-variable +RELEASE_COREBOOT_X64_CC_FLAGS = DEF(GCC5_X64_CC_FLAGS) -flto -DUSING_LTO -Os -Wno-unused-but-set-variable -Wno-dangling-pointer RELEASE_COREBOOT_X64_DLINK_FLAGS = DEF(GCC5_X64_DLINK_FLAGS) -flto -Os
NOOPT_COREBOOT_X64_CC_FLAGS = DEF(GCC5_X64_CC_FLAGS) -O0 diff --git a/src/commonlib/bsd/include/commonlib/bsd/cbmem_id.h b/src/commonlib/bsd/include/commonlib/bsd/cbmem_id.h index 0cf9c7f..80d658d 100644 --- a/src/commonlib/bsd/include/commonlib/bsd/cbmem_id.h +++ b/src/commonlib/bsd/include/commonlib/bsd/cbmem_id.h @@ -82,6 +82,7 @@ #define CBMEM_ID_SMM_COMBUFFER 0x53534d32 #define CBMEM_ID_TYPE_C_INFO 0x54595045 #define CBMEM_ID_MEM_CHIP_INFO 0x5048434D +#define CBMEM_ID_FDT_HANDOFF 0x46445448
#define CBMEM_ID_TO_NAME_TABLE \ { CBMEM_ID_ACPI, "ACPI " }, \ @@ -156,6 +157,7 @@ { CBMEM_ID_CBFS_RW_MCACHE, "RW MCACHE "}, \ { CBMEM_ID_FSP_LOGO, "FSP LOGO "}, \ { CBMEM_ID_SMM_COMBUFFER, "SMM COMBUFFER"}, \ - { CBMEM_ID_TYPE_C_INFO, "TYPE_C INFO"},\ - { CBMEM_ID_MEM_CHIP_INFO, "MEM CHIP INFO"} + { CBMEM_ID_TYPE_C_INFO, "TYPE_C INFO"}, \ + { CBMEM_ID_MEM_CHIP_INFO, "MEM CHIP INFO"}, \ + { CBMEM_ID_FDT_HANDOFF, "FDT HANDOFF"} #endif /* _CBMEM_ID_H_ */ diff --git a/src/include/boot/tables.h b/src/include/boot/tables.h index b440c8b..bfd6e3b 100644 --- a/src/include/boot/tables.h +++ b/src/include/boot/tables.h @@ -11,6 +11,13 @@ void *write_tables(void);
/* + * Write architecture specific tables as well as the common + * info in flattened devicetree. + * Returns a pointer to the flattened devicetree or NULL on error. + */ +void *write_fdt_handoff(void); + +/* * Allow per-architecture table writes called from write_tables(). The * coreboot_table parameter provides a reference to where the coreboot * table will be written. The parameter is to allow architectures to diff --git a/src/include/bootmem.h b/src/include/bootmem.h index 6ccdd88..82da6c6 100644 --- a/src/include/bootmem.h +++ b/src/include/bootmem.h @@ -55,6 +55,9 @@ /* Platform hook to add bootmem areas the platform / board controls. */ void bootmem_platform_add_ranges(void);
+/* Initialize bootmem ranges */ +void bootmem_init(void); + /* Add a range of a given type to the bootmem address space. */ void bootmem_add_range(uint64_t start, uint64_t size, const enum bootmem_type tag); diff --git a/src/include/device_tree.h b/src/include/device_tree.h index ae30c59..0d27c33 100644 --- a/src/include/device_tree.h +++ b/src/include/device_tree.h @@ -86,6 +86,8 @@ struct device_tree_node *root; };
+void fdt_print_reserved(struct device_tree *tree); + /* * Flattened device tree functions. These generally return the number of bytes * which were consumed reading the requested value. diff --git a/src/include/fit.h b/src/include/fit.h index a1e970d..ae90c0d 100644 --- a/src/include/fit.h +++ b/src/include/fit.h @@ -56,6 +56,11 @@ */ void fit_update_memory(struct device_tree *tree);
+void fit_add_default_compat_strings(void); + +void add_cb_fdt_data(struct device_tree *tree); +void add_fb_fdt(struct device_tree *tree); + /* * Do architecture specific payload placements and fixups. * Set entrypoint and first argument (if any). diff --git a/src/lib/Kconfig b/src/lib/Kconfig index 0142300..f9c4cc0 100644 --- a/src/lib/Kconfig +++ b/src/lib/Kconfig @@ -114,3 +114,17 @@ in the background before they are actually required. This feature depends on the read-only boot_device having a DMA controller to perform the background transfer. + +config COREBOOT_TABLES + bool + default y + help + Select this to generate the coreboot tables as payload handoff + structure. + +config FDT_PAYLOAD_HANDOFF + bool + default n + select FLATTENED_DEVICE_TREE + help + Create a payload handoff in the flattened devicetree format. diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index 68a2960..480a911 100644 --- a/src/lib/Makefile.inc +++ b/src/lib/Makefile.inc @@ -128,6 +128,7 @@ ramstage-y += hardwaremain.c ramstage-y += selfboot.c ramstage-y += coreboot_table.c +ramstage-$(CONFIG_FDT_PAYLOAD_HANDOFF) += fdt_handoff.c ramstage-y += bootmem.c ramstage-y += fmap.c ramstage-y += memchr.c @@ -157,8 +158,8 @@ ramstage-y += b64_decode.c ramstage-$(CONFIG_ACPI_NHLT) += nhlt.c ramstage-$(CONFIG_FLATTENED_DEVICE_TREE) += device_tree.c -ramstage-$(CONFIG_PAYLOAD_FIT_SUPPORT) += fit.c -ramstage-$(CONFIG_PAYLOAD_FIT_SUPPORT) += fit_payload.c +ramstage-$(CONFIG_FLATTENED_DEVICE_TREE) += fit.c +ramstage-$(CONFIG_FLATTENED_DEVICE_TREE) += fit_payload.c
romstage-$(CONFIG_TIMER_QUEUE) += timer_queue.c ramstage-$(CONFIG_TIMER_QUEUE) += timer_queue.c diff --git a/src/lib/bootmem.c b/src/lib/bootmem.c index 078f9609..9dc1eb5 100644 --- a/src/lib/bootmem.c +++ b/src/lib/bootmem.c @@ -56,7 +56,7 @@ } }
-static void bootmem_init(void) +void bootmem_init(void) { const unsigned long cacheable = IORESOURCE_CACHEABLE; const unsigned long reserved = IORESOURCE_RESERVE; diff --git a/src/lib/device_tree.c b/src/lib/device_tree.c index b846c25..374a735 100644 --- a/src/lib/device_tree.c +++ b/src/lib/device_tree.c @@ -2,6 +2,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */
#include <assert.h> +#include <stdbool.h> #include <commonlib/stdlib.h> #include <console/console.h> #include <ctype.h> @@ -72,8 +73,11 @@
static void print_property(const struct fdt_property *prop, int depth) { - int is_string = prop->size > 0 && - ((char *)prop->data)[prop->size - 1] == '\0'; + bool is_string = prop->size > 0 && + ((char *)prop->data)[prop->size - 1] == '\0'; + + if (!strcmp(prop->name, "reg")) + is_string = false;
if (is_string) for (const char *c = prop->data; *c != '\0'; c++) @@ -136,7 +140,13 @@ print_flat_node(blob, offset, 0); }
+void fdt_print_reserved(struct device_tree *tree) +{
+ struct device_tree_reserve_map_entry *reserved_entry; + list_for_each(reserved_entry, tree->reserve_map, list_node) + printk(BIOS_DEBUG, "/memreserve/ 0x%016llx 0x%016llx\n", reserved_entry->start, reserved_entry->size); +}
/* * A utility function to skip past nodes in flattened trees. diff --git a/src/lib/fdt_handoff.c b/src/lib/fdt_handoff.c new file mode 100644 index 0000000..e8b6eb0 --- /dev/null +++ b/src/lib/fdt_handoff.c @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <lib.h> +#include <cbmem.h> +#include <endian.h> +#include <boot/tables.h> +#include <fit.h> + +void *write_fdt_handoff(void) +{ + struct fdt_header header = {}; + header.magic = htobe32(FDT_HEADER_MAGIC); + header.reserve_map_offset = htobe32(sizeof(struct fdt_header)); + header.version = htobe32(FDT_SUPPORTED_VERSION); + header.last_comp_version = htobe32(FDT_SUPPORTED_VERSION - 1); + + struct device_tree tree = {}; + tree.header = &header; + tree.header_size = sizeof(struct fdt_header); + + struct device_tree_node root_node = { + .name = "" + }; + dt_add_u32_prop(&root_node, "#address-cells", 2); + dt_add_u32_prop(&root_node, "#size-cells", 2); + tree.root = &root_node; + + fit_add_default_compat_strings(); + + add_cb_fdt_data(&tree); + + bootmem_init(); + bootmem_dump_ranges(); + fit_update_memory(&tree); + + add_fb_fdt(&tree); + fdt_print_reserved(&tree); + dt_print_node(tree.root); + + /* convert the tree to a flat dt */ + void *dt = cbmem_add(CBMEM_ID_FDT_HANDOFF, dt_flat_size(&tree)); + dt_flatten(&tree, dt); + hexdump(dt, dt_flat_size(&tree)); + return dt; +} diff --git a/src/lib/fit.c b/src/lib/fit.c index 0513950..ee14ac0 100644 --- a/src/lib/fit.c +++ b/src/lib/fit.c @@ -35,7 +35,7 @@ return str; }
-static void fit_add_default_compat_strings(void) +void fit_add_default_compat_strings(void) { char compat_string[80] = {};
diff --git a/src/lib/fit_payload.c b/src/lib/fit_payload.c index 21bc4e8..d5d68b2 100644 --- a/src/lib/fit_payload.c +++ b/src/lib/fit_payload.c @@ -102,11 +102,41 @@ return fdt_unflatten(data); }
+void add_fb_fdt(struct device_tree *tree) +{ + struct lb_framebuffer fb = {}; + if (!CONFIG(LINEAR_FRAMEBUFFER) || fill_lb_framebuffer(&fb)) + return; + + u32 addr_cells = 1, size_cells = 1; + + static const char *framebuffer_path[] = {"framebuffer", NULL}; + struct device_tree_node *framebuffer_node = dt_find_node(tree->root, + framebuffer_path, &addr_cells, &size_cells, 1); + dt_add_string_prop(framebuffer_node, "compatible", "simple-framebuffer"); + uint64_t phys_base = fb.physical_address; + uint64_t phys_size = fb.y_resolution * fb.bytes_per_line; + dt_add_reg_prop(framebuffer_node, &phys_base, &phys_size, 1, addr_cells, size_cells); + dt_add_u32_prop(framebuffer_node, "width", fb.x_resolution); + dt_add_u32_prop(framebuffer_node, "height", fb.y_resolution); + dt_add_u32_prop(framebuffer_node, "stride", fb.bytes_per_line); + dt_add_u32_prop(framebuffer_node, "height", fb.y_resolution); + + if (fb.red_mask_pos == 0 && fb.red_mask_size == 8 && + fb.green_mask_pos == 8 && fb.green_mask_size == 8 && + fb.blue_mask_pos == 16 && fb.blue_mask_size == 8) + dt_add_string_prop(framebuffer_node, "format", "a8b8g8r8"); + else if (fb.red_mask_pos == 16 && fb.red_mask_size == 8 && + fb.green_mask_pos == 8 && fb.green_mask_size == 8 && + fb.blue_mask_pos == 0 && fb.blue_mask_size == 8) + dt_add_string_prop(framebuffer_node, "format", "x8r8g8b8"); +} + /** * Add coreboot tables, CBMEM information and optional board specific strapping * IDs to the device tree loaded via FIT. */ -static void add_cb_fdt_data(struct device_tree *tree) +void add_cb_fdt_data(struct device_tree *tree) { u32 addr_cells = 1, size_cells = 1; u64 reg_addrs[2], reg_sizes[2]; @@ -119,6 +149,9 @@
/* Need to add 'ranges' to the intermediate node to make 'reg' work. */ dt_add_bin_prop(firmware_node, "ranges", NULL, 0); + dt_add_u32_prop(firmware_node, "#address-cells", 2); + dt_add_u32_prop(firmware_node, "#size-cells", 2); +
static const char *coreboot_path[] = {"coreboot", NULL}; struct device_tree_node *coreboot_node = dt_find_node(firmware_node, @@ -128,15 +161,19 @@
/* Fetch CB tables from cbmem */ void *cbtable = cbmem_find(CBMEM_ID_CBTABLE); - if (!cbtable) { + if (!cbtable && CONFIG(COREBOOT_TABLES)) { printk(BIOS_WARNING, "FIT: No coreboot table found!\n"); return; - } + } else if (!cbtable) { + reg_addrs[0] = 0; + reg_sizes[0] = 0;
- /* First 'reg' address range is the coreboot table. */ - const struct lb_header *header = cbtable; - reg_addrs[0] = (uintptr_t)header; - reg_sizes[0] = header->header_bytes + header->table_bytes; + } else { + /* First 'reg' address range is the coreboot table. */ + const struct lb_header *header = cbtable; + reg_addrs[0] = (uintptr_t)header; + reg_sizes[0] = header->header_bytes + header->table_bytes; + }
/* Second is the CBMEM area (which usually includes the coreboot table). */ @@ -161,6 +198,38 @@
if (ram_code() != UNDEFINED_STRAPPING_ID) dt_add_u32_prop(coreboot_node, "ram-code", ram_code()); + + struct coreboot_devicetree_nodes { + int cbmem_id; + const char *dt_node; + const char *dt_compatible; + } sections_ids[] = { + {CBMEM_ID_TIMESTAMP, "coreboot-timestamps", "coreboot-timestamps"}, + {CBMEM_ID_CONSOLE, "coreboot-console", "coreboot-console"}, + {CBMEM_ID_ACPI_GNVS, "coreboot-acpi-gnvs", "coreboot-acpi-gnvs"}, + {CBMEM_ID_ACPI_CNVS, "coreboot-acpi-cnvs", "coreboot-acpi-cnvs"}, + {CBMEM_ID_VPD, "coreboot-vpd", "coreboot-vpd"}, + {CBMEM_ID_WIFI_CALIBRATION, "coreboot-wifi-calibration", "coreboot-wifi-calibration"}, + {CBMEM_ID_TCPA_LOG, "coreboot-tcpa-log", "coreboot-tcpa-log"}, + {CBMEM_ID_FMAP, "coreboot-fmap", "coreboot-fmap"}, + {CBMEM_ID_VBOOT_WORKBUF, "coreboot-vboot-workbuf", "coreboot-vboot-workbuf"}, + {CBMEM_ID_TYPE_C_INFO, "coreboot-type-c-info", "coreboot-type-c-info"}, +}; + + for (int i = 0; i < ARRAY_SIZE(sections_ids); i++) { + const struct cbmem_entry *cbmem_entry = cbmem_entry_find(sections_ids[i].cbmem_id); + if (!cbmem_entry) + continue; // This section is not present + uint64_t section_base = (uintptr_t)cbmem_entry_start(cbmem_entry); + uint64_t section_size = cbmem_entry_size(cbmem_entry); + + const char *node_path[] = { sections_ids[i].dt_node, NULL}; + struct device_tree_node *dt_node = dt_find_node(firmware_node, + node_path, + &addr_cells, &size_cells, 1); + dt_add_string_prop(dt_node, "compatible", sections_ids[i].dt_compatible); + dt_add_reg_prop(dt_node, §ion_base, §ion_size, 1, addr_cells, size_cells); + } }
/* diff --git a/src/lib/hardwaremain.c b/src/lib/hardwaremain.c index e45ac9f..fc8ae67 100644 --- a/src/lib/hardwaremain.c +++ b/src/lib/hardwaremain.c @@ -182,7 +182,10 @@ /* Now that we have collected all of our information * write our configuration tables. */ - write_tables(); + if (CONFIG(COREBOOT_TABLES)) + write_tables(); + else if (CONFIG(FDT_PAYLOAD_HANDOFF)) + write_fdt_handoff();
timestamp_add_now(TS_FINALIZE_CHIPS); dev_finalize_chips(); diff --git a/src/lib/hexdump.c b/src/lib/hexdump.c index 533411f..6d44223 100644 --- a/src/lib/hexdump.c +++ b/src/lib/hexdump.c @@ -33,7 +33,7 @@ }
if ((all_zero < 2) && (all_one < 2)) { - printk(BIOS_DEBUG, "%p:", memory + i); + printk(BIOS_DEBUG, "%04lx:", i); for (j = 0; j < num_bytes; j++) printk(BIOS_DEBUG, " %02x", line[j]); for (; j < 16; j++) diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c index 637ad13..0b6bcf6 100644 --- a/src/lib/selfboot.c +++ b/src/lib/selfboot.c @@ -251,7 +251,10 @@ printk(BIOS_SPEW, "Loaded segments\n");
/* Pass cbtables to payload if architecture desires it. */ - prog_set_entry(payload, (void *)entry, cbmem_find(CBMEM_ID_CBTABLE)); + if (CONFIG(COREBOOT_TABLES)) + prog_set_entry(payload, (void *)entry, cbmem_find(CBMEM_ID_CBTABLE)); + else if (CONFIG(FDT_PAYLOAD_HANDOFF)) + prog_set_entry(payload, (void *)entry, cbmem_find(CBMEM_ID_FDT_HANDOFF));
return true; } diff --git a/src/mainboard/emulation/qemu-q35/Kconfig b/src/mainboard/emulation/qemu-q35/Kconfig index a20092f..5f1e1b5 100644 --- a/src/mainboard/emulation/qemu-q35/Kconfig +++ b/src/mainboard/emulation/qemu-q35/Kconfig @@ -17,6 +17,10 @@ select SOUTHBRIDGE_INTEL_COMMON_ACPI_MADT select BOOT_DEVICE_NOT_SPI_FLASH select BOOT_DEVICE_MEMORY_MAPPED + select FDT_PAYLOAD_HANDOFF + +config COREBOOT_TABLES + default n
config VBOOT select VBOOT_MUST_REQUEST_DISPLAY diff --git a/src/mainboard/emulation/qemu-q35/mainboard.c b/src/mainboard/emulation/qemu-q35/mainboard.c index 594b256..548ff7f 100644 --- a/src/mainboard/emulation/qemu-q35/mainboard.c +++ b/src/mainboard/emulation/qemu-q35/mainboard.c @@ -1,5 +1,10 @@ /* SPDX-License-Identifier: GPL-2.0-only */
+#include <endian.h> +#include <lib.h> +#include <cbfs.h> +#include <fit.h> +#include <bootstate.h> #include <device/device.h> #include <device/pci.h> #include <device/pci_ops.h>