use core::ptr::NonNull;
use crate::FdtError;
use crate::data::U32_SIZE;
#[repr(align(4))]
struct AlignedHeader([u8; size_of::<Header>()]);
#[derive(Debug, Clone)]
pub struct Header {
pub magic: u32,
pub totalsize: u32,
pub off_dt_struct: u32,
pub off_dt_strings: u32,
pub off_mem_rsvmap: u32,
pub version: u32,
pub last_comp_version: u32,
pub boot_cpuid_phys: u32,
pub size_dt_strings: u32,
pub size_dt_struct: u32,
}
impl Header {
pub fn from_bytes(data: &[u8]) -> Result<Self, FdtError> {
if data.len() < core::mem::size_of::<Header>() {
return Err(FdtError::BufferTooSmall {
pos: core::mem::size_of::<Header>(),
});
}
let ptr = NonNull::new(data.as_ptr() as *mut u8).ok_or(FdtError::InvalidPtr)?;
unsafe { Self::from_ptr(ptr.as_ptr()) }
}
pub unsafe fn from_ptr(ptr: *mut u8) -> Result<Self, FdtError> {
if !(ptr as usize).is_multiple_of(Self::alignment()) {
let mut aligned = AlignedHeader([0u8; core::mem::size_of::<Header>()]);
unsafe {
core::ptr::copy_nonoverlapping(
ptr,
aligned.0.as_mut_ptr(),
core::mem::size_of::<Header>(),
);
}
Self::from_aligned_ptr(aligned.0.as_mut_ptr())
} else {
Self::from_aligned_ptr(ptr)
}
}
fn from_aligned_ptr(ptr: *mut u8) -> Result<Self, FdtError> {
let ptr = NonNull::new(ptr).ok_or(FdtError::InvalidPtr)?;
let raw = unsafe { &*(ptr.cast::<Header>().as_ptr()) };
let magic = u32::from_be(raw.magic);
if magic != crate::FDT_MAGIC {
return Err(FdtError::InvalidMagic(magic));
}
Ok(Header {
magic,
totalsize: u32::from_be(raw.totalsize),
off_dt_struct: u32::from_be(raw.off_dt_struct),
off_dt_strings: u32::from_be(raw.off_dt_strings),
off_mem_rsvmap: u32::from_be(raw.off_mem_rsvmap),
version: u32::from_be(raw.version),
last_comp_version: u32::from_be(raw.last_comp_version),
boot_cpuid_phys: u32::from_be(raw.boot_cpuid_phys),
size_dt_strings: u32::from_be(raw.size_dt_strings),
size_dt_struct: u32::from_be(raw.size_dt_struct),
})
}
#[inline]
pub const fn alignment() -> usize {
U32_SIZE
}
}