Skip to content

Commit 35696e6

Browse files
committed
feat: 实现设备地址到CPU物理地址的转换功能,优化节点结构,更新版本号至0.1.2
1 parent 7f6ab2b commit 35696e6

File tree

5 files changed

+120
-21
lines changed

5 files changed

+120
-21
lines changed

fdt-edit/src/node/mod.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,21 +86,22 @@ impl Node {
8686
}
8787

8888
pub fn get_child(&self, name: &str) -> Option<&Node> {
89-
if let Some(&index) = self.name_cache.get(name) {
90-
if let Some(child) = self.children.get(index) {
91-
return Some(child);
92-
}
89+
if let Some(&index) = self.name_cache.get(name)
90+
&& let Some(child) = self.children.get(index)
91+
{
92+
return Some(child);
9393
}
9494

9595
// Fallback if the cache is stale
9696
self.children.iter().find(|c| c.name == name)
9797
}
9898

9999
pub fn get_child_mut(&mut self, name: &str) -> Option<&mut Node> {
100-
if let Some(&index) = self.name_cache.get(name) {
101-
if index < self.children.len() && self.children[index].name == name {
102-
return self.children.get_mut(index);
103-
}
100+
if let Some(&index) = self.name_cache.get(name)
101+
&& index < self.children.len()
102+
&& self.children[index].name == name
103+
{
104+
return self.children.get_mut(index);
104105
}
105106

106107
// Cache miss or mismatch: search and rebuild cache to keep indices in sync
@@ -117,7 +118,7 @@ impl Node {
117118
.filter(|&idx| self.children.get(idx).map(|c| c.name.as_str()) == Some(name))
118119
.or_else(|| self.children.iter().position(|c| c.name == name));
119120

120-
let Some(idx) = index else { return None };
121+
let idx = index?;
121122

122123
let removed = self.children.remove(idx);
123124
self.rebuild_name_cache();

fdt-raw/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ name = "fdt-raw"
1111
readme = "README.md"
1212
homepage = "https://github.com/drivercraft/fdt-parser"
1313
repository = "https://github.com/drivercraft/fdt-parser"
14-
version = "0.1.1"
14+
version = "0.1.2"
1515

1616
[dependencies]
1717
heapless = "0.9"

fdt-raw/src/fdt.rs

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,94 @@ impl<'a> Fdt<'a> {
135135
}
136136
}
137137

138+
/// Translate device address to CPU physical address.
139+
///
140+
/// This function implements address translation similar to Linux's of_translate_address.
141+
/// It walks up the device tree hierarchy, applying each parent's ranges property to
142+
/// translate the child address space to parent address space, ultimately obtaining
143+
/// the CPU physical address.
144+
///
145+
/// # Arguments
146+
/// * `path` - Node path (absolute path starting with '/' or alias name)
147+
/// * `address` - Device address from the node's reg property
148+
///
149+
/// # Returns
150+
/// The translated CPU physical address. If translation fails, returns the original address.
138151
pub fn translate_address(&self, path: &'a str, address: u64) -> u64 {
139152
let path = match self.normalize_path(path) {
140153
Some(p) => p,
141154
None => return address,
142155
};
143-
let split = path.trim_matches('/').split('/');
156+
157+
// 分割路径为各级节点名称
158+
let path_parts: heapless::Vec<&str, 16> = path
159+
.trim_matches('/')
160+
.split('/')
161+
.filter(|s| !s.is_empty())
162+
.collect();
163+
164+
if path_parts.is_empty() {
165+
return address;
166+
}
167+
144168
let mut current_address = address;
145-
146-
169+
170+
// 从最深层的节点向上遍历,对每一层应用 ranges 转换
171+
// 注意:我们需要从倒数第二层开始(因为最后一层是目标节点本身)
172+
for depth in (0..path_parts.len()).rev() {
173+
// 构建到当前层的路径
174+
let parent_parts = &path_parts[..depth];
175+
if parent_parts.is_empty() {
176+
// 已经到达根节点,不需要继续转换
177+
break;
178+
}
179+
180+
// 查找父节点
181+
let mut parent_path = heapless::String::<256>::new();
182+
parent_path.push('/').ok();
183+
for (i, part) in parent_parts.iter().enumerate() {
184+
if i > 0 {
185+
parent_path.push('/').ok();
186+
}
187+
parent_path.push_str(part).ok();
188+
}
189+
190+
let parent_node = match self.find_by_path(parent_path.as_str()) {
191+
Some(node) => node,
192+
None => continue,
193+
};
194+
195+
// 获取父节点的 ranges 属性
196+
let ranges = match parent_node.ranges() {
197+
Some(r) => r,
198+
None => {
199+
// 没有 ranges 属性,停止转换
200+
break;
201+
}
202+
};
203+
204+
// 在 ranges 中查找匹配的转换规则
205+
let mut found = false;
206+
for range in ranges.iter() {
207+
// 检查地址是否在当前 range 的范围内
208+
if current_address >= range.child_address
209+
&& current_address < range.child_address + range.length
210+
{
211+
// 计算在 child address space 中的偏移
212+
let offset = current_address - range.child_address;
213+
// 转换到 parent address space
214+
current_address = range.parent_address + offset;
215+
found = true;
216+
break;
217+
}
218+
}
219+
220+
if !found {
221+
// 如果在 ranges 中没有找到匹配项,保持当前地址不变
222+
// 这通常意味着地址转换失败,但我们继续尝试上层
223+
}
224+
}
225+
147226
current_address
148227
}
149228

fdt-raw/src/node/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub struct NodeBase<'a> {
4141
data: Bytes<'a>,
4242
strings: Bytes<'a>,
4343
level: usize,
44-
fdt: Fdt<'a>,
44+
_fdt: Fdt<'a>,
4545
/// 当前节点的 #address-cells(用于子节点)
4646
pub address_cells: u8,
4747
/// 当前节点的 #size-cells(用于子节点)
@@ -275,7 +275,7 @@ impl<'a> OneNodeIter<'a> {
275275
address_cells: 2,
276276
size_cells: 1,
277277
context: self.context.clone(),
278-
fdt: self.fdt.clone(),
278+
_fdt: self.fdt.clone(),
279279
})
280280
}
281281

fdt-raw/tests/ranges.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::sync::Once;
22

3-
use dtb_file::{fdt_qemu, fdt_rpi_4b};
3+
use dtb_file::fdt_rpi_4b;
44
use fdt_raw::Fdt;
55

66
fn init_logging() {
@@ -29,10 +29,29 @@ fn test_ranges() {
2929
}
3030

3131
#[test]
32-
fn test_memory() {
33-
init_logging();
34-
let raw = fdt_qemu();
32+
fn test_reg() {
33+
let raw = fdt_rpi_4b();
3534
let fdt = Fdt::from_bytes(&raw).unwrap();
36-
let memory = fdt.memory().unwrap();
37-
println!("Memory node: {:#x?}", memory);
35+
36+
let path = "/soc/serial@7e215040";
37+
38+
let node = fdt.find_by_path(path).unwrap();
39+
40+
let reg = node.reg().unwrap().next().unwrap();
41+
println!("reg: {:#x?}", reg);
42+
let child_bus_address = reg.address;
43+
let address = fdt.translate_address(path, child_bus_address);
44+
45+
assert_eq!(address, 0xfe215040, "want 0xfe215040, got {:#x}", address);
46+
assert_eq!(
47+
child_bus_address, 0x7e215040,
48+
"want 0x7e215040, got {:#x}",
49+
child_bus_address
50+
);
51+
assert_eq!(
52+
reg.size,
53+
Some(0x40),
54+
"want 0x40, got {:#x}",
55+
reg.size.unwrap()
56+
);
3857
}

0 commit comments

Comments
 (0)