1use core::ops::Range;
2
3use crate::{is_aligned, U32BigEndian};
4
5pub(crate) struct FdtHeader {
6 magic: U32BigEndian,
7 pub totalsize: U32BigEndian,
8 pub off_dt_struct: U32BigEndian,
9 pub off_dt_strings: U32BigEndian,
10 pub off_mem_rsvmap: U32BigEndian,
11 pub version: U32BigEndian,
12 pub last_comp_version: U32BigEndian,
13 #[allow(unused)]
14 pub boot_cpuid_phys: U32BigEndian,
15 pub size_dt_strings: U32BigEndian,
16 pub size_dt_struct: U32BigEndian,
17}
18
19#[derive(Debug)]
20pub enum HeaderError {
21 Misaligned(u32),
22 Magic(u32),
23 Version(u32),
24 LastCompVersion(u32),
25 TotalSize(u32),
26 StructMisaligned(u32),
27 StructOffset { value: u32, expected: Range<u32> },
28 StructSize { value: u32, max: u32 },
29 StructContent,
30 MemRsvMisaligned(u32),
31 MemRsvOffset { value: u32, expected: Range<u32> },
32 StringsOffset { value: u32, expected: Range<u32> },
33 StringsSize { value: u32, max: u32 },
34}
35
36const FOUR: usize = 4;
37const DTB_ALIGN_BITS: usize = 8;
38const MEMREV_ALIGN_BITS: usize = FOUR;
39const STRUCT_ALIGN_BITS: usize = FOUR;
40const STRUCT_SIZE_ALIGN_BITS: usize = FOUR;
41
42const MAGIC: U32BigEndian = U32BigEndian::from_u32(0xd00dfeed);
43const VERSION: u32 = 17;
44const LAST_COMP_VERSION: u32 = 16;
45const LEN_HEADER: u32 = core::mem::size_of::<FdtHeader>() as _;
46
47impl FdtHeader {
48 pub fn verify(&self, filter: impl Fn(&HeaderError) -> bool) -> Result<(), HeaderError> {
49 use HeaderError as E;
50 if !is_aligned(self as *const _ as _, DTB_ALIGN_BITS) {
52 check(&filter, E::Misaligned(misaligned(self as *const _ as _)))?;
53 }
54 if self.magic != MAGIC {
56 check(&filter, E::Magic(self.magic.into_u32()))?;
57 }
58 if self.version.into_u32() < VERSION {
59 check(&filter, E::Version(self.version.into_u32()))?;
60 }
61 if self.last_comp_version.into_u32() != LAST_COMP_VERSION {
62 check(
63 &filter,
64 E::LastCompVersion(self.last_comp_version.into_u32()),
65 )?;
66 }
67 let len_total = self.totalsize.into_u32();
69 if len_total < LEN_HEADER {
70 check(&filter, E::TotalSize(len_total))?;
71 }
72 let mut range = LEN_HEADER..len_total;
73 let off_memrev = self.off_mem_rsvmap.into_u32();
75 if !is_aligned(off_memrev as _, MEMREV_ALIGN_BITS) {
76 check(&filter, E::MemRsvMisaligned(misaligned(off_memrev)))?;
77 }
78 if !range.contains(&off_memrev) {
79 check(
80 &filter,
81 E::MemRsvOffset {
82 value: off_memrev,
83 expected: range.clone(),
84 },
85 )?;
86 }
87 range = off_memrev..len_total;
88 let off_struct = self.off_dt_struct.into_u32();
90 if !is_aligned(off_struct as _, STRUCT_ALIGN_BITS) {
91 check(&filter, E::StructMisaligned(misaligned(off_struct)))?;
92 }
93 if !range.contains(&off_struct) {
94 check(
95 &filter,
96 E::StructOffset {
97 value: off_struct,
98 expected: range.clone(),
99 },
100 )?;
101 }
102 let len_struct = self.size_dt_struct.into_u32();
103 if !is_aligned(len_struct as _, STRUCT_SIZE_ALIGN_BITS) {
104 check(&filter, E::StructMisaligned(misaligned(len_struct)))?;
105 }
106 if len_struct > range.len() as u32 {
107 check(
108 &filter,
109 E::StructSize {
110 value: len_struct,
111 max: range.len() as _,
112 },
113 )?;
114 }
115 unsafe {
116 use crate::StructureBlock as Blk;
117 match core::slice::from_raw_parts(
118 (self as *const _ as *const u8)
119 .offset(off_struct as _)
120 .cast::<Blk>(),
121 len_struct as usize / Blk::LEN,
122 ) {
123 [Blk::NODE_BEGIN, Blk::EMPTY_STR, .., Blk::END] => {}
124 _ => check(&filter, E::StructContent)?,
125 }
126 }
127 range = off_struct + len_struct..len_total;
128 let off_strings = self.off_dt_strings.into_u32();
130 if !range.contains(&off_strings) {
131 check(
132 &filter,
133 E::StringsOffset {
134 value: off_strings,
135 expected: range.clone(),
136 },
137 )?;
138 }
139 let len_strings = self.size_dt_strings.into_u32();
140 if len_strings > range.len() as u32 {
141 check(
142 filter,
143 E::StringsSize {
144 value: len_strings,
145 max: range.len() as _,
146 },
147 )?;
148 }
149 Ok(())
150 }
151}
152
153#[inline]
154fn misaligned(addr: u32) -> u32 {
155 1 << addr.trailing_zeros()
156}
157
158#[inline]
159fn check(filter: impl Fn(&HeaderError) -> bool, err: HeaderError) -> Result<(), HeaderError> {
160 if filter(&err) {
161 Ok(())
162 } else {
163 Err(err)
164 }
165}