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