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