Skip to main content

fdt_edit/
encode.rs

1//! FDT 编码模块
2//!
3//! 将 Fdt 结构序列化为 DTB 二进制格式
4
5use alloc::{string::String, vec::Vec};
6use core::ops::Deref;
7
8use fdt_raw::{FDT_MAGIC, Token};
9
10use crate::{Fdt, NodeId};
11
12/// FDT 二进制数据
13#[derive(Clone, Debug)]
14pub struct FdtData(Vec<u32>);
15
16impl FdtData {
17    /// 获取数据长度(字节)
18    pub fn len(&self) -> usize {
19        self.0.len() * 4
20    }
21
22    /// 数据是否为空
23    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
47/// FDT 编码器
48pub 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    /// 创建新的编码器
57    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    /// 获取或添加字符串,返回偏移量
67    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); // null terminator
77        self.string_offsets.push((s.into(), offset));
78        offset
79    }
80
81    /// 写入 BEGIN_NODE token 和节点名
82    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; // +1 for null
88        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    /// 写入 END_NODE token
100    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    /// 写入属性
106    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    /// 执行编码
128    pub fn encode(mut self) -> FdtData {
129        // 从根节点开始递归编码节点树
130        self.encode_node(self.fdt.root_id());
131
132        // 添加 END token
133        let token: u32 = Token::End.into();
134        self.struct_data.push(token.to_be());
135
136        self.finalize()
137    }
138
139    /// 递归编码节点及其子节点(适配 arena 结构)
140    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        // 写入 BEGIN_NODE 和节点名
147        self.write_begin_node(&node.name);
148
149        // 写入所有属性
150        for prop in node.properties() {
151            self.write_property(&prop.name, &prop.data);
152        }
153
154        // 递归编码子节点
155        for &child_id in node.children() {
156            self.encode_node(child_id);
157        }
158
159        // 写入 END_NODE
160        self.write_end_node();
161    }
162
163    /// 生成最终 FDT 数据
164    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; // 10 * 4 bytes
169        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        // Header
182        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()); // version
188        data.push(16u32.to_be()); // last_comp_version
189        data.push(boot_cpuid_phys.to_be());
190        data.push(strings_size.to_be());
191        data.push(struct_size.to_be());
192
193        // Memory reservation block
194        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        // Terminator
205        data.push(0);
206        data.push(0);
207        data.push(0);
208        data.push(0);
209
210        // Struct block
211        data.extend_from_slice(&self.struct_data);
212
213        // Strings block
214        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}