Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert library to no_std #5

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ description = "Reads and parses Linux device tree images"
repository = "https://github.com/mbr/device_tree-rs"
documentation = "https://mbr.github.io/device_tree-rs/device_tree/"

[dependencies]
hashbrown = "0.13"

[features]
string-dedup = [] # Requires std
173 changes: 75 additions & 98 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
//!
//! # Examples
//!
//! ```ignore
//! ```rust
//! # use std::{fs, io::Read};
//! fn main() {
//! // read file into memory
//! let mut input = fs::File::open("sample.dtb").unwrap();
//! let mut input = fs::File::open("examples/bcm2709-rpi-2-b.dtb").unwrap();
//! let mut buf = Vec::new();
//! input.read_to_end(&mut buf).unwrap();
//!
Expand All @@ -30,10 +31,14 @@
//! }
//! ```

extern crate core;
#![no_std]

extern crate alloc;
extern crate hashbrown;

pub mod util;

use alloc::{borrow::ToOwned, string::String, vec::Vec};
use core::str;
use util::{align, SliceRead, SliceReadError, VecWrite, VecWriteError};

Expand Down Expand Up @@ -131,7 +136,7 @@ impl From<str::Utf8Error> for DeviceTreeError {

#[cfg(feature = "string-dedup")]
mod advancedstringtable {
use std::collections::HashMap;
use hashbrown::HashMap;

pub struct StringTable {
pub buffer: Vec<u8>,
Expand Down Expand Up @@ -161,6 +166,8 @@ mod advancedstringtable {

#[cfg(not(feature = "string-dedup"))]
mod stringtable {
use alloc::vec::Vec;

pub struct StringTable {
pub buffer: Vec<u8>,
}
Expand Down Expand Up @@ -206,34 +213,34 @@ impl DeviceTree {
// // version 17 fields
// 36 size_dt_struct: u32,

if try!(buffer.read_be_u32(0)) != MAGIC_NUMBER {
if buffer.read_be_u32(0)? != MAGIC_NUMBER {
return Err(DeviceTreeError::InvalidMagicNumber);
}

// check total size
if try!(buffer.read_be_u32(4)) as usize != buffer.len() {
if buffer.read_be_u32(4)? as usize != buffer.len() {
return Err(DeviceTreeError::SizeMismatch);
}

// check version
let version = try!(buffer.read_be_u32(20));
let version = buffer.read_be_u32(20)?;
if version != SUPPORTED_VERSION {
return Err(DeviceTreeError::VersionNotSupported);
}

let off_dt_struct = try!(buffer.read_be_u32(8)) as usize;
let off_dt_strings = try!(buffer.read_be_u32(12)) as usize;
let off_mem_rsvmap = try!(buffer.read_be_u32(16)) as usize;
let boot_cpuid_phys = try!(buffer.read_be_u32(28));
let off_dt_struct = buffer.read_be_u32(8)? as usize;
let off_dt_strings = buffer.read_be_u32(12)? as usize;
let off_mem_rsvmap = buffer.read_be_u32(16)? as usize;
let boot_cpuid_phys = buffer.read_be_u32(28)?;

// load reserved memory list
let mut reserved = Vec::new();
let mut pos = off_mem_rsvmap;

loop {
let offset = try!(buffer.read_be_u64(pos));
let offset = buffer.read_be_u64(pos)?;
pos += 8;
let size = try!(buffer.read_be_u64(pos));
let size = buffer.read_be_u64(pos)?;
pos += 8;

reserved.push((offset, size));
Expand All @@ -243,7 +250,7 @@ impl DeviceTree {
}
}

let (_, root) = try!(Node::load(buffer, off_dt_struct, off_dt_strings));
let (_, root) = Node::load(buffer, off_dt_struct, off_dt_strings)?;

Ok(DeviceTree {
version: version,
Expand All @@ -268,67 +275,67 @@ impl DeviceTree {

// Magic
let len = dtb.len();
try!(dtb.write_be_u32(len, MAGIC_NUMBER));
dtb.write_be_u32(len, MAGIC_NUMBER)?;

let size_off = dtb.len();
try!(dtb.write_be_u32(size_off, 0)); // Fill in size later
dtb.write_be_u32(size_off, 0)?; // Fill in size later
let off_dt_struct = dtb.len();
try!(dtb.write_be_u32(off_dt_struct, 0)); // Fill in off_dt_struct later
dtb.write_be_u32(off_dt_struct, 0)?; // Fill in off_dt_struct later
let off_dt_strings = dtb.len();
try!(dtb.write_be_u32(off_dt_strings, 0)); // Fill in off_dt_strings later
dtb.write_be_u32(off_dt_strings, 0)?; // Fill in off_dt_strings later
let off_mem_rsvmap = dtb.len();
try!(dtb.write_be_u32(off_mem_rsvmap, 0)); // Fill in off_mem_rsvmap later
dtb.write_be_u32(off_mem_rsvmap, 0)?; // Fill in off_mem_rsvmap later

// Version
let len = dtb.len();
try!(dtb.write_be_u32(len, SUPPORTED_VERSION));
dtb.write_be_u32(len, SUPPORTED_VERSION)?;
// Last comp version
let len = dtb.len();
try!(dtb.write_be_u32(len, COMPAT_VERSION));
dtb.write_be_u32(len, COMPAT_VERSION)?;
// boot_cpuid_phys
let len = dtb.len();
try!(dtb.write_be_u32(len, self.boot_cpuid_phys));
dtb.write_be_u32(len, self.boot_cpuid_phys)?;

let off_size_strings = dtb.len();
try!(dtb.write_be_u32(off_size_strings, 0)); // Fill in size_dt_strings later
dtb.write_be_u32(off_size_strings, 0)?; // Fill in size_dt_strings later
let off_size_struct = dtb.len();
try!(dtb.write_be_u32(off_size_struct, 0)); // Fill in size_dt_struct later
dtb.write_be_u32(off_size_struct, 0)?; // Fill in size_dt_struct later

// Memory Reservation Block
try!(dtb.pad(8));
dtb.pad(8)?;
let len = dtb.len();
try!(dtb.write_be_u32(off_mem_rsvmap, len as u32));
dtb.write_be_u32(off_mem_rsvmap, len as u32)?;
for reservation in self.reserved.iter() {
// address
let len = dtb.len();
try!(dtb.write_be_u64(len, reservation.0));
dtb.write_be_u64(len, reservation.0)?;
// size
let len = dtb.len();
try!(dtb.write_be_u64(len, reservation.1));
dtb.write_be_u64(len, reservation.1)?;
}

// Structure Block
try!(dtb.pad(4));
dtb.pad(4)?;
let structure_start = dtb.len();
try!(dtb.write_be_u32(off_dt_struct, structure_start as u32));
try!(self.root.store(&mut dtb, &mut strings));
dtb.write_be_u32(off_dt_struct, structure_start as u32)?;
self.root.store(&mut dtb, &mut strings)?;

try!(dtb.pad(4));
dtb.pad(4)?;
let len = dtb.len();
try!(dtb.write_be_u32(len, OF_DT_END));
dtb.write_be_u32(len, OF_DT_END)?;

let len = dtb.len();
try!(dtb.write_be_u32(off_size_struct, (len - structure_start) as u32));
try!(dtb.write_be_u32(off_size_strings, strings.buffer.len() as u32));
dtb.write_be_u32(off_size_struct, (len - structure_start) as u32)?;
dtb.write_be_u32(off_size_strings, strings.buffer.len() as u32)?;

// Strings Block
try!(dtb.pad(4));
dtb.pad(4)?;
let len = dtb.len();
try!(dtb.write_be_u32(off_dt_strings, len as u32));
dtb.write_be_u32(off_dt_strings, len as u32)?;
dtb.extend_from_slice(&strings.buffer);

let len = dtb.len();
try!(dtb.write_be_u32(size_off, len as u32));
dtb.write_be_u32(size_off, len as u32)?;

Ok(dtb)
}
Expand All @@ -341,45 +348,45 @@ impl Node {
off_dt_strings: usize,
) -> Result<(usize, Node), DeviceTreeError> {
// check for DT_BEGIN_NODE
if try!(buffer.read_be_u32(start)) != OF_DT_BEGIN_NODE {
if buffer.read_be_u32(start)? != OF_DT_BEGIN_NODE {
return Err(DeviceTreeError::ParseError(start));
}

let raw_name = try!(buffer.read_bstring0(start + 4));
let raw_name = buffer.read_bstring0(start + 4)?;

// read all the props
let mut pos = align(start + 4 + raw_name.len() + 1, 4);

let mut props = Vec::new();

while try!(buffer.read_be_u32(pos)) == OF_DT_PROP {
let val_size = try!(buffer.read_be_u32(pos + 4)) as usize;
let name_offset = try!(buffer.read_be_u32(pos + 8)) as usize;
while buffer.read_be_u32(pos)? == OF_DT_PROP {
let val_size = buffer.read_be_u32(pos + 4)? as usize;
let name_offset = buffer.read_be_u32(pos + 8)? as usize;

// get value slice
let val_start = pos + 12;
let val_end = val_start + val_size;
let val = try!(buffer.subslice(val_start, val_end));
let val = buffer.subslice(val_start, val_end)?;

// lookup name in strings table
let prop_name = try!(buffer.read_bstring0(off_dt_strings + name_offset));
let prop_name = buffer.read_bstring0(off_dt_strings + name_offset)?;

props.push((try!(str::from_utf8(prop_name)).to_owned(), val.to_owned()));
props.push((str::from_utf8(prop_name)?.to_owned(), val.to_owned()));

pos = align(val_end, 4);
}

// finally, parse children
let mut children = Vec::new();

while try!(buffer.read_be_u32(pos)) == OF_DT_BEGIN_NODE {
let (new_pos, child_node) = try!(Node::load(buffer, pos, off_dt_strings));
while buffer.read_be_u32(pos)? == OF_DT_BEGIN_NODE {
let (new_pos, child_node) = Node::load(buffer, pos, off_dt_strings)?;
pos = new_pos;

children.push(child_node);
}

if try!(buffer.read_be_u32(pos)) != OF_DT_END_NODE {
if buffer.read_be_u32(pos)? != OF_DT_END_NODE {
return Err(DeviceTreeError::ParseError(pos));
}

Expand All @@ -388,7 +395,7 @@ impl Node {
Ok((
pos,
Node {
name: try!(str::from_utf8(raw_name)).to_owned(),
name: str::from_utf8(raw_name)?.to_owned(),
props: props,
children: children,
},
Expand Down Expand Up @@ -431,14 +438,14 @@ impl Node {
}

pub fn prop_str<'a>(&'a self, name: &str) -> Result<&'a str, PropError> {
let raw = try!(self.prop_raw(name).ok_or(PropError::NotFound));
let raw = self.prop_raw(name).ok_or(PropError::NotFound)?;

let l = raw.len();
if l < 1 || raw[l - 1] != 0 {
return Err(PropError::Missing0);
}

Ok(try!(str::from_utf8(&raw[..(l - 1)])))
Ok(str::from_utf8(&raw[..(l - 1)])?)
}

pub fn prop_raw<'a>(&'a self, name: &str) -> Option<&'a Vec<u8>> {
Expand All @@ -451,54 +458,54 @@ impl Node {
}

pub fn prop_u64(&self, name: &str) -> Result<u64, PropError> {
let raw = try!(self.prop_raw(name).ok_or(PropError::NotFound));
let raw = self.prop_raw(name).ok_or(PropError::NotFound)?;

Ok(try!(raw.as_slice().read_be_u64(0)))
Ok(raw.as_slice().read_be_u64(0)?)
}

pub fn prop_u32(&self, name: &str) -> Result<u32, PropError> {
let raw = try!(self.prop_raw(name).ok_or(PropError::NotFound));
let raw = self.prop_raw(name).ok_or(PropError::NotFound)?;

Ok(try!(raw.as_slice().read_be_u32(0)))
Ok(raw.as_slice().read_be_u32(0)?)
}

pub fn store(
&self,
structure: &mut Vec<u8>,
strings: &mut StringTable,
) -> Result<(), DeviceTreeError> {
try!(structure.pad(4));
structure.pad(4)?;
let len = structure.len();
try!(structure.write_be_u32(len, OF_DT_BEGIN_NODE));
structure.write_be_u32(len, OF_DT_BEGIN_NODE)?;

try!(structure.write_bstring0(&self.name));
structure.write_bstring0(&self.name)?;
for prop in self.props.iter() {
try!(structure.pad(4));
structure.pad(4)?;
let len = structure.len();
try!(structure.write_be_u32(len, OF_DT_PROP));
structure.write_be_u32(len, OF_DT_PROP)?;

// Write property value length
try!(structure.pad(4));
structure.pad(4)?;
let len = structure.len();
try!(structure.write_be_u32(len, prop.1.len() as u32));
structure.write_be_u32(len, prop.1.len() as u32)?;

// Write name offset
try!(structure.pad(4));
structure.pad(4)?;
let len = structure.len();
try!(structure.write_be_u32(len, strings.add_string(&prop.0)));
structure.write_be_u32(len, strings.add_string(&prop.0))?;

// Store the property value
structure.extend_from_slice(&prop.1);
}

// Recurse on children
for child in self.children.iter() {
try!(child.store(structure, strings));
child.store(structure, strings)?;
}

try!(structure.pad(4));
structure.pad(4)?;
let len = structure.len();
try!(structure.write_be_u32(len, OF_DT_END_NODE));
structure.write_be_u32(len, OF_DT_END_NODE)?;
Ok(())
}
}
Expand All @@ -514,33 +521,3 @@ impl From<SliceReadError> for PropError {
PropError::SliceReadError(e)
}
}

#[cfg(test)]
mod test {
use std::fs;
use std::io::{Read, Write};

use super::*;

#[test]
fn roundtrip() {
// read file into memory
let buf = include_bytes!("../examples/bcm2709-rpi-2-b.dtb");
let original_fdt = DeviceTree::load(buf).unwrap();

let dtb = original_fdt.store().unwrap();
let mut output = fs::OpenOptions::new()
.write(true)
.create(true)
.open("output.dtb")
.unwrap();
output.write_all(&dtb).unwrap();

let mut input = fs::File::open("output.dtb").unwrap();
let mut buf = Vec::new();
input.read_to_end(&mut buf).unwrap();
let generated_fdt = DeviceTree::load(buf.as_slice()).unwrap();

assert!(original_fdt == generated_fdt);
}
}
Loading