diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-05-02 23:35:19 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-05-02 23:35:19 +0800 |
| commit | 70b0c0f6032abfd820ccee22c23bc66d171bee34 (patch) | |
| tree | 1ca89104a6f484f7edf8b19523acb1dedb3133a2 /na/fdt | |
| parent | b1b0b1aad65b57900e18539d6f25b38e51801822 (diff) | |
| download | lume-70b0c0f6032abfd820ccee22c23bc66d171bee34.tar.gz lume-70b0c0f6032abfd820ccee22c23bc66d171bee34.tar.xz | |
feat: reorganize includes and improve FdtManager documentation
Co-authored-by: Copilot <copilot@github.com>
Diffstat (limited to 'na/fdt')
| -rw-r--r-- | na/fdt/fdt.cc | 878 |
1 files changed, 461 insertions, 417 deletions
diff --git a/na/fdt/fdt.cc b/na/fdt/fdt.cc index a572b1b..ef614e4 100644 --- a/na/fdt/fdt.cc +++ b/na/fdt/fdt.cc @@ -17,10 +17,10 @@ * Reference: docs/specs/fdt.md */ +#include <lume/addr.h> #include <lume/fdt.h> -#include <lume/new.h> #include <lume/klog.h> -#include <lume/addr.h> +#include <lume/new.h> /* ------------------------------------------------------------------ */ /* Global singleton (Placement New pattern, see global_init.md §3.1) */ @@ -34,45 +34,43 @@ FdtManager *g_fdt = nullptr; /* ------------------------------------------------------------------ */ struct fdt_header { - uint32 magic; - uint32 totalsize; - uint32 off_dt_struct; - uint32 off_dt_strings; - uint32 off_mem_rsvmap; - uint32 version; - uint32 last_comp_version; - uint32 boot_cpuid_phys; - uint32 size_dt_strings; - uint32 size_dt_struct; + uint32 magic; + uint32 totalsize; + uint32 off_dt_struct; + uint32 off_dt_strings; + uint32 off_mem_rsvmap; + uint32 version; + uint32 last_comp_version; + uint32 boot_cpuid_phys; + uint32 size_dt_strings; + uint32 size_dt_struct; }; -#define FDT_MAGIC 0xd00dfeed +#define FDT_MAGIC 0xd00dfeed #define FDT_BEGIN_NODE 1 -#define FDT_END_NODE 2 -#define FDT_PROP 3 -#define FDT_NOP 4 -#define FDT_END 9 +#define FDT_END_NODE 2 +#define FDT_PROP 3 +#define FDT_NOP 4 +#define FDT_END 9 /* ------------------------------------------------------------------ */ /* Minimal string helpers (no lib/ dependency for early boot) */ /* ------------------------------------------------------------------ */ -static inline bool str_starts_with(const char *str, const char *prefix) -{ - while (*prefix) { - if (*str++ != *prefix++) - return false; - } - return true; +static inline bool str_starts_with(const char *str, const char *prefix) { + while (*prefix) { + if (*str++ != *prefix++) + return false; + } + return true; } -static inline bool str_equals(const char *s1, const char *s2) -{ - while (*s1 && *s1 == *s2) { - s1++; - s2++; - } - return *s1 == *s2; +static inline bool str_equals(const char *s1, const char *s2) { + while (*s1 && *s1 == *s2) { + s1++; + s2++; + } + return *s1 == *s2; } /* @@ -80,18 +78,17 @@ static inline bool str_equals(const char *s1, const char *s2) * property) contains @target. */ static bool prop_contains_string(const char *prop_val, uint32 len, - const char *target) -{ - uint32 i = 0; - while (i < len) { - const char *s = prop_val + i; - if (str_equals(s, target)) - return true; - while (i < len && prop_val[i] != '\0') - i++; - i++; // skip '\0' separator - } - return false; + const char *target) { + uint32 i = 0; + while (i < len) { + const char *s = prop_val + i; + if (str_equals(s, target)) + return true; + while (i < len && prop_val[i] != '\0') + i++; + i++; // skip '\0' separator + } + return false; } /* ------------------------------------------------------------------ */ @@ -104,12 +101,9 @@ static bool prop_contains_string(const char *prop_val, uint32 len, * extension the compiler emits a call to libgcc's __bswapsi2, which * is unavailable in a freestanding (-nostdlib) environment. */ -static inline uint32 bswap32(uint32 x) -{ - return ((x & 0xFF000000u) >> 24) | - ((x & 0x00FF0000u) >> 8) | - ((x & 0x0000FF00u) << 8) | - ((x & 0x000000FFu) << 24); +static inline uint32 bswap32(uint32 x) { + return ((x & 0xFF000000u) >> 24) | ((x & 0x00FF0000u) >> 8) | + ((x & 0x0000FF00u) << 8) | ((x & 0x000000FFu) << 24); } /* @@ -117,22 +111,22 @@ static inline uint32 bswap32(uint32 x) * @cells: number of 32-bit cells (1 or 2). * 2-cell values are common for 64-bit addresses/sizes. */ -static inline uint64 read_cells(const uint8 *data, uint32 cells) -{ - const uint32 *p = reinterpret_cast<const uint32 *>(data); - if (cells == 2) { - uint64 high = bswap32(p[0]); - uint64 low = bswap32(p[1]); - return (high << 32) | low; - } - return bswap32(p[0]); +static inline uint64 read_cells(const uint8 *data, uint32 cells) { + const uint32 *p = reinterpret_cast<const uint32 *>(data); + if (cells == 2) { + uint64 high = bswap32(p[0]); + uint64 low = bswap32(p[1]); + return (high << 32) | low; + } + return bswap32(p[0]); } /* ------------------------------------------------------------------ */ /* FdtManager construction */ /* ------------------------------------------------------------------ */ -FdtManager::FdtManager(uint64 fdt_paddr) : fdt_paddr_(ensure_va(fdt_paddr)) {} +FdtManager::FdtManager(uint64 fdt_paddr) + : fdt_paddr_(pa_to_va(phys_addr(fdt_paddr)).raw) {} /* ------------------------------------------------------------------ */ /* Phase 1: Early scan — memory layout */ @@ -148,95 +142,93 @@ FdtManager::FdtManager(uint64 fdt_paddr) : fdt_paddr_(ensure_va(fdt_paddr)) {} * Panics on invalid magic or missing /memory node — there is no * recovery path this early in boot. */ -void FdtManager::early_scan_mem(uint64 fdt_paddr, uint64 *base, uint64 *size) -{ - const fdt_header *hdr = reinterpret_cast<const fdt_header *>(fdt_paddr); - if (bswap32(hdr->magic) != FDT_MAGIC) - kernel_panic("FDT early_scan_mem: invalid magic number", nullptr); - - const uint8 *dt_struct = - reinterpret_cast<const uint8 *>(fdt_paddr) + bswap32(hdr->off_dt_struct); - const char *dt_strings = - reinterpret_cast<const char *>(fdt_paddr) + bswap32(hdr->off_dt_strings); - - uint32 offset = 0; - int depth = -1; - - // Per-depth cell sizes (inherit from parent on entry) - uint32 address_cells[16] = {2}; - uint32 size_cells[16] = {1}; - bool in_memory_node = false; - - while (true) { - uint32 token = bswap32( - *reinterpret_cast<const uint32 *>(dt_struct + offset)); - offset += 4; - - if (token == FDT_BEGIN_NODE) { - const char *name = reinterpret_cast<const char *>(dt_struct + offset); - uint32 name_len = 0; - while (name[name_len] != '\0') - name_len++; - offset = (offset + name_len + 1 + 3) & ~3u; // align to 4 bytes - - depth++; - - // Inherit parent's cell sizes - if (depth > 0 && depth < 16) { - address_cells[depth] = address_cells[depth - 1]; - size_cells[depth] = size_cells[depth - 1]; - } - - // Match top-level "memory" or "memory@..." nodes - in_memory_node = (depth == 1 && str_starts_with(name, "memory")); - - } else if (token == FDT_END_NODE) { - if (depth >= 0) - depth--; - in_memory_node = false; - - } else if (token == FDT_PROP) { - uint32 len = bswap32( - *reinterpret_cast<const uint32 *>(dt_struct + offset)); - uint32 nameoff = bswap32( - *reinterpret_cast<const uint32 *>(dt_struct + offset + 4)); - offset += 8; - - const char *prop_name = dt_strings + nameoff; - const uint8 *prop_val = dt_struct + offset; - - if (depth >= 0 && depth < 16) { - // Track cell size overrides at the current depth - if (str_equals(prop_name, "#address-cells")) { - address_cells[depth] = bswap32( - *reinterpret_cast<const uint32 *>(prop_val)); - } else if (str_equals(prop_name, "#size-cells")) { - size_cells[depth] = bswap32( - *reinterpret_cast<const uint32 *>(prop_val)); - } - // Decode the "reg" property using the parent's cell sizes - else if (in_memory_node && str_equals(prop_name, "reg")) { - uint32 p_depth = (depth > 0) ? depth - 1 : 0; - *base = read_cells(prop_val, address_cells[p_depth]); - *size = read_cells( - prop_val + address_cells[p_depth] * 4, - size_cells[p_depth]); - return; // Success - } - } +void FdtManager::early_scan_mem(uint64 fdt_paddr, uint64 *base, uint64 *size) { + const fdt_header *hdr = reinterpret_cast<const fdt_header *>(fdt_paddr); + if (bswap32(hdr->magic) != FDT_MAGIC) + kernel_panic("FDT early_scan_mem: invalid magic number", nullptr); + + const uint8 *dt_struct = + reinterpret_cast<const uint8 *>(fdt_paddr) + bswap32(hdr->off_dt_struct); + const char *dt_strings = + reinterpret_cast<const char *>(fdt_paddr) + bswap32(hdr->off_dt_strings); + + uint32 offset = 0; + int depth = -1; + + // Per-depth cell sizes (inherit from parent on entry) + uint32 address_cells[16] = {2}; + uint32 size_cells[16] = {1}; + bool in_memory_node = false; + + while (true) { + uint32 token = + bswap32(*reinterpret_cast<const uint32 *>(dt_struct + offset)); + offset += 4; + + if (token == FDT_BEGIN_NODE) { + const char *name = reinterpret_cast<const char *>(dt_struct + offset); + uint32 name_len = 0; + while (name[name_len] != '\0') + name_len++; + offset = (offset + name_len + 1 + 3) & ~3u; // align to 4 bytes + + depth++; + + // Inherit parent's cell sizes + if (depth > 0 && depth < 16) { + address_cells[depth] = address_cells[depth - 1]; + size_cells[depth] = size_cells[depth - 1]; + } + + // Match top-level "memory" or "memory@..." nodes + in_memory_node = (depth == 1 && str_starts_with(name, "memory")); + + } else if (token == FDT_END_NODE) { + if (depth >= 0) + depth--; + in_memory_node = false; + + } else if (token == FDT_PROP) { + uint32 len = + bswap32(*reinterpret_cast<const uint32 *>(dt_struct + offset)); + uint32 nameoff = + bswap32(*reinterpret_cast<const uint32 *>(dt_struct + offset + 4)); + offset += 8; + + const char *prop_name = dt_strings + nameoff; + const uint8 *prop_val = dt_struct + offset; + + if (depth >= 0 && depth < 16) { + // Track cell size overrides at the current depth + if (str_equals(prop_name, "#address-cells")) { + address_cells[depth] = + bswap32(*reinterpret_cast<const uint32 *>(prop_val)); + } else if (str_equals(prop_name, "#size-cells")) { + size_cells[depth] = + bswap32(*reinterpret_cast<const uint32 *>(prop_val)); + } + // Decode the "reg" property using the parent's cell sizes + else if (in_memory_node && str_equals(prop_name, "reg")) { + uint32 p_depth = (depth > 0) ? depth - 1 : 0; + *base = read_cells(prop_val, address_cells[p_depth]); + *size = read_cells(prop_val + address_cells[p_depth] * 4, + size_cells[p_depth]); + return; // Success + } + } - offset = (offset + len + 3) & ~3u; // align to 4 bytes + offset = (offset + len + 3) & ~3u; // align to 4 bytes - } else if (token == FDT_NOP) { - continue; - } else if (token == FDT_END) { - break; - } else { - kernel_panic("FDT early_scan_mem: unknown token", nullptr); - } + } else if (token == FDT_NOP) { + continue; + } else if (token == FDT_END) { + break; + } else { + kernel_panic("FDT early_scan_mem: unknown token", nullptr); } + } - kernel_panic("FDT early_scan_mem: /memory node not found", nullptr); + kernel_panic("FDT early_scan_mem: /memory node not found", nullptr); } /* ------------------------------------------------------------------ */ @@ -250,325 +242,377 @@ void FdtManager::early_scan_mem(uint64 fdt_paddr, uint64 *base, uint64 *size) * Unlike early_scan_mem, failure here is non-fatal: we fall back to * the platform's default UART address (0x10000000 for QEMU virt). */ -void FdtManager::early_scan_uart(uint64 fdt_paddr, uint64 *uart_addr, uint64 *uart_size) -{ - if (!uart_addr || !uart_size) - return; - - const fdt_header *hdr = reinterpret_cast<const fdt_header *>(fdt_paddr); - if (bswap32(hdr->magic) != FDT_MAGIC) - return; +void FdtManager::early_scan_uart(uint64 fdt_paddr, uint64 *uart_addr, + uint64 *uart_size) { + if (!uart_addr || !uart_size) + return; + + const fdt_header *hdr = reinterpret_cast<const fdt_header *>(fdt_paddr); + if (bswap32(hdr->magic) != FDT_MAGIC) + return; + + const uint8 *dt_struct = + reinterpret_cast<const uint8 *>(fdt_paddr) + bswap32(hdr->off_dt_struct); + const char *dt_strings = + reinterpret_cast<const char *>(fdt_paddr) + bswap32(hdr->off_dt_strings); + + uint32 offset = 0; + int depth = -1; + uint32 address_cells[16] = {2}; + uint32 size_cells[16] = {1}; + bool in_uart_node = false; + bool has_current_node_reg = false; + uint64 current_node_reg = 0; + uint64 current_node_size = 0; + + while (true) { + uint32 token = + bswap32(*reinterpret_cast<const uint32 *>(dt_struct + offset)); + offset += 4; + + if (token == FDT_BEGIN_NODE) { + const char *name = reinterpret_cast<const char *>(dt_struct + offset); + uint32 name_len = 0; + while (name[name_len] != '\0') + name_len++; + offset = (offset + name_len + 1 + 3) & ~3u; + + depth++; + if (depth > 0 && depth < 16) { + address_cells[depth] = address_cells[depth - 1]; + size_cells[depth] = size_cells[depth - 1]; + } + in_uart_node = false; + has_current_node_reg = false; + + } else if (token == FDT_END_NODE) { + if (depth >= 0) + depth--; + in_uart_node = false; + has_current_node_reg = false; + + } else if (token == FDT_PROP) { + uint32 len = + bswap32(*reinterpret_cast<const uint32 *>(dt_struct + offset)); + uint32 nameoff = + bswap32(*reinterpret_cast<const uint32 *>(dt_struct + offset + 4)); + offset += 8; + + const char *prop_name = dt_strings + nameoff; + const uint8 *prop_val = dt_struct + offset; + + if (depth >= 0 && depth < 16) { + if (str_equals(prop_name, "#address-cells")) { + address_cells[depth] = + bswap32(*reinterpret_cast<const uint32 *>(prop_val)); + } else if (str_equals(prop_name, "#size-cells")) { + size_cells[depth] = + bswap32(*reinterpret_cast<const uint32 *>(prop_val)); + } else if (str_equals(prop_name, "compatible")) { + if (prop_contains_string(reinterpret_cast<const char *>(prop_val), + len, "ns16550a")) { + in_uart_node = true; + if (has_current_node_reg) { + *uart_addr = current_node_reg; + *uart_size = current_node_size; + return; + } + } + } else if (str_equals(prop_name, "reg")) { + uint32 p_depth = (depth > 0) ? depth - 1 : 0; + current_node_reg = read_cells(prop_val, address_cells[p_depth]); + current_node_size = read_cells(prop_val + address_cells[p_depth] * 4, + size_cells[p_depth]); + has_current_node_reg = true; + if (in_uart_node) { + *uart_addr = current_node_reg; + *uart_size = current_node_size; + return; // Found it + } + } + } - const uint8 *dt_struct = - reinterpret_cast<const uint8 *>(fdt_paddr) + bswap32(hdr->off_dt_struct); - const char *dt_strings = - reinterpret_cast<const char *>(fdt_paddr) + bswap32(hdr->off_dt_strings); + offset = (offset + len + 3) & ~3u; - uint32 offset = 0; - int depth = -1; - uint32 address_cells[16] = {2}; - uint32 size_cells[16] = {1}; - bool in_uart_node = false; - bool has_current_node_reg = false; - uint64 current_node_reg = 0; - uint64 current_node_size = 0; + } else if (token == FDT_NOP) { + continue; + } else if (token == FDT_END) { + break; + } else { + break; // Unknown token — give up silently + } + } - while (true) { - uint32 token = bswap32( - *reinterpret_cast<const uint32 *>(dt_struct + offset)); - offset += 4; + *uart_addr = 0; + *uart_size = 0; +} - if (token == FDT_BEGIN_NODE) { - const char *name = reinterpret_cast<const char *>(dt_struct + offset); - uint32 name_len = 0; - while (name[name_len] != '\0') - name_len++; - offset = (offset + name_len + 1 + 3) & ~3u; +/* ------------------------------------------------------------------ */ +/* Phase 2: Unflatten (stub — requires Slab) */ +/* ------------------------------------------------------------------ */ - depth++; - if (depth > 0 && depth < 16) { - address_cells[depth] = address_cells[depth - 1]; - size_cells[depth] = size_cells[depth - 1]; - } - in_uart_node = false; - has_current_node_reg = false; +void FdtManager::unflatten() { + const fdt_header *hdr = reinterpret_cast<const fdt_header *>(fdt_paddr_); + if (bswap32(hdr->magic) != FDT_MAGIC) + kernel_panic("fdt unflatten: invalid magic", nullptr); + + const uint8 *dt_struct = + reinterpret_cast<const uint8 *>(fdt_paddr_) + bswap32(hdr->off_dt_struct); + const char *dt_strings = + reinterpret_cast<const char *>(fdt_paddr_) + bswap32(hdr->off_dt_strings); + + uint32 offset = 0; + + /* Stack to track current node at each depth (max 16 levels) */ + DeviceNode *stack[16] = {}; + int depth = -1; + + while (true) { + uint32 token = + bswap32(*reinterpret_cast<const uint32 *>(dt_struct + offset)); + offset += 4; + + if (token == FDT_BEGIN_NODE) { + const char *name = reinterpret_cast<const char *>(dt_struct + offset); + uint32 name_len = 0; + while (name[name_len] != '\0') + name_len++; + offset = (offset + name_len + 1 + 3) & ~3u; + + depth++; + if (depth >= 16) + kernel_panic("fdt unflatten: tree too deep", nullptr); + + DeviceNode *parent = (depth > 0) ? stack[depth - 1] : nullptr; + DeviceNode *node = new DeviceNode(parent, name); + if (!node) + kernel_panic("fdt unflatten: OOM creating DeviceNode", nullptr); + + stack[depth] = node; + + if (parent) + parent->add_child(node); + else + root_ = node; /* Root node */ + + } else if (token == FDT_END_NODE) { + if (depth >= 0) + depth--; + + } else if (token == FDT_PROP) { + uint32 len = + bswap32(*reinterpret_cast<const uint32 *>(dt_struct + offset)); + uint32 nameoff = + bswap32(*reinterpret_cast<const uint32 *>(dt_struct + offset + 4)); + offset += 8; + + const char *prop_name = dt_strings + nameoff; + const void *prop_val = dt_struct + offset; + + if (depth >= 0 && depth < 16 && stack[depth]) { + FdtProperty *prop = new FdtProperty; + if (!prop) + kernel_panic("fdt unflatten: OOM creating FdtProperty", nullptr); + prop->name = prop_name; + prop->value = prop_val; + prop->len = static_cast<int>(len); + prop->link.init(); + stack[depth]->add_prop(prop); + } + + offset = (offset + len + 3) & ~3u; + + } else if (token == FDT_NOP) { + continue; + } else if (token == FDT_END) { + break; + } else { + kernel_panic("fdt unflatten: unknown token", nullptr); + } + } - } else if (token == FDT_END_NODE) { - if (depth >= 0) - depth--; - in_uart_node = false; - has_current_node_reg = false; + is_unflattened_ = true; +} - } else if (token == FDT_PROP) { - uint32 len = bswap32( - *reinterpret_cast<const uint32 *>(dt_struct + offset)); - uint32 nameoff = bswap32( - *reinterpret_cast<const uint32 *>(dt_struct + offset + 4)); - offset += 8; +/* Recursive helper: find first node with matching compatible string */ +static DeviceNode *find_compat_recursive(DeviceNode *node, const char *compat) { + const FdtProperty *prop = node->get_prop("compatible"); + if (prop) { + const char *val = static_cast<const char *>(prop->value); + uint32 i = 0; + while (i < static_cast<uint32>(prop->len)) { + const char *s = val + i; + if (str_equals(s, compat)) + return node; + while (i < static_cast<uint32>(prop->len) && val[i] != '\0') + i++; + i++; + } + } + + /* Search children */ + list_node *cur = node->children_list_head(); + list_node *end = node->children_list_sentinel(); + while (cur != end) { + DeviceNode *child = list_entry<DeviceNode, &DeviceNode::sibling_link_>(cur); + DeviceNode *found = find_compat_recursive(child, compat); + if (found) + return found; + cur = cur->next; + } + return nullptr; +} - const char *prop_name = dt_strings + nameoff; - const uint8 *prop_val = dt_struct + offset; - - if (depth >= 0 && depth < 16) { - if (str_equals(prop_name, "#address-cells")) { - address_cells[depth] = bswap32( - *reinterpret_cast<const uint32 *>(prop_val)); - } else if (str_equals(prop_name, "#size-cells")) { - size_cells[depth] = bswap32( - *reinterpret_cast<const uint32 *>(prop_val)); - } else if (str_equals(prop_name, "compatible")) { - if (prop_contains_string( - reinterpret_cast<const char *>(prop_val), - len, "ns16550a")) { - in_uart_node = true; - if (has_current_node_reg) { - *uart_addr = current_node_reg; - *uart_size = current_node_size; - return; - } - } - } else if (str_equals(prop_name, "reg")) { - uint32 p_depth = (depth > 0) ? depth - 1 : 0; - current_node_reg = read_cells(prop_val, address_cells[p_depth]); - current_node_size = read_cells( - prop_val + address_cells[p_depth] * 4, - size_cells[p_depth]); - has_current_node_reg = true; - if (in_uart_node) { - *uart_addr = current_node_reg; - *uart_size = current_node_size; - return; // Found it - } - } - } +DeviceNode *FdtManager::find_compatible(const char *compat_string) { + if (!is_unflattened_) + kernel_panic("fdt: tree not unflattened yet", nullptr); + if (!root_) + return nullptr; + return find_compat_recursive(root_, compat_string); +} - offset = (offset + len + 3) & ~3u; +DeviceNode *FdtManager::get_node_by_path(const char *path) { + if (!is_unflattened_) + kernel_panic("fdt: tree not unflattened yet", nullptr); + if (!root_ || !path) + return nullptr; - } else if (token == FDT_NOP) { - continue; - } else if (token == FDT_END) { - break; - } else { - break; // Unknown token — give up silently + /* Skip leading '/' */ + if (*path == '/') + path++; + if (*path == '\0') + return root_; + + DeviceNode *cur = root_; + while (*path && cur) { + /* Extract next path component */ + const char *end = path; + while (*end && *end != '/') + end++; + + /* Search children for a name matching this component */ + bool found = false; + list_node *lc = cur->children_list_head(); + list_node *le = cur->children_list_sentinel(); + while (lc != le) { + DeviceNode *child = + list_entry<DeviceNode, &DeviceNode::sibling_link_>(lc); + /* Compare name up to the component length */ + const char *cn = child->get_name(); + const char *p = path; + const char *e = end; + bool match = true; + while (p < e) { + if (*cn != *p) { + match = false; + break; } + cn++; + p++; + } + if (match && *cn == '\0') { + cur = child; + found = true; + break; + } + lc = lc->next; } - *uart_addr = 0; - *uart_size = 0; + if (!found) + return nullptr; + + path = (*end == '/') ? end + 1 : end; + } + return cur; } /* ------------------------------------------------------------------ */ -/* Phase 2: Unflatten (stub — requires Slab) */ +/* Public free-function API */ /* ------------------------------------------------------------------ */ -void FdtManager::unflatten() +void fdt_init(uint64 fdt_paddr) { + const uint32 *magic_ptr = reinterpret_cast<const uint32 *>(fdt_paddr); + if (bswap32(*magic_ptr) != FDT_MAGIC) + kernel_panic("fdt_init: invalid FDT magic number", nullptr); + + g_fdt = new (g_fdt_buf) FdtManager(fdt_paddr); +} + +void fdt_unflatten() { g_fdt->unflatten(); } + +DeviceNode *fdt_find_compatible(const char *compat_string) { + return g_fdt->find_compatible(compat_string); +} + +DeviceNode *fdt_get_node_by_path(const char *path) { + return g_fdt->get_node_by_path(path); +} + +void fdt_early_get_mem_info(uint64 *base, uint64 *size) { + FdtManager::early_scan_mem(g_fdt->get_paddr(), base, size); +} + +void fdt_early_get_uart_info(uint64 *uart_addr, uint64 *uart_size) { + FdtManager::early_scan_uart(g_fdt->get_paddr(), uart_addr, uart_size); +} + +void FdtManager::early_scan_kaslr(uint64 fdt_paddr, uint64 *seed) { - const fdt_header *hdr = reinterpret_cast<const fdt_header *>(fdt_paddr_); - if (bswap32(hdr->magic) != FDT_MAGIC) - kernel_panic("fdt unflatten: invalid magic", nullptr); + if (!seed) return; + *seed = 0; + + const fdt_header *hdr = reinterpret_cast<const fdt_header *>(fdt_paddr); + if (bswap32(hdr->magic) != FDT_MAGIC) return; - const uint8 *dt_struct = - reinterpret_cast<const uint8 *>(fdt_paddr_) + bswap32(hdr->off_dt_struct); - const char *dt_strings = - reinterpret_cast<const char *>(fdt_paddr_) + bswap32(hdr->off_dt_strings); + const uint8 *dt_struct = reinterpret_cast<const uint8 *>(fdt_paddr) + bswap32(hdr->off_dt_struct); + const char *dt_strings = reinterpret_cast<const char *>(fdt_paddr) + bswap32(hdr->off_dt_strings); uint32 offset = 0; - - /* Stack to track current node at each depth (max 16 levels) */ - DeviceNode *stack[16] = {}; int depth = -1; + bool in_chosen = false; while (true) { - uint32 token = bswap32( - *reinterpret_cast<const uint32 *>(dt_struct + offset)); + uint32 token = bswap32(*reinterpret_cast<const uint32 *>(dt_struct + offset)); offset += 4; if (token == FDT_BEGIN_NODE) { const char *name = reinterpret_cast<const char *>(dt_struct + offset); uint32 name_len = 0; - while (name[name_len] != '\0') - name_len++; + while (name[name_len] != '\0') name_len++; offset = (offset + name_len + 1 + 3) & ~3u; depth++; - if (depth >= 16) - kernel_panic("fdt unflatten: tree too deep", nullptr); - - DeviceNode *parent = (depth > 0) ? stack[depth - 1] : nullptr; - DeviceNode *node = new DeviceNode(parent, name); - if (!node) - kernel_panic("fdt unflatten: OOM creating DeviceNode", nullptr); - - stack[depth] = node; - - if (parent) - parent->add_child(node); - else - root_ = node; /* Root node */ - + if (depth == 1 && str_starts_with(name, "chosen")) { + in_chosen = true; + } else if (depth == 1) { + in_chosen = false; + } } else if (token == FDT_END_NODE) { - if (depth >= 0) - depth--; - + if (depth >= 0) depth--; + if (depth < 1) in_chosen = false; } else if (token == FDT_PROP) { - uint32 len = bswap32( - *reinterpret_cast<const uint32 *>(dt_struct + offset)); - uint32 nameoff = bswap32( - *reinterpret_cast<const uint32 *>(dt_struct + offset + 4)); + uint32 len = bswap32(*reinterpret_cast<const uint32 *>(dt_struct + offset)); + uint32 nameoff = bswap32(*reinterpret_cast<const uint32 *>(dt_struct + offset + 4)); offset += 8; - const char *prop_name = dt_strings + nameoff; - const void *prop_val = dt_struct + offset; - - if (depth >= 0 && depth < 16 && stack[depth]) { - FdtProperty *prop = new FdtProperty; - if (!prop) - kernel_panic("fdt unflatten: OOM creating FdtProperty", nullptr); - prop->name = prop_name; - prop->value = prop_val; - prop->len = static_cast<int>(len); - prop->link.init(); - stack[depth]->add_prop(prop); + if (in_chosen) { + const char *prop_name = dt_strings + nameoff; + if (str_starts_with(prop_name, "kaslr-seed") && len == 8) { + *seed = read_cells(dt_struct + offset, 2); + return; + } } - offset = (offset + len + 3) & ~3u; - } else if (token == FDT_NOP) { continue; } else if (token == FDT_END) { break; } else { - kernel_panic("fdt unflatten: unknown token", nullptr); - } - } - - is_unflattened_ = true; -} - -/* Recursive helper: find first node with matching compatible string */ -static DeviceNode *find_compat_recursive(DeviceNode *node, const char *compat) -{ - const FdtProperty *prop = node->get_prop("compatible"); - if (prop) { - const char *val = static_cast<const char *>(prop->value); - uint32 i = 0; - while (i < static_cast<uint32>(prop->len)) { - const char *s = val + i; - if (str_equals(s, compat)) - return node; - while (i < static_cast<uint32>(prop->len) && val[i] != '\0') - i++; - i++; - } - } - - /* Search children */ - list_node *cur = node->children_list_head(); - list_node *end = node->children_list_sentinel(); - while (cur != end) { - DeviceNode *child = list_entry<DeviceNode, &DeviceNode::sibling_link_>(cur); - DeviceNode *found = find_compat_recursive(child, compat); - if (found) - return found; - cur = cur->next; - } - return nullptr; -} - -DeviceNode *FdtManager::find_compatible(const char *compat_string) -{ - if (!is_unflattened_) - kernel_panic("fdt: tree not unflattened yet", nullptr); - if (!root_) - return nullptr; - return find_compat_recursive(root_, compat_string); -} - -DeviceNode *FdtManager::get_node_by_path(const char *path) -{ - if (!is_unflattened_) - kernel_panic("fdt: tree not unflattened yet", nullptr); - if (!root_ || !path) - return nullptr; - - /* Skip leading '/' */ - if (*path == '/') - path++; - if (*path == '\0') - return root_; - - DeviceNode *cur = root_; - while (*path && cur) { - /* Extract next path component */ - const char *end = path; - while (*end && *end != '/') - end++; - - /* Search children for a name matching this component */ - bool found = false; - list_node *lc = cur->children_list_head(); - list_node *le = cur->children_list_sentinel(); - while (lc != le) { - DeviceNode *child = list_entry<DeviceNode, &DeviceNode::sibling_link_>(lc); - /* Compare name up to the component length */ - const char *cn = child->get_name(); - const char *p = path; - const char *e = end; - bool match = true; - while (p < e) { - if (*cn != *p) { match = false; break; } - cn++; p++; - } - if (match && *cn == '\0') { - cur = child; - found = true; - break; - } - lc = lc->next; + break; } - - if (!found) - return nullptr; - - path = (*end == '/') ? end + 1 : end; } - return cur; -} - -/* ------------------------------------------------------------------ */ -/* Public free-function API */ -/* ------------------------------------------------------------------ */ - -void fdt_init(uint64 fdt_paddr) -{ - const uint32 *magic_ptr = reinterpret_cast<const uint32 *>(fdt_paddr); - if (bswap32(*magic_ptr) != FDT_MAGIC) - kernel_panic("fdt_init: invalid FDT magic number", nullptr); - - g_fdt = new (g_fdt_buf) FdtManager(fdt_paddr); -} - -void fdt_unflatten() -{ - g_fdt->unflatten(); } -DeviceNode *fdt_find_compatible(const char *compat_string) -{ - return g_fdt->find_compatible(compat_string); -} - -DeviceNode *fdt_get_node_by_path(const char *path) -{ - return g_fdt->get_node_by_path(path); -} - -void fdt_early_get_mem_info(uint64 *base, uint64 *size) -{ - FdtManager::early_scan_mem(g_fdt->get_paddr(), base, size); -} - -void fdt_early_get_uart_info(uint64 *uart_addr, uint64 *uart_size) -{ - FdtManager::early_scan_uart(g_fdt->get_paddr(), uart_addr, uart_size); +void fdt_early_get_kaslr_seed(uint64 *seed) { + FdtManager::early_scan_kaslr(g_fdt->get_paddr(), seed); } |
