fdt_edit/
encode.rs

1//! FDT 编码模块
2//!
3//! 将 Fdt 结构序列化为 DTB 二进制格式
4
5use alloc::{string::String, vec::Vec};
6use core::ops::Deref;
7use fdt_raw::{FDT_MAGIC, Token};
8
9use crate::{Fdt, Node};
10
11/// FDT 二进制数据
12#[derive(Clone, Debug)]
13pub struct FdtData(Vec<u32>);
14
15impl FdtData {
16    /// 获取数据长度(字节)
17    pub fn len(&self) -> usize {
18        self.0.len() * 4
19    }
20
21    /// 数据是否为空
22    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
46/// FDT 编码器
47pub 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    /// 创建新的编码器
56    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    /// 获取或添加字符串,返回偏移量
66    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); // null terminator
76        self.string_offsets.push((s.into(), offset));
77        offset
78    }
79
80    /// 写入 BEGIN_NODE token 和节点名
81    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; // +1 for null
87        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    /// 写入 END_NODE token
99    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    /// 写入属性
105    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    /// 执行编码
127    pub fn encode(mut self) -> FdtData {
128        // 递归编码节点树
129        self.encode_node(&self.fdt.root.clone());
130
131        // 添加 END token
132        let token: u32 = Token::End.into();
133        self.struct_data.push(token.to_be());
134
135        self.finalize()
136    }
137
138    /// 递归编码节点及其子节点
139    fn encode_node(&mut self, node: &Node) {
140        // 写入 BEGIN_NODE 和节点名
141        self.write_begin_node(node.name());
142
143        // 写入所有属性(直接使用原始数据)
144        for prop in node.properties() {
145            self.write_property(prop.name(), &prop.data);
146        }
147
148        // 递归编码子节点
149        for child in node.children() {
150            self.encode_node(child);
151        }
152
153        // 写入 END_NODE
154        self.write_end_node();
155    }
156
157    /// 生成最终 FDT 数据
158    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; // 10 * 4 bytes
163        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        // Header
176        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()); // version
182        data.push(16u32.to_be()); // last_comp_version
183        data.push(boot_cpuid_phys.to_be());
184        data.push(strings_size.to_be());
185        data.push(struct_size.to_be());
186
187        // Memory reservation block
188        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        // Terminator
199        data.push(0);
200        data.push(0);
201        data.push(0);
202        data.push(0);
203
204        // Struct block
205        data.extend_from_slice(&self.struct_data);
206
207        // Strings block
208        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}