use scroll::Pread;
use anyhow::{anyhow, Result};
#[derive(Clone, Debug)]
pub(crate) struct SectorInfo {
pub address: u32,
pub size: u32,
}
impl SectorInfo {
const SECTOR_END: u32 = 0xFFFF_FFFF;
fn new(data: &[u8]) -> Option<Self> {
let size = data.pread(0).unwrap();
let address = data.pread(4).unwrap();
if size != Self::SECTOR_END && address != Self::SECTOR_END {
Some(Self { address, size })
} else {
None
}
}
}
#[derive(Clone, Debug)]
pub(crate) struct FlashDevice {
pub(crate) _driver_version: u16,
pub(crate) name: String, pub(crate) _typ: u16,
pub(crate) start_address: u32,
pub(crate) device_size: u32,
pub(crate) page_size: u32,
_reserved: u32,
pub(crate) erased_default_value: u8,
pub(crate) program_page_timeout: u32, pub(crate) erase_sector_timeout: u32, pub(crate) sectors: Vec<SectorInfo>,
}
impl FlashDevice {
const INFO_SIZE: u32 = 160;
const SECTOR_INFO_SIZE: u32 = 8;
const MAX_ID_STRING_LENGTH: usize = 128;
pub(crate) fn new(elf: &goblin::elf::Elf<'_>, buffer: &[u8], address: u32) -> Result<Self> {
let sectors = Self::parse_sectors(elf, buffer, address);
let data = crate::parser::read_elf_bin_data(elf, buffer, address, Self::INFO_SIZE)
.ok_or_else(|| anyhow!("Failed to read binary data for flash device. Read address: {:#010x}, size: {} bytes", address, Self::INFO_SIZE))?;
let hypothetical_length = data[2..2 + Self::MAX_ID_STRING_LENGTH]
.iter()
.position(|&c| c == 0)
.unwrap_or(Self::MAX_ID_STRING_LENGTH);
let sanitized_length = Self::MAX_ID_STRING_LENGTH.min(hypothetical_length);
Ok(Self {
_driver_version: data.pread(0).unwrap(),
name: String::from_utf8_lossy(&data[2..2 + sanitized_length]).to_string(),
_typ: data.pread(130).unwrap(),
start_address: data.pread(132).unwrap(),
device_size: data.pread(136).unwrap(),
page_size: data.pread(140).unwrap(),
_reserved: data.pread(144).unwrap(),
erased_default_value: data.pread(148).unwrap(),
program_page_timeout: data.pread(152).unwrap(),
erase_sector_timeout: data.pread(156).unwrap(),
sectors,
})
}
pub(crate) fn parse_sectors(
elf: &goblin::elf::Elf<'_>,
buffer: &[u8],
address: u32,
) -> Vec<SectorInfo> {
let mut sectors = vec![];
let mut offset = Self::INFO_SIZE;
while let Some(data) =
crate::parser::read_elf_bin_data(elf, buffer, address + offset, Self::SECTOR_INFO_SIZE)
{
if let Some(sector) = SectorInfo::new(data) {
sectors.push(sector);
offset += 8;
} else {
break;
}
}
sectors
}
}