|
1 | 1 | # fdt-edit |
2 | 2 |
|
3 | | -用于创建、编辑和编码设备树(FDT)的高级 Rust 库。 |
| 3 | +A high-level Rust library for creating, editing, and encoding Flattened Device Tree (FDT) structures. |
4 | 4 |
|
5 | | -## 概述 |
| 5 | +## Overview |
6 | 6 |
|
7 | | -`fdt-edit` 是一个功能丰富的设备树操作库,基于 `fdt-raw` 构建,提供了完整的设备树创建、编辑和编码功能。该库支持从零创建新的设备树,修改现有的设备树,以及将编辑后的设备树编码为标准 DTB 格式。 |
| 7 | +`fdt-edit` is a feature-rich device tree manipulation library built on top of `fdt-raw`. It provides comprehensive functionality for creating new device trees from scratch, modifying existing device trees, and encoding the edited device trees into standard DTB format. |
8 | 8 |
|
9 | | -## 特性 |
| 9 | +## Features |
10 | 10 |
|
11 | | -- **完整的设备树编辑**:支持节点和属性的增删改查 |
12 | | -- **类型安全的节点操作**:提供专门的节点类型(时钟、内存、PCI、中断控制器等) |
13 | | -- **高效的编码器**:将内存中的设备树结构编码为标准 DTB 格式 |
14 | | -- **phandle 管理**:自动 phandle 分配和引用管理 |
15 | | -- **内存保留块支持**:完整的内存保留区域操作 |
16 | | -- **`no_std` 兼容**:适用于嵌入式环境 |
| 11 | +- **Complete device tree editing**: Full CRUD operations for nodes and properties |
| 12 | +- **Type-safe node operations**: Specialized node types (clocks, memory, PCI, interrupt controllers, etc.) |
| 13 | +- **Efficient encoder**: Converts in-memory device tree structures to standard DTB format |
| 14 | +- **phandle management**: Automatic phandle allocation and reference management |
| 15 | +- **Memory reservation support**: Complete memory reservation region operations |
| 16 | +- **`no_std` compatible**: Suitable for embedded environments |
17 | 17 |
|
18 | | -## 核心组件 |
| 18 | +## Core Components |
19 | 19 |
|
20 | | -### Fdt 结构 |
21 | | -可编辑的设备树容器: |
22 | | -- 从原始 DTB 数据解析 |
23 | | -- 创建新的空设备树 |
24 | | -- 管理 phandle 缓存 |
25 | | -- 编码为 DTB 格式 |
| 20 | +### Fdt Structure |
| 21 | +An editable device tree container that: |
| 22 | +- Parses from raw DTB data |
| 23 | +- Creates new empty device trees |
| 24 | +- Manages phandle cache |
| 25 | +- Encodes to DTB format |
26 | 26 |
|
27 | | -### 节点系统 |
28 | | -支持多种专用节点类型: |
29 | | -- **时钟节点**:时钟源和时钟消费者 |
30 | | -- **内存节点**:内存区域定义 |
31 | | -- **PCI 节点**:PCI 总线和设备 |
32 | | -- **中断控制器**:中断映射和管理 |
33 | | -- **通用节点**:可自定义的节点类型 |
| 27 | +### Node System |
| 28 | +Supports multiple specialized node types: |
| 29 | +- **Clock nodes**: Clock sources and clock consumers |
| 30 | +- **Memory nodes**: Memory region definitions |
| 31 | +- **PCI nodes**: PCI buses and devices |
| 32 | +- **Interrupt controllers**: Interrupt mapping and management |
| 33 | +- **Generic nodes**: Customizable node types |
34 | 34 |
|
35 | | -### 属性系统 |
36 | | -- **强类型属性**:各种数据类型的属性支持 |
37 | | -- **自动属性管理**:智能的属性增删改查 |
38 | | -- **格式化显示**:友好的节点和属性显示 |
| 35 | +### Property System |
| 36 | +- **Type-safe properties**: Support for various data types |
| 37 | +- **Automatic property management**: Intelligent property CRUD operations |
| 38 | +- **Formatted display**: Friendly node and property display |
39 | 39 |
|
40 | | -## 快速开始 |
| 40 | +## Quick Start |
41 | 41 |
|
42 | 42 | ```rust |
43 | | -use fdt_edit::{Fdt, Node, NodeKind}; |
44 | | - |
45 | | -// 创建新的空设备树 |
46 | | -let mut fdt = Fdt::new(); |
47 | | - |
48 | | -// 添加根节点下的子节点 |
49 | | -let memory_node = fdt.root_mut() |
50 | | - .add_child("memory@80000000") |
51 | | - .unwrap(); |
52 | | -memory_node.add_property("device_type", "memory")?; |
53 | | -memory_node.add_property("reg", &[0x8000_0000u64, 0x1000_0000u64])?; |
54 | | - |
55 | | -// 添加时钟节点 |
56 | | -let clock_node = fdt.root_mut() |
57 | | - .add_child("clk_osc") |
58 | | - .unwrap(); |
59 | | -clock_node.add_property("compatible", &["fixed-clock"])?; |
60 | | -clock_node.add_property("#clock-cells", &[0u32])?; |
61 | | -clock_node.add_property("clock-frequency", &[24_000_000u32])?; |
62 | | - |
63 | | -// 编码为 DTB 数据 |
64 | | -let dtb_data = fdt.encode()?; |
65 | | -``` |
66 | | - |
67 | | -### 从现有 DTB 编辑 |
| 43 | +use fdt_edit::Fdt; |
68 | 44 |
|
69 | | -```rust |
70 | | -// 解析现有 DTB |
71 | | -let mut fdt = Fdt::from_bytes(&existing_dtb)?; |
| 45 | +// Parse existing DTB from bytes |
| 46 | +let raw_data = include_bytes!("path/to/device-tree.dtb"); |
| 47 | +let fdt = Fdt::from_bytes(&raw_data)?; |
72 | 48 |
|
73 | | -// 查找并修改节点 |
74 | | -if let Some(cpu_node) = fdt.root_mut() |
75 | | - .find_child_mut("cpus")? |
76 | | - .and_then(|n| n.find_child_mut("cpu@0")) { |
77 | | - |
78 | | - // 修改时钟频率 |
79 | | - cpu_node.set_property("clock-frequency", &[1_200_000_000u32])?; |
| 49 | +// Access nodes by path |
| 50 | +let node = fdt.get_by_path("/chosen"); |
| 51 | +if let Some(chosen) = node { |
| 52 | + println!("Found chosen node: {}", chosen.name()); |
80 | 53 | } |
81 | 54 |
|
82 | | -// 添加新的属性 |
83 | | -cpu_node.add_property("new-property", "value")?; |
84 | | - |
85 | | -// 重新编码 |
86 | | -let modified_dtb = fdt.encode()?; |
| 55 | +// Encode back to DTB format |
| 56 | +let dtb_data = fdt.encode(); |
| 57 | +std::fs::write("output.dtb", dtb_data.as_bytes())?; |
87 | 58 | ``` |
88 | 59 |
|
89 | | -### 节点遍历和查找 |
| 60 | +### Node Traversal and Searching |
90 | 61 |
|
91 | 62 | ```rust |
92 | | -// 遍历所有节点 |
93 | | -for node in fdt.root().traverse() { |
94 | | - match node.kind() { |
| 63 | +use fdt_edit::{Fdt, NodeKind}; |
| 64 | + |
| 65 | +let fdt = Fdt::from_bytes(&dtb_data)?; |
| 66 | + |
| 67 | +// Iterate through all nodes |
| 68 | +for node in fdt.all_nodes() { |
| 69 | + println!("Node: {} at path {}", node.name(), node.path()); |
| 70 | + |
| 71 | + // Match specialized node types |
| 72 | + match node.as_ref() { |
95 | 73 | NodeKind::Memory(mem) => { |
96 | | - println!("Memory node: {:x?}", mem.regions()); |
| 74 | + println!(" Memory node with regions:"); |
| 75 | + for region in mem.regions() { |
| 76 | + println!(" address=0x{:x}, size=0x{:x}", region.address, region.size); |
| 77 | + } |
97 | 78 | } |
98 | 79 | NodeKind::Clock(clock) => { |
99 | | - println!("Clock: {}, freq: {}", clock.name(), clock.frequency()?); |
| 80 | + println!(" Clock node: {} (#clock-cells={})", clock.name(), clock.clock_cells); |
| 81 | + } |
| 82 | + NodeKind::Pci(pci) => { |
| 83 | + if let Some(range) = pci.bus_range() { |
| 84 | + println!(" PCI bus range: {:?}", range); |
| 85 | + } |
100 | 86 | } |
101 | 87 | _ => { |
102 | | - println!("Generic node: {}", node.name()); |
| 88 | + println!(" Generic node"); |
| 89 | + } |
| 90 | + } |
| 91 | +} |
| 92 | + |
| 93 | +// Find nodes by path pattern |
| 94 | +let virtio_nodes: Vec<_> = fdt.find_by_path("/virtio_mmio").collect(); |
| 95 | +println!("Found {} virtio_mmio nodes", virtio_nodes.len()); |
| 96 | +``` |
| 97 | + |
| 98 | +### Node Modification and Creation |
| 99 | + |
| 100 | +```rust |
| 101 | +use fdt_edit::{Fdt, Node}; |
| 102 | + |
| 103 | +let mut fdt = Fdt::from_bytes(&dtb_data)?; |
| 104 | + |
| 105 | +// Create new node manually |
| 106 | +let mut new_node = Node::new("test-device@12340000"); |
| 107 | +// Add properties (API in development) |
| 108 | +// new_node.add_property("compatible", &["vendor,test-device"]); |
| 109 | +// new_node.add_property("reg", &[0x12340000u64, 0x1000u64]); |
| 110 | + |
| 111 | +// Add to root node |
| 112 | +fdt.root.add_child(new_node); |
| 113 | + |
| 114 | +// Remove existing node |
| 115 | +if fdt.get_by_path("/psci").is_some() { |
| 116 | + let removed = fdt.remove_node("/psci")?; |
| 117 | + println!("Removed psci node: {}", removed.unwrap().name()); |
| 118 | +} |
| 119 | + |
| 120 | +// Save the modified device tree |
| 121 | +let modified_dtb = fdt.encode(); |
| 122 | +std::fs::write("modified.dtb", modified_dtb.as_bytes())?; |
| 123 | +``` |
| 124 | + |
| 125 | +### Specialized Node Access |
| 126 | + |
| 127 | +```rust |
| 128 | +use fdt_edit::{Fdt, NodeKind}; |
| 129 | + |
| 130 | +let fdt = Fdt::from_bytes(&dtb_data)?; |
| 131 | + |
| 132 | +// Find and work with memory nodes |
| 133 | +for node in fdt.all_nodes() { |
| 134 | + if let NodeKind::Memory(mem) = node.as_ref() { |
| 135 | + let regions = mem.regions(); |
| 136 | + if !regions.is_empty() { |
| 137 | + println!("Memory node '{}' has {} regions:", mem.name(), regions.len()); |
| 138 | + for (i, region) in regions.iter().enumerate() { |
| 139 | + println!(" Region {}: 0x{:x}-0x{:x}", i, region.address, region.address + region.size); |
| 140 | + } |
103 | 141 | } |
104 | 142 | } |
105 | 143 | } |
106 | 144 |
|
107 | | -// 查找特定节点 |
108 | | -if let Some(chosen) = fdt.root().find_child("chosen") { |
109 | | - if let Some(bootargs) = chosen.get_property("bootargs") { |
110 | | - println!("Boot args: {}", bootargs.as_str()?); |
| 145 | +// Find clock nodes |
| 146 | +let mut clock_count = 0; |
| 147 | +for node in fdt.all_nodes() { |
| 148 | + if let NodeKind::Clock(clock) = node.as_ref() { |
| 149 | + clock_count += 1; |
| 150 | + println!("Clock {}: cells={}, output-names={:?}", |
| 151 | + clock.name(), |
| 152 | + clock.clock_cells, |
| 153 | + clock.clock_output_names); |
111 | 154 | } |
112 | 155 | } |
113 | 156 | ``` |
114 | 157 |
|
115 | | -## 依赖 |
| 158 | +### Display as Device Tree Source |
116 | 159 |
|
117 | | -- `fdt-raw` - 底层 FDT 解析库 |
118 | | -- `log = "0.4"` - 日志记录 |
119 | | -- `enum_dispatch = "0.3.13"` - 枚举分发优化 |
| 160 | +```rust |
| 161 | +use fdt_edit::Fdt; |
| 162 | + |
| 163 | +let fdt = Fdt::from_bytes(&dtb_data)?; |
| 164 | + |
| 165 | +// Display as DTS format (including memory reservations) |
| 166 | +println!("{}", fdt); |
| 167 | +// Output will show: |
| 168 | +// /dts-v1/; |
| 169 | +// /memreserve/ 0x80000000 0x100000; |
| 170 | +// / { |
| 171 | +// #address-cells = <0x2>; |
| 172 | +// #size-cells = <0x2>; |
| 173 | +// compatible = "qemu,arm64"; |
| 174 | +// ... |
| 175 | +// }; |
| 176 | +``` |
120 | 177 |
|
121 | | -## 开发依赖 |
| 178 | +## Current Status |
| 179 | + |
| 180 | +This library is under active development. Currently supported features: |
| 181 | +- ✅ Parse DTB files into editable structures |
| 182 | +- ✅ Encode device trees back to DTB format |
| 183 | +- ✅ Display device trees in DTS format |
| 184 | +- ✅ Access to memory reservations |
| 185 | +- 🚧 Node editing APIs (in development) |
| 186 | + |
| 187 | +## Dependencies |
| 188 | + |
| 189 | +- `fdt-raw` - Low-level FDT parsing library |
| 190 | +- `log = "0.4"` - Logging support |
| 191 | +- `enum_dispatch = "0.3.13"` - Enum dispatch optimization |
| 192 | + |
| 193 | +## Dev Dependencies |
| 194 | + |
| 195 | +- `dtb-file` - Test data |
| 196 | +- `env_logger = "0.11"` - Logger implementation |
| 197 | + |
| 198 | +## Testing |
| 199 | + |
| 200 | +The library includes comprehensive tests that verify round-trip compatibility: |
| 201 | + |
| 202 | +```bash |
| 203 | +cargo test |
| 204 | +``` |
122 | 205 |
|
123 | | -- `dtb-file` - 测试数据 |
124 | | -- `env_logger = "0.11"` - 日志实现 |
| 206 | +The main test (`test_parse_and_rebuild`) ensures that: |
| 207 | +1. A DTB file can be parsed successfully |
| 208 | +2. The parsed structure can be encoded back to DTB |
| 209 | +3. The original and rebuilt DTB files produce identical DTS output when using `dtc` |
125 | 210 |
|
126 | | -## 许可证 |
| 211 | +## License |
127 | 212 |
|
128 | | -本项目采用开源许可证,具体许可证类型请查看项目根目录的 LICENSE 文件。 |
| 213 | +This project is licensed under open source licenses. Please see the LICENSE file in the project root for specific license types. |
129 | 214 |
|
130 | | -## 贡献 |
| 215 | +## Contributing |
131 | 216 |
|
132 | | -欢迎提交 Issue 和 Pull Request。请确保: |
| 217 | +Issues and Pull Requests are welcome. Please ensure: |
133 | 218 |
|
134 | | -1. 代码遵循项目的格式规范(`cargo fmt`) |
135 | | -2. 通过所有测试(`cargo test`) |
136 | | -3. 通过 Clippy 检查(`cargo clippy`) |
137 | | -4. 新功能添加相应的测试用例 |
| 219 | +1. Code follows the project's formatting standards (`cargo fmt`) |
| 220 | +2. All tests pass (`cargo test`) |
| 221 | +3. Clippy checks pass (`cargo clippy`) |
| 222 | +4. New features include appropriate test cases |
138 | 223 |
|
139 | | -## 相关项目 |
| 224 | +## Related Projects |
140 | 225 |
|
141 | | -- [fdt-raw](../fdt-raw/) - 底层 FDT 解析库 |
142 | | -- [fdt-parser](../fdt-parser/) - 高级缓存式 FDT 解析器 |
143 | | -- [dtb-tool](../dtb-tool/) - DTB 文件检查工具 |
144 | | -- [dtb-file](../dtb-file/) - 测试数据包 |
| 226 | +- [fdt-raw](../fdt-raw/) - Low-level FDT parsing library |
| 227 | +- [fdt-parser](../fdt-parser/) - High-level cached FDT parser |
| 228 | +- [dtb-tool](../dtb-tool/) - DTB file inspection tool |
| 229 | +- [dtb-file](../dtb-file/) - Test data package |
145 | 230 |
|
146 | | -## 示例 |
| 231 | +## Examples |
147 | 232 |
|
148 | | -更多使用示例请查看 `examples/` 目录(如果存在)或源码中的测试用例。 |
| 233 | +More usage examples can be found in the source code test files, particularly in `tests/edit.rs`. |
0 commit comments