Kernel/DeviceTree: Store devices in an IntrusiveList

We never query devices by their name, so using a HashMap is unnecessary.
Additionally, the next commit will make it possible for drivers to
scan for new child devices and probe drivers on them.
This means that the HashMap will then potentially resize while the
parent driver is still being probed, causing Device references to get
invalid.

Now that this code doesn't use a HashMap anymore, we need to ensure that
every device is only scanned once, so I added a comment mentioning that
requirement.
Alternatively, we could store a bool somewhere whether the device was
already scanned or not. But there's no good place to put that other
than in LibDeviceTree's Node class. However, I don't think we should
modify LibDeviceTree for this kernel-specific use case.
This commit is contained in:
Sönke Holz authored and Sönke Holz committed 2026-02-22 01:33:56 +01:00
1 parent 0e4f404103
commit bfda800128
3 files changed
+18 -9

No files matched your search

+6
View File
@@ -7,6 +7,7 @@
#pragma once
#include <AK/Badge.h>
#include <AK/IntrusiveList.h>
#include <AK/Noncopyable.h>
#include <Kernel/Memory/PhysicalAddress.h>
#include <LibDeviceTree/DeviceTree.h>
@@ -51,6 +52,11 @@ private:
::DeviceTree::Node const* m_node;
StringView m_node_name;
Driver const* m_driver { nullptr };
IntrusiveListNode<Device> m_list_node;
public:
using List = IntrusiveList<&Device::m_list_node>;
};
}
+10 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024, Sönke Holz <[email protected]>
* Copyright (c) 2024-2026, Sönke Holz <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -54,6 +54,8 @@ ErrorOr<size_t> Management::resolve_interrupt_number(::DeviceTree::Interrupt int
return maybe_interrupt_controller.value()->translate_interrupt_specifier_to_interrupt_number(interrupt.interrupt_specifier);
}
// NOTE: This function has to only be called once for each device!
// Otherwise duplicate `DeviceTree::Device`s may be created for each node.
ErrorOr<void> Management::scan_node_for_devices(::DeviceTree::Node const& node)
{
for (auto const& [child_name, child] : node.children()) {
@@ -65,8 +67,11 @@ ErrorOr<void> Management::scan_node_for_devices(::DeviceTree::Node const& node)
if (maybe_status.has_value() && maybe_status->as_string() != "okay" && !ignore_status_disabled)
continue;
if (TRY(m_devices.try_set(&child, Device { child, child_name })) != HashSetResult::InsertedNewEntry)
continue;
auto* device = new (nothrow) Device { child, child_name };
if (device == nullptr)
return ENOMEM;
m_devices.append(*device);
if (child.is_compatible_with("simple-bus"sv)) {
TRY(scan_node_for_devices(child));
@@ -92,13 +97,11 @@ bool Management::attach_device_to_driver(Device& device, Driver const& driver, S
ErrorOr<void> Management::probe_drivers(Driver::ProbeStage probe_stage)
{
for (auto& [device_node, device] : m_devices) {
VERIFY(device_node != nullptr);
for (auto& device : m_devices) {
if (device.driver() != nullptr)
continue;
auto maybe_compatible = device_node->get_property("compatible"sv);
auto maybe_compatible = device.node().get_property("compatible"sv);
if (!maybe_compatible.has_value())
continue;
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024, Sönke Holz <[email protected]>
* Copyright (c) 2024-2026, Sönke Holz <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -33,7 +33,7 @@ private:
Vector<NonnullOwnPtr<Driver>> m_drivers;
HashMap<StringView, Driver*> m_driver_by_compatible_string;
HashMap<::DeviceTree::Node const*, Device> m_devices;
Device::List m_devices;
HashMap<::DeviceTree::Node const*, DeviceTree::InterruptController const*> m_interrupt_controllers;
};