diff --git a/Userland/Libraries/LibDeviceTree/FlattenedDeviceTree.cpp b/Userland/Libraries/LibDeviceTree/FlattenedDeviceTree.cpp index 5d2f235dad..a9a5bda556 100644 --- a/Userland/Libraries/LibDeviceTree/FlattenedDeviceTree.cpp +++ b/Userland/Libraries/LibDeviceTree/FlattenedDeviceTree.cpp @@ -108,4 +108,80 @@ ErrorOr walk_device_tree(FlattenedDeviceTreeHeader const& header, Readonly return Error::from_string_view_or_print_error_and_return_errno("Unexpected end of stream"sv, EINVAL); } +static ErrorOr slow_get_property_raw(StringView name, FlattenedDeviceTreeHeader const& header, ReadonlyBytes raw_device_tree) +{ + // Name is a path like /path/to/node/property + Vector path; + TRY(name.for_each_split_view('/', SplitBehavior::Nothing, [&path](StringView view) -> ErrorOr { + if (path.size() == path.capacity()) { + return Error::from_errno(ENAMETOOLONG); + } + MUST(path.try_append(view)); + return {}; + })); + + bool check_property_name = path.size() == 1; // Properties on root node should be checked immediately + ssize_t current_path_idx = -1; // Start "before" the root FDT_BEGIN_NODE tag + ReadonlyBytes found_property_value; + + DeviceTreeCallbacks callbacks = { + .on_node_begin = [&](StringView token_name) -> ErrorOr { + if (current_path_idx < 0) { + ++current_path_idx; // Root node + return IterationDecision::Continue; + } + if (token_name == path[current_path_idx]) { + ++current_path_idx; + if (current_path_idx == static_cast(path.size() - 1)) { + check_property_name = true; + } + } + return IterationDecision::Continue; + }, + .on_node_end = [&](StringView) -> ErrorOr { + if (check_property_name) { + // Not found, but we were looking for the property + return Error::from_errno(EINVAL); + } + return IterationDecision::Continue; + }, + .on_property = [&](StringView property_name, ReadonlyBytes property_value) -> ErrorOr { + if (check_property_name && property_name == path[current_path_idx]) { + found_property_value = property_value; + return IterationDecision::Break; + } + return IterationDecision::Continue; + }, + .on_noop = nullptr, + .on_end = [&]() -> ErrorOr { + return Error::from_string_view_or_print_error_and_return_errno("Property not found"sv, EINVAL); + } + }; + + TRY(walk_device_tree(header, raw_device_tree, move(callbacks))); + return found_property_value; +} + +template +ErrorOr slow_get_property(StringView name, FlattenedDeviceTreeHeader const& header, ReadonlyBytes raw_device_tree) +{ + [[maybe_unused]] auto bytes = TRY(slow_get_property_raw(name, header, raw_device_tree)); + if constexpr (IsVoid) { + return {}; + } else if constexpr (IsArithmetic) { + if (bytes.size() != sizeof(T)) { + return Error::from_errno(EINVAL); + } + return *bit_cast(bytes.data()); + } else { + static_assert(IsSame); + return T(bytes); + } +} + +template ErrorOr slow_get_property(StringView name, FlattenedDeviceTreeHeader const& header, ReadonlyBytes raw_device_tree); +template ErrorOr slow_get_property(StringView name, FlattenedDeviceTreeHeader const& header, ReadonlyBytes raw_device_tree); +template ErrorOr slow_get_property(StringView name, FlattenedDeviceTreeHeader const& header, ReadonlyBytes raw_device_tree); +template ErrorOr slow_get_property(StringView name, FlattenedDeviceTreeHeader const& header, ReadonlyBytes raw_device_tree); + } // namespace DeviceTree diff --git a/Userland/Libraries/LibDeviceTree/FlattenedDeviceTree.h b/Userland/Libraries/LibDeviceTree/FlattenedDeviceTree.h index c11d9fcfb2..36c85ef6c3 100644 --- a/Userland/Libraries/LibDeviceTree/FlattenedDeviceTree.h +++ b/Userland/Libraries/LibDeviceTree/FlattenedDeviceTree.h @@ -60,4 +60,12 @@ struct DeviceTreeCallbacks { ErrorOr walk_device_tree(FlattenedDeviceTreeHeader const&, ReadonlyBytes raw_device_tree, DeviceTreeCallbacks); +template +ErrorOr slow_get_property(StringView name, FlattenedDeviceTreeHeader const&, ReadonlyBytes raw_device_tree); + +extern template ErrorOr slow_get_property(StringView name, FlattenedDeviceTreeHeader const& header, ReadonlyBytes raw_device_tree); +extern template ErrorOr slow_get_property(StringView name, FlattenedDeviceTreeHeader const& header, ReadonlyBytes raw_device_tree); +extern template ErrorOr slow_get_property(StringView name, FlattenedDeviceTreeHeader const& header, ReadonlyBytes raw_device_tree); +extern template ErrorOr slow_get_property(StringView name, FlattenedDeviceTreeHeader const& header, ReadonlyBytes raw_device_tree); + } // namespace DeviceTree diff --git a/Userland/Utilities/fdtdump.cpp b/Userland/Utilities/fdtdump.cpp index 46ab0e3094..481bd448a3 100644 --- a/Userland/Utilities/fdtdump.cpp +++ b/Userland/Utilities/fdtdump.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -34,5 +35,15 @@ ErrorOr serenity_main(Main::Arguments arguments) TRY(DeviceTree::dump(*fdt_header, bytes)); + auto compatible = TRY(DeviceTree::slow_get_property("/compatible"sv, *fdt_header, bytes)); + auto compatible_strings = compatible.split_view('\0'); + dbgln("compatible with: {}", compatible_strings); + + auto bootargs = TRY(DeviceTree::slow_get_property("/chosen/bootargs"sv, *fdt_header, bytes)); + dbgln("bootargs: {}", bootargs); + + auto cpu_compatible = TRY(DeviceTree::slow_get_property("/cpus/cpu@0/compatible"sv, *fdt_header, bytes)); + dbgln("cpu0 compatible: {}", cpu_compatible); + return 0; }