Skip to content

Commit dded18f

Browse files
committed
address review comment
1 parent 2358a49 commit dded18f

1 file changed

Lines changed: 82 additions & 79 deletions

File tree

src/model/writer.rs

Lines changed: 82 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use alloc::collections::btree_map::BTreeMap;
1111
use alloc::string::String;
1212
use alloc::vec::Vec;
1313

14-
use zerocopy::IntoBytes;
14+
use zerocopy::{FromZeros, IntoBytes};
1515

1616
use crate::fdt::{FDT_BEGIN_NODE, FDT_END, FDT_END_NODE, FDT_MAGIC, FDT_PROP, Fdt, FdtHeader};
1717
use crate::memreserve::MemoryReservation;
@@ -22,17 +22,26 @@ const LAST_VERSION: u32 = 17;
2222
const LAST_COMP_VERSION: u32 = 16;
2323

2424
pub(crate) fn to_bytes(tree: &DeviceTree) -> Vec<u8> {
25-
let memory_reservations = write_memory_reservations(&tree.memory_reservations);
26-
let (struct_block, strings_block) = write_root(&tree.root);
25+
let mut dtb = Vec::new();
2726

28-
let off_mem_rsvmap = size_of::<FdtHeader>();
29-
let off_dt_struct = off_mem_rsvmap + memory_reservations.len();
30-
let off_dt_strings = off_dt_struct + struct_block.len();
31-
let totalsize = off_dt_strings + strings_block.len();
27+
// reserve space for header
28+
dtb.extend_from_slice(FdtHeader::new_zeroed().as_bytes());
3229

33-
let mut dtb = Vec::new();
30+
let off_mem_rsvmap = dtb.len();
31+
write_memory_reservations(&mut dtb, &tree.memory_reservations);
32+
33+
let off_dt_struct = dtb.len();
34+
let mut string_map = StringMap::new();
35+
write_root(&mut dtb, &mut string_map, &tree.root);
3436

35-
// Header
37+
let off_dt_strings = dtb.len();
38+
string_map.write_string_block(&mut dtb);
39+
40+
let totalsize = dtb.len();
41+
let size_dt_strings = totalsize - off_dt_strings;
42+
let size_dt_struct = off_dt_strings - off_dt_struct;
43+
44+
// write header
3645
let header = FdtHeader {
3746
magic: FDT_MAGIC.into(),
3847
totalsize: u32::try_from(totalsize)
@@ -50,110 +59,104 @@ pub(crate) fn to_bytes(tree: &DeviceTree) -> Vec<u8> {
5059
version: LAST_VERSION.into(),
5160
last_comp_version: LAST_COMP_VERSION.into(),
5261
boot_cpuid_phys: 0u32.into(),
53-
size_dt_strings: u32::try_from(strings_block.len())
62+
size_dt_strings: u32::try_from(size_dt_strings)
5463
.expect("size_dt_strings exceeds u32")
5564
.into(),
56-
size_dt_struct: u32::try_from(struct_block.len())
65+
size_dt_struct: u32::try_from(size_dt_struct)
5766
.expect("size_dt_struct exceeds u32")
5867
.into(),
5968
};
60-
dtb.extend_from_slice(header.as_bytes());
61-
assert_eq!(
62-
dtb.len(),
63-
size_of::<FdtHeader>(),
64-
"invalid header size after writing"
65-
);
6669

67-
// Memory reservations block
68-
dtb.extend_from_slice(&memory_reservations);
69-
70-
// Struct block
71-
dtb.extend_from_slice(&struct_block);
72-
73-
// Strings block
74-
dtb.extend_from_slice(&strings_block);
70+
dtb[..size_of::<FdtHeader>()].copy_from_slice(header.as_bytes());
7571

7672
dtb
7773
}
7874

79-
fn write_memory_reservations(reservations: &[MemoryReservation]) -> Vec<u8> {
80-
let mut memory_reservations = Vec::new();
75+
fn write_memory_reservations(dtb: &mut Vec<u8>, reservations: &[MemoryReservation]) {
8176
for reservation in reservations {
82-
memory_reservations.extend_from_slice(&reservation.address().to_be_bytes());
83-
memory_reservations.extend_from_slice(&reservation.size().to_be_bytes());
77+
dtb.extend_from_slice(&reservation.address().to_be_bytes());
78+
dtb.extend_from_slice(&reservation.size().to_be_bytes());
8479
}
85-
memory_reservations.extend_from_slice(&0u64.to_be_bytes());
86-
memory_reservations.extend_from_slice(&0u64.to_be_bytes());
87-
memory_reservations
80+
dtb.extend_from_slice(&0u64.to_be_bytes());
81+
dtb.extend_from_slice(&0u64.to_be_bytes());
8882
}
8983

90-
fn write_root(root_node: &DeviceTreeNode) -> (Vec<u8>, Vec<u8>) {
91-
let mut struct_block = Vec::new();
92-
let mut strings_block = Vec::new();
93-
let mut string_map = BTreeMap::new();
94-
95-
write_node(
96-
&mut struct_block,
97-
&mut strings_block,
98-
&mut string_map,
99-
root_node,
100-
);
101-
struct_block.extend_from_slice(&FDT_END.to_be_bytes());
102-
103-
(struct_block, strings_block)
84+
fn write_root(dtb: &mut Vec<u8>, string_map: &mut StringMap, root_node: &DeviceTreeNode) {
85+
write_node(dtb, string_map, root_node);
86+
dtb.extend_from_slice(&FDT_END.to_be_bytes());
10487
}
10588

106-
fn write_node(
107-
struct_block: &mut Vec<u8>,
108-
strings_block: &mut Vec<u8>,
109-
string_map: &mut BTreeMap<String, u32>,
110-
node: &DeviceTreeNode,
111-
) {
112-
struct_block.extend_from_slice(&FDT_BEGIN_NODE.to_be_bytes());
113-
struct_block.extend_from_slice(node.name().as_bytes());
114-
struct_block.push(0);
115-
align(struct_block);
89+
fn write_node(dtb: &mut Vec<u8>, string_map: &mut StringMap, node: &DeviceTreeNode) {
90+
dtb.extend_from_slice(&FDT_BEGIN_NODE.to_be_bytes());
91+
dtb.extend_from_slice(node.name().as_bytes());
92+
dtb.push(0);
93+
align(dtb);
11694

11795
for prop in node.properties() {
118-
write_prop(struct_block, strings_block, string_map, prop);
96+
write_prop(dtb, string_map, prop);
11997
}
12098

12199
for child in node.children() {
122-
write_node(struct_block, strings_block, string_map, child);
100+
write_node(dtb, string_map, child);
123101
}
124102

125-
struct_block.extend_from_slice(&FDT_END_NODE.to_be_bytes());
103+
dtb.extend_from_slice(&FDT_END_NODE.to_be_bytes());
126104
}
127105

128-
fn write_prop(
129-
struct_block: &mut Vec<u8>,
130-
strings_block: &mut Vec<u8>,
131-
string_map: &mut BTreeMap<String, u32>,
132-
prop: &DeviceTreeProperty,
133-
) {
134-
let name_offset = if let Some(offset) = string_map.get(prop.name()) {
135-
*offset
136-
} else {
137-
let offset = u32::try_from(strings_block.len()).expect("string block length exceeds u32");
138-
strings_block.extend_from_slice(prop.name().as_bytes());
139-
strings_block.push(0);
140-
string_map.insert(prop.name().to_owned(), offset);
141-
offset
142-
};
106+
fn write_prop(dtb: &mut Vec<u8>, string_map: &mut StringMap, prop: &DeviceTreeProperty) {
107+
let name_offset = string_map.get_offset(prop.name());
143108

144-
struct_block.extend_from_slice(&FDT_PROP.to_be_bytes());
145-
struct_block.extend_from_slice(
109+
dtb.extend_from_slice(&FDT_PROP.to_be_bytes());
110+
dtb.extend_from_slice(
146111
&u32::try_from(prop.value().len())
147112
.expect("property value length exceeds u32")
148113
.to_be_bytes(),
149114
);
150-
struct_block.extend_from_slice(&name_offset.to_be_bytes());
151-
struct_block.extend_from_slice(prop.value());
152-
align(struct_block);
115+
dtb.extend_from_slice(&name_offset.to_be_bytes());
116+
dtb.extend_from_slice(prop.value());
117+
align(dtb);
153118
}
154119

155120
fn align(vec: &mut Vec<u8>) {
156121
let len = vec.len();
157122
let new_len = Fdt::align_tag_offset(len);
158123
vec.resize(new_len, 0);
159124
}
125+
126+
struct StringMap {
127+
string_map: BTreeMap<String, u32>,
128+
next_offset: u32,
129+
}
130+
131+
impl StringMap {
132+
fn new() -> Self {
133+
Self {
134+
string_map: BTreeMap::new(),
135+
next_offset: 0,
136+
}
137+
}
138+
139+
fn get_offset(&mut self, key: &str) -> u32 {
140+
if let Some(&offset) = self.string_map.get(key) {
141+
offset
142+
} else {
143+
let offset = self.next_offset;
144+
self.string_map.insert(key.to_owned(), offset);
145+
self.next_offset = u32::try_from(self.next_offset as usize + key.len() + 1)
146+
.expect("string block length exceeds u32");
147+
offset
148+
}
149+
}
150+
151+
fn write_string_block(self, dtb: &mut Vec<u8>) {
152+
// write the strings in the order when they appear, mimicking the behavior
153+
// of `dtc` (Device Tree Compiler)
154+
let mut items: Vec<_> = self.string_map.into_iter().collect();
155+
items.sort_unstable_by_key(|(_s, offset)| *offset);
156+
157+
for (s, _offset) in items {
158+
dtb.extend_from_slice(s.as_bytes());
159+
dtb.push(0);
160+
}
161+
}
162+
}

0 commit comments

Comments
 (0)