diff --git a/libconfig/src/bootgen.rs b/libconfig/src/bootgen.rs index 004e1d9..d4ca3b0 100644 --- a/libconfig/src/bootgen.rs +++ b/libconfig/src/bootgen.rs @@ -1,9 +1,12 @@ use alloc::vec::Vec; -use crate::sd_reader::Error -use fatfs::io::{Read, Seek, SeekFrom}; +use fatfs::{self, IoBase, Read, Seek, SeekFrom}; use libboard_zynq::devc; +use crate::sd_reader; +use crate::File; use log::debug; +type Error = fatfs::Error; + #[derive(Debug)] pub enum BootgenLoadingError { InvalidBootImageHeader, @@ -13,8 +16,8 @@ pub enum BootgenLoadingError { DevcError(devc::DevcError), } -impl From for BootgenLoadingError { - fn from(error: sd_reader::Error) -> Self { +impl From for BootgenLoadingError { + fn from(error: Error) -> Self { BootgenLoadingError::IoError(error) } } @@ -59,7 +62,7 @@ struct PartitionHeader { } /// Read a u32 word from the reader. -fn read_u32(reader: &mut Reader) -> Result { +fn read_u32<'a>(reader: &mut File<'a>) -> Result { let mut buffer: [u8; 4] = [0; 4]; reader.read_exact(&mut buffer)?; let mut result: u32 = 0; @@ -70,8 +73,8 @@ fn read_u32(reader: &mut Reader) -> Result( - file: &mut File, +fn load_pl_header<'a>( + file: &mut File<'a>, ) -> Result, BootgenLoadingError> { let mut buffer: [u8; 0x40] = [0; 0x40]; file.read_exact(&mut buffer)?; @@ -83,8 +86,8 @@ fn load_pl_header( } } -fn load_ps_header( - file: &mut File, +fn load_ps_header<'a>( + file: &mut File<'a>, ) -> Result, BootgenLoadingError> { let mut buffer: [u8; 0x40] = [0; 0x40]; file.read_exact(&mut buffer)?; @@ -99,10 +102,10 @@ fn load_ps_header( /// Locate the partition from the image, and return the size (in bytes) of the partition if successful. /// This function would seek the file to the location of the partition. fn locate< - File: Read + Seek, - F: Fn(&mut File) -> Result, BootgenLoadingError>, + 'a, + F: Fn(&mut File<'a>) -> Result, BootgenLoadingError>, >( - file: &mut File, + file: &mut File<'a>, f: F, ) -> Result { file.seek(SeekFrom::Start(0))?; @@ -150,7 +153,7 @@ fn locate< /// Load bitstream from bootgen file. /// This function parses the file, locate the bitstream and load it through the PCAP driver. /// It requires a large buffer, please enable the DDR RAM before using it. -pub fn load_bitstream(file: &mut File) -> Result<(), BootgenLoadingError> { +pub fn load_bitstream<'a>(file: &mut File<'a>) -> Result<(), BootgenLoadingError> { let size = locate(file, load_pl_header)?; unsafe { // align to 64 bytes @@ -171,7 +174,7 @@ pub fn load_bitstream(file: &mut File) -> Result<(), BootgenL } } -pub fn get_runtime(file: &mut File) -> Result, BootgenLoadingError> { +pub fn get_runtime<'a>(file: &mut File<'a>) -> Result, BootgenLoadingError> { let size = locate(file, load_ps_header)?; let mut buffer = Vec::with_capacity(size); unsafe { diff --git a/libconfig/src/lib.rs b/libconfig/src/lib.rs index 8aaf9dd..970c1a3 100644 --- a/libconfig/src/lib.rs +++ b/libconfig/src/lib.rs @@ -1,19 +1,24 @@ #![no_std] extern crate alloc; +use alloc::{rc::Rc, string::FromUtf8Error, string::String, vec::Vec}; +use sd_reader::SdReader; use core::fmt; -use alloc::{string::FromUtf8Error, string::String, vec::Vec, rc::Rc}; -use fatfs::io::{Read, Write, Seek, SeekFrom} +use fatfs::{self, IoBase, Read, Seek, SeekFrom, Write}; use libboard_zynq::sdio; -pub mod sd_reader; -pub mod net_settings; pub mod bootgen; +pub mod net_settings; +pub mod sd_reader; + +type SdReadError = fatfs::Error; + +pub type File<'a> = fatfs::File<'a, SdReader, fatfs::NullTimeProvider, fatfs::LossyOemCpConverter>; #[derive(Debug)] pub enum Error<'a> { SdError(sdio::sd_card::CardInitializationError), - IoError(sd_reader::Error), + IoError(SdReadError), Utf8Error(FromUtf8Error), KeyNotFoundError(&'a str), NoConfig, @@ -39,8 +44,8 @@ impl<'a> From for Error<'a> { } } -impl<'a> From for Error<'a> { - fn from(error: sd_reader::Error) -> Self { +impl<'a> From for Error<'a> { + fn from(error: SdReadError) -> Self { Error::IoError(error) } } @@ -51,14 +56,31 @@ impl<'a> From for Error<'a> { } } +fn read_to_string<'a>(file: &mut File<'a>, read_str: &mut String) -> Result<'a, ()> { + let mut buffer = Vec::new(); + let mut temp_buffer = [0; 500]; + loop { + let read_bytes = file.read(&mut temp_buffer)?; + if read_bytes != buffer.len() { + buffer.extend_from_slice(&temp_buffer[..read_bytes]); + break; + } + else { + buffer.extend_from_slice(&temp_buffer); + } + } + read_str.extend(String::from_utf8(buffer)); + Ok(()) +} + fn parse_config<'a>( key: &'a str, buffer: &mut Vec, - file: fatfs::File, + mut file: File<'a>, ) -> Result<'a, ()> { let prefix = [key, "="].concat().to_ascii_lowercase(); let mut read_buffer = String::new(); - file.read_to_string(&mut read_buffer); + read_to_string(&mut file, &mut read_buffer)?; for line in read_buffer.lines() { let line = line.to_ascii_lowercase(); if line.starts_with(&prefix) { @@ -85,7 +107,9 @@ impl Config { let reader = sd_reader::SdReader::new(sd); let fs = reader.mount_fatfs(sd_reader::PartitionEntry::Entry1)?; - Ok(Config { fs: Some(Rc::new(fs)) }) + Ok(Config { + fs: Some(Rc::new(fs)), + }) } pub fn from_fs(fs: Option>>) -> Self { @@ -96,12 +120,12 @@ impl Config { Config { fs: None } } - pub fn read<'b>(&self, key: &'b str) -> Result<'b, Vec> { + pub fn read<'b>(&'b self, key: &'b str) -> Result<'b, Vec> { if let Some(fs) = &self.fs { let root_dir = fs.root_dir(); let mut buffer: Vec = Vec::new(); match root_dir.open_file(&["/CONFIG/", key, ".BIN"].concat()) { - Ok(mut f) => f.read_to_end(&mut buffer).map(|_| ())?, + Ok(mut f) => f.read(&mut buffer).map(|_| ())?, Err(_) => match root_dir.open_file("/CONFIG.TXT") { Ok(f) => parse_config(key, &mut buffer, f)?, Err(_) => return Err(Error::KeyNotFoundError(key)), @@ -113,11 +137,11 @@ impl Config { } } - pub fn read_str<'b>(&self, key: &'b str) -> Result<'b, String> { + pub fn read_str<'b>(&'b self, key: &'b str) -> Result<'b, String> { Ok(String::from_utf8(self.read(key)?)?) } - pub fn remove<'b>(&self, key: &'b str) -> Result<'b, ()> { + pub fn remove<'b>(&'b self, key: &'b str) -> Result<'b, ()> { if let Some(fs) = &self.fs { let root_dir = fs.root_dir(); match root_dir.remove(&["/CONFIG/", key, ".BIN"].concat()) { @@ -127,18 +151,19 @@ impl Config { match root_dir.create_file("/CONFIG.TXT") { Ok(mut f) => { let mut buffer = String::new(); - f.read_to_string(&mut buffer)?; + read_to_string(&mut f, &mut buffer)?; f.seek(SeekFrom::Start(0))?; f.truncate()?; for line in buffer.lines() { - if line.len() > 0 && !line.to_ascii_lowercase().starts_with(&prefix) { + if line.len() > 0 && !line.to_ascii_lowercase().starts_with(&prefix) + { f.write(line.as_bytes())?; f.write(NEWLINE)?; } } Ok(()) - }, - Err(_) => Err(Error::KeyNotFoundError(key)) + } + Err(_) => Err(Error::KeyNotFoundError(key)), } } } @@ -164,7 +189,10 @@ impl Config { if is_str { let mut f = root_dir.create_file("/CONFIG.TXT")?; f.seek(SeekFrom::End(0))?; - write!(f, "{}={}\n", key, String::from_utf8(value).unwrap())?; + f.write(key.as_bytes()); + f.write("=".as_bytes()); + f.write(value.as_slice()); + f.write(NEWLINE); } else { let dir = root_dir.create_dir("/CONFIG")?; let mut f = dir.create_file(&[key, ".BIN"].concat())?; diff --git a/libconfig/src/sd_reader.rs b/libconfig/src/sd_reader.rs index c1da67b..6a11ea9 100644 --- a/libconfig/src/sd_reader.rs +++ b/libconfig/src/sd_reader.rs @@ -1,9 +1,8 @@ -use fatfs; -use fatfs::io::{Read, Seek, SeekFrom, Write} -use libboard_zynq::sdio::{sd_card::SdCard, CmdTransferError}; -use log::debug; use alloc::vec::Vec; use core::fmt; +use fatfs::{self, IoBase, IoError, Read, Seek, SeekFrom, Write}; +use libboard_zynq::sdio::{sd_card::SdCard, CmdTransferError}; +use log::debug; const MBR_SIGNATURE: [u8; 2] = [0x55, 0xAA]; const PARTID_FAT12: u8 = 0x01; @@ -17,24 +16,24 @@ const BLOCK_SIZE: usize = 512; #[derive(Debug)] pub struct Error { - message: String + message: &'static str, } impl Error { - pub fn new(message: &str) -> Self { - Self { message: String::new(message) } + pub fn new(message: &'static str) -> Self { + Self { message: message } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, self.message) + write!(f, "{}", self.message) } } impl IoError for Error { fn is_interrupted(&self) -> bool { - false + false } fn new_unexpected_eof_error() -> Self { @@ -110,7 +109,7 @@ impl SdReader { /// Internal read function for unaligned read. /// The read must not cross block boundary. - fn read_unaligned(&mut self, buf: &mut [u8]) -> Result { + fn read_unaligned(&mut self, buf: &mut [u8]) -> Result { if buf.len() == 0 { return Ok(0); } @@ -124,7 +123,7 @@ impl SdReader { /// Internal write function for unaligned write. /// The write must not cross block boundary. - fn write_unaligned(&mut self, buf: &[u8]) -> Result { + fn write_unaligned(&mut self, buf: &[u8]) -> Result { if buf.len() == 0 { return Ok(0); } @@ -175,7 +174,7 @@ impl SdReader { } /// Set the base offset of the SD card, to transform from physical address to logical address. - fn set_base_offset(&mut self, offset: u32) -> Result { + fn set_base_offset(&mut self, offset: u32) -> Result { self.offset = offset; self.seek(SeekFrom::Start(0)) } @@ -183,27 +182,28 @@ impl SdReader { /// Mount fatfs from partition entry, and return the fatfs object if success. /// This takes the ownership of self, so currently there is no way to recover from an error, /// except creating a new SD card instance. - pub fn mount_fatfs(mut self, entry: PartitionEntry) -> Result> { + pub fn mount_fatfs( + mut self, + entry: PartitionEntry, + ) -> Result, fatfs::Error> { let mut buffer: [u8; 4] = [0; 4]; self.seek(SeekFrom::Start(0x1FE))?; self.read_exact(&mut buffer[..2])?; // check MBR signature if buffer[..2] != MBR_SIGNATURE { - return Err(Error::new( - "Incorrect signature for MBR sector.", - )); + return Err(fatfs::Error::Io(Error::new("Incorrect signature for MBR sector."))); } // Read partition ID. self.seek(SeekFrom::Start(entry as u64 + 0x4))?; self.read_exact(&mut buffer[..1])?; debug!("Partition ID: {:0X}", buffer[0]); match buffer[0] { - PARTID_FAT12 | PARTID_FAT16_LESS32M | PARTID_FAT16 | - PARTID_FAT16_LBA | PARTID_FAT32 | PARTID_FAT32_LBA => {} + PARTID_FAT12 | PARTID_FAT16_LESS32M | PARTID_FAT16 | PARTID_FAT16_LBA + | PARTID_FAT32 | PARTID_FAT32_LBA => {} _ => { - return Err(Error::new( + return Err(fatfs::Error::Io(Error::new( "No FAT partition found for the specified entry.", - )); + ))); } } // Read LBA @@ -219,6 +219,25 @@ impl SdReader { // setup fatfs fatfs::FileSystem::new(self, fatfs::FsOptions::new()) } + + fn fill_buf(&mut self) -> Result<&[u8], Error> { + if self.index == BLOCK_SIZE { + // flush the buffer if it is dirty before overwriting it with new data + if self.dirty { + self.flush()?; + } + // reload buffer + self.sd + .read_block(self.byte_addr / (BLOCK_SIZE as u32), 1, &mut self.buffer)?; + self.index = (self.byte_addr as usize) % BLOCK_SIZE; + } + Ok(&self.buffer[self.index..]) + } + + fn consume(&mut self, amt: usize) { + self.index += amt; + self.byte_addr += amt as u32; + } } impl Read for SdReader { @@ -272,8 +291,7 @@ impl Write for SdReader { fn flush(&mut self) -> Result<(), Error> { if self.dirty { let block_addr = (self.byte_addr - self.index as u32) / (BLOCK_SIZE as u32); - self.sd - .write_block(block_addr, 1, &self.buffer)?; + self.sd.write_block(block_addr, 1, &self.buffer)?; self.dirty = false; } Ok(()) diff --git a/szl/src/main.rs b/szl/src/main.rs index 82dee7a..cc19d1e 100644 --- a/szl/src/main.rs +++ b/szl/src/main.rs @@ -8,7 +8,7 @@ mod netboot; use alloc::rc::Rc; use core::mem; -use fatfs::io::{Read, Seek}; +use fatfs::{self, DefaultTimeProvider, LossyOemCpConverter, Read, Seek}; use libboard_zynq::{ self as zynq, clocks::source::{ArmPll, ClockSource, IoPll}, @@ -16,7 +16,7 @@ use libboard_zynq::{ logger, println, sdio, slcr, timer::GlobalTimer, }; -use libconfig::{bootgen, sd_reader, Config}; +use libconfig::{bootgen, sd_reader, Config, File}; use libcortex_a9::{ asm::{dsb, isb}, cache::{bpiall, dcciall, iciallu}, @@ -30,8 +30,8 @@ extern "C" { static mut __runtime_end: usize; } -fn boot_sd( - file: &mut Option, +fn boot_sd<'a>( + file: &mut Option>, runtime_start: *mut u8, runtime_max: usize, ) -> Result<(), ()> { diff --git a/szl/src/netboot.rs b/szl/src/netboot.rs index 770c270..26e9413 100644 --- a/szl/src/netboot.rs +++ b/szl/src/netboot.rs @@ -1,7 +1,7 @@ use alloc::vec; use alloc::vec::Vec; use byteorder::{ByteOrder, NetworkEndian}; -use fatfs::io::{Read, Seek}; +use fatfs::{Read, Seek}; use libboard_zynq::{ devc, eth::Eth, @@ -13,7 +13,7 @@ use libboard_zynq::{ }, timer::GlobalTimer, }; -use libconfig::{bootgen, net_settings, Config}; +use libconfig::{bootgen, net_settings, Config, File}; enum NetConnState { WaitCommand, @@ -48,7 +48,7 @@ impl NetConn { self.gateware_downloaded = false; } - fn input_partial( + fn input_partial( &mut self, bootgen_file: &mut Option, runtime_start: *mut u8, @@ -284,9 +284,9 @@ impl NetConn { } } - fn input( + fn input<'a>( &mut self, - bootgen_file: &mut Option, + bootgen_file: &mut Option>, runtime_start: *mut u8, runtime_max_len: usize, buf: &[u8], @@ -309,8 +309,8 @@ impl NetConn { } } -pub fn netboot( - bootgen_file: &mut Option, +pub fn netboot<'a>( + bootgen_file: &mut Option>, cfg: Config, runtime_start: *mut u8, runtime_max_len: usize,