1use alloc::collections::BTreeMap;
8use alloc::ffi::CString;
9use alloc::string::String;
10use alloc::vec::Vec;
11use core::cmp::{Ord, Ordering};
12use core::convert::TryInto;
13use core::fmt;
14use core::mem::size_of_val;
15#[cfg(feature = "std")]
16use std::collections::HashSet;
17
18#[cfg(all(feature = "alloc", not(feature = "std")))]
19use hashbrown::HashSet;
20
21use crate::{
22 FDT_BEGIN_NODE, FDT_END, FDT_END_NODE, FDT_MAGIC, FDT_PROP, NODE_NAME_MAX_LEN,
23 PROPERTY_NAME_MAX_LEN,
24};
25
26#[derive(Debug, Eq, PartialEq)]
27pub enum Error {
29 PropertyBeforeBeginNode,
31 PropertyAfterEndNode,
33 PropertyValueTooLarge,
35 TotalSizeTooLarge,
37 InvalidString,
39 OutOfOrderEndNode,
41 UnclosedNode,
43 InvalidMemoryReservation,
45 OverlappingMemoryReservations,
47 InvalidNodeName,
49 InvalidPropertyName,
51 NodeDepthTooLarge,
53 DuplicatePhandle,
55}
56
57impl fmt::Display for Error {
58 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59 match self {
60 Error::PropertyBeforeBeginNode => {
61 write!(f, "Properties may not be added before beginning a node")
62 }
63 Error::PropertyAfterEndNode => {
64 write!(f, "Properties may not be added after a node has been ended")
65 }
66 Error::PropertyValueTooLarge => write!(f, "Property value size must fit in 32 bits"),
67 Error::TotalSizeTooLarge => write!(f, "Total size must fit in 32 bits"),
68 Error::InvalidString => write!(f, "Strings cannot contain NUL"),
69 Error::OutOfOrderEndNode => {
70 write!(f, "Attempted to end a node that was not the most recent")
71 }
72 Error::UnclosedNode => write!(f, "Attempted to call finish without ending all nodes"),
73 Error::InvalidMemoryReservation => write!(f, "Memory reservation is invalid"),
74 Error::OverlappingMemoryReservations => {
75 write!(f, "Memory reservations are overlapping")
76 }
77 Error::InvalidNodeName => write!(f, "Invalid node name"),
78 Error::InvalidPropertyName => write!(f, "Invalid property name"),
79 Error::NodeDepthTooLarge => write!(f, "Node depth exceeds FDT_MAX_NODE_DEPTH"),
80 Error::DuplicatePhandle => write!(f, "Duplicate phandle value"),
81 }
82 }
83}
84
85#[cfg(feature = "std")]
86impl std::error::Error for Error {}
87
88pub type Result<T> = core::result::Result<T, Error>;
90
91const FDT_HEADER_SIZE: usize = 40;
92const FDT_VERSION: u32 = 17;
93const FDT_LAST_COMP_VERSION: u32 = 16;
94const FDT_MAX_NODE_DEPTH: usize = 64;
96
97#[derive(Debug)]
99pub struct FdtWriter {
100 data: Vec<u8>,
101 off_mem_rsvmap: u32,
102 off_dt_struct: u32,
103 strings: Vec<u8>,
104 string_offsets: BTreeMap<CString, u32>,
105 node_depth: usize,
106 node_ended: bool,
107 boot_cpuid_phys: u32,
108 phandles: HashSet<u32>,
111}
112
113#[derive(Clone, Debug, Eq, PartialEq)]
118pub struct FdtReserveEntry {
119 address: u64,
120 size: u64,
121}
122
123impl FdtReserveEntry {
124 pub fn new(address: u64, size: u64) -> Result<Self> {
131 if address.checked_add(size).is_none() || size == 0 {
132 return Err(Error::InvalidMemoryReservation);
133 }
134
135 Ok(FdtReserveEntry { address, size })
136 }
137}
138
139impl Ord for FdtReserveEntry {
140 fn cmp(&self, other: &Self) -> Ordering {
141 self.address.cmp(&other.address)
142 }
143}
144
145impl PartialOrd for FdtReserveEntry {
146 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
147 Some(self.cmp(other))
148 }
149}
150
151fn check_overlapping(mem_reservations: &[FdtReserveEntry]) -> Result<()> {
153 let mut mem_rsvmap_copy = mem_reservations.to_vec();
154 mem_rsvmap_copy.sort();
155 let overlapping = mem_rsvmap_copy.windows(2).any(|w| {
156 w[0].address + w[0].size > w[1].address
159 });
160
161 if overlapping {
162 return Err(Error::OverlappingMemoryReservations);
163 }
164
165 Ok(())
166}
167
168fn node_name_valid(name: &str) -> bool {
171 if name.is_empty() {
174 return true;
175 }
176
177 let mut parts = name.split('@');
178
179 let node_name = parts.next().unwrap(); let unit_address = parts.next();
181
182 if unit_address.is_some() && parts.next().is_some() {
183 return false;
185 }
186
187 if node_name.is_empty() || node_name.len() > NODE_NAME_MAX_LEN {
188 return false;
189 }
190
191 if !node_name.starts_with(node_name_valid_first_char) {
192 return false;
193 }
194
195 if node_name.contains(|c: char| !node_name_valid_char(c)) {
196 return false;
197 }
198
199 if let Some(unit_address) = unit_address {
200 if unit_address.contains(|c: char| !node_name_valid_char(c)) {
201 return false;
202 }
203 }
204
205 true
206}
207
208fn node_name_valid_char(c: char) -> bool {
209 c.is_ascii_alphanumeric() || matches!(c, ',' | '.' | '_' | '+' | '-')
210}
211
212fn node_name_valid_first_char(c: char) -> bool {
213 c.is_ascii_alphabetic()
214}
215
216fn property_name_valid(name: &str) -> bool {
219 if name.is_empty() || name.len() > PROPERTY_NAME_MAX_LEN {
220 return false;
221 }
222
223 if name.contains(|c: char| !property_name_valid_char(c)) {
224 return false;
225 }
226
227 true
228}
229
230fn property_name_valid_char(c: char) -> bool {
231 matches!(c, '0'..='9' | 'a'..='z' | 'A'..='Z' | ',' | '.' | '_' | '+' | '?' | '#' | '-')
232}
233
234#[derive(Debug)]
240pub struct FdtWriterNode {
241 depth: usize,
242}
243
244impl FdtWriter {
245 pub fn new() -> Result<Self> {
247 FdtWriter::new_with_mem_reserv(&[])
248 }
249
250 pub fn new_with_mem_reserv(mem_reservations: &[FdtReserveEntry]) -> Result<Self> {
256 let data = vec![0u8; FDT_HEADER_SIZE]; let mut fdt = FdtWriter {
259 data,
260 off_mem_rsvmap: 0,
261 off_dt_struct: 0,
262 strings: Vec::new(),
263 string_offsets: BTreeMap::new(),
264 node_depth: 0,
265 node_ended: false,
266 boot_cpuid_phys: 0,
267 phandles: HashSet::new(),
268 };
269
270 fdt.align(8);
271 fdt.off_mem_rsvmap = fdt.data.len() as u32;
273
274 check_overlapping(mem_reservations)?;
275 fdt.write_mem_rsvmap(mem_reservations);
276
277 fdt.align(4);
278 fdt.off_dt_struct = fdt
279 .data
280 .len()
281 .try_into()
282 .map_err(|_| Error::TotalSizeTooLarge)?;
283
284 Ok(fdt)
285 }
286
287 fn write_mem_rsvmap(&mut self, mem_reservations: &[FdtReserveEntry]) {
288 for rsv in mem_reservations {
289 self.append_u64(rsv.address);
290 self.append_u64(rsv.size);
291 }
292
293 self.append_u64(0);
294 self.append_u64(0);
295 }
296
297 pub fn set_boot_cpuid_phys(&mut self, boot_cpuid_phys: u32) {
314 self.boot_cpuid_phys = boot_cpuid_phys;
315 }
316
317 fn pad(&mut self, num_bytes: usize) {
319 self.data.extend(core::iter::repeat(0).take(num_bytes));
320 }
321
322 fn align(&mut self, alignment: usize) {
324 let offset = self.data.len() % alignment;
325 if offset != 0 {
326 self.pad(alignment - offset);
327 }
328 }
329
330 fn update_u32(&mut self, offset: usize, val: u32) {
332 let data_slice = &mut self.data[offset..offset + 4];
335 data_slice.copy_from_slice(&val.to_be_bytes());
336 }
337
338 fn append_u32(&mut self, val: u32) {
339 self.data.extend_from_slice(&val.to_be_bytes());
340 }
341
342 fn append_u64(&mut self, val: u64) {
343 self.data.extend_from_slice(&val.to_be_bytes());
344 }
345
346 pub fn begin_node(&mut self, name: &str) -> Result<FdtWriterNode> {
354 if self.node_depth >= FDT_MAX_NODE_DEPTH {
355 return Err(Error::NodeDepthTooLarge);
356 }
357
358 let name_cstr = CString::new(name).map_err(|_| Error::InvalidString)?;
359 if !node_name_valid(name) {
363 return Err(Error::InvalidNodeName);
364 }
365 self.append_u32(FDT_BEGIN_NODE);
366 self.data.extend(name_cstr.to_bytes_with_nul());
367 self.align(4);
368 self.node_depth += 1;
371 self.node_ended = false;
372 Ok(FdtWriterNode {
373 depth: self.node_depth,
374 })
375 }
376
377 pub fn end_node(&mut self, node: FdtWriterNode) -> Result<()> {
379 if node.depth != self.node_depth {
380 return Err(Error::OutOfOrderEndNode);
381 }
382
383 self.append_u32(FDT_END_NODE);
384 self.node_depth -= 1;
387 self.node_ended = true;
388 Ok(())
389 }
390
391 fn intern_string(&mut self, s: CString) -> Result<u32> {
394 if let Some(off) = self.string_offsets.get(&s) {
395 Ok(*off)
396 } else {
397 let off = self
398 .strings
399 .len()
400 .try_into()
401 .map_err(|_| Error::TotalSizeTooLarge)?;
402 self.strings.extend_from_slice(s.to_bytes_with_nul());
403 self.string_offsets.insert(s, off);
404 Ok(off)
405 }
406 }
407
408 pub fn property(&mut self, name: &str, val: &[u8]) -> Result<()> {
415 if self.node_ended {
416 return Err(Error::PropertyAfterEndNode);
417 }
418
419 if self.node_depth == 0 {
420 return Err(Error::PropertyBeforeBeginNode);
421 }
422
423 let name_cstr = CString::new(name).map_err(|_| Error::InvalidString)?;
424
425 if !property_name_valid(name) {
426 return Err(Error::InvalidPropertyName);
427 }
428
429 let len = val
430 .len()
431 .try_into()
432 .map_err(|_| Error::PropertyValueTooLarge)?;
433
434 let nameoff = self.intern_string(name_cstr)?;
435 self.append_u32(FDT_PROP);
436 self.append_u32(len);
437 self.append_u32(nameoff);
438 self.data.extend_from_slice(val);
439 self.align(4);
440 Ok(())
441 }
442
443 pub fn property_null(&mut self, name: &str) -> Result<()> {
445 self.property(name, &[])
446 }
447
448 pub fn property_string(&mut self, name: &str, val: &str) -> Result<()> {
450 let cstr_value = CString::new(val).map_err(|_| Error::InvalidString)?;
451 self.property(name, cstr_value.to_bytes_with_nul())
452 }
453
454 pub fn property_string_list(&mut self, name: &str, values: Vec<String>) -> Result<()> {
456 let mut bytes = Vec::new();
457 for s in values {
458 let cstr = CString::new(s).map_err(|_| Error::InvalidString)?;
459 bytes.extend_from_slice(cstr.to_bytes_with_nul());
460 }
461 self.property(name, &bytes)
462 }
463
464 pub fn property_u32(&mut self, name: &str, val: u32) -> Result<()> {
466 self.property(name, &val.to_be_bytes())
467 }
468
469 pub fn property_u64(&mut self, name: &str, val: u64) -> Result<()> {
471 self.property(name, &val.to_be_bytes())
472 }
473
474 pub fn property_array_u32(&mut self, name: &str, cells: &[u32]) -> Result<()> {
476 let mut arr = Vec::with_capacity(size_of_val(cells));
477 for &c in cells {
478 arr.extend(c.to_be_bytes());
479 }
480 self.property(name, &arr)
481 }
482
483 pub fn property_array_u64(&mut self, name: &str, cells: &[u64]) -> Result<()> {
485 let mut arr = Vec::with_capacity(size_of_val(cells));
486 for &c in cells {
487 arr.extend(c.to_be_bytes());
488 }
489 self.property(name, &arr)
490 }
491
492 pub fn property_phandle(&mut self, val: u32) -> Result<()> {
496 if !self.phandles.insert(val) {
497 return Err(Error::DuplicatePhandle);
498 }
499 self.property("phandle", &val.to_be_bytes())
500 }
501
502 pub fn finish(mut self) -> Result<Vec<u8>> {
506 if self.node_depth > 0 {
507 return Err(Error::UnclosedNode);
508 }
509
510 self.append_u32(FDT_END);
511 let size_dt_plus_header: u32 = self
512 .data
513 .len()
514 .try_into()
515 .map_err(|_| Error::TotalSizeTooLarge)?;
516 let size_dt_struct = size_dt_plus_header - self.off_dt_struct;
520
521 let off_dt_strings = self
522 .data
523 .len()
524 .try_into()
525 .map_err(|_| Error::TotalSizeTooLarge)?;
526 let size_dt_strings = self
527 .strings
528 .len()
529 .try_into()
530 .map_err(|_| Error::TotalSizeTooLarge)?;
531
532 let totalsize = self
533 .data
534 .len()
535 .checked_add(self.strings.len())
536 .ok_or(Error::TotalSizeTooLarge)?;
537 let totalsize = totalsize.try_into().map_err(|_| Error::TotalSizeTooLarge)?;
538
539 self.update_u32(0, FDT_MAGIC);
541 self.update_u32(4, totalsize);
542 self.update_u32(2 * 4, self.off_dt_struct);
543 self.update_u32(3 * 4, off_dt_strings);
544 self.update_u32(4 * 4, self.off_mem_rsvmap);
545 self.update_u32(5 * 4, FDT_VERSION);
546 self.update_u32(6 * 4, FDT_LAST_COMP_VERSION);
547 self.update_u32(7 * 4, self.boot_cpuid_phys);
548 self.update_u32(8 * 4, size_dt_strings);
549 self.update_u32(9 * 4, size_dt_struct);
550
551 self.data.append(&mut self.strings);
553
554 Ok(self.data)
555 }
556}
557
558#[cfg(test)]
559mod tests {
560 use super::*;
561
562 #[test]
563 fn minimal() {
564 let mut fdt = FdtWriter::new().unwrap();
565 let root_node = fdt.begin_node("").unwrap();
566 fdt.end_node(root_node).unwrap();
567 let actual_fdt = fdt.finish().unwrap();
568 let expected_fdt = vec![
569 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, ];
588 assert_eq!(expected_fdt, actual_fdt);
589 }
590
591 #[test]
592 fn reservemap() {
593 let mut fdt = FdtWriter::new_with_mem_reserv(&[
594 FdtReserveEntry::new(0x12345678AABBCCDD, 0x1234).unwrap(),
595 FdtReserveEntry::new(0x1020304050607080, 0x5678).unwrap(),
596 ])
597 .unwrap();
598 let root_node = fdt.begin_node("").unwrap();
599 fdt.end_node(root_node).unwrap();
600 let actual_fdt = fdt.finish().unwrap();
601 let expected_fdt = vec![
602 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, ];
629 assert_eq!(expected_fdt, actual_fdt);
630 }
631
632 #[test]
633 fn prop_null() {
634 let mut fdt = FdtWriter::new().unwrap();
635 let root_node = fdt.begin_node("").unwrap();
636 fdt.property_null("null").unwrap();
637 fdt.end_node(root_node).unwrap();
638 let actual_fdt = fdt.finish().unwrap();
639 let expected_fdt = vec![
640 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, b'n', b'u', b'l', b'l', 0x00, ];
663 assert_eq!(expected_fdt, actual_fdt);
664 }
665
666 #[test]
667 fn prop_u32() {
668 let mut fdt = FdtWriter::new().unwrap();
669 let root_node = fdt.begin_node("").unwrap();
670 fdt.property_u32("u32", 0x12345678).unwrap();
671 fdt.end_node(root_node).unwrap();
672 let actual_fdt = fdt.finish().unwrap();
673 let expected_fdt = vec![
674 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, b'u', b'3', b'2', 0x00, ];
698 assert_eq!(expected_fdt, actual_fdt);
699 }
700
701 #[test]
702 fn all_props() {
703 let mut fdt = FdtWriter::new().unwrap();
704 let root_node = fdt.begin_node("").unwrap();
705 fdt.property_null("null").unwrap();
706 fdt.property_u32("u32", 0x12345678).unwrap();
707 fdt.property_u64("u64", 0x1234567887654321).unwrap();
708 fdt.property_string("str", "hello").unwrap();
709 fdt.property_string_list("strlst", vec!["hi".into(), "bye".into()])
710 .unwrap();
711 fdt.property_array_u32("arru32", &[0x12345678, 0xAABBCCDD])
712 .unwrap();
713 fdt.property_array_u64("arru64", &[0x1234567887654321])
714 .unwrap();
715 fdt.end_node(root_node).unwrap();
716 let actual_fdt = fdt.finish().unwrap();
717 let expected_fdt = vec![
718 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x12, 0x34, 0x56, 0x78, 0x87, 0x65, 0x43, 0x21, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0D, b'h', b'e', b'l', b'l', b'o', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x11, b'h', b'i', 0x00, b'b', b'y', b'e', 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1f, 0x12, 0x34, 0x56, 0x78, 0x87, 0x65, 0x43, 0x21, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, b'n', b'u', b'l', b'l', 0x00, b'u', b'3', b'2', 0x00, b'u', b'6', b'4', 0x00, b's', b't', b'r', 0x00, b's', b't', b'r', b'l', b's', b't', 0x00, b'a', b'r', b'r', b'u', b'3', b'2', 0x00, b'a', b'r', b'r', b'u', b'6', b'4', 0x00, ];
776 assert_eq!(expected_fdt, actual_fdt);
777 }
778
779 #[test]
780 fn property_before_begin_node() {
781 let mut fdt = FdtWriter::new().unwrap();
782 assert_eq!(
784 fdt.property_string("invalid", "property").unwrap_err(),
785 Error::PropertyBeforeBeginNode
786 );
787
788 let node = fdt.begin_node("root").unwrap();
790 fdt.end_node(node).unwrap();
791 assert_eq!(
792 fdt.property_string("invalid", "property").unwrap_err(),
793 Error::PropertyAfterEndNode
794 );
795 }
796
797 #[test]
798 fn nested_nodes() {
799 let mut fdt = FdtWriter::new().unwrap();
800 let root_node = fdt.begin_node("").unwrap();
801 fdt.property_u32("abc", 0x13579024).unwrap();
802 let nested_node = fdt.begin_node("nested").unwrap();
803 fdt.property_u32("def", 0x12121212).unwrap();
804 fdt.end_node(nested_node).unwrap();
805 fdt.end_node(root_node).unwrap();
806 let actual_fdt = fdt.finish().unwrap();
807 let expected_fdt = vec![
808 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x57, 0x90, 0x24, 0x00, 0x00, 0x00, 0x01, b'n', b'e', b's', b't', b'e', b'd', 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x12, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, b'a', b'b', b'c', 0x00, b'd', b'e', b'f', 0x00, ];
841 assert_eq!(expected_fdt, actual_fdt);
842 }
843
844 #[test]
845 fn prop_name_string_reuse() {
846 let mut fdt = FdtWriter::new().unwrap();
847 let root_node = fdt.begin_node("").unwrap();
848 fdt.property_u32("abc", 0x13579024).unwrap();
849 let nested_node = fdt.begin_node("nested").unwrap();
850 fdt.property_u32("def", 0x12121212).unwrap();
851 fdt.property_u32("abc", 0x12121212).unwrap(); fdt.end_node(nested_node).unwrap();
853 fdt.end_node(root_node).unwrap();
854 let actual_fdt = fdt.finish().unwrap();
855 let expected_fdt = vec![
856 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x57, 0x90, 0x24, 0x00, 0x00, 0x00, 0x01, b'n', b'e', b's', b't', b'e', b'd', 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x12, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, b'a', b'b', b'c', 0x00, b'd', b'e', b'f', 0x00, ];
893 assert_eq!(expected_fdt, actual_fdt);
894 }
895
896 #[test]
897 fn boot_cpuid() {
898 let mut fdt = FdtWriter::new().unwrap();
899 fdt.set_boot_cpuid_phys(0x12345678);
900 let root_node = fdt.begin_node("").unwrap();
901 fdt.end_node(root_node).unwrap();
902 let actual_fdt = fdt.finish().unwrap();
903 let expected_fdt = vec![
904 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, ];
923 assert_eq!(expected_fdt, actual_fdt);
924 }
925
926 #[test]
927 fn invalid_node_name_nul() {
928 let mut fdt = FdtWriter::new().unwrap();
929 fdt.begin_node("root").unwrap();
930 assert_eq!(
931 fdt.begin_node("abc\0def").unwrap_err(),
932 Error::InvalidString
933 );
934 }
935
936 #[test]
937 fn invalid_prop_name_nul() {
938 let mut fdt = FdtWriter::new().unwrap();
939 fdt.begin_node("root").unwrap();
940 assert_eq!(
941 fdt.property_u32("abc\0def", 0).unwrap_err(),
942 Error::InvalidString
943 );
944 }
945
946 #[test]
947 fn invalid_prop_string_value_nul() {
948 let mut fdt = FdtWriter::new().unwrap();
949 fdt.begin_node("root").unwrap();
950 assert_eq!(
951 fdt.property_string("mystr", "abc\0def").unwrap_err(),
952 Error::InvalidString
953 );
954 }
955
956 #[test]
957 fn invalid_prop_string_list_value_nul() {
958 let mut fdt = FdtWriter::new().unwrap();
959 let strs = vec!["test".into(), "abc\0def".into()];
960 assert_eq!(
961 fdt.property_string_list("mystr", strs).unwrap_err(),
962 Error::InvalidString
963 );
964 }
965
966 #[test]
967 fn invalid_prop_after_end_node() {
968 let mut fdt = FdtWriter::new().unwrap();
969 let _root_node = fdt.begin_node("").unwrap();
970 fdt.property_u32("ok_prop", 1234).unwrap();
971 let nested_node = fdt.begin_node("mynode").unwrap();
972 fdt.property_u32("ok_nested_prop", 5678).unwrap();
973 fdt.end_node(nested_node).unwrap();
974 assert_eq!(
975 fdt.property_u32("bad_prop_after_end_node", 1357)
976 .unwrap_err(),
977 Error::PropertyAfterEndNode
978 );
979 }
980
981 #[test]
982 fn invalid_end_node_out_of_order() {
983 let mut fdt = FdtWriter::new().unwrap();
984 let root_node = fdt.begin_node("").unwrap();
985 fdt.property_u32("ok_prop", 1234).unwrap();
986 let _nested_node = fdt.begin_node("mynode").unwrap();
987 assert_eq!(
988 fdt.end_node(root_node).unwrap_err(),
989 Error::OutOfOrderEndNode
990 );
991 }
992
993 #[test]
994 fn invalid_finish_while_node_open() {
995 let mut fdt = FdtWriter::new().unwrap();
996 let _root_node = fdt.begin_node("").unwrap();
997 fdt.property_u32("ok_prop", 1234).unwrap();
998 let _nested_node = fdt.begin_node("mynode").unwrap();
999 fdt.property_u32("ok_nested_prop", 5678).unwrap();
1000 assert_eq!(fdt.finish().unwrap_err(), Error::UnclosedNode);
1001 }
1002
1003 #[test]
1004 #[cfg(feature = "long_running_test")]
1005 fn test_overflow_subtract() {
1006 let overflow_size = u32::MAX / std::mem::size_of::<FdtReserveEntry>() as u32 - 3;
1007 let too_large_mem_reserve: Vec<FdtReserveEntry> = (0..overflow_size)
1008 .map(|i| FdtReserveEntry::new(u64::from(i) * 2, 1).unwrap())
1009 .collect();
1010 let mut fdt = FdtWriter::new_with_mem_reserv(&too_large_mem_reserve).unwrap();
1011 let root_node = fdt.begin_node("").unwrap();
1012 fdt.end_node(root_node).unwrap();
1013 assert_eq!(fdt.finish().unwrap_err(), Error::TotalSizeTooLarge);
1014 }
1015
1016 #[test]
1017 fn test_invalid_mem_reservations() {
1018 assert_eq!(
1021 FdtReserveEntry::new(0x1, u64::MAX).unwrap_err(),
1022 Error::InvalidMemoryReservation
1023 );
1024
1025 assert_eq!(
1027 FdtReserveEntry::new(0x1, 0).unwrap_err(),
1028 Error::InvalidMemoryReservation
1029 );
1030 }
1031
1032 #[test]
1033 fn test_cmp_mem_reservations() {
1034 assert_eq!(
1036 FdtReserveEntry::new(0x1, 10)
1037 .unwrap()
1038 .cmp(&FdtReserveEntry::new(0x1, 11).unwrap()),
1039 Ordering::Equal
1040 );
1041 assert_eq!(
1042 FdtReserveEntry::new(0x1, 10)
1043 .unwrap()
1044 .cmp(&FdtReserveEntry::new(0x2, 10).unwrap()),
1045 Ordering::Less
1046 );
1047 assert_eq!(
1048 FdtReserveEntry::new(0x1, 10)
1049 .unwrap()
1050 .cmp(&FdtReserveEntry::new(0x0, 10).unwrap()),
1051 Ordering::Greater
1052 );
1053 }
1054
1055 #[test]
1056 fn test_overlapping_mem_reservations() {
1057 let overlapping = [
1060 FdtReserveEntry::new(0x3, 1).unwrap(), FdtReserveEntry::new(0x0, 1).unwrap(),
1062 FdtReserveEntry::new(0x2, 2).unwrap(), ];
1064 let fdt = FdtWriter::new_with_mem_reserv(&overlapping);
1065 assert_eq!(fdt.unwrap_err(), Error::OverlappingMemoryReservations);
1066
1067 let overlapping = [
1069 FdtReserveEntry::new(0x100, 100).unwrap(),
1070 FdtReserveEntry::new(0x50, 300).unwrap(),
1071 ];
1072 let fdt = FdtWriter::new_with_mem_reserv(&overlapping);
1073 assert_eq!(fdt.unwrap_err(), Error::OverlappingMemoryReservations);
1074 }
1075
1076 #[test]
1077 fn test_off_by_one_mem_rsv() {
1078 let non_overlapping = [
1081 FdtReserveEntry::new(0x0, 1).unwrap(),
1082 FdtReserveEntry::new(0x1, 1).unwrap(),
1083 FdtReserveEntry::new(0x2, 2).unwrap(),
1084 ];
1085
1086 assert!(FdtWriter::new_with_mem_reserv(&non_overlapping).is_ok());
1087 }
1088
1089 #[test]
1090 fn test_node_name_valid() {
1091 assert!(node_name_valid("abcdef"));
1092 assert!(node_name_valid("abcdef@1000"));
1093 assert!(node_name_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
1094 assert!(node_name_valid("azAZ09,._+-"));
1095 assert!(node_name_valid("Abcd"));
1096
1097 assert!(node_name_valid(""));
1098
1099 assert!(!node_name_valid("@1000"));
1101
1102 assert!(!node_name_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
1104 assert!(!node_name_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@1234"));
1105
1106 assert!(!node_name_valid("abc#def"));
1108 assert!(!node_name_valid("abc/def"));
1109
1110 assert!(!node_name_valid("1abc"));
1112
1113 assert!(!node_name_valid("abcdef@1000#"));
1115
1116 assert!(!node_name_valid("abc@1000@def"));
1118 }
1119
1120 #[test]
1121 fn test_property_name_valid() {
1122 assert!(property_name_valid("abcdef"));
1123 assert!(property_name_valid("01234"));
1124 assert!(property_name_valid("azAZ09,._+?#-"));
1125 assert!(property_name_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
1126
1127 assert!(!property_name_valid("abc!def"));
1129 assert!(!property_name_valid("abc@1234"));
1130
1131 assert!(!property_name_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
1133 }
1134
1135 #[test]
1136 fn depth_overflow() {
1137 let mut fdt = FdtWriter::new().unwrap();
1138 for _ in 1..=FDT_MAX_NODE_DEPTH {
1139 fdt.begin_node("test").unwrap();
1140 }
1141 assert_eq!(
1142 fdt.begin_node("test").unwrap_err(),
1143 Error::NodeDepthTooLarge
1144 );
1145 }
1146
1147 #[test]
1148 fn unique_phandles() {
1149 let mut fdt = FdtWriter::new().unwrap();
1150 let root_node = fdt.begin_node("root").unwrap();
1151
1152 let prim_node = fdt.begin_node("phandle-1").unwrap();
1153 fdt.property_phandle(1).unwrap();
1154 fdt.end_node(prim_node).unwrap();
1155
1156 let prim_node = fdt.begin_node("phandle-2").unwrap();
1157 fdt.property_phandle(2).unwrap();
1158 fdt.end_node(prim_node).unwrap();
1159
1160 fdt.end_node(root_node).unwrap();
1161 fdt.finish().unwrap();
1162 }
1163
1164 #[test]
1165 fn duplicate_phandles() {
1166 let mut fdt = FdtWriter::new().unwrap();
1167 let _root_node = fdt.begin_node("root").unwrap();
1168
1169 let prim_node = fdt.begin_node("phandle-1").unwrap();
1170 fdt.property_phandle(1).unwrap();
1171 fdt.end_node(prim_node).unwrap();
1172
1173 let _sec_node = fdt.begin_node("phandle-2").unwrap();
1174 assert_eq!(
1175 fdt.property_phandle(1).unwrap_err(),
1176 Error::DuplicatePhandle
1177 );
1178 }
1179}