1use alloc::{string::String, vec::Vec};
6use core::ops::Deref;
7
8use fdt_raw::{FDT_MAGIC, Token};
9
10use crate::{Fdt, NodeId};
11
12#[derive(Clone, Debug)]
14pub struct FdtData(Vec<u32>);
15
16impl FdtData {
17 pub fn len(&self) -> usize {
19 self.0.len() * 4
20 }
21
22 pub fn is_empty(&self) -> bool {
24 self.0.is_empty()
25 }
26}
27
28impl Deref for FdtData {
29 type Target = [u8];
30
31 fn deref(&self) -> &Self::Target {
32 unsafe {
33 core::slice::from_raw_parts(
34 self.0.as_ptr() as *const u8,
35 self.0.len() * core::mem::size_of::<u32>(),
36 )
37 }
38 }
39}
40
41impl AsRef<[u8]> for FdtData {
42 fn as_ref(&self) -> &[u8] {
43 self
44 }
45}
46
47pub struct FdtEncoder<'a> {
49 fdt: &'a Fdt,
50 struct_data: Vec<u32>,
51 strings_data: Vec<u8>,
52 string_offsets: Vec<(String, u32)>,
53}
54
55impl<'a> FdtEncoder<'a> {
56 pub fn new(fdt: &'a Fdt) -> Self {
58 Self {
59 fdt,
60 struct_data: Vec::new(),
61 strings_data: Vec::new(),
62 string_offsets: Vec::new(),
63 }
64 }
65
66 fn get_or_add_string(&mut self, s: &str) -> u32 {
68 for (existing, offset) in &self.string_offsets {
69 if existing == s {
70 return *offset;
71 }
72 }
73
74 let offset = self.strings_data.len() as u32;
75 self.strings_data.extend_from_slice(s.as_bytes());
76 self.strings_data.push(0); self.string_offsets.push((s.into(), offset));
78 offset
79 }
80
81 fn write_begin_node(&mut self, name: &str) {
83 let begin_token: u32 = Token::BeginNode.into();
84 self.struct_data.push(begin_token.to_be());
85
86 let name_bytes = name.as_bytes();
87 let name_len = name_bytes.len() + 1; let aligned_len = (name_len + 3) & !3;
89
90 let mut name_buf = vec![0u8; aligned_len];
91 name_buf[..name_bytes.len()].copy_from_slice(name_bytes);
92
93 for chunk in name_buf.chunks(4) {
94 let word = u32::from_ne_bytes(chunk.try_into().unwrap());
95 self.struct_data.push(word);
96 }
97 }
98
99 fn write_end_node(&mut self) {
101 let end_token: u32 = Token::EndNode.into();
102 self.struct_data.push(end_token.to_be());
103 }
104
105 fn write_property(&mut self, name: &str, data: &[u8]) {
107 let prop_token: u32 = Token::Prop.into();
108 self.struct_data.push(prop_token.to_be());
109
110 self.struct_data.push((data.len() as u32).to_be());
111
112 let nameoff = self.get_or_add_string(name);
113 self.struct_data.push(nameoff.to_be());
114
115 if !data.is_empty() {
116 let aligned_len = (data.len() + 3) & !3;
117 let mut data_buf = vec![0u8; aligned_len];
118 data_buf[..data.len()].copy_from_slice(data);
119
120 for chunk in data_buf.chunks(4) {
121 let word = u32::from_ne_bytes(chunk.try_into().unwrap());
122 self.struct_data.push(word);
123 }
124 }
125 }
126
127 pub fn encode(mut self) -> FdtData {
129 self.encode_node(self.fdt.root_id());
131
132 let token: u32 = Token::End.into();
134 self.struct_data.push(token.to_be());
135
136 self.finalize()
137 }
138
139 fn encode_node(&mut self, id: NodeId) {
141 let node = match self.fdt.node(id) {
142 Some(n) => n,
143 None => return,
144 };
145
146 self.write_begin_node(&node.name);
148
149 for prop in node.properties() {
151 self.write_property(&prop.name, &prop.data);
152 }
153
154 for &child_id in node.children() {
156 self.encode_node(child_id);
157 }
158
159 self.write_end_node();
161 }
162
163 fn finalize(self) -> FdtData {
165 let memory_reservations = &self.fdt.memory_reservations;
166 let boot_cpuid_phys = self.fdt.boot_cpuid_phys;
167
168 let header_size = 40u32; let mem_rsv_size = ((memory_reservations.len() + 1) * 16) as u32;
170 let struct_size = (self.struct_data.len() * 4) as u32;
171 let strings_size = self.strings_data.len() as u32;
172
173 let off_mem_rsvmap = header_size;
174 let off_dt_struct = off_mem_rsvmap + mem_rsv_size;
175 let off_dt_strings = off_dt_struct + struct_size;
176 let totalsize = off_dt_strings + strings_size;
177 let totalsize_aligned = (totalsize + 3) & !3;
178
179 let mut data = Vec::with_capacity(totalsize_aligned as usize / 4);
180
181 data.push(FDT_MAGIC.to_be());
183 data.push(totalsize_aligned.to_be());
184 data.push(off_dt_struct.to_be());
185 data.push(off_dt_strings.to_be());
186 data.push(off_mem_rsvmap.to_be());
187 data.push(17u32.to_be()); data.push(16u32.to_be()); data.push(boot_cpuid_phys.to_be());
190 data.push(strings_size.to_be());
191 data.push(struct_size.to_be());
192
193 for rsv in memory_reservations {
195 let addr_hi = (rsv.address >> 32) as u32;
196 let addr_lo = rsv.address as u32;
197 let size_hi = (rsv.size >> 32) as u32;
198 let size_lo = rsv.size as u32;
199 data.push(addr_hi.to_be());
200 data.push(addr_lo.to_be());
201 data.push(size_hi.to_be());
202 data.push(size_lo.to_be());
203 }
204 data.push(0);
206 data.push(0);
207 data.push(0);
208 data.push(0);
209
210 data.extend_from_slice(&self.struct_data);
212
213 let strings_aligned_len = (self.strings_data.len() + 3) & !3;
215 let mut strings_buf = vec![0u8; strings_aligned_len];
216 strings_buf[..self.strings_data.len()].copy_from_slice(&self.strings_data);
217
218 for chunk in strings_buf.chunks(4) {
219 let word = u32::from_ne_bytes(chunk.try_into().unwrap());
220 data.push(word);
221 }
222
223 FdtData(data)
224 }
225}