dtb_walker/
header.rs

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        // 检查整体对齐
51        if !is_aligned(self as *const _ as _, DTB_ALIGN_BITS) {
52            check(&filter, E::Misaligned(misaligned(self as *const _ as _)))?;
53        }
54        // 检查 magic 和版本
55        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        // 检查结构
68        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        // 保留内存块
74        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        // 结构块
89        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        // 字符串块
129        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}