use core::{cmp, mem};
use super::{Error, Result};
pub const DEF_SOFS: u32 = 0x240;
pub const DEF_VERS: u32 = 0x01010101;
pub const DEF_BACKUP: u32 = 0x20_0000;
pub const DEF_RESL: u32 = 0x400;
pub const DEF_SPL_FILE: &str = "u-boot-spl.bin";
pub const PATH_MAX: usize = 4096;
pub const CRC_FAILED: u32 = 0x5a5a5a5a;
pub const SPL_HEADER_LEN: usize = 1024;
pub const MAX_SPL_LEN: usize = 180048;
const PATH_ZERO_BYTES: [u8; PATH_MAX] = [0u8; PATH_MAX];
const RES_PAD2_LEN: usize = 636;
const RES_PAD3_LEN: usize = 364;
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct UbootSplHeader {
sofs: u32,
bofs: u32,
zro2: [u8; RES_PAD2_LEN],
vers: u32,
fsiz: u32,
resl: u32,
crcs: u32,
zro3: [u8; RES_PAD3_LEN],
}
impl UbootSplHeader {
pub const fn new() -> Self {
Self {
sofs: DEF_SOFS,
bofs: DEF_BACKUP,
zro2: [0; 636],
vers: DEF_VERS,
fsiz: 0,
resl: DEF_RESL,
crcs: 0,
zro3: [0; 364],
}
}
pub const fn sofs(&self) -> u32 {
self.sofs
}
pub const fn bofs(&self) -> u32 {
self.bofs
}
pub fn set_bofs(&mut self, val: u32) {
self.bofs = val;
}
pub fn with_bofs(mut self, val: u32) -> Self {
self.set_bofs(val);
self
}
pub const fn vers(&self) -> u32 {
self.vers
}
pub fn set_vers(&mut self, val: u32) {
self.vers = val;
}
pub fn with_vers(mut self, val: u32) -> Self {
self.set_vers(val);
self
}
pub const fn fsiz(&self) -> u32 {
self.fsiz
}
pub fn set_fsiz(&mut self, val: u32) {
self.fsiz = val;
}
pub fn with_fsiz(mut self, val: u32) -> Self {
self.set_fsiz(val);
self
}
pub const fn resl(&self) -> u32 {
self.resl
}
pub fn set_resl(&mut self, val: u32) {
self.resl = val;
}
pub fn with_resl(mut self, val: u32) -> Self {
self.set_resl(val);
self
}
pub const fn crcs(&self) -> u32 {
self.crcs
}
pub fn set_crcs(&mut self, val: u32) {
self.crcs = val;
}
pub fn with_crcs(mut self, val: u32) -> Self {
self.set_crcs(val);
self
}
}
impl From<&UbootSplHeader> for [u8; SPL_HEADER_LEN] {
fn from(val: &UbootSplHeader) -> Self {
const WORD_LEN: usize = mem::size_of::<u32>();
let mut res = [0u8; SPL_HEADER_LEN];
let mut idx = 0usize;
res[idx..idx.saturating_add(WORD_LEN)].copy_from_slice(val.sofs.to_le_bytes().as_ref());
idx = idx.saturating_add(WORD_LEN);
res[idx..idx.saturating_add(WORD_LEN)].copy_from_slice(val.bofs.to_le_bytes().as_ref());
idx = idx.saturating_add(WORD_LEN);
idx = idx.saturating_add(RES_PAD2_LEN);
res[idx..idx.saturating_add(WORD_LEN)].copy_from_slice(val.vers.to_le_bytes().as_ref());
idx = idx.saturating_add(WORD_LEN);
res[idx..idx.saturating_add(WORD_LEN)].copy_from_slice(val.fsiz.to_le_bytes().as_ref());
idx = idx.saturating_add(WORD_LEN);
res[idx..idx.saturating_add(WORD_LEN)].copy_from_slice(val.resl.to_le_bytes().as_ref());
idx = idx.saturating_add(WORD_LEN);
res[idx..idx.saturating_add(WORD_LEN)].copy_from_slice(val.crcs.to_le_bytes().as_ref());
res
}
}
impl From<UbootSplHeader> for [u8; SPL_HEADER_LEN] {
fn from(val: UbootSplHeader) -> Self {
(&val).into()
}
}
impl TryFrom<&[u8]> for UbootSplHeader {
type Error = Error;
fn try_from(val: &[u8]) -> Result<Self> {
const WORD_LEN: usize = mem::size_of::<u32>();
if val.len() < SPL_HEADER_LEN {
Err(Error::InvalidHeaderLen((val.len(), SPL_HEADER_LEN)))
} else {
let mut idx = 0usize;
let sofs = u32::from_le_bytes(val[idx..idx.saturating_add(WORD_LEN)].try_into()?);
idx = idx.saturating_add(WORD_LEN);
let bofs = u32::from_le_bytes(val[idx..idx.saturating_add(WORD_LEN)].try_into()?);
idx = idx.saturating_add(WORD_LEN);
let zro2 = [0u8; RES_PAD2_LEN];
idx = idx.saturating_add(RES_PAD2_LEN);
let vers = u32::from_le_bytes(val[idx..idx.saturating_add(WORD_LEN)].try_into()?);
idx = idx.saturating_add(WORD_LEN);
let fsiz = u32::from_le_bytes(val[idx..idx.saturating_add(WORD_LEN)].try_into()?);
idx = idx.saturating_add(WORD_LEN);
let resl = u32::from_le_bytes(val[idx..idx.saturating_add(WORD_LEN)].try_into()?);
idx = idx.saturating_add(WORD_LEN);
let crcs = u32::from_le_bytes(val[idx..idx.saturating_add(WORD_LEN)].try_into()?);
let zro3 = [0u8; RES_PAD3_LEN];
Ok(Self {
sofs,
bofs,
zro2,
vers,
fsiz,
resl,
crcs,
zro3,
})
}
}
}
impl<const N: usize> TryFrom<&[u8; N]> for UbootSplHeader {
type Error = Error;
fn try_from(val: &[u8; N]) -> Result<Self> {
val.as_ref().try_into()
}
}
impl<const N: usize> TryFrom<[u8; N]> for UbootSplHeader {
type Error = Error;
fn try_from(val: [u8; N]) -> Result<Self> {
val.as_ref().try_into()
}
}
impl Default for UbootSplHeader {
fn default() -> Self {
Self::new()
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct HeaderConf {
name: [u8; PATH_MAX],
vers: u32,
bofs: u32,
create_header: bool,
fix_image_header: bool,
resl: u32,
}
impl HeaderConf {
pub const fn new() -> Self {
Self {
name: [0u8; PATH_MAX],
vers: DEF_VERS,
bofs: DEF_BACKUP,
resl: DEF_RESL,
create_header: false,
fix_image_header: false,
}
}
pub fn name(&self) -> &str {
core::str::from_utf8(self.name[..self.name_len()].as_ref()).unwrap_or("")
}
fn name_len(&self) -> usize {
self.name
.iter()
.position(|&b| b == 0)
.unwrap_or(self.name.len())
}
pub fn set_name(&mut self, val: &str) {
let val_bytes = val.as_bytes();
let len = cmp::min(PATH_MAX - 1, val_bytes.len());
self.name[..len].copy_from_slice(val_bytes[..len].as_ref());
self.name[len..].copy_from_slice(PATH_ZERO_BYTES[len..].as_ref());
}
pub fn with_name(mut self, val: &str) -> Self {
self.set_name(val);
self
}
pub const fn vers(&self) -> u32 {
self.vers
}
pub fn set_vers(&mut self, val: u32) {
self.vers = val;
}
pub fn with_vers(mut self, val: u32) -> Self {
self.set_vers(val);
self
}
pub const fn bofs(&self) -> u32 {
self.bofs
}
pub fn set_bofs(&mut self, val: u32) {
self.bofs = val;
}
pub fn with_bofs(mut self, val: u32) -> Self {
self.set_bofs(val);
self
}
pub const fn resl(&self) -> u32 {
self.resl
}
pub fn set_resl(&mut self, val: u32) {
self.resl = val;
}
pub fn with_resl(mut self, val: u32) -> Self {
self.set_resl(val);
self
}
pub const fn create_header(&self) -> bool {
self.create_header
}
pub fn set_create_header(&mut self, val: bool) {
self.create_header = val;
}
pub fn with_create_header(mut self, val: bool) -> Self {
self.set_create_header(val);
self
}
pub const fn fix_image_header(&self) -> bool {
self.fix_image_header
}
pub fn set_fix_image_header(&mut self, val: bool) {
self.fix_image_header = val;
}
pub fn with_fix_image_header(mut self, val: bool) -> Self {
self.set_fix_image_header(val);
self
}
}
impl Default for HeaderConf {
fn default() -> Self {
Self::new()
}
}