1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
use crate::{DeviceError, DeviceResult, PhysAddr, VirtAddr};
use alloc::vec::Vec;
use core::ops::Range;
use device_tree::{DeviceTree as DeviceTreeInner, PropError};
pub use device_tree::{util::StringList, Node};
pub type InterruptsProp = Vec<u32>;
pub struct Devicetree(DeviceTreeInner);
#[derive(Clone, Copy, Debug, Default)]
pub struct InheritProps {
pub parent_address_cells: u32,
pub parent_size_cells: u32,
pub interrupt_parent: u32,
}
impl Devicetree {
pub fn from(dtb_base_vaddr: VirtAddr) -> DeviceResult<Self> {
info!("Loading device tree blob from {:#x}", dtb_base_vaddr);
match unsafe { DeviceTreeInner::load_from_raw_pointer(dtb_base_vaddr as *const _) } {
Ok(dt) => Ok(Self(dt)),
Err(err) => {
warn!(
"device-tree: failed to load DTB @ {:#x}: {:?}",
dtb_base_vaddr, err
);
Err(DeviceError::InvalidParam)
}
}
}
fn walk_inner<F>(&self, node: &Node, props: InheritProps, device_node_op: &mut F)
where
F: FnMut(&Node, &StringList, &InheritProps),
{
let mut props = props;
if let Ok(num) = node.prop_u32("interrupt-parent") {
props.interrupt_parent = num;
}
if let Ok(comp) = node.prop_str_list("compatible") {
device_node_op(node, &comp, &props);
}
props.parent_address_cells = node.prop_u32("#address-cells").unwrap_or(0);
props.parent_size_cells = node.prop_u32("#size-cells").unwrap_or(0);
for child in node.children.iter() {
self.walk_inner(child, props, device_node_op);
}
}
pub fn walk<F>(&self, device_node_op: &mut F)
where
F: FnMut(&Node, &StringList, &InheritProps),
{
self.walk_inner(&self.0.root, InheritProps::default(), device_node_op)
}
pub fn bootargs(&self) -> Option<&str> {
self.0.find("/chosen")?.prop_str("bootargs").ok()
}
pub fn timebase_frequency(&self) -> Option<u32> {
self.0.find("/cpus")?.prop_u32("timebase-frequency").ok()
}
pub fn initrd_region(&self) -> Option<Range<PhysAddr>> {
let chosen = self.0.find("/chosen")?;
let start = chosen.prop_u32("linux,initrd-start").ok()? as _;
let end = chosen.prop_u32("linux,initrd-end").ok()? as _;
Some(start..end)
}
pub fn memory_regions(&self) -> DeviceResult<Vec<Range<PhysAddr>>> {
let props = InheritProps {
parent_address_cells: self.0.root.prop_u32("#address-cells").unwrap_or(0),
parent_size_cells: self.0.root.prop_u32("#size-cells").unwrap_or(0),
..Default::default()
};
let mut regions = Vec::new();
for node in &self.0.root.children {
if node.name.starts_with("memory@")
|| node.prop_str("device_type").unwrap_or_default() == "memory"
{
let (addr, size) = parse_reg(node, &props)?;
regions.push(addr as usize..addr as usize + size as usize)
}
}
Ok(regions)
}
}
fn from_cells(cells: &[u32], cell_num: u32) -> DeviceResult<u64> {
if cell_num as usize > cells.len() {
return Err(DeviceError::InvalidParam);
}
let mut value = 0;
for &c in &cells[..cell_num as usize] {
value = value << 32 | c as u64;
}
Ok(value)
}
pub fn parse_reg(node: &Node, props: &InheritProps) -> DeviceResult<(u64, u64)> {
let cells = node.prop_cells("reg")?;
let addr = from_cells(&cells, props.parent_address_cells)?;
let size = from_cells(
&cells[props.parent_address_cells as usize..],
props.parent_size_cells,
)?;
Ok((addr, size))
}
pub fn parse_interrupts(node: &Node, props: &InheritProps) -> DeviceResult<InterruptsProp> {
if node.has_prop("interrupts-extended") {
Ok(node.prop_cells("interrupts-extended")?)
} else if node.has_prop("interrupts") && props.interrupt_parent > 0 {
let mut ret = node.prop_cells("interrupts")?;
ret.insert(0, props.interrupt_parent);
Ok(ret)
} else {
Ok(Vec::new())
}
}
impl From<PropError> for DeviceError {
fn from(_err: PropError) -> Self {
Self::InvalidParam
}
}