From d08861e586d714c9a0d3d4d3fe47cdd84da6d066 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Tue, 16 Jul 2024 05:23:00 +0300 Subject: [PATCH] Upgrade fdt library to the very latest The new helpers remove a lot of boilerplace. Unfortunately some rough edges still remain (in particular issue gh#12 which renders interrupts() helper useless) --- Cargo.lock | 7 +- Cargo.toml | 2 +- src/arch/aarch64/device/generic_timer.rs | 22 +- src/arch/aarch64/device/irqchip/gic.rs | 32 +-- src/arch/aarch64/device/irqchip/gicv3.rs | 39 +-- .../aarch64/device/irqchip/irq_bcm2835.rs | 33 +-- .../aarch64/device/irqchip/irq_bcm2836.rs | 22 +- src/arch/aarch64/device/irqchip/mod.rs | 67 ++--- src/arch/aarch64/device/mod.rs | 2 +- src/arch/aarch64/device/serial.rs | 21 +- src/arch/aarch64/init/device_tree/mod.rs | 272 ++++-------------- 11 files changed, 149 insertions(+), 370 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3728b418eb..a10cec34cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,11 +76,8 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "fdt" -version = "0.1.0" -source = "git+https://gitlab.redox-os.org/rosehuds/fdt.git#7358607679114ccab5f97e14894ed3b59c5d42d6" -dependencies = [ - "byteorder", -] +version = "0.2.0-alpha1" +source = "git+https://github.com/repnop/fdt.git?rev=2fb1409edd1877c714a0aa36b6a7c5351004be54#2fb1409edd1877c714a0aa36b6a7c5351004be54" [[package]] name = "goblin" diff --git a/Cargo.toml b/Cargo.toml index ad871e9ec3..6632049ecc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ default-features = false [target.'cfg(target_arch = "aarch64")'.dependencies] byteorder = { version = "1", default-features = false } -fdt = { git = "https://gitlab.redox-os.org/rosehuds/fdt.git", default-features = false } +fdt = { git = "https://github.com/repnop/fdt.git", rev = "2fb1409edd1877c714a0aa36b6a7c5351004be54" } [target.'cfg(any(target_arch = "x86", target_arch = "x86_64"))'.dependencies] raw-cpuid = "10.2.0" diff --git a/src/arch/aarch64/device/generic_timer.rs b/src/arch/aarch64/device/generic_timer.rs index 027e1e6b75..86e1028f8b 100644 --- a/src/arch/aarch64/device/generic_timer.rs +++ b/src/arch/aarch64/device/generic_timer.rs @@ -3,11 +3,11 @@ use log::info; use crate::{ arch::device::irqchip::IRQ_CHIP, context, context::timeout, - device::cpu::registers::control_regs, dtb::DTB_BINARY, init::device_tree::find_compatible_node, - interrupt::irq::trigger, time, + device::cpu::registers::control_regs, dtb::DTB_BINARY, interrupt::irq::trigger, time, }; use alloc::vec::Vec; use byteorder::{ByteOrder, BE}; +use fdt::Fdt; use super::irqchip::{register_irq, InterruptHandler}; @@ -26,23 +26,17 @@ pub unsafe fn init() { }; timer.init(); let data = DTB_BINARY.get().unwrap(); - let fdt = fdt::DeviceTree::new(data).unwrap(); - if let Some(node) = find_compatible_node(&fdt, "arm,armv7-timer") { - let interrupts = node - .properties() - .find(|p| p.name.contains("interrupts")) - .unwrap(); + let fdt = Fdt::new(data).unwrap(); + if let Some(node) = fdt.find_compatible(&["arm,armv7-timer"]) { + let interrupts = node.property("interrupts").unwrap(); let mut intr_data = Vec::new(); - for chunk in interrupts.data.chunks(4) { + for chunk in interrupts.value.chunks(4) { let val = BE::read_u32(chunk); intr_data.push(val); } let mut ic_idx = IRQ_CHIP.irq_chip_list.root_idx; - if let Some(interrupt_parent) = node - .properties() - .find(|p| p.name.contains("interrupt-parent")) - { - let phandle = BE::read_u32(interrupt_parent.data); + if let Some(interrupt_parent) = node.property("interrupt-parent") { + let phandle = interrupt_parent.as_usize().unwrap() as u32; let mut i = 0; while i < IRQ_CHIP.irq_chip_list.chips.len() { let item = &IRQ_CHIP.irq_chip_list.chips[i]; diff --git a/src/arch/aarch64/device/irqchip/gic.rs b/src/arch/aarch64/device/irqchip/gic.rs index 8178b3a351..7cb7e485a7 100644 --- a/src/arch/aarch64/device/irqchip/gic.rs +++ b/src/arch/aarch64/device/irqchip/gic.rs @@ -1,10 +1,7 @@ use core::ptr::{read_volatile, write_volatile}; +use fdt::{node::FdtNode, Fdt}; -use byteorder::{ByteOrder, BE}; -use fdt::{DeviceTree, Node}; - -use crate::init::device_tree::find_compatible_node; -use log::{debug, info}; +use log::info; use syscall::{ error::{Error, EINVAL}, Result, @@ -46,30 +43,29 @@ impl GenericInterruptController { irq_range: (0, 0), } } - pub fn parse(fdt: &DeviceTree) -> Result<(usize, usize, usize, usize)> { - if let Some(node) = find_compatible_node(fdt, "arm,cortex-a15-gic") { + pub fn parse(fdt: &Fdt) -> Result<(usize, usize, usize, usize)> { + if let Some(node) = fdt.find_compatible(&["arm,cortex-a15-gic"]) { return GenericInterruptController::parse_inner(&node); } else { return Err(Error::new(EINVAL)); } } - fn parse_inner(node: &Node) -> Result<(usize, usize, usize, usize)> { + fn parse_inner(node: &FdtNode) -> Result<(usize, usize, usize, usize)> { //assert address_cells == 0x2, size_cells == 0x2 - let reg = node.properties().find(|p| p.name.contains("reg")).unwrap(); + let reg = node.reg().unwrap(); let mut regs = (0, 0, 0, 0); let mut idx = 0; - for chunk in reg.data.chunks(8) { - let val = BE::read_u64(chunk) as usize; - debug!("idx{} = {:08x}", idx, val); + for chunk in reg { + if chunk.size.is_none() { + break; + } match idx { - 0 => regs.0 = val, - 1 => regs.1 = val, - 2 => regs.2 = val, - 3 => regs.3 = val, + 0 => (regs.0, regs.1) = (chunk.starting_address as usize, chunk.size.unwrap()), + 2 => (regs.2, regs.3) = (chunk.starting_address as usize, chunk.size.unwrap()), _ => break, } - idx += 1; + idx += 2; } if idx == 4 { @@ -83,7 +79,7 @@ impl GenericInterruptController { impl InterruptController for GenericInterruptController { fn irq_init( &mut self, - fdt: &DeviceTree, + fdt: &Fdt, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize, diff --git a/src/arch/aarch64/device/irqchip/gicv3.rs b/src/arch/aarch64/device/irqchip/gicv3.rs index 81a6e9cc74..026c548f18 100644 --- a/src/arch/aarch64/device/irqchip/gicv3.rs +++ b/src/arch/aarch64/device/irqchip/gicv3.rs @@ -1,11 +1,9 @@ use alloc::vec::Vec; use core::arch::asm; - -use byteorder::{ByteOrder, BE}; -use fdt::DeviceTree; +use fdt::{node::NodeProperty, Fdt}; use super::gic::GicDistIf; -use crate::init::device_tree::find_compatible_node; +use log::info; use syscall::{ error::{Error, EINVAL}, Result, @@ -36,8 +34,8 @@ impl GicV3 { } } - pub fn parse(&mut self, fdt: &DeviceTree) -> Result<()> { - let Some(node) = find_compatible_node(fdt, "arm,gic-v3") else { + pub fn parse(&mut self, fdt: &Fdt) -> Result<()> { + let Some(node) = fdt.find_compatible(&["arm,gic-v3"]) else { return Err(Error::new(EINVAL)); }; @@ -47,30 +45,23 @@ impl GicV3 { self.gicrs.clear(); // Get number of GICRs - let gicrs = match node - .properties() - .find(|p| p.name.contains("#redistributor-regions")) - { - Some(prop) => BE::read_u32(prop.data), - None => 1, - }; + let gicrs = node + .property("#redistributor-regions") + .and_then(NodeProperty::as_usize) + .unwrap_or(1); // Read registers - let reg = node.properties().find(|p| p.name.contains("reg")).unwrap(); - let mut chunks = reg.data.chunks_exact(16).map(|chunk| { - ( - BE::read_u64(&chunk[0..8]) as usize, - BE::read_u64(&chunk[8..16]) as usize, - ) - }); - if let Some((gicd_addr, _gicd_size)) = chunks.next() { + let mut chunks = node.reg().unwrap(); + if let Some(gicd) = chunks.next() { unsafe { - self.gic_dist_if.init(crate::PHYS_OFFSET + gicd_addr); + self.gic_dist_if + .init(crate::PHYS_OFFSET + gicd.starting_address as usize); } } for _ in 0..gicrs { if let Some(gicr) = chunks.next() { - self.gicrs.push(gicr); + self.gicrs + .push((gicr.starting_address as usize, gicr.size.unwrap())); } } @@ -85,7 +76,7 @@ impl GicV3 { impl InterruptController for GicV3 { fn irq_init( &mut self, - fdt: &DeviceTree, + fdt: &Fdt, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize, diff --git a/src/arch/aarch64/device/irqchip/irq_bcm2835.rs b/src/arch/aarch64/device/irqchip/irq_bcm2835.rs index 6565edfb3b..e7d3542860 100644 --- a/src/arch/aarch64/device/irqchip/irq_bcm2835.rs +++ b/src/arch/aarch64/device/irqchip/irq_bcm2835.rs @@ -3,9 +3,8 @@ use core::ptr::{read_volatile, write_volatile}; use crate::arch::device::irqchip::IRQ_CHIP; use byteorder::{ByteOrder, BE}; -use fdt::{DeviceTree, Node}; +use fdt::{node::FdtNode, Fdt}; -use crate::init::device_tree::find_compatible_node; use log::{debug, error, info}; use syscall::{ @@ -67,33 +66,25 @@ impl Bcm2835ArmInterruptController { irq_range: (0, 0), } } - pub fn parse(fdt: &DeviceTree) -> Result<(usize, usize, Option)> { - //TODO: try to parse dtb using stable library - if let Some(node) = find_compatible_node(fdt, "brcm,bcm2836-armctrl-ic") { + pub fn parse(fdt: &Fdt) -> Result<(usize, usize, Option)> { + if let Some(node) = fdt.find_compatible(&["brcm,bcm2836-armctrl-ic"]) { return unsafe { Bcm2835ArmInterruptController::parse_inner(&node) }; } else { return Err(Error::new(EINVAL)); } } - unsafe fn parse_inner(node: &Node) -> Result<(usize, usize, Option)> { + unsafe fn parse_inner(node: &FdtNode) -> Result<(usize, usize, Option)> { //assert address_cells == 0x1, size_cells == 0x1 - let reg = node.properties().find(|p| p.name.contains("reg")).unwrap(); - let (base, size) = reg.data.split_at(4); - let base = BE::read_u32(base); - let size = BE::read_u32(size); + let mem = node.reg().unwrap().nth(0).unwrap(); + let base = mem.starting_address as u32; + let size = mem.size.unwrap() as u32; let mut ret_virq = None; - if let Some(interrupt_parent) = node - .properties() - .find(|p| p.name.contains("interrupt-parent")) - { - let phandle = BE::read_u32(interrupt_parent.data); - let interrupts = node - .properties() - .find(|p| p.name.contains("interrupts")) - .unwrap(); + if let Some(interrupt_parent) = node.property("interrupt-parent") { + let phandle = interrupt_parent.as_usize().unwrap() as u32; + let interrupts = node.property("interrupts").unwrap(); let mut intr_data = Vec::new(); - for chunk in interrupts.data.chunks(4) { + for chunk in interrupts.value.chunks(4) { let val = BE::read_u32(chunk); intr_data.push(val); } @@ -141,7 +132,7 @@ impl Bcm2835ArmInterruptController { impl InterruptController for Bcm2835ArmInterruptController { fn irq_init( &mut self, - fdt: &DeviceTree, + fdt: &Fdt, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize, diff --git a/src/arch/aarch64/device/irqchip/irq_bcm2836.rs b/src/arch/aarch64/device/irqchip/irq_bcm2836.rs index 495f4e9997..9fbfe38e75 100644 --- a/src/arch/aarch64/device/irqchip/irq_bcm2836.rs +++ b/src/arch/aarch64/device/irqchip/irq_bcm2836.rs @@ -2,13 +2,9 @@ use core::{ arch::asm, ptr::{read_volatile, write_volatile}, }; +use fdt::{node::FdtNode, Fdt}; -use byteorder::{ByteOrder, BE}; -use fdt::{DeviceTree, Node}; - -use crate::init::device_tree::find_compatible_node; use log::{debug, info}; - use syscall::{ error::{Error, EINVAL}, Result, @@ -71,22 +67,18 @@ impl Bcm2836ArmInterruptController { active_cpu: 0, } } - pub fn parse(fdt: &DeviceTree) -> Result<(usize, usize)> { - //TODO: try to parse dtb using stable library - if let Some(node) = find_compatible_node(fdt, "brcm,bcm2836-l1-intc") { + pub fn parse(fdt: &Fdt) -> Result<(usize, usize)> { + if let Some(node) = fdt.find_compatible(&["brcm,bcm2836-l1-intc"]) { return Bcm2836ArmInterruptController::parse_inner(&node); } else { return Err(Error::new(EINVAL)); } } - fn parse_inner(node: &Node) -> Result<(usize, usize)> { + fn parse_inner(node: &FdtNode) -> Result<(usize, usize)> { //assert address_cells == 0x1, size_cells == 0x1 - let reg = node.properties().find(|p| p.name.contains("reg")).unwrap(); - let (base, size) = reg.data.split_at(4); - let base = BE::read_u32(base); - let size = BE::read_u32(size); + let reg = node.reg().unwrap().nth(0).unwrap(); - Ok((base as usize, size as usize)) + Ok((reg.starting_address as usize, reg.size.unwrap())) } unsafe fn init(&mut self) { @@ -114,7 +106,7 @@ impl Bcm2836ArmInterruptController { impl InterruptController for Bcm2836ArmInterruptController { fn irq_init( &mut self, - fdt: &DeviceTree, + fdt: &Fdt, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize, diff --git a/src/arch/aarch64/device/irqchip/mod.rs b/src/arch/aarch64/device/irqchip/mod.rs index 4f1c3a375e..25de0cb807 100644 --- a/src/arch/aarch64/device/irqchip/mod.rs +++ b/src/arch/aarch64/device/irqchip/mod.rs @@ -1,6 +1,6 @@ use alloc::{boxed::Box, vec::Vec}; use byteorder::{ByteOrder, BE}; -use fdt::DeviceTree; +use fdt::Fdt; use syscall::Result; use crate::init::device_tree::travel_interrupt_ctrl; @@ -14,7 +14,7 @@ mod irq_bcm2836; pub trait InterruptController { fn irq_init( &mut self, - fdt: &DeviceTree, + fdt: &Fdt, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize, @@ -62,62 +62,41 @@ pub struct IrqDesc { } impl IrqChipList { - fn init_inner1(&mut self, fdt: &fdt::DeviceTree) { - let root_node = fdt.nodes().nth(0).unwrap(); + fn init_inner1(&mut self, fdt: &Fdt) { + let root_node = fdt.root(); let mut idx = 0; - let intr = root_node - .properties() - .find(|p| p.name.contains("interrupt-parent")) - .unwrap(); + let intr = root_node.property("interrupt-parent").unwrap(); - let root_intr_parent = BE::read_u32(&intr.data); + let root_intr_parent = intr.as_usize().unwrap() as u32; debug!("root parent = 0x{:08x}", root_intr_parent); self.root_phandle = root_intr_parent; - for node in fdt.nodes() { - if node - .properties() - .find(|p| p.name.contains("interrupt-controller")) - .is_some() - { - let compatible = node - .properties() - .find(|p| p.name.contains("compatible")) - .unwrap(); - let phandle = node - .properties() - .find(|p| p.name.contains("phandle")) - .unwrap(); - let intr_cells = node - .properties() - .find(|p| p.name.contains("#interrupt-cells")) - .unwrap(); - let _intr = node - .properties() - .find(|p| p.name.contains("interrupt-parent")); - let _intr_data = node.properties().find(|p| p.name.contains("interrupts")); + for node in fdt.all_nodes() { + if node.property("interrupt-controller").is_some() { + let compatible = node.property("compatible").unwrap().as_str().unwrap(); + let phandle = node.property("phandle").unwrap().as_usize().unwrap() as u32; + let intr_cells = node.interrupt_cells().unwrap(); + let _intr = node.property("interrupt-parent"); + let _intr_data = node.property("interrupts"); - let s = core::str::from_utf8(compatible.data).unwrap(); debug!( "{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}", - node.name, - s, - BE::read_u32(intr_cells.data), - BE::read_u32(phandle.data) + node.name, compatible, intr_cells, phandle ); let mut item = IrqChipItem { - phandle: BE::read_u32(phandle.data), + phandle, parent_phandle: None, parent: None, childs: Vec::new(), interrupts: Vec::new(), - ic: IrqChipCore::new_ic(&s).unwrap(), + ic: IrqChipCore::new_ic(compatible).unwrap(), }; if let Some(intr) = _intr { if let Some(intr_data) = _intr_data { - debug!("interrupt-parent = 0x{:08x}", BE::read_u32(intr.data)); - item.parent_phandle = Some(BE::read_u32(intr.data)); + let intr = intr.as_usize().unwrap() as u32; + debug!("interrupt-parent = 0x{:08x}", intr); + item.parent_phandle = Some(intr); debug!("interrupts begin:"); - for chunk in intr_data.data.chunks(4) { + for chunk in intr_data.value.chunks(4) { debug!("0x{:08x}, ", BE::read_u32(chunk)); item.interrupts.push(BE::read_u32(chunk)); } @@ -157,7 +136,7 @@ impl IrqChipList { } } - fn init_inner3(&mut self, fdt: &fdt::DeviceTree, irq_desc: &mut [IrqDesc; 1024]) { + fn init_inner3(&mut self, fdt: &fdt::Fdt, irq_desc: &mut [IrqDesc; 1024]) { //run init let mut queue = Vec::new(); let mut irq_idx: usize = 0; @@ -219,7 +198,7 @@ impl IrqChipCore { .irq_to_virq(hwirq) } - pub fn init(&mut self, fdt: &DeviceTree) { + pub fn init(&mut self, fdt: &Fdt) { for i in 0..1024 { self.irq_desc[i].basic.idx = i; } @@ -264,7 +243,7 @@ pub static mut IRQ_CHIP: IrqChipCore = IrqChipCore { irq_desc: [INIT_IRQ_DESC; 1024], }; -pub fn init(fdt: &DeviceTree) { +pub fn init(fdt: &Fdt) { travel_interrupt_ctrl(fdt); unsafe { IRQ_CHIP.init(fdt); diff --git a/src/arch/aarch64/device/mod.rs b/src/arch/aarch64/device/mod.rs index 9a15014624..fcc96c132a 100644 --- a/src/arch/aarch64/device/mod.rs +++ b/src/arch/aarch64/device/mod.rs @@ -10,7 +10,7 @@ pub mod uart_pl011; pub unsafe fn init() { info!("IRQCHIP INIT"); let data = DTB_BINARY.get().unwrap(); - let fdt = fdt::DeviceTree::new(data).unwrap(); + let fdt = fdt::Fdt::new(data).unwrap(); irqchip::init(&fdt); info!("GIT INIT"); generic_timer::init(); diff --git a/src/arch/aarch64/device/serial.rs b/src/arch/aarch64/device/serial.rs index f85cab7c59..e5a543a5cb 100644 --- a/src/arch/aarch64/device/serial.rs +++ b/src/arch/aarch64/device/serial.rs @@ -4,9 +4,10 @@ use spin::Mutex; use crate::{device::uart_pl011::SerialPort, init::device_tree, interrupt::irq::trigger}; use super::irqchip::{register_irq, InterruptHandler, IRQ_CHIP}; -use crate::{dtb::DTB_BINARY, init::device_tree::find_compatible_node}; +use crate::dtb::DTB_BINARY; use alloc::vec::Vec; use byteorder::{ByteOrder, BE}; +use fdt::Fdt; use log::info; pub static COM1: Mutex> = Mutex::new(None); @@ -43,23 +44,17 @@ pub unsafe fn init_early(dtb_base: usize, dtb_size: usize) { pub unsafe fn init() { let data = DTB_BINARY.get().unwrap(); - let fdt = fdt::DeviceTree::new(data).unwrap(); - if let Some(node) = find_compatible_node(&fdt, "arm,pl011") { - let interrupts = node - .properties() - .find(|p| p.name.contains("interrupts")) - .unwrap(); + let fdt = Fdt::new(data).unwrap(); + if let Some(node) = fdt.find_compatible(&["arm,pl011"]) { + let interrupts = node.property("interrupts").unwrap(); let mut intr_data = Vec::new(); - for chunk in interrupts.data.chunks(4) { + for chunk in interrupts.value.chunks(4) { let val = BE::read_u32(chunk); intr_data.push(val); } let mut ic_idx = IRQ_CHIP.irq_chip_list.root_idx; - if let Some(interrupt_parent) = node - .properties() - .find(|p| p.name.contains("interrupt-parent")) - { - let phandle = BE::read_u32(interrupt_parent.data); + if let Some(interrupt_parent) = node.property("interrupt-parent") { + let phandle = interrupt_parent.as_usize().unwrap() as u32; let mut i = 0; while i < IRQ_CHIP.irq_chip_list.chips.len() { let item = &IRQ_CHIP.irq_chip_list.chips[i]; diff --git a/src/arch/aarch64/init/device_tree/mod.rs b/src/arch/aarch64/init/device_tree/mod.rs index beebf5d0f4..86c64744f2 100644 --- a/src/arch/aarch64/init/device_tree/mod.rs +++ b/src/arch/aarch64/init/device_tree/mod.rs @@ -1,9 +1,6 @@ -extern crate byteorder; -extern crate fdt; - -use self::byteorder::{ByteOrder, BE}; +use byteorder::{ByteOrder, BE}; use core::slice; -use fdt::Node; +use fdt::{node::NodeProperty, Fdt}; use log::debug; #[derive(Copy, Clone, Debug, Default)] @@ -22,68 +19,32 @@ pub static mut MEMORY_MAP: [MemoryArea; 512] = [MemoryArea { acpi: 0, }; 512]; -pub fn root_cell_sz(dt: &fdt::DeviceTree) -> Option<(u32, u32)> { - let root_node = dt.nodes().nth(0).unwrap(); - let address_cells = root_node - .properties() - .find(|p| p.name.contains("#address-cells")) +pub fn travel_interrupt_ctrl(fdt: &Fdt) { + let root_intr_parent = fdt + .root() + .property("interrupt-parent") + .and_then(NodeProperty::as_usize) .unwrap(); - let size_cells = root_node - .properties() - .find(|p| p.name.contains("#size-cells")) - .unwrap(); - - Some(( - BE::read_u32(&address_cells.data), - BE::read_u32(&size_cells.data), - )) -} - -pub fn travel_interrupt_ctrl(fdt: &fdt::DeviceTree) { - let root_node = fdt.nodes().nth(0).unwrap(); - let intr = root_node - .properties() - .find(|p| p.name.contains("interrupt-parent")) - .unwrap(); - - let root_intr_parent = BE::read_u32(&intr.data); debug!("root parent = 0x{:08x}", root_intr_parent); - for node in fdt.nodes() { - if node - .properties() - .find(|p| p.name.contains("interrupt-controller")) - .is_some() - { - let compatible = node - .properties() - .find(|p| p.name.contains("compatible")) - .unwrap(); - let phandle = node - .properties() - .find(|p| p.name.contains("phandle")) - .unwrap(); - let intr_cells = node - .properties() - .find(|p| p.name.contains("#interrupt-cells")) - .unwrap(); + for node in fdt.all_nodes() { + if node.property("interrupt-controller").is_some() { + let compatible = node.property("compatible").unwrap().as_str().unwrap(); + let phandle = node.property("phandle").unwrap().as_usize().unwrap(); + let intr_cells = node.interrupt_cells().unwrap(); let _intr = node - .properties() - .find(|p| p.name.contains("interrupt-parent")); - let _intr_data = node.properties().find(|p| p.name.contains("interrupts")); + .property("interrupt-parent") + .and_then(NodeProperty::as_usize); + let _intr_data = node.property("interrupts"); - let s = core::str::from_utf8(compatible.data).unwrap(); debug!( "{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}", - node.name, - s, - BE::read_u32(intr_cells.data), - BE::read_u32(phandle.data) + node.name, compatible, intr_cells, phandle ); if let Some(intr) = _intr { if let Some(intr_data) = _intr_data { - debug!("interrupt-parent = 0x{:08x}", BE::read_u32(intr.data)); + debug!("interrupt-parent = 0x{:08x}", intr); debug!("interrupts begin:"); - for chunk in intr_data.data.chunks(4) { + for chunk in intr_data.value.chunks(4) { debug!("0x{:08x}, ", BE::read_u32(chunk)); } debug!("interrupts end"); @@ -94,56 +55,23 @@ pub fn travel_interrupt_ctrl(fdt: &fdt::DeviceTree) { } #[allow(unused)] -fn memory_ranges( - dt: &fdt::DeviceTree, - address_cells: usize, - size_cells: usize, - ranges: &mut [(usize, usize); 10], -) -> usize { - let (memory_node, _memory_cells) = dt.find_node("/memory").unwrap(); - let reg = memory_node - .properties() - .find(|p| p.name.contains("reg")) - .unwrap(); - let chunk_sz = (address_cells + size_cells) * 4; - let chunk_count = reg.data.len() / chunk_sz; +fn memory_ranges(dt: &Fdt, ranges: &mut [(usize, usize); 10]) -> usize { let mut index = 0; - for chunk in reg.data.chunks(chunk_sz as usize) { - if index == chunk_count { - return index; + for chunk in dt.memory().regions() { + if index >= ranges.len() || chunk.size.is_none() { + break; } - let (base, size) = chunk.split_at((address_cells * 4) as usize); - let mut b = 0; - for base_chunk in base.rchunks(4) { - b += BE::read_u32(base_chunk); - } - let mut s = 0; - for sz_chunk in size.rchunks(4) { - s += BE::read_u32(sz_chunk); - } - ranges[index] = (b as usize, s as usize); + ranges[index] = (chunk.starting_address as usize, chunk.size.unwrap()); index += 1; } index } -fn dev_memory_ranges( - dt: &fdt::DeviceTree, - address_cells: usize, - size_cells: usize, - ranges: &mut [(usize, usize); 10], -) -> usize { +fn dev_memory_ranges(dt: &Fdt, ranges: &mut [(usize, usize); 10]) -> usize { // work around for qemu-arm64 // dev mem: 128MB - 1GB, see https://github.com/qemu/qemu/blob/master/hw/arm/virt.c for details - let root_node = dt.nodes().nth(0).unwrap(); - let is_qemu_virt = { - if let Some(model) = root_node.properties().find(|p| p.name.contains("model")) { - let model_str = core::str::from_utf8(model.data).unwrap(); - model_str.contains("linux,dummy-virt") - } else { - true - } - }; + let root_node = dt.root(); + let is_qemu_virt = root_node.model().contains("linux,dummy-virt"); if is_qemu_virt { ranges[0] = (0x08000000, 0x08000000); @@ -151,54 +79,23 @@ fn dev_memory_ranges( return 2; } - let (memory_node, _memory_cells) = dt.find_node("/soc").unwrap(); - let reg = memory_node - .properties() - .find(|p| p.name.contains("ranges")) - .unwrap(); - let chunk_sz = (address_cells * 2 + size_cells) * 4; - let chunk_count = reg.data.len() / chunk_sz; + let soc_node = dt.find_node("/soc").unwrap(); + let reg = soc_node.ranges().unwrap(); + let mut index = 0; - for chunk in reg.data.chunks(chunk_sz as usize) { - if index == chunk_count { - return index; + for chunk in reg { + if index >= ranges.len() { + break; } - let child_bus_addr = { - if address_cells == 1 { - BE::read_u32(&chunk[0..4]) as u64 - } else if address_cells == 2 { - BE::read_u64(&chunk[0..8]) - } else { - return 0; - } - }; - - let parent_bus_addr = { - if address_cells == 1 { - BE::read_u32(&chunk[4..8]) as u64 - } else if address_cells == 2 { - BE::read_u64(&chunk[8..16]) - } else { - return 0; - } - }; - - let addr_size = { - // FIXME offsets incorrect if address_cells != size_cells - if address_cells == 1 { - BE::read_u32(&chunk[8..12]) as u64 - } else if address_cells == 2 { - BE::read_u64(&chunk[16..24]) - } else { - return 0; - } - }; debug!( - "dev mem 0x{:08x} 0x{:08x} 0x{:08x}", - child_bus_addr, parent_bus_addr, addr_size + "dev mem 0x{:08x} 0x{:08x} 0x{:08x} 0x{:08x}", + chunk.child_bus_address_hi, + chunk.child_bus_address, + chunk.parent_bus_address, + chunk.size ); - ranges[index] = (parent_bus_addr as usize, addr_size as usize); + ranges[index] = (chunk.parent_bus_address, chunk.size); index += 1; } index @@ -206,82 +103,35 @@ fn dev_memory_ranges( pub fn diag_uart_range(dtb_base: usize, dtb_size: usize) -> Option<(usize, usize, bool, bool)> { let data = unsafe { slice::from_raw_parts(dtb_base as *const u8, dtb_size) }; - let dt = fdt::DeviceTree::new(data).unwrap(); + let dt = Fdt::new(data).unwrap(); - let (chosen_node, _chosen_cells) = dt.find_node("/chosen").unwrap(); - let stdout_path = chosen_node - .properties() - .find(|p| p.name.contains("stdout-path")) - .unwrap(); - let uart_node_name = core::str::from_utf8(stdout_path.data) - .unwrap() - .split('/') - .nth(1)? - .trim_end(); - let len = uart_node_name.len(); - let uart_node_name = &uart_node_name[0..len - 1]; - let uart_node = dt - .nodes() - .find(|n| n.name.contains(uart_node_name)) - .unwrap(); - let skip_init = uart_node - .properties() - .find(|p| p.name.contains("skip-init")) - .is_some(); - let cts_event_walkaround = uart_node - .properties() - .find(|p| p.name.contains("cts-event-walkaround")) - .is_some(); - let reg = uart_node - .properties() - .find(|p| p.name.contains("reg")) - .unwrap(); + let stdout_path = dt.chosen().stdout().unwrap(); + let uart_node = stdout_path.node(); + let skip_init = uart_node.property("skip-init").is_some(); + let cts_event_walkaround = uart_node.property("cts-event-walkaround").is_some(); - let (address_cells, size_cells) = root_cell_sz(&dt).unwrap(); - let _chunk_sz = (address_cells + size_cells) * 4; - let (base, size) = reg.data.split_at((address_cells * 4) as usize); - let mut b = 0; - // FIXME likely needs shifting before addition - for base_chunk in base.rchunks(4) { - b += BE::read_u32(base_chunk); - } - let mut s = 0; - for sz_chunk in size.rchunks(4) { - s += BE::read_u32(sz_chunk); - } - Some((b as usize, s as usize, skip_init, cts_event_walkaround)) -} + let mut reg = uart_node.reg().unwrap(); + let memory = reg.nth(0).unwrap(); -pub fn find_compatible_node<'a>( - dt: &'a fdt::DeviceTree<'a>, - compat_string: &str, -) -> Option> { - for node in dt.nodes() { - if let Some(compatible) = node.properties().find(|p| p.name.contains("compatible")) { - let s = core::str::from_utf8(compatible.data).unwrap(); - if s.contains(compat_string) { - return Some(node); - } - } - } - None + Some(( + memory.starting_address as usize, + memory.size.unwrap(), + skip_init, + cts_event_walkaround, + )) } #[allow(unused)] pub fn fill_env_data(dtb_base: usize, dtb_size: usize, env_base: usize) -> usize { let data = unsafe { slice::from_raw_parts(dtb_base as *const u8, dtb_size) }; - let dt = fdt::DeviceTree::new(data).unwrap(); + let dt = Fdt::new(data).unwrap(); - let (chosen_node, _chosen_cells) = dt.find_node("/chosen").unwrap(); - if let Some(bootargs) = chosen_node - .properties() - .find(|p| p.name.contains("bootargs")) - { - let bootargs_len = bootargs.data.len(); + if let Some(bootargs) = dt.chosen().bootargs() { + let bootargs_len = bootargs.len(); let env_base_slice = unsafe { slice::from_raw_parts_mut(env_base as *mut u8, bootargs_len) }; - env_base_slice[..bootargs_len].clone_from_slice(bootargs.data); + env_base_slice[..bootargs_len].clone_from_slice(bootargs.as_bytes()); bootargs_len } else { @@ -291,19 +141,13 @@ pub fn fill_env_data(dtb_base: usize, dtb_size: usize, env_base: usize) -> usize pub fn fill_memory_map(dtb_base: usize, dtb_size: usize) { let data = unsafe { slice::from_raw_parts(dtb_base as *const u8, dtb_size) }; - let dt = fdt::DeviceTree::new(data).unwrap(); + let dt = Fdt::new(data).unwrap(); - let (address_cells, size_cells) = root_cell_sz(&dt).unwrap(); let mut ranges: [(usize, usize); 10] = [(0, 0); 10]; //in uefi boot mode, ignore memory node, just read the device memory range - //let nranges = memory_ranges(&dt, address_cells as usize, size_cells as usize, &mut ranges); - let nranges = dev_memory_ranges( - &dt, - address_cells as usize, - size_cells as usize, - &mut ranges, - ); + //let nranges = memory_ranges(&dt, &mut ranges); + let nranges = dev_memory_ranges(&dt, &mut ranges); for index in 0..nranges { let (base, size) = ranges[index];