standard_nodes.rs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // This Source Code Form is subject to the terms of the Mozilla Public License,
  2. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  3. // obtain one at https://mozilla.org/MPL/2.0/.
  4. use crate::{
  5. node::{CellSizes, FdtNode, NodeProperty},
  6. parsing::{BigEndianU32, BigEndianU64, CStr, FdtData},
  7. Fdt,
  8. };
  9. /// Represents the `/chosen` node with specific helper methods
  10. #[derive(Debug, Clone, Copy)]
  11. pub struct Chosen<'b, 'a: 'b> {
  12. pub(crate) node: FdtNode<'b, 'a>,
  13. }
  14. impl<'b, 'a: 'b> Chosen<'b, 'a> {
  15. /// Contains the bootargs, if they exist
  16. pub fn bootargs(self) -> Option<&'a str> {
  17. self.node
  18. .properties()
  19. .find(|n| n.name == "bootargs")
  20. .and_then(|n| core::str::from_utf8(&n.value[..n.value.len() - 1]).ok())
  21. }
  22. /// Searches for the node representing `stdout`, if the property exists,
  23. /// attempting to resolve aliases if the node name doesn't exist as-is
  24. pub fn stdout(self) -> Option<FdtNode<'b, 'a>> {
  25. self.node
  26. .properties()
  27. .find(|n| n.name == "stdout-path")
  28. .and_then(|n| core::str::from_utf8(&n.value[..n.value.len() - 1]).ok())
  29. .and_then(|name| self.node.header.find_node(name))
  30. }
  31. /// Searches for the node representing `stdout`, if the property exists,
  32. /// attempting to resolve aliases if the node name doesn't exist as-is. If
  33. /// no `stdin` property exists, but `stdout` is present, it will return the
  34. /// node specified by the `stdout` property.
  35. pub fn stdin(self) -> Option<FdtNode<'b, 'a>> {
  36. self.node
  37. .properties()
  38. .find(|n| n.name == "stdin-path")
  39. .and_then(|n| core::str::from_utf8(&n.value[..n.value.len() - 1]).ok())
  40. .and_then(|name| self.node.header.find_node(name))
  41. .or_else(|| self.stdout())
  42. }
  43. }
  44. /// Represents the root (`/`) node with specific helper methods
  45. #[derive(Debug, Clone, Copy)]
  46. pub struct Root<'b, 'a: 'b> {
  47. pub(crate) node: FdtNode<'b, 'a>,
  48. }
  49. impl<'b, 'a: 'b> Root<'b, 'a> {
  50. /// Root node cell sizes
  51. pub fn cell_sizes(self) -> CellSizes {
  52. self.node.cell_sizes()
  53. }
  54. /// `model` property
  55. pub fn model(self) -> &'a str {
  56. self.node
  57. .properties()
  58. .find(|p| p.name == "model")
  59. .and_then(|p| core::str::from_utf8(p.value).map(|s| s.trim_end_matches('\0')).ok())
  60. .unwrap()
  61. }
  62. /// `compatible` property
  63. pub fn compatible(self) -> Compatible<'a> {
  64. self.node.compatible().unwrap()
  65. }
  66. /// Returns an iterator over all of the available properties
  67. pub fn properties(self) -> impl Iterator<Item = NodeProperty<'a>> + 'b {
  68. self.node.properties()
  69. }
  70. /// Attempts to find the a property by its name
  71. pub fn property(self, name: &str) -> Option<NodeProperty<'a>> {
  72. self.node.properties().find(|p| p.name == name)
  73. }
  74. }
  75. /// Represents the `/aliases` node with specific helper methods
  76. #[derive(Debug, Clone, Copy)]
  77. pub struct Aliases<'b, 'a: 'b> {
  78. pub(crate) header: &'b Fdt<'a>,
  79. pub(crate) node: FdtNode<'b, 'a>,
  80. }
  81. impl<'b, 'a: 'b> Aliases<'b, 'a> {
  82. /// Attempt to resolve an alias to a node name
  83. pub fn resolve(self, alias: &str) -> Option<&'a str> {
  84. self.node
  85. .properties()
  86. .find(|p| p.name == alias)
  87. .and_then(|p| core::str::from_utf8(p.value).map(|s| s.trim_end_matches('\0')).ok())
  88. }
  89. /// Attempt to find the node specified by the given alias
  90. pub fn resolve_node(self, alias: &str) -> Option<FdtNode<'b, 'a>> {
  91. self.resolve(alias).and_then(|name| self.header.find_node(name))
  92. }
  93. /// Returns an iterator over all of the available aliases
  94. pub fn all(self) -> impl Iterator<Item = (&'a str, &'a str)> + 'b {
  95. self.node.properties().filter_map(|p| {
  96. Some((p.name, core::str::from_utf8(p.value).map(|s| s.trim_end_matches('\0')).ok()?))
  97. })
  98. }
  99. }
  100. /// Represents a `/cpus/cpu*` node with specific helper methods
  101. #[derive(Debug, Clone, Copy)]
  102. pub struct Cpu<'b, 'a: 'b> {
  103. pub(crate) parent: FdtNode<'b, 'a>,
  104. pub(crate) node: FdtNode<'b, 'a>,
  105. }
  106. impl<'b, 'a: 'b> Cpu<'b, 'a> {
  107. /// Return the IDs for the given CPU
  108. pub fn ids(self) -> CpuIds<'a> {
  109. let address_cells = self.node.parent_cell_sizes().address_cells;
  110. CpuIds {
  111. reg: self
  112. .node
  113. .properties()
  114. .find(|p| p.name == "reg")
  115. .expect("reg is a required property of cpu nodes"),
  116. address_cells,
  117. }
  118. }
  119. /// `clock-frequency` property
  120. pub fn clock_frequency(self) -> usize {
  121. self.node
  122. .properties()
  123. .find(|p| p.name == "clock-frequency")
  124. .or_else(|| self.parent.property("clock-frequency"))
  125. .map(|p| match p.value.len() {
  126. 4 => BigEndianU32::from_bytes(p.value).unwrap().get() as usize,
  127. 8 => BigEndianU64::from_bytes(p.value).unwrap().get() as usize,
  128. _ => unreachable!(),
  129. })
  130. .expect("clock-frequency is a required property of cpu nodes")
  131. }
  132. /// `timebase-frequency` property
  133. pub fn timebase_frequency(self) -> usize {
  134. self.node
  135. .properties()
  136. .find(|p| p.name == "timebase-frequency")
  137. .or_else(|| self.parent.property("timebase-frequency"))
  138. .map(|p| match p.value.len() {
  139. 4 => BigEndianU32::from_bytes(p.value).unwrap().get() as usize,
  140. 8 => BigEndianU64::from_bytes(p.value).unwrap().get() as usize,
  141. _ => unreachable!(),
  142. })
  143. .expect("timebase-frequency is a required property of cpu nodes")
  144. }
  145. /// Returns an iterator over all of the properties for the CPU node
  146. pub fn properties(self) -> impl Iterator<Item = NodeProperty<'a>> + 'b {
  147. self.node.properties()
  148. }
  149. /// Attempts to find the a property by its name
  150. pub fn property(self, name: &str) -> Option<NodeProperty<'a>> {
  151. self.node.properties().find(|p| p.name == name)
  152. }
  153. }
  154. /// Represents the value of the `reg` property of a `/cpus/cpu*` node which may
  155. /// contain more than one CPU or thread ID
  156. #[derive(Debug, Clone, Copy)]
  157. pub struct CpuIds<'a> {
  158. pub(crate) reg: NodeProperty<'a>,
  159. pub(crate) address_cells: usize,
  160. }
  161. impl<'a> CpuIds<'a> {
  162. /// The first listed CPU ID, which will always exist
  163. pub fn first(self) -> usize {
  164. match self.address_cells {
  165. 1 => BigEndianU32::from_bytes(self.reg.value).unwrap().get() as usize,
  166. 2 => BigEndianU64::from_bytes(self.reg.value).unwrap().get() as usize,
  167. n => panic!("address-cells of size {} is currently not supported", n),
  168. }
  169. }
  170. /// Returns an iterator over all of the listed CPU IDs
  171. pub fn all(self) -> impl Iterator<Item = usize> + 'a {
  172. let mut vals = FdtData::new(self.reg.value);
  173. core::iter::from_fn(move || match vals.remaining() {
  174. [] => None,
  175. _ => Some(match self.address_cells {
  176. 1 => vals.u32()?.get() as usize,
  177. 2 => vals.u64()?.get() as usize,
  178. n => panic!("address-cells of size {} is currently not supported", n),
  179. }),
  180. })
  181. }
  182. }
  183. /// Represents the `compatible` property of a node
  184. #[derive(Clone, Copy)]
  185. pub struct Compatible<'a> {
  186. pub(crate) data: &'a [u8],
  187. }
  188. impl<'a> Compatible<'a> {
  189. /// First compatible string
  190. pub fn first(self) -> &'a str {
  191. CStr::new(self.data).expect("expected C str").as_str().unwrap()
  192. }
  193. /// Returns an iterator over all available compatible strings
  194. pub fn all(self) -> impl Iterator<Item = &'a str> {
  195. let mut data = self.data;
  196. core::iter::from_fn(move || {
  197. if data.is_empty() {
  198. return None;
  199. }
  200. match data.iter().position(|b| *b == b'\0') {
  201. Some(idx) => {
  202. let ret = Some(core::str::from_utf8(&data[..idx]).ok()?);
  203. data = &data[idx + 1..];
  204. ret
  205. }
  206. None => {
  207. let ret = Some(core::str::from_utf8(data).ok()?);
  208. data = &[];
  209. ret
  210. }
  211. }
  212. })
  213. }
  214. }
  215. /// Represents the `/memory` node with specific helper methods
  216. #[derive(Debug, Clone, Copy)]
  217. pub struct Memory<'b, 'a: 'b> {
  218. pub(crate) node: FdtNode<'b, 'a>,
  219. }
  220. impl<'a> Memory<'_, 'a> {
  221. /// Returns an iterator over all of the available memory regions
  222. pub fn regions(&self) -> impl Iterator<Item = MemoryRegion> + 'a {
  223. self.node.reg().unwrap()
  224. }
  225. /// Returns the initial mapped area, if it exists
  226. pub fn initial_mapped_area(&self) -> Option<MappedArea> {
  227. let mut mapped_area = None;
  228. if let Some(init_mapped_area) = self.node.property("initial_mapped_area") {
  229. let mut stream = FdtData::new(init_mapped_area.value);
  230. let effective_address = stream.u64().expect("effective address");
  231. let physical_address = stream.u64().expect("physical address");
  232. let size = stream.u32().expect("size");
  233. mapped_area = Some(MappedArea {
  234. effective_address: effective_address.get() as usize,
  235. physical_address: physical_address.get() as usize,
  236. size: size.get() as usize,
  237. });
  238. }
  239. mapped_area
  240. }
  241. }
  242. /// An area described by the `initial-mapped-area` property of the `/memory`
  243. /// node
  244. #[derive(Debug, Clone, Copy, PartialEq)]
  245. #[repr(C)]
  246. pub struct MappedArea {
  247. /// Effective address of the mapped area
  248. pub effective_address: usize,
  249. /// Physical address of the mapped area
  250. pub physical_address: usize,
  251. /// Size of the mapped area
  252. pub size: usize,
  253. }
  254. /// A memory region
  255. #[derive(Debug, Clone, Copy, PartialEq)]
  256. pub struct MemoryRegion {
  257. /// Starting address represented as a pointer
  258. pub starting_address: *const u8,
  259. /// Size of the memory region
  260. pub size: Option<usize>,
  261. }