diff --git a/Userland/Libraries/LibDeviceTree/DeviceTree.cpp b/Userland/Libraries/LibDeviceTree/DeviceTree.cpp index 51cfef64572..f29951ee2a6 100644 --- a/Userland/Libraries/LibDeviceTree/DeviceTree.cpp +++ b/Userland/Libraries/LibDeviceTree/DeviceTree.cpp @@ -39,14 +39,7 @@ ErrorOr> DeviceTree::parse(ReadonlyBytes flattened_dev current_node = current_node->parent(); return IterationDecision::Continue; }, - .on_property = [&device_tree, ¤t_node](StringView name, ReadonlyBytes value) -> ErrorOr { - DeviceTreeProperty property { value }; - - if (name == "phandle"sv) { - auto phandle = property.as(); - TRY(device_tree->set_phandle(phandle, current_node)); - } - + .on_property = [¤t_node](StringView name, ReadonlyBytes value) -> ErrorOr { TRY(current_node->properties().try_set(name, DeviceTreeProperty { value })); return IterationDecision::Continue; }, @@ -58,6 +51,25 @@ ErrorOr> DeviceTree::parse(ReadonlyBytes flattened_dev }, })); + // FIXME: While growing the a nodes children map, we might have reallocated it's storage + // breaking the parent pointers of the children, so we need to fix them here + auto fix_parent = [](auto self, DeviceTreeNodeView& node) -> void { + for (auto& [name, child] : node.children()) { + child.m_parent = &node; + self(self, child); + } + }; + + fix_parent(fix_parent, *device_tree); + // Note: For the same reason as above, we need to postpone setting the phandles until the tree is fully built + TRY(device_tree->for_each_node([&device_tree]([[maybe_unused]] StringView name, DeviceTreeNodeView& node) -> ErrorOr { + if (auto phandle = node.get_property("phandle"sv); phandle.has_value()) { + auto phandle_value = phandle.value().as(); + TRY(device_tree->set_phandle(phandle_value, &node)); + } + return RecursionDecision::Recurse; + })); + return device_tree; } diff --git a/Userland/Libraries/LibDeviceTree/DeviceTree.h b/Userland/Libraries/LibDeviceTree/DeviceTree.h index b50cba50029..b4ccf8670c4 100644 --- a/Userland/Libraries/LibDeviceTree/DeviceTree.h +++ b/Userland/Libraries/LibDeviceTree/DeviceTree.h @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace DeviceTree { @@ -168,6 +169,28 @@ public: // bonus points if it could automatically recurse in the tree under some conditions, // like "simple-bus" or "pci-bridge" nodes + auto for_each_node(CallableAs, StringView, DeviceTreeNodeView const&> auto callback) const + { + auto iterate = [&](auto self, StringView name, DeviceTreeNodeView const& node) -> ErrorOr { + auto result = TRY(callback(name, node)); + + if (result == RecursionDecision::Recurse) { + for (auto const& [name, child] : node.children()) { + auto child_result = TRY(self(self, name, child)); + + if (child_result == RecursionDecision::Break) + return RecursionDecision::Break; + } + + return RecursionDecision::Continue; + } + + return result; + }; + + return iterate(iterate, "/"sv, *this); + } + DeviceTreeNodeView const* phandle(u32 phandle) const { if (phandle >= m_phandles.size()) @@ -184,6 +207,28 @@ private: { } + auto for_each_node(CallableAs, StringView, DeviceTreeNodeView&> auto callback) + { + auto iterate = [&](auto self, StringView name, DeviceTreeNodeView& node) -> ErrorOr { + auto result = TRY(callback(name, node)); + + if (result == RecursionDecision::Recurse) { + for (auto& [name, child] : node.children()) { + auto child_result = TRY(self(self, name, child)); + + if (child_result == RecursionDecision::Break) + return RecursionDecision::Break; + } + + return RecursionDecision::Continue; + } + + return result; + }; + + return iterate(iterate, "/"sv, *this); + } + ErrorOr set_phandle(u32 phandle, DeviceTreeNodeView* node) { if (m_phandles.size() > phandle && m_phandles[phandle] != nullptr)