aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/device_tree.h6
-rw-r--r--src/lib/Makefile.mk4
-rw-r--r--src/lib/device_tree.c93
3 files changed, 102 insertions, 1 deletions
diff --git a/src/include/device_tree.h b/src/include/device_tree.h
index 6d2d65600f..bb522bf1da 100644
--- a/src/include/device_tree.h
+++ b/src/include/device_tree.h
@@ -129,6 +129,12 @@ u32 fdt_find_node_by_alias(const void *blob, const char *alias_name,
*/
int fdt_next_node_name(const void *blob, uint32_t node_offset, const char **name);
+ /* Read memory regions from a flat device-tree. */
+size_t fdt_read_memory_regions(const void *blob, struct device_tree_region regions[],
+ size_t regions_count);
+ /* Find top of memory from a flat device-tree. */
+uint64_t fdt_get_memory_top(const void *blob);
+
/* Read a flattened device tree into a hierarchical structure which refers to
the contents of the flattened tree in place. Modifying the flat tree
invalidates the unflattened one. */
diff --git a/src/lib/Makefile.mk b/src/lib/Makefile.mk
index e22fd08723..59e2116e30 100644
--- a/src/lib/Makefile.mk
+++ b/src/lib/Makefile.mk
@@ -160,10 +160,12 @@ ramstage-$(CONFIG_GENERIC_GPIO_LIB) += gpio.c
ramstage-$(CONFIG_GENERIC_UDELAY) += timer.c
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
+romstage-$(CONFIG_FLATTENED_DEVICE_TREE) += device_tree.c
+ramstage-$(CONFIG_FLATTENED_DEVICE_TREE) += device_tree.c
+
romstage-$(CONFIG_TIMER_QUEUE) += timer_queue.c
ramstage-$(CONFIG_TIMER_QUEUE) += timer_queue.c
diff --git a/src/lib/device_tree.c b/src/lib/device_tree.c
index 4f5cc07e91..5087d3940d 100644
--- a/src/lib/device_tree.c
+++ b/src/lib/device_tree.c
@@ -12,9 +12,12 @@
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
+#include <limits.h>
#define FDT_PATH_MAX_DEPTH 10 // should be a good enough upper bound
#define FDT_PATH_MAX_LEN 128 // should be a good enough upper bound
+#define FDT_MAX_MEMORY_NODES 4 // should be a good enough upper bound
+#define FDT_MAX_MEMORY_REGIONS 16 // should be a good enough upper bound
/*
* Functions for picking apart flattened trees.
@@ -504,6 +507,96 @@ void fdt_print_node(const void *blob, uint32_t offset)
}
/*
+ * fdt_read_memory_regions finds memory ranges from a flat device-tree
+ *
+ * @params blob address of FDT
+ * @params regions all regions that are read inside the reg property of
+ * memory nodes are saved inside this array
+ * @params regions_count maximum number of entries that can be saved inside
+ * the regions array.
+ *
+ * Returns: Either 0 on error or returns the number of regions put into the regions array.
+ */
+size_t fdt_read_memory_regions(const void *blob,
+ struct device_tree_region regions[],
+ size_t regions_count)
+{
+ u32 node, root, addrcp, sizecp;
+ u32 nodes[FDT_MAX_MEMORY_NODES] = {0};
+ size_t region_idx = 0;
+ size_t node_count = 0;
+
+ if (!fdt_is_valid(blob))
+ return 0;
+
+ node = fdt_find_node_by_path(blob, "/memory", &addrcp, &sizecp);
+ if (node) {
+ region_idx += fdt_read_reg_prop(blob, node, addrcp, sizecp,
+ regions, regions_count);
+ if (region_idx >= regions_count) {
+ printk(BIOS_WARNING, "FDT: Too many memory regions\n");
+ goto out;
+ }
+ }
+
+ root = fdt_find_node_by_path(blob, "/", &addrcp, &sizecp);
+ node_count = fdt_find_subnodes_by_prefix(blob, root, "memory@",
+ &addrcp, &sizecp, nodes,
+ FDT_MAX_MEMORY_NODES);
+ if (node_count >= FDT_MAX_MEMORY_NODES) {
+ printk(BIOS_WARNING, "FDT: Too many memory nodes\n");
+ /* Can still reading the regions for those we got */
+ }
+
+ for (size_t i = 0; i < MIN(node_count, FDT_MAX_MEMORY_NODES); i++) {
+ region_idx += fdt_read_reg_prop(blob, nodes[i], addrcp, sizecp,
+ &regions[region_idx],
+ regions_count - region_idx);
+ if (region_idx >= regions_count) {
+ printk(BIOS_WARNING, "FDT: Too many memory regions\n");
+ goto out;
+ }
+ }
+
+out:
+ for (size_t i = 0; i < MIN(region_idx, regions_count); i++) {
+ printk(BIOS_DEBUG, "FDT: Memory region [%#llx - %#llx]\n",
+ regions[i].addr, regions[i].addr + regions[i].size);
+ }
+
+ return region_idx;
+}
+
+/*
+ * fdt_get_memory_top finds top of memory from a flat device-tree
+ *
+ * @params blob address of FDT
+ *
+ * Returns: Either 0 on error or returns the maximum memory address
+ */
+uint64_t fdt_get_memory_top(const void *blob)
+{
+ struct device_tree_region regions[FDT_MAX_MEMORY_REGIONS] = {0};
+ uint64_t top = 0;
+ uint64_t total = 0;
+ size_t count;
+
+ if (!fdt_is_valid(blob))
+ return 0;
+
+ count = fdt_read_memory_regions(blob, regions, FDT_MAX_MEMORY_REGIONS);
+ for (size_t i = 0; i < MIN(count, FDT_MAX_MEMORY_REGIONS); i++) {
+ top = MAX(top, regions[i].addr + regions[i].size);
+ total += regions[i].size;
+ }
+
+ printk(BIOS_DEBUG, "FDT: Found %u MiB of RAM\n",
+ (uint32_t)(total / MiB));
+
+ return top;
+}
+
+/*
* Functions to turn a flattened tree into an unflattened one.
*/