node.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  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. parsing::{BigEndianU32, BigEndianU64, CStr, FdtData},
  6. standard_nodes::{Compatible, MemoryRange, MemoryRegion},
  7. Fdt,
  8. };
  9. const FDT_BEGIN_NODE: u32 = 1;
  10. const FDT_END_NODE: u32 = 2;
  11. const FDT_PROP: u32 = 3;
  12. pub(crate) const FDT_NOP: u32 = 4;
  13. const FDT_END: u32 = 5;
  14. #[derive(Debug, Clone, Copy)]
  15. #[repr(C)]
  16. struct FdtProperty {
  17. len: BigEndianU32,
  18. name_offset: BigEndianU32,
  19. }
  20. impl FdtProperty {
  21. fn from_bytes(bytes: &mut FdtData<'_>) -> Option<Self> {
  22. let len = bytes.u32()?;
  23. let name_offset = bytes.u32()?;
  24. Some(Self { len, name_offset })
  25. }
  26. }
  27. /// A devicetree node
  28. #[derive(Debug, Clone, Copy)]
  29. pub struct FdtNode<'b, 'a: 'b> {
  30. pub name: &'a str,
  31. pub(crate) header: &'b Fdt<'a>,
  32. props: &'a [u8],
  33. parent_props: Option<&'a [u8]>,
  34. }
  35. #[cfg(feature = "pretty-printing")]
  36. impl core::fmt::Display for FdtNode<'_, '_> {
  37. fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
  38. crate::pretty_print::print_node(f, *self, 0)?;
  39. Ok(())
  40. }
  41. }
  42. impl<'b, 'a: 'b> FdtNode<'b, 'a> {
  43. fn new(
  44. name: &'a str,
  45. header: &'b Fdt<'a>,
  46. props: &'a [u8],
  47. parent_props: Option<&'a [u8]>,
  48. ) -> Self {
  49. Self { name, header, props, parent_props }
  50. }
  51. /// Returns an iterator over the available properties of the node
  52. pub fn properties(self) -> impl Iterator<Item = NodeProperty<'a>> + 'b {
  53. let mut stream = FdtData::new(self.props);
  54. let mut done = false;
  55. core::iter::from_fn(move || {
  56. if stream.is_empty() || done {
  57. return None;
  58. }
  59. while stream.peek_u32()?.get() == FDT_NOP {
  60. stream.skip(4);
  61. }
  62. if stream.peek_u32().unwrap().get() == FDT_PROP {
  63. Some(NodeProperty::parse(&mut stream, self.header))
  64. } else {
  65. done = true;
  66. None
  67. }
  68. })
  69. }
  70. /// Attempts to find the a property by its name
  71. pub fn property(self, name: &str) -> Option<NodeProperty<'a>> {
  72. self.properties().find(|p| p.name == name)
  73. }
  74. /// Returns an iterator over the children of the current node
  75. pub fn children(self) -> impl Iterator<Item = FdtNode<'b, 'a>> {
  76. let mut stream = FdtData::new(self.props);
  77. while stream.peek_u32().unwrap().get() == FDT_NOP {
  78. stream.skip(4);
  79. }
  80. while stream.peek_u32().unwrap().get() == FDT_PROP {
  81. NodeProperty::parse(&mut stream, self.header);
  82. }
  83. let mut done = false;
  84. core::iter::from_fn(move || {
  85. if stream.is_empty() || done {
  86. return None;
  87. }
  88. while stream.peek_u32()?.get() == FDT_NOP {
  89. stream.skip(4);
  90. }
  91. if stream.peek_u32()?.get() == FDT_BEGIN_NODE {
  92. let origin = stream.remaining();
  93. let ret = {
  94. stream.skip(4);
  95. let unit_name = CStr::new(stream.remaining()).expect("unit name").as_str()?;
  96. let full_name_len = unit_name.len() + 1;
  97. stream.skip(full_name_len);
  98. if full_name_len % 4 != 0 {
  99. stream.skip(4 - (full_name_len % 4));
  100. }
  101. Some(Self::new(unit_name, self.header, stream.remaining(), Some(self.props)))
  102. };
  103. stream = FdtData::new(origin);
  104. skip_current_node(&mut stream, self.header);
  105. ret
  106. } else {
  107. done = true;
  108. None
  109. }
  110. })
  111. }
  112. /// `reg` property
  113. ///
  114. /// Important: this method assumes that the value(s) inside the `reg`
  115. /// property represent CPU-addressable addresses that are able to fit within
  116. /// the platform's pointer size (e.g. `#address-cells` and `#size-cells` are
  117. /// less than or equal to 2 for a 64-bit platform). If this is not the case
  118. /// or you're unsure of whether this applies to the node, it is recommended
  119. /// to use the [`FdtNode::property`] method to extract the raw value slice
  120. /// or use the provided [`FdtNode::raw_reg`] helper method to give you an
  121. /// iterator over the address and size slices. One example of where this
  122. /// would return `None` for a node is a `pci` child node which contains the
  123. /// PCI address information in the `reg` property, of which the address has
  124. /// an `#address-cells` value of 3.
  125. pub fn reg(self) -> Option<impl Iterator<Item = crate::MemoryRegion> + 'a> {
  126. let sizes = self.parent_cell_sizes();
  127. if sizes.address_cells > 2 || sizes.size_cells > 2 {
  128. return None;
  129. }
  130. let mut reg = None;
  131. for prop in self.properties() {
  132. if prop.name == "reg" {
  133. let mut stream = FdtData::new(prop.value);
  134. reg = Some(core::iter::from_fn(move || {
  135. let starting_address = match sizes.address_cells {
  136. 1 => stream.u32()?.get() as usize,
  137. 2 => stream.u64()?.get() as usize,
  138. _ => return None,
  139. } as *const u8;
  140. let size = match sizes.size_cells {
  141. 0 => None,
  142. 1 => Some(stream.u32()?.get() as usize),
  143. 2 => Some(stream.u64()?.get() as usize),
  144. _ => return None,
  145. };
  146. Some(MemoryRegion { starting_address, size })
  147. }));
  148. break;
  149. }
  150. }
  151. reg
  152. }
  153. pub fn ranges(self) -> Option<impl Iterator<Item = crate::MemoryRange> + 'a> {
  154. let sizes = self.cell_sizes();
  155. let parent_sizes = self.parent_cell_sizes();
  156. if sizes.address_cells > 3 || sizes.size_cells > 2 || parent_sizes.size_cells > 2 {
  157. return None;
  158. }
  159. let mut ranges = None;
  160. for prop in self.properties() {
  161. if prop.name == "ranges" {
  162. let mut stream = FdtData::new(prop.value);
  163. ranges = Some(core::iter::from_fn(move || {
  164. let (child_bus_address_hi, child_bus_address) = match sizes.address_cells {
  165. 1 => (0, stream.u32()?.get() as usize),
  166. 2 => (0, stream.u64()?.get() as usize),
  167. 3 => (stream.u32()?.get(), stream.u64()?.get() as usize),
  168. _ => return None,
  169. };
  170. let parent_bus_address = match parent_sizes.address_cells {
  171. 1 => stream.u32()?.get() as usize,
  172. 2 => stream.u64()?.get() as usize,
  173. _ => return None,
  174. };
  175. let size = match sizes.size_cells {
  176. 1 => stream.u32()?.get() as usize,
  177. 2 => stream.u64()?.get() as usize,
  178. _ => return None,
  179. };
  180. Some(MemoryRange {
  181. child_bus_address,
  182. child_bus_address_hi,
  183. parent_bus_address,
  184. size,
  185. })
  186. }));
  187. break;
  188. }
  189. }
  190. ranges
  191. }
  192. /// Convenience method that provides an iterator over the raw bytes for the
  193. /// address and size values inside of the `reg` property
  194. pub fn raw_reg(self) -> Option<impl Iterator<Item = RawReg<'a>> + 'a> {
  195. let sizes = self.parent_cell_sizes();
  196. if let Some(prop) = self.property("reg") {
  197. let mut stream = FdtData::new(prop.value);
  198. return Some(core::iter::from_fn(move || {
  199. Some(RawReg {
  200. address: stream.take(sizes.address_cells * 4)?,
  201. size: stream.take(sizes.size_cells * 4)?,
  202. })
  203. }));
  204. }
  205. None
  206. }
  207. /// `compatible` property
  208. pub fn compatible(self) -> Option<Compatible<'a>> {
  209. let mut s = None;
  210. for prop in self.properties() {
  211. if prop.name == "compatible" {
  212. s = Some(Compatible { data: prop.value });
  213. }
  214. }
  215. s
  216. }
  217. /// Cell sizes for child nodes
  218. pub fn cell_sizes(self) -> CellSizes {
  219. let mut cell_sizes = CellSizes::default();
  220. for property in self.properties() {
  221. match property.name {
  222. "#address-cells" => {
  223. cell_sizes.address_cells = BigEndianU32::from_bytes(property.value)
  224. .expect("not enough bytes for #address-cells value")
  225. .get() as usize;
  226. }
  227. "#size-cells" => {
  228. cell_sizes.size_cells = BigEndianU32::from_bytes(property.value)
  229. .expect("not enough bytes for #size-cells value")
  230. .get() as usize;
  231. }
  232. _ => {}
  233. }
  234. }
  235. cell_sizes
  236. }
  237. /// Searches for the interrupt parent, if the node contains one
  238. pub fn interrupt_parent(self) -> Option<FdtNode<'b, 'a>> {
  239. self.properties()
  240. .find(|p| p.name == "interrupt-parent")
  241. .and_then(|p| self.header.find_phandle(BigEndianU32::from_bytes(p.value)?.get()))
  242. }
  243. /// `#interrupt-cells` property
  244. pub fn interrupt_cells(self) -> Option<usize> {
  245. let mut interrupt_cells = None;
  246. if let Some(prop) = self.property("#interrupt-cells") {
  247. interrupt_cells = BigEndianU32::from_bytes(prop.value).map(|n| n.get() as usize)
  248. }
  249. interrupt_cells
  250. }
  251. /// `interrupts` property
  252. pub fn interrupts(self) -> Option<impl Iterator<Item = usize> + 'a> {
  253. let sizes = self.parent_interrupt_cells()?;
  254. let mut interrupt = None;
  255. for prop in self.properties() {
  256. if prop.name == "interrupts" {
  257. let mut stream = FdtData::new(prop.value);
  258. interrupt = Some(core::iter::from_fn(move || {
  259. let interrupt = match sizes {
  260. 1 => stream.u32()?.get() as usize,
  261. 2 => stream.u64()?.get() as usize,
  262. _ => return None,
  263. };
  264. Some(interrupt)
  265. }));
  266. break;
  267. }
  268. }
  269. interrupt
  270. }
  271. pub(crate) fn parent_cell_sizes(self) -> CellSizes {
  272. let mut cell_sizes = CellSizes::default();
  273. if let Some(parent) = self.parent_props {
  274. let parent =
  275. FdtNode { name: "", props: parent, header: self.header, parent_props: None };
  276. cell_sizes = parent.cell_sizes();
  277. }
  278. cell_sizes
  279. }
  280. pub(crate) fn parent_interrupt_cells(self) -> Option<usize> {
  281. let mut interrupt_cells = None;
  282. let parent = self
  283. .property("interrupt-parent")
  284. .and_then(|p| self.header.find_phandle(BigEndianU32::from_bytes(p.value)?.get()))
  285. .or_else(|| {
  286. Some(FdtNode {
  287. name: "",
  288. props: self.parent_props?,
  289. header: self.header,
  290. parent_props: None,
  291. })
  292. });
  293. if let Some(size) = parent.and_then(|parent| parent.interrupt_cells()) {
  294. interrupt_cells = Some(size);
  295. }
  296. interrupt_cells
  297. }
  298. }
  299. /// The number of cells (big endian u32s) that addresses and sizes take
  300. #[derive(Debug, Clone, Copy)]
  301. pub struct CellSizes {
  302. /// Size of values representing an address
  303. pub address_cells: usize,
  304. /// Size of values representing a size
  305. pub size_cells: usize,
  306. }
  307. impl Default for CellSizes {
  308. fn default() -> Self {
  309. CellSizes { address_cells: 2, size_cells: 1 }
  310. }
  311. }
  312. /// A raw `reg` property value set
  313. #[derive(Debug, Clone, Copy, PartialEq)]
  314. pub struct RawReg<'a> {
  315. /// Big-endian encoded bytes making up the address portion of the property.
  316. /// Length will always be a multiple of 4 bytes.
  317. pub address: &'a [u8],
  318. /// Big-endian encoded bytes making up the size portion of the property.
  319. /// Length will always be a multiple of 4 bytes.
  320. pub size: &'a [u8],
  321. }
  322. pub(crate) fn find_node<'b, 'a: 'b>(
  323. stream: &mut FdtData<'a>,
  324. name: &str,
  325. header: &'b Fdt<'a>,
  326. parent_props: Option<&'a [u8]>,
  327. ) -> Option<FdtNode<'b, 'a>> {
  328. let mut parts = name.splitn(2, '/');
  329. let looking_for = parts.next()?;
  330. stream.skip_nops();
  331. let curr_data = stream.remaining();
  332. match stream.u32()?.get() {
  333. FDT_BEGIN_NODE => {}
  334. _ => return None,
  335. }
  336. let unit_name = CStr::new(stream.remaining()).expect("unit name C str").as_str()?;
  337. let full_name_len = unit_name.len() + 1;
  338. skip_4_aligned(stream, full_name_len);
  339. let looking_contains_addr = looking_for.contains('@');
  340. let addr_name_same = unit_name == looking_for;
  341. let base_name_same = unit_name.split('@').next()? == looking_for;
  342. if (looking_contains_addr && !addr_name_same) || (!looking_contains_addr && !base_name_same) {
  343. *stream = FdtData::new(curr_data);
  344. skip_current_node(stream, header);
  345. return None;
  346. }
  347. let next_part = match parts.next() {
  348. None | Some("") => {
  349. return Some(FdtNode::new(unit_name, header, stream.remaining(), parent_props))
  350. }
  351. Some(part) => part,
  352. };
  353. stream.skip_nops();
  354. let parent_props = Some(stream.remaining());
  355. while stream.peek_u32()?.get() == FDT_PROP {
  356. let _ = NodeProperty::parse(stream, header);
  357. }
  358. while stream.peek_u32()?.get() == FDT_BEGIN_NODE {
  359. if let Some(p) = find_node(stream, next_part, header, parent_props) {
  360. return Some(p);
  361. }
  362. }
  363. stream.skip_nops();
  364. if stream.u32()?.get() != FDT_END_NODE {
  365. return None;
  366. }
  367. None
  368. }
  369. // FIXME: this probably needs refactored
  370. pub(crate) fn all_nodes<'b, 'a: 'b>(header: &'b Fdt<'a>) -> impl Iterator<Item = FdtNode<'b, 'a>> {
  371. let mut stream = FdtData::new(header.structs_block());
  372. let mut done = false;
  373. let mut parents: [&[u8]; 64] = [&[]; 64];
  374. let mut parent_index = 0;
  375. core::iter::from_fn(move || {
  376. if stream.is_empty() || done {
  377. return None;
  378. }
  379. while stream.peek_u32()?.get() == FDT_END_NODE {
  380. parent_index -= 1;
  381. stream.skip(4);
  382. }
  383. if stream.peek_u32()?.get() == FDT_END {
  384. done = true;
  385. return None;
  386. }
  387. while stream.peek_u32()?.get() == FDT_NOP {
  388. stream.skip(4);
  389. }
  390. match stream.u32()?.get() {
  391. FDT_BEGIN_NODE => {}
  392. _ => return None,
  393. }
  394. let unit_name = CStr::new(stream.remaining()).expect("unit name C str").as_str().unwrap();
  395. let full_name_len = unit_name.len() + 1;
  396. skip_4_aligned(&mut stream, full_name_len);
  397. let curr_node = stream.remaining();
  398. parent_index += 1;
  399. parents[parent_index] = curr_node;
  400. while stream.peek_u32()?.get() == FDT_NOP {
  401. stream.skip(4);
  402. }
  403. while stream.peek_u32()?.get() == FDT_PROP {
  404. NodeProperty::parse(&mut stream, header);
  405. }
  406. Some(FdtNode {
  407. name: if unit_name.is_empty() { "/" } else { unit_name },
  408. header,
  409. parent_props: match parent_index {
  410. 1 => None,
  411. _ => Some(parents[parent_index - 1]),
  412. },
  413. props: curr_node,
  414. })
  415. })
  416. }
  417. pub(crate) fn skip_current_node<'a>(stream: &mut FdtData<'a>, header: &Fdt<'a>) {
  418. assert_eq!(stream.u32().unwrap().get(), FDT_BEGIN_NODE, "bad node");
  419. let unit_name = CStr::new(stream.remaining()).expect("unit_name C str").as_str().unwrap();
  420. let full_name_len = unit_name.len() + 1;
  421. skip_4_aligned(stream, full_name_len);
  422. while stream.peek_u32().unwrap().get() == FDT_PROP {
  423. NodeProperty::parse(stream, header);
  424. }
  425. while stream.peek_u32().unwrap().get() == FDT_BEGIN_NODE {
  426. skip_current_node(stream, header);
  427. }
  428. stream.skip_nops();
  429. assert_eq!(stream.u32().unwrap().get(), FDT_END_NODE, "bad node");
  430. }
  431. /// A node property
  432. #[derive(Debug, Clone, Copy)]
  433. pub struct NodeProperty<'a> {
  434. /// Property name
  435. pub name: &'a str,
  436. /// Property value
  437. pub value: &'a [u8],
  438. }
  439. impl<'a> NodeProperty<'a> {
  440. /// Attempt to parse the property value as a `usize`
  441. pub fn as_usize(self) -> Option<usize> {
  442. match self.value.len() {
  443. 4 => BigEndianU32::from_bytes(self.value).map(|i| i.get() as usize),
  444. 8 => BigEndianU64::from_bytes(self.value).map(|i| i.get() as usize),
  445. _ => None,
  446. }
  447. }
  448. /// Attempt to parse the property value as a `&str`
  449. pub fn as_str(self) -> Option<&'a str> {
  450. core::str::from_utf8(self.value).map(|s| s.trim_end_matches('\0')).ok()
  451. }
  452. fn parse(stream: &mut FdtData<'a>, header: &Fdt<'a>) -> Self {
  453. match stream.u32().unwrap().get() {
  454. FDT_PROP => {}
  455. other => panic!("bad prop, tag: {}", other),
  456. }
  457. let prop = FdtProperty::from_bytes(stream).expect("FDT property");
  458. let data_len = prop.len.get() as usize;
  459. let data = &stream.remaining()[..data_len];
  460. skip_4_aligned(stream, data_len);
  461. NodeProperty { name: header.str_at_offset(prop.name_offset.get() as usize), value: data }
  462. }
  463. }
  464. /// A memory reservation
  465. #[derive(Debug)]
  466. #[repr(C)]
  467. pub struct MemoryReservation {
  468. pub(crate) address: BigEndianU64,
  469. pub(crate) size: BigEndianU64,
  470. }
  471. impl MemoryReservation {
  472. /// Pointer representing the memory reservation address
  473. pub fn address(&self) -> *const u8 {
  474. self.address.get() as usize as *const u8
  475. }
  476. /// Size of the memory reservation
  477. pub fn size(&self) -> usize {
  478. self.size.get() as usize
  479. }
  480. pub(crate) fn from_bytes(bytes: &mut FdtData<'_>) -> Option<Self> {
  481. let address = bytes.u64()?;
  482. let size = bytes.u64()?;
  483. Some(Self { address, size })
  484. }
  485. }
  486. fn skip_4_aligned(stream: &mut FdtData<'_>, len: usize) {
  487. stream.skip((len + 3) & !0x3);
  488. }