diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-07-10 11:31:46 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-07-10 11:31:46 +0800 |
| commit | e90b72ec3082588b296956730bd2930cf8d5d671 (patch) | |
| tree | 36ff6916af9b4176ea5a9662219d11e721f0b691 /fdt/device_node.cc | |
| parent | 1767d390fbf3d0c65389de46caf0b6d43ef3b6ad (diff) | |
| download | lume-e90b72ec3082588b296956730bd2930cf8d5d671.tar.gz lume-e90b72ec3082588b296956730bd2930cf8d5d671.tar.xz | |
refactor: promote new architecture to repository root
Archive the deprecated implementation under lume-legacy, make the new kernel the default root-level build, and update repository entry points without changing kernel behavior.
Diffstat (limited to 'fdt/device_node.cc')
| -rw-r--r-- | fdt/device_node.cc | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/fdt/device_node.cc b/fdt/device_node.cc new file mode 100644 index 0000000..0c8ad46 --- /dev/null +++ b/fdt/device_node.cc @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2026 Richard Qin */ + +/* + * device_node.cc — DeviceNode implementation + * + * Provides property lookup and child traversal for the unflattened + * device tree. After construction, the tree is globally read-only. + * + * Reference: docs/specs/fdt.md §3.2 + */ + +#include <lume/device_node.h> + +/* Minimal strcmp — no lib dependency */ +static bool str_eq(const char *a, const char *b) +{ + while (*a && *a == *b) { a++; b++; } + return *a == *b; +} + +/* ------------------------------------------------------------------ */ +/* Construction / Destruction */ +/* ------------------------------------------------------------------ */ + +DeviceNode::DeviceNode(DeviceNode *parent, const char *name) + : name_(name), parent_(parent) +{ + children_list_.init(); + props_list_.init(); + sibling_link_.init(); +} + +DeviceNode::~DeviceNode() +{ + /* Recursively delete children */ + list_node *cur = children_list_.next; + while (cur != &children_list_) { + list_node *next = cur->next; + /* Recover DeviceNode* from sibling_link_ offset */ + DeviceNode *child = list_entry<DeviceNode, &DeviceNode::sibling_link_>(cur); + delete child; + cur = next; + } + + /* Delete properties */ + list_node *pc = props_list_.next; + while (pc != &props_list_) { + list_node *pn = pc->next; + FdtProperty *prop = reinterpret_cast<FdtProperty *>( + reinterpret_cast<uintptr>(pc) - + __builtin_offsetof(FdtProperty, link)); + delete prop; + pc = pn; + } +} + +/* ------------------------------------------------------------------ */ +/* Tree construction (used by FdtManager::unflatten) */ +/* ------------------------------------------------------------------ */ + +void DeviceNode::add_child(DeviceNode *child) +{ + /* Append to end of children list */ + list_node *node = &child->sibling_link_; + node->prev = children_list_.prev; + node->next = &children_list_; + children_list_.prev->next = node; + children_list_.prev = node; +} + +void DeviceNode::add_prop(FdtProperty *prop) +{ + list_node *node = &prop->link; + node->prev = props_list_.prev; + node->next = &props_list_; + props_list_.prev->next = node; + props_list_.prev = node; +} + +/* ------------------------------------------------------------------ */ +/* Property access */ +/* ------------------------------------------------------------------ */ + +const FdtProperty *DeviceNode::get_prop(const char *name) const +{ + const list_node *cur = props_list_.next; + while (cur != &props_list_) { + const FdtProperty *prop = reinterpret_cast<const FdtProperty *>( + reinterpret_cast<uintptr>(cur) - + __builtin_offsetof(FdtProperty, link)); + if (str_eq(prop->name, name)) + return prop; + cur = cur->next; + } + return nullptr; +} + +/* Big-endian helpers for decoding property values */ +static inline uint32 be32(const void *p) +{ + const uint8 *b = static_cast<const uint8 *>(p); + return (uint32(b[0]) << 24) | (uint32(b[1]) << 16) | + (uint32(b[2]) << 8) | uint32(b[3]); +} + +static inline uint64 be64(const void *p) +{ + const uint8 *b = static_cast<const uint8 *>(p); + return (uint64(be32(b)) << 32) | uint64(be32(b + 4)); +} + +uint32 DeviceNode::get_prop_u32(const char *name, uint32 default_val) const +{ + const FdtProperty *p = get_prop(name); + if (!p || p->len < 4) + return default_val; + return be32(p->value); +} + +uint64 DeviceNode::get_prop_u64(const char *name, uint64 default_val) const +{ + const FdtProperty *p = get_prop(name); + if (!p) + return default_val; + if (p->len >= 8) + return be64(p->value); + if (p->len >= 4) + return be32(p->value); + return default_val; +} + +const char *DeviceNode::get_prop_string(const char *name) const +{ + const FdtProperty *p = get_prop(name); + if (!p || p->len == 0) + return nullptr; + return static_cast<const char *>(p->value); +} + +/* ------------------------------------------------------------------ */ +/* Child traversal */ +/* ------------------------------------------------------------------ */ + +DeviceNode *DeviceNode::find_child(const char *name) +{ + list_node *cur = children_list_.next; + while (cur != &children_list_) { + DeviceNode *child = list_entry<DeviceNode, &DeviceNode::sibling_link_>(cur); + if (str_eq(child->name_, name)) + return child; + cur = cur->next; + } + return nullptr; +} + +void DeviceNode::for_each_child(void (*callback)(DeviceNode *)) +{ + list_node *cur = children_list_.next; + while (cur != &children_list_) { + list_node *next = cur->next; + DeviceNode *child = list_entry<DeviceNode, &DeviceNode::sibling_link_>(cur); + callback(child); + cur = next; + } +} |
