1extern crate core;
34
35pub mod util;
36
37use core::str;
38use util::{align, SliceRead, SliceReadError};
39
40const MAGIC_NUMBER : u32 = 0xd00dfeed;
41const SUPPORTED_VERSION: u32 = 17;
42const OF_DT_BEGIN_NODE : u32 = 0x00000001;
43const OF_DT_END_NODE : u32 = 0x00000002;
44const OF_DT_PROP : u32 = 0x00000003;
45
46
47#[derive(Debug)]
49pub enum DeviceTreeError {
50 InvalidMagicNumber,
53
54 SizeMismatch,
57
58 SliceReadError(SliceReadError),
60
61 ParseError(usize),
63
64 Utf8Error,
67
68 VersionNotSupported,
70}
71
72#[derive(Debug)]
74pub struct DeviceTree {
75 pub version: u32,
77
78 pub boot_cpuid_phys: u32,
80
81 pub reserved: Vec<(u64, u64)>,
84
85 pub root: Node,
87}
88
89#[derive(Debug)]
91pub struct Node {
92 pub name: String,
94
95 pub props: Vec<(String, Vec<u8>)>,
97
98 pub children: Vec<Node>,
100}
101
102#[derive(Debug)]
103pub enum PropError {
104 NotFound,
105 Utf8Error,
106 Missing0,
107 SliceReadError(SliceReadError),
108}
109
110impl From<SliceReadError> for DeviceTreeError {
111 fn from(e: SliceReadError) -> DeviceTreeError {
112 DeviceTreeError::SliceReadError(e)
113 }
114}
115
116impl From<str::Utf8Error> for DeviceTreeError {
117 fn from(_: str::Utf8Error) -> DeviceTreeError {
118 DeviceTreeError::Utf8Error
119 }
120}
121
122impl DeviceTree {
123 pub fn load(buffer: &[u8]) -> Result<DeviceTree, DeviceTreeError> {
125 if try!(buffer.read_be_u32(0)) != MAGIC_NUMBER {
144 return Err(DeviceTreeError::InvalidMagicNumber)
145 }
146
147 if try!(buffer.read_be_u32(4)) as usize != buffer.len() {
149 return Err(DeviceTreeError::SizeMismatch);
150 }
151
152 let version = try!(buffer.read_be_u32(20));
154 if version != SUPPORTED_VERSION {
155 return Err(DeviceTreeError::VersionNotSupported);
156 }
157
158 let off_dt_struct = try!(buffer.read_be_u32(8)) as usize;
159 let off_dt_strings = try!(buffer.read_be_u32(12)) as usize;
160 let off_mem_rsvmap = try!(buffer.read_be_u32(16)) as usize;
161 let boot_cpuid_phys = try!(buffer.read_be_u32(28));
162
163 let mut reserved = Vec::new();
165 let mut pos = off_mem_rsvmap;
166
167 loop {
168 let offset = try!(buffer.read_be_u64(pos));
169 pos += 8;
170 let size = try!(buffer.read_be_u64(pos));
171 pos += 8;
172
173 reserved.push((offset, size));
174
175 if size == 0 {
176 break;
177 }
178 }
179
180 let (_, root) = try!(Node::load(buffer, off_dt_struct, off_dt_strings));
181
182 Ok(DeviceTree{
183 version: version,
184 boot_cpuid_phys: boot_cpuid_phys,
185 reserved: reserved,
186 root: root,
187 })
188 }
189
190 pub fn find<'a>(&'a self, path: &str) -> Option<&'a Node> {
191 if ! path.starts_with('/') {
193 return None
194 }
195
196 self.root.find(&path[1..])
197 }
198}
199
200
201impl Node {
202 fn load(buffer: &[u8], start: usize, off_dt_strings: usize)
203 -> Result<(usize, Node), DeviceTreeError> {
204 if try!(buffer.read_be_u32(start)) != OF_DT_BEGIN_NODE {
206 return Err(DeviceTreeError::ParseError(start))
207 }
208
209 let raw_name = try!(buffer.read_bstring0(start+4));
210
211 let mut pos = align(start + 4 + raw_name.len() + 1, 4);
213
214 let mut props = Vec::new();
215
216 while try!(buffer.read_be_u32(pos)) == OF_DT_PROP {
217 let val_size = try!(buffer.read_be_u32(pos+4)) as usize;
218 let name_offset = try!(buffer.read_be_u32(pos+8)) as usize;
219
220 let val_start = pos + 12;
222 let val_end = val_start + val_size;
223 let val = try!(buffer.subslice(val_start, val_end));
224
225 let prop_name = try!(
227 buffer.read_bstring0(off_dt_strings + name_offset)
228 );
229
230 props.push((
231 try!(str::from_utf8(prop_name)).to_owned(),
232 val.to_owned(),
233 ));
234
235 pos = align(val_end, 4);
236 }
237
238 let mut children = Vec::new();
240
241 while try!(buffer.read_be_u32(pos)) == OF_DT_BEGIN_NODE {
242 let (new_pos, child_node) = try!(Node::load(buffer, pos,
243 off_dt_strings));
244 pos = new_pos;
245
246 children.push(child_node);
247 }
248
249 if try!(buffer.read_be_u32(pos)) != OF_DT_END_NODE {
250 return Err(DeviceTreeError::ParseError(pos))
251 }
252
253 pos += 4;
254
255 Ok((pos, Node{
256 name: try!(str::from_utf8(raw_name)).to_owned(),
257 props: props,
258 children: children,
259 }))
260 }
261
262 pub fn find<'a>(&'a self, path: &str) -> Option<&'a Node> {
263 if path == "" {
264 return Some(self)
265 }
266
267 match path.find('/') {
268 Some(idx) => {
269 let (l, r) = path.split_at(idx);
272
273 let subpath = &r[1..];
275
276 for child in self.children.iter() {
277 if child.name == l {
278 return child.find(subpath);
279 }
280 }
281
282 None
284 },
285 None => self.children.iter().find(|n| n.name == path)
286 }
287 }
288
289 pub fn has_prop(&self, name: &str) -> bool {
290 if let Some(_) = self.prop_raw(name) {
291 true
292 } else {
293 false
294 }
295 }
296
297 pub fn prop_str<'a>(&'a self, name: &str) -> Result<&'a str, PropError> {
298 let raw = try!(self.prop_raw(name).ok_or(PropError::NotFound));
299
300 let l = raw.len();
301 if l < 1 || raw[l-1] != 0 {
302 return Err(PropError::Missing0)
303 }
304
305 Ok(try!(str::from_utf8(&raw[..(l-1)])))
306 }
307
308 pub fn prop_raw<'a>(&'a self, name: &str) -> Option<&'a Vec<u8>> {
309 for &(ref key, ref val) in self.props.iter() {
310 if key == name {
311 return Some(val)
312 }
313 }
314 None
315 }
316
317 pub fn prop_u64(&self, name: &str) -> Result<u64, PropError> {
318 let raw = try!(self.prop_raw(name).ok_or(PropError::NotFound));
319
320 Ok(try!(raw.as_slice().read_be_u64(0)))
321 }
322
323 pub fn prop_u32(&self, name: &str) -> Result<u32, PropError> {
324 let raw = try!(self.prop_raw(name).ok_or(PropError::NotFound));
325
326 Ok(try!(raw.as_slice().read_be_u32(0)))
327 }
328}
329
330impl From<str::Utf8Error> for PropError {
331 fn from(_: str::Utf8Error) -> PropError {
332 PropError::Utf8Error
333 }
334}
335
336impl From<SliceReadError> for PropError {
337 fn from(e: SliceReadError) -> PropError {
338 PropError::SliceReadError(e)
339 }
340}