DeviceTree.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * Copyright (c) 2024, Leon Albrecht <leon.a@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Concepts.h>
  8. #include <AK/Endian.h>
  9. #include <AK/Function.h>
  10. #include <AK/HashMap.h>
  11. #include <AK/IterationDecision.h>
  12. #include <AK/MemoryStream.h>
  13. #include <AK/Optional.h>
  14. #include <AK/Span.h>
  15. namespace DeviceTree {
  16. struct DeviceTreeProperty {
  17. ReadonlyBytes raw_data;
  18. size_t size() const { return raw_data.size(); }
  19. StringView as_string() const { return StringView(raw_data.data(), raw_data.size() - 1); }
  20. Vector<StringView> as_strings() const { return as_string().split_view('\0'); }
  21. template<typename T>
  22. auto for_each_string(T callback) const { return as_string().for_each_split_view('\0', SplitBehavior::Nothing, callback); }
  23. // Note: as<T> does not convert endianness, so all structures passed in
  24. // should use BigEndian<T>s for their members and keep ordering in mind
  25. // Note: The Integral variant does convert endianness, so no need to pass in BigEndian<T>s
  26. template<typename T>
  27. T as() const
  28. {
  29. VERIFY(raw_data.size() == sizeof(T));
  30. T value;
  31. __builtin_memcpy(&value, raw_data.data(), sizeof(T));
  32. return value;
  33. }
  34. template<typename T>
  35. requires(alignof(T) <= 4 && !IsIntegral<T>)
  36. T const& as() const
  37. {
  38. return *reinterpret_cast<T const*>(raw_data.data());
  39. }
  40. template<Integral I>
  41. I as() const
  42. {
  43. VERIFY(raw_data.size() == sizeof(I));
  44. BigEndian<I> value;
  45. __builtin_memcpy(&value, raw_data.data(), sizeof(I));
  46. return value;
  47. }
  48. template<typename T>
  49. ErrorOr<void> for_each_in_array_of(CallableAs<ErrorOr<IterationDecision>, T const&> auto callback) const
  50. {
  51. VERIFY(raw_data.size() % sizeof(T) == 0);
  52. size_t count = raw_data.size() / sizeof(T);
  53. size_t offset = 0;
  54. for (size_t i = 0; i < count; ++i, offset += sizeof(T)) {
  55. auto sub_property = DeviceTreeProperty { raw_data.slice(offset, sizeof(T)) };
  56. auto result = callback(sub_property.as<T>());
  57. if (result.is_error())
  58. return result;
  59. if (result.value() == IterationDecision::Break)
  60. break;
  61. }
  62. return {};
  63. }
  64. FixedMemoryStream as_stream() const { return FixedMemoryStream { raw_data }; }
  65. };
  66. class DeviceTreeNodeView {
  67. public:
  68. bool has_property(StringView prop) const { return m_properties.contains(prop); }
  69. bool has_child(StringView child) const { return m_children.contains(child); }
  70. bool child(StringView name) const { return has_property(name) || has_child(name); }
  71. Optional<DeviceTreeProperty> get_property(StringView prop) const { return m_properties.get(prop); }
  72. // FIXME: The spec says that @address parts of the name should be ignored when looking up nodes
  73. // when they do not appear in the queried name, and all nodes with the same name should be returned
  74. Optional<DeviceTreeNodeView const&> get_child(StringView child) const { return m_children.get(child); }
  75. HashMap<StringView, DeviceTreeNodeView> const& children() const { return m_children; }
  76. HashMap<StringView, DeviceTreeProperty> const& properties() const { return m_properties; }
  77. DeviceTreeNodeView const* parent() const { return m_parent; }
  78. // FIXME: Add convenience functions for common properties like "reg" and "compatible"
  79. // Note: The "reg" property is a list of address and size pairs, but the address is not always a u32 or u64
  80. // In pci devices the #address-size is 3 cells: (phys.lo phys.mid phys.hi)
  81. // with the following format:
  82. // phys.lo, phys.mid: 64-bit Address - BigEndian
  83. // phys.hi: relocatable(1), prefetchable(1), aliased(1), 000(3), space type(2), bus number(8), device number(5), function number(3), register number(8) - BigEndian
  84. // FIXME: Stringify?
  85. // FIXME: Flatten?
  86. // Note: That we dont have a oder of children and properties in this view
  87. protected:
  88. friend class DeviceTree;
  89. DeviceTreeNodeView(DeviceTreeNodeView* parent)
  90. : m_parent(parent)
  91. {
  92. }
  93. HashMap<StringView, DeviceTreeNodeView>& children() { return m_children; }
  94. HashMap<StringView, DeviceTreeProperty>& properties() { return m_properties; }
  95. DeviceTreeNodeView* parent() { return m_parent; }
  96. private:
  97. DeviceTreeNodeView* m_parent;
  98. HashMap<StringView, DeviceTreeNodeView> m_children;
  99. HashMap<StringView, DeviceTreeProperty> m_properties;
  100. };
  101. class DeviceTree : public DeviceTreeNodeView {
  102. public:
  103. static ErrorOr<NonnullOwnPtr<DeviceTree>> parse(ReadonlyBytes);
  104. DeviceTreeNodeView const* resolve_node(StringView path) const
  105. {
  106. // FIXME: May children of aliases be referenced?
  107. // Note: Aliases may not contain a '/' in their name
  108. // And as all paths other than aliases should start with '/', we can just check for the first '/'
  109. if (!path.starts_with('/')) {
  110. if (auto alias_list = get_child("aliases"sv); alias_list.has_value()) {
  111. if (auto alias = alias_list->get_property(path); alias.has_value()) {
  112. path = alias.value().as_string();
  113. } else {
  114. dbgln("DeviceTree: '{}' not found in /aliases, treating as absolute path", path);
  115. }
  116. } else {
  117. dbgln("DeviceTree: No /aliases node found, treating '{}' as absolute path", path);
  118. }
  119. }
  120. DeviceTreeNodeView const* node = this;
  121. path.for_each_split_view('/', SplitBehavior::Nothing, [&](auto const& part) {
  122. if (auto child = node->get_child(part); child.has_value()) {
  123. node = &child.value();
  124. } else {
  125. node = nullptr;
  126. return IterationDecision::Break;
  127. }
  128. return IterationDecision::Continue;
  129. });
  130. return node;
  131. }
  132. Optional<DeviceTreeProperty> resolve_property(StringView path) const
  133. {
  134. auto property_name = path.find_last_split_view('/');
  135. auto node_path = path.substring_view(0, path.length() - property_name.length() - 1);
  136. auto const* node = resolve_node(node_path);
  137. if (!node)
  138. return {};
  139. return node->get_property(property_name);
  140. }
  141. // FIXME: Add a helper to iterate over each descendant fulfilling some properties
  142. // Like each node with a "compatible" property containing "pci" or "usb",
  143. // bonus points if it could automatically recurse in the tree under some conditions,
  144. // like "simple-bus" or "pci-bridge" nodes
  145. DeviceTreeNodeView const* phandle(u32 phandle) const
  146. {
  147. if (phandle >= m_phandles.size())
  148. return nullptr;
  149. return m_phandles[phandle];
  150. }
  151. ReadonlyBytes flattened_device_tree() const { return m_flattened_device_tree; }
  152. private:
  153. DeviceTree(ReadonlyBytes flattened_device_tree)
  154. : DeviceTreeNodeView(nullptr)
  155. , m_flattened_device_tree(flattened_device_tree)
  156. {
  157. }
  158. ErrorOr<void> set_phandle(u32 phandle, DeviceTreeNodeView* node)
  159. {
  160. if (m_phandles.size() > phandle && m_phandles[phandle] != nullptr)
  161. return Error::from_string_view_or_print_error_and_return_errno("Duplicate phandle entry in DeviceTree"sv, EINVAL);
  162. if (m_phandles.size() <= phandle)
  163. TRY(m_phandles.try_resize(phandle + 1));
  164. m_phandles[phandle] = node;
  165. return {};
  166. }
  167. ReadonlyBytes m_flattened_device_tree;
  168. Vector<DeviceTreeNodeView*> m_phandles;
  169. };
  170. }