device_tree-1.1.0/Cargo.toml00006000001750000175000000001373127344751010014137 0ustar0000000000000000# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] name = "device_tree" version = "1.1.0" authors = ["Marc Brinkmann "] description = "Reads and parses Linux device tree images" documentation = "https://mbr.github.io/device_tree-rs/device_tree/" license = "MIT" repository = "https://github.com/mbr/device_tree-rs" device_tree-1.1.0/Cargo.toml.orig00006000001750000175000000000450127344751010015071 0ustar0000000000000000[package] name = "device_tree" version = "1.1.0" authors = ["Marc Brinkmann "] license = "MIT" 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/" device_tree-1.1.0/examples/bcm2709-rpi-2-b.dtb00006000001750000175000000027474126730465750016776 0ustar0000000000000000Ð þí/<8*h(Ô*0 ,brcm,bcm27097Raspberry Pi 2 Model Bchosen=aliasesF/audioL/soundR/socV/soc/dma@7e007000#Z/soc/interrupt-controller@7e00b200_/soc/watchdog@7e100000h/soc/rng@7e104000o/soc/mailbox@7e00b800w/soc/gpio@7e200000|/soc/uart@7e201000‚/soc/sdhost@7e202000‰/soc/i2s@7e203000/soc/spi@7e204000’/soc/i2c@7e205000—/soc/uart@7e215040/soc/mmc@7e300000¡/soc/i2c@7e804000¦/soc/i2c@7e805000«/soc/usb@7e980000 ¯/soc/leds´/soc/fb ·/soc/vchiq ½/soc/thermalÅ/clocksmemoryÌmemoryØaudio,brcm,bcm2835-audioÜ îdisabledõûsoundõ#û#soc ,simple-bus ~?õ$û$dma@7e007000,brcm,bcm2835-dmaØ~p`  5õûinterrupt-controller@7e00b200,brcm,bcm2708-armctrl-icØ~²6Kõûmailbox@7e00b800,brcm,bcm2835-mboxØ~¸€@ \õûwatchdog@7e100000,brcm,bcm2835-pm-wdtØ~( îdisabledõ û cprman@7e101000,brcm,bcm2835-cprmanhØ~ Å îdisabledõ%û%rng@7e104000,brcm,bcm2835-rngØ~@îokayõ!û!gpio@7e200000,brcm,bcm2835-gpioØ~ ´ u…6Kõûsdhost_pins‘012345›õûspi0_pins‘ ›õ û i2c0‘›õ û i2c1‘›õûi2s‘›õûuart@7e201000,arm,pl011arm,primecellØ~  Å©uartclkapb_pclkµ$îokayõûsdhost@7e202000,brcm,bcm2835-sdhostØ~  ÅÌ Ñrx-txÛíîokayüdefault õ"û"i2s@7e203000,brcm,bcm2708-i2sØ~ 0$~˜Ñtxrx îdisabledüdefault õûspi@7e204000,brcm,bcm2835-spiØ~ @ Å îdisabledÌÑtxrx/üdefault õûspidev@0,spidevØ8¡ spidev@1,spidevØ8¡ i2c@7e205000,brcm,bcm2708-i2cØ~ P Å îdisabledüdefault J† õûpwm@7e20c000,brcm,bcm2835-pwmØ~ À(Å Z îdisabledõ&û&uart@7e215040,brcm,bcm2835-aux-uartns16550Ø~!P@@ Å eo îdisabledõ'û'mmc@7e300000,brcm,bcm2835-mmcØ~0 Å Ì Ñrx-txÛ îdisabledõ(û(i2c@7e804000,brcm,bcm2708-i2cØ~€@ Å îdisabledüdefault J† õûi2c@7e805000,brcm,bcm2708-i2cØ~€P Å îdisabledJ† õûsmi@7e600000,brcm,bcm2835-smiØ~`D~° €–ÌÑrx-tx îdisabledõ)û)usb@7e980000,brcm,bcm2708-usbØ~˜~`  õ*û*firmware,raspberrypi,bcm2835-firmware­õûleds ,gpio-ledsõ+û+act´led0ºmmc0 2/õûpwr´led1ºinput 2#õûfb,brcm,bcm2708-fbÐîokayõ,û,vchiq,brcm,bcm2835-vchiqØ~¸@ Ù Ðõûthermal,brcm,bcm2835-thermalÐõ-û-arm-pmu,arm,cortex-a7-pmu  gpiomem,brcm,bcm2835-gpiomemØ~ îokayclocks ,simple-busõ.û.clock@0 ,fixed-clockØhécoreJæ²€õûclock@1 ,fixed-clockØhémmcJæ²€õ û clock@2 ,fixed-clockØh éuart0_pclkJ-ÆÀõûclock@3 ,fixed-clockØh éapb_pclkJ‚›€õûclock@4 ,fixed-clockØhépwmJõáõ û clock@5,fixed-factor-clockØÅhüõ û clock@6 ,fixed-clockØhéoscJ$øõû__overrides__cache-line-size:0X!clock-frequency:0clock-frequency:0clock-frequency:0clock-frequency:0 |status*clock-frequency:0 ‰status 8status ’status ¡status <statusRclock-frequency:0`clock-frequency:0nclock-frequency:0|clock-frequency:0 †gpios:4 “gpios:8¥linux,default-trigger µgpios:4 Âgpios:8Ôlinux,default-trigger Fstatus _ status h!statusä"brcm,overclock-50:0ñ"brcm,force-pio?þ"brcm,pio-limit:0 "brcm,debugtimer,arm,armv7-timerJ$ø  cpusõ/û/cpu@0Ìcpu,arm,cortex-a7ØJ/¯õûcpu@1Ìcpu,arm,cortex-a7ØJ/¯õûcpu@2Ìcpu,arm,cortex-a7ØJ/¯õûcpu@3Ìcpu,arm,cortex-a7ØJ/¯õû__symbols__F/audioL/soundR/socV/soc/dma@7e007000#Z/soc/interrupt-controller@7e00b200o/soc/mailbox@7e00b800_/soc/watchdog@7e100000/soc/cprman@7e101000h/soc/rng@7e104000w/soc/gpio@7e200000%/soc/gpio@7e200000/sdhost_pins1/soc/gpio@7e200000/spi0_pins;/soc/gpio@7e200000/i2c0E/soc/gpio@7e200000/i2c1O/soc/gpio@7e200000/i2s|/soc/uart@7e201000‚/soc/sdhost@7e202000‰/soc/i2s@7e203000/soc/spi@7e204000’/soc/i2c@7e205000X/soc/pwm@7e20c000—/soc/uart@7e215040/soc/mmc@7e300000¡/soc/i2c@7e804000¦/soc/i2c@7e805000\/soc/smi@7e600000«/soc/usb@7e980000Ð/soc/firmware ¯/soc/leds`/soc/leds/acth/soc/leds/pwr´/soc/fb ·/soc/vchiq ½/soc/thermalÅ/clocksp/clocks/clock@0y/clocks/clock@1/clocks/clock@2‹/clocks/clock@3•/clocks/clock@4/clocks/clock@5§/clocks/clock@6¯/cpus ´/cpus/cpu@0 ¼/cpus/cpu@1 Ä/cpus/cpu@2 Ì/cpus/cpu@3 #address-cells#size-cellsinterrupt-parentcompatiblemodelbootargsaudiosoundsocdmaintcwatchdograndommailboxgpiouart0sdhosti2sspi0i2c0uart1mmci2c1i2c2usbledsfbvchiqthermalclocksdevice_typeregbrcm,pwm-channelsstatuslinux,phandlerangesinterrupts#dma-cellsbrcm,dma-channel-maskinterrupt-controller#interrupt-cells#mbox-cells#clock-cellsgpio-controller#gpio-cellsbrcm,pinsbrcm,functionclock-namesarm,primecell-periphiddmasdma-namesbrcm,overclock-50brcm,pio-limitpinctrl-namespinctrl-0bus-width#sound-dai-cellscs-gpiosspi-max-frequencyclock-frequency#pwm-cellsreg-shiftno-loopback-testbrcm,smi-clock-sourcebrcm,smi-clock-divisormboxeslabellinux,default-triggerfirmwarecache-line-sizeclock-output-namesclock-divclock-multcache_line_sizearm_frequart0_clkratespii2c2_iknowwhatimdoingi2c0_baudratei2c1_baudratei2c2_baudratecore_freqact_led_gpioact_led_activelowact_led_triggerpwr_led_gpiopwr_led_activelowpwr_led_triggersd_overclocksd_force_piosd_pio_limitsd_debugalways-oncprmansdhost_pinsspi0_pinsi2c0_pinsi2c1_pinsi2s_pinspwmsmiact_ledpwr_ledclk_coreclk_mmcclk_uart0clk_apb_pclk_pwmclk_uart1clk_osccpusv7_cpu0v7_cpu1v7_cpu2v7_cpu3device_tree-1.1.0/src/lib.rs00006000001750000175000000022561127031377400014114 0ustar0000000000000000//! Parse flattened linux device trees //! //! Device trees are used to describe a lot of hardware, especially in the ARM //! embedded world and are also used to boot Linux on these device. A device //! tree describes addresses and other attributes for many parts on these //! boards //! //! This library allows parsing the so-called flattened device trees, which //! are the compiled binary forms of these trees. //! //! To read more about device trees, check out //! [the kernel docs](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/Documentation/devicetree/booting-without-of.txt?id=HEAD). //! Some example device trees //! to try out are [the Raspberry Pi ones] //! (https://github.com/raspberrypi/firmware/tree/master/boot). //! //! The library does not use `std`, just `core`. //! //! # Examples //! //! ```ignore //! fn main() { //! // read file into memory //! let mut input = fs::File::open("sample.dtb").unwrap(); //! let mut buf = Vec::new(); //! input.read_to_end(&mut buf).unwrap(); //! //! let dt = device_tree::DeviceTree::load(buf.as_slice ()).unwrap(); //! println!("{:?}", dt); //! } //! ``` extern crate core; pub mod util; use core::str; use util::{align, SliceRead, SliceReadError}; const MAGIC_NUMBER : u32 = 0xd00dfeed; const SUPPORTED_VERSION: u32 = 17; const OF_DT_BEGIN_NODE : u32 = 0x00000001; const OF_DT_END_NODE : u32 = 0x00000002; const OF_DT_PROP : u32 = 0x00000003; /// An error describe parsing problems when creating device trees. #[derive(Debug)] pub enum DeviceTreeError { /// The magic number `MAGIC_NUMBER` was not found at the start of the /// structure. InvalidMagicNumber, /// An offset or size found inside the device tree is outside of what was /// supplied to `load()`. SizeMismatch, /// Failed to read data from slice. SliceReadError(SliceReadError), /// The data format was not as expected at the given position ParseError(usize), /// While trying to convert a string that was supposed to be ASCII, invalid /// utf8 sequences were encounted Utf8Error, /// The device tree version is not supported by this library. VersionNotSupported, } /// Device tree structure. #[derive(Debug)] pub struct DeviceTree { /// Version, as indicated by version header pub version: u32, /// The number of the CPU the system boots from pub boot_cpuid_phys: u32, /// A list of tuples of `(offset, length)`, indicating reserved memory // regions. pub reserved: Vec<(u64, u64)>, /// The root node. pub root: Node, } /// A single node in the device tree. #[derive(Debug)] pub struct Node { /// The name of the node, as it appears in the node path. pub name: String, /// A list of node properties, `(key, value)`. pub props: Vec<(String, Vec)>, /// Child nodes of this node. pub children: Vec, } #[derive(Debug)] pub enum PropError { NotFound, Utf8Error, Missing0, SliceReadError(SliceReadError), } impl From for DeviceTreeError { fn from(e: SliceReadError) -> DeviceTreeError { DeviceTreeError::SliceReadError(e) } } impl From for DeviceTreeError { fn from(_: str::Utf8Error) -> DeviceTreeError { DeviceTreeError::Utf8Error } } impl DeviceTree { //! Load a device tree from a memory buffer. pub fn load(buffer: &[u8]) -> Result { // 0 magic_number: u32, // 4 totalsize: u32, // 8 off_dt_struct: u32, // 12 off_dt_strings: u32, // 16 off_mem_rsvmap: u32, // 20 version: u32, // 24 last_comp_version: u32, // // version 2 fields // 28 boot_cpuid_phys: u32, // // version 3 fields // 32 size_dt_strings: u32, // // version 17 fields // 36 size_dt_struct: u32, if try!(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() { return Err(DeviceTreeError::SizeMismatch); } // check version let version = try!(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)); // load reserved memory list let mut reserved = Vec::new(); let mut pos = off_mem_rsvmap; loop { let offset = try!(buffer.read_be_u64(pos)); pos += 8; let size = try!(buffer.read_be_u64(pos)); pos += 8; reserved.push((offset, size)); if size == 0 { break; } } let (_, root) = try!(Node::load(buffer, off_dt_struct, off_dt_strings)); Ok(DeviceTree{ version: version, boot_cpuid_phys: boot_cpuid_phys, reserved: reserved, root: root, }) } pub fn find<'a>(&'a self, path: &str) -> Option<&'a Node> { // we only find root nodes on the device tree if ! path.starts_with('/') { return None } self.root.find(&path[1..]) } } impl Node { fn load(buffer: &[u8], start: usize, off_dt_strings: usize) -> Result<(usize, Node), DeviceTreeError> { // check for DT_BEGIN_NODE if try!(buffer.read_be_u32(start)) != OF_DT_BEGIN_NODE { return Err(DeviceTreeError::ParseError(start)) } let raw_name = try!(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; // get value slice let val_start = pos + 12; let val_end = val_start + val_size; let val = try!(buffer.subslice(val_start, val_end)); // lookup name in strings table let prop_name = try!( buffer.read_bstring0(off_dt_strings + name_offset) ); props.push(( try!(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)); pos = new_pos; children.push(child_node); } if try!(buffer.read_be_u32(pos)) != OF_DT_END_NODE { return Err(DeviceTreeError::ParseError(pos)) } pos += 4; Ok((pos, Node{ name: try!(str::from_utf8(raw_name)).to_owned(), props: props, children: children, })) } pub fn find<'a>(&'a self, path: &str) -> Option<&'a Node> { if path == "" { return Some(self) } match path.find('/') { Some(idx) => { // find should return the proper index, so we're safe to // use indexing here let (l, r) = path.split_at(idx); // we know that the first char of slashed is a '/' let subpath = &r[1..]; for child in self.children.iter() { if child.name == l { return child.find(subpath); } } // no matching child found None }, None => self.children.iter().find(|n| n.name == path) } } pub fn has_prop(&self, name: &str) -> bool { if let Some(_) = self.prop_raw(name) { true } else { false } } 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 l = raw.len(); if l < 1 || raw[l-1] != 0 { return Err(PropError::Missing0) } Ok(try!(str::from_utf8(&raw[..(l-1)]))) } pub fn prop_raw<'a>(&'a self, name: &str) -> Option<&'a Vec> { for &(ref key, ref val) in self.props.iter() { if key == name { return Some(val) } } None } pub fn prop_u64(&self, name: &str) -> Result { let raw = try!(self.prop_raw(name).ok_or(PropError::NotFound)); Ok(try!(raw.as_slice().read_be_u64(0))) } pub fn prop_u32(&self, name: &str) -> Result { let raw = try!(self.prop_raw(name).ok_or(PropError::NotFound)); Ok(try!(raw.as_slice().read_be_u32(0))) } } impl From for PropError { fn from(_: str::Utf8Error) -> PropError { PropError::Utf8Error } } impl From for PropError { fn from(e: SliceReadError) -> PropError { PropError::SliceReadError(e) } } device_tree-1.1.0/src/util.rs00006400001750000175000000004024127031373010014312 0ustar0000000000000000pub use core::{convert, fmt, option, result, str}; #[inline] pub fn align(val: usize, to: usize) -> usize { val + (to - (val % to)) % to } #[derive(Debug)] pub enum SliceReadError { UnexpectedEndOfInput, } pub type SliceReadResult = Result; pub trait SliceRead { fn read_be_u32(&self, pos: usize) -> SliceReadResult; fn read_be_u64(&self, pos: usize) -> SliceReadResult; fn read_bstring0(&self, pos: usize) -> SliceReadResult<&[u8]>; fn subslice(&self, start: usize, len: usize) -> SliceReadResult<&[u8]>; } impl<'a> SliceRead for &'a [u8] { fn read_be_u32(&self, pos: usize) -> SliceReadResult { // check size is valid if ! (pos+4 <= self.len()) { return Err(SliceReadError::UnexpectedEndOfInput) } Ok( (self[pos] as u32) << 24 | (self[pos+1] as u32) << 16 | (self[pos+2] as u32) << 8 | (self[pos+3] as u32) ) } fn read_be_u64(&self, pos: usize) -> SliceReadResult { // check size is valid if ! (pos+8 <= self.len()) { return Err(SliceReadError::UnexpectedEndOfInput) } Ok( (self[pos] as u64) << 56 | (self[pos+1] as u64) << 48 | (self[pos+2] as u64) << 40 | (self[pos+3] as u64) << 32 | (self[pos+4] as u64) << 24 | (self[pos+5] as u64) << 16 | (self[pos+6] as u64) << 8 | (self[pos+7] as u64) ) } fn read_bstring0(&self, pos: usize) -> SliceReadResult<&[u8]> { let mut cur = pos; while cur < self.len() { if self[cur] == 0 { return Ok(&self[pos..cur]) } cur += 1; } Err(SliceReadError::UnexpectedEndOfInput) } fn subslice(&self, start: usize, end: usize) -> SliceReadResult<&[u8]> { if ! (end < self.len()) { return Err(SliceReadError::UnexpectedEndOfInput) } Ok(&self[start..end]) } } device_tree-1.1.0/update-docs.sh00007000001750000175000000000173126733656750014771 0ustar0000000000000000#!/bin/sh set -e rm -rf target/doc cargo doc -p device_tree gittar -b gh-pages file:target/doc/* git push origin gh-pages