Skip to content
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
86 changes: 85 additions & 1 deletion src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use crate::{
parsing::{BigEndianU32, BigEndianU64, CStr, FdtData},
standard_nodes::{Compatible, MemoryRange, MemoryRegion},
standard_nodes::{Compatible, InterruptMapMask, InterruptMapping, MemoryRange, MemoryRegion},
Fdt,
};

Expand Down Expand Up @@ -322,6 +322,90 @@ impl<'b, 'a: 'b> FdtNode<'b, 'a> {
interrupt
}

/// `interrupt-map` property
pub fn interrupt_map(self) -> Option<impl Iterator<Item = InterruptMapping> + 'b> {
let address_size = self.cell_sizes().address_cells;
let interrupt_size = self.interrupt_cells()?;

let mut map = None;
for prop in self.properties() {
if prop.name == "interrupt-map" {
let mut stream = FdtData::new(prop.value);
map = Some(core::iter::from_fn(move || {
let (child_unit_address_hi, child_unit_address) = match address_size {
0 => (0x0, 0x0),
1 => (0x0, stream.u32()?.get() as usize),
2 => (0x0, stream.u64()?.get() as usize),
3 => (stream.u32()?.get(), stream.u64()?.get() as usize),
_ => return None,
};
let child_interrupt_specifier = match interrupt_size {
1 => stream.u32()?.get() as usize,
2 => stream.u64()?.get() as usize,
_ => return None,
};
let parent_phandle = stream.u32()?.get();
let parent = self.header.find_phandle(parent_phandle)?;
let (parent_unit_address_hi, parent_unit_address) =
match parent.cell_sizes().address_cells {
0 => (0x0, 0x0),
1 => (0x0, stream.u32()?.get() as usize),
2 => (0x0, stream.u64()?.get() as usize),
3 => (stream.u32()?.get(), stream.u64()?.get() as usize),
_ => return None,
};
let parent_interrupt_specifier = match parent.interrupt_cells()? {
1 => stream.u32()?.get() as usize,
2 => stream.u64()?.get() as usize,
_ => return None,
};

Some(InterruptMapping {
child_unit_address,
child_unit_address_hi,
child_interrupt_specifier,
parent_phandle,
parent_unit_address,
parent_unit_address_hi,
parent_interrupt_specifier,
})
}));
break;
}
}

map
}

/// `interrupt-map-mask` property
pub fn interrupt_map_mask(self) -> Option<InterruptMapMask> {
let address_size = self.cell_sizes().address_cells;
let interrupt_size = self.interrupt_cells()?;

let mut mask = None;
for prop in self.properties() {
if prop.name == "interrupt-map-mask" {
let mut stream = FdtData::new(prop.value);
let (address_mask_hi, address_mask) = match address_size {
0 => (0, 0),
1 => (0, stream.u32()?.get() as usize),
2 => (0, stream.u64()?.get() as usize),
3 => (stream.u32()?.get(), stream.u64()?.get() as usize),
_ => return None,
};
let interrupt_mask = match interrupt_size {
1 => stream.u32()?.get() as usize,
2 => stream.u64()?.get() as usize,
_ => return None,
};
mask = Some(InterruptMapMask { address_mask, address_mask_hi, interrupt_mask });
break;
}
}

mask
}

pub(crate) fn parent_cell_sizes(self) -> CellSizes {
let mut cell_sizes = CellSizes::default();

Expand Down
20 changes: 20 additions & 0 deletions src/standard_nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,3 +347,23 @@ pub struct MemoryRange {
/// Size of range
pub size: usize,
}

/// Interrupt mapping, described by `interrupt-map` properties
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct InterruptMapping {
pub child_unit_address: usize,
/// The high bits of the child unit address, if present
pub child_unit_address_hi: u32,
pub child_interrupt_specifier: usize,
pub parent_phandle: u32,
pub parent_unit_address: usize,
/// The high bits of the parent unit address, if present
pub parent_unit_address_hi: u32,
pub parent_interrupt_specifier: usize,
}

pub struct InterruptMapMask {
pub address_mask: usize,
pub address_mask_hi: u32,
pub interrupt_mask: usize,
}