use super::error::DtbError;
use alloc::vec::Vec;
#[derive(Debug, Clone, PartialEq)]
pub struct MemoryReservation {
pub address: u64,
pub size: u64,
}
impl MemoryReservation {
pub const SIZE: usize = 16;
pub fn parse_all(input: &[u8]) -> Result<(&[u8], Vec<Self>), DtbError> {
if (input.as_ptr() as usize) % 8 != 0 {
return Err(DtbError::AlignmentError);
}
let mut reservations = Vec::new();
let mut chunks = input.chunks_exact(Self::SIZE);
for chunk in &mut chunks {
let address_bytes: [u8; 8] = chunk[0..8]
.try_into()
.map_err(|_| DtbError::MalformedHeader)?;
let size_bytes: [u8; 8] = chunk[8..16]
.try_into()
.map_err(|_| DtbError::MalformedHeader)?;
let address = u64::from_be_bytes(address_bytes);
let size = u64::from_be_bytes(size_bytes);
if address == 0 && size == 0 {
break;
}
reservations.push(MemoryReservation { address, size });
}
let consumed = reservations.len() * Self::SIZE + Self::SIZE; let remaining = if consumed <= input.len() {
&input[consumed..]
} else {
&input[input.len()..]
};
Ok((remaining, reservations))
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn test_memory_reservation_parse_empty() {
let data = vec![
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
let result = MemoryReservation::parse_all(&data);
assert!(result.is_ok());
let (_, reservations) = result.unwrap();
assert_eq!(reservations.len(), 0);
}
#[test]
fn test_memory_reservation_parse_single() {
let data = vec![
0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0, 0, 0, 0, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
let result = MemoryReservation::parse_all(&data);
assert!(result.is_ok());
let (_, reservations) = result.unwrap();
assert_eq!(reservations.len(), 1);
assert_eq!(reservations[0].address, 0x1000);
assert_eq!(reservations[0].size, 0x2000);
}
#[test]
fn test_memory_reservation_parse_multiple() {
let data = vec![
0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0, 0, 0, 0, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
let result = MemoryReservation::parse_all(&data);
assert!(result.is_ok());
let (_, reservations) = result.unwrap();
assert_eq!(reservations.len(), 2);
assert_eq!(reservations[0].address, 0x1000);
assert_eq!(reservations[0].size, 0x2000);
assert_eq!(reservations[1].address, 0x3000);
assert_eq!(reservations[1].size, 0x4000);
}
}