Documentation and added mounting function
This commit is contained in:
parent
7238e69f10
commit
5bb051d1f0
|
@ -10,10 +10,6 @@ use log::info;
|
|||
use libboard_zynq::{timer::GlobalTimer, logger, devc, ddr, sdio};
|
||||
use libsupport_zynq::ram;
|
||||
|
||||
use core_io::{Seek, Read, Write, SeekFrom};
|
||||
|
||||
use fatfs;
|
||||
|
||||
mod proto_core_io;
|
||||
mod proto_async;
|
||||
// mod comms;
|
||||
|
@ -57,19 +53,7 @@ pub fn main_core0() {
|
|||
let mut sd = sdio::sd_card::SdCard::from_sdio(sdio0).unwrap();
|
||||
let mut reader = sd_reader::SdReader::new(&mut sd);
|
||||
|
||||
let mut lba_buffer: [u8; 4] = [0; 4];
|
||||
reader.seek(SeekFrom::Start(0x1BE + 0x8));
|
||||
reader.read(&mut lba_buffer).unwrap();
|
||||
// read MBR and get first partition LBA, hopefully it is FAT32
|
||||
let mut lba: u32 = 0;
|
||||
for i in 0..4 {
|
||||
lba |= (lba_buffer[i] as u32) << (i * 8);
|
||||
}
|
||||
info!("LBA = 0x{:0X}", lba);
|
||||
reader.seek(SeekFrom::Start(0)).unwrap();
|
||||
reader.set_base_offset(lba * 0x200);
|
||||
|
||||
let fs = fatfs::FileSystem::new(reader, fatfs::FsOptions::new()).unwrap();
|
||||
let fs = reader.mount_fatfs(sd_reader::PartitionEntry::Entry1).unwrap();
|
||||
let root_dir = fs.root_dir();
|
||||
for entry in root_dir.iter() {
|
||||
if let Ok(entry) = entry {
|
||||
|
@ -78,10 +62,8 @@ pub fn main_core0() {
|
|||
for b in bytes {
|
||||
info!("{}", *b as char);
|
||||
}
|
||||
// info!("- {}", entry.short_file_name_as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
info!("Card not inserted")
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use core_io::{BufRead, Error, ErrorKind, Read, Result as IoResult, Seek, SeekFrom, Write};
|
||||
use fatfs;
|
||||
use libboard_zynq::sdio::{sd_card::SdCard, CmdTransferError};
|
||||
|
||||
fn cmd_error_to_io_error(_: CmdTransferError) -> Error {
|
||||
|
@ -7,6 +8,12 @@ fn cmd_error_to_io_error(_: CmdTransferError) -> Error {
|
|||
|
||||
const BLOCK_SIZE: usize = 512;
|
||||
|
||||
/// SdReader struct implementing `Read + BufRead + Write + Seek` traits for `core_io`.
|
||||
/// Used as an adaptor for fatfs crate, but could be used directly for raw data access.
|
||||
///
|
||||
/// Implementation: all read/writes would be split into unaligned and block-aligned parts,
|
||||
/// unaligned read/writes would do a buffered read/write using a block-sized internal buffer,
|
||||
/// while aligned transactions would be sent to the SD card directly for performance reason.
|
||||
pub struct SdReader<'a> {
|
||||
/// Internal SdCard handle.
|
||||
sd: &'a mut SdCard,
|
||||
|
@ -22,11 +29,22 @@ pub struct SdReader<'a> {
|
|||
index: usize,
|
||||
/// Dirty flag indicating the content has to be flushed.
|
||||
dirty: bool,
|
||||
/// Base offset for upcoming read/writes
|
||||
/// Base offset for translation from logical address to physical address.
|
||||
offset: u32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(unused)]
|
||||
// Partition entry enum, normally we would use entry1.
|
||||
pub enum PartitionEntry {
|
||||
Entry1 = 0x1BE,
|
||||
Entry2 = 0x1CE,
|
||||
Entry3 = 0x1DE,
|
||||
Entry4 = 0x1EE,
|
||||
}
|
||||
|
||||
impl<'a> SdReader<'a> {
|
||||
/// Create SdReader from SdCard
|
||||
pub fn new(sd: &'a mut SdCard) -> SdReader<'a> {
|
||||
SdReader {
|
||||
sd,
|
||||
|
@ -38,7 +56,7 @@ impl<'a> SdReader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Internal read function for not block aligned read.
|
||||
/// Internal read function for unaligned read.
|
||||
/// The read must not cross block boundary.
|
||||
fn read_unaligned(&mut self, buf: &mut [u8]) -> IoResult<usize> {
|
||||
if buf.len() == 0 {
|
||||
|
@ -52,13 +70,13 @@ impl<'a> SdReader<'a> {
|
|||
Ok(buf.len())
|
||||
}
|
||||
|
||||
/// Internal write function for not block aligned write.
|
||||
/// Internal write function for unaligned write.
|
||||
/// The write must not cross block boundary.
|
||||
fn write_unaligned(&mut self, buf: &[u8]) -> IoResult<usize> {
|
||||
if buf.len() == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
// update buffer
|
||||
// update buffer if needed, as we will flush the entire block later.
|
||||
self.fill_buf()?;
|
||||
self.dirty = true;
|
||||
let dest_buffer = &mut self.buffer[self.index..];
|
||||
|
@ -69,6 +87,8 @@ impl<'a> SdReader<'a> {
|
|||
Ok(buf.len())
|
||||
}
|
||||
|
||||
/// Split the slice into three segments, with the middle block-aligned.
|
||||
/// Alignment depends on the current `self.byte_addr` instead of the slice pointer address
|
||||
fn block_align<'b>(&self, buf: &'b [u8]) -> (&'b [u8], &'b [u8], &'b [u8]) {
|
||||
let head_len = BLOCK_SIZE - (self.byte_addr as usize % BLOCK_SIZE);
|
||||
if head_len > buf.len() {
|
||||
|
@ -82,6 +102,8 @@ impl<'a> SdReader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Split the mutable slice into three segments, with the middle block-aligned.
|
||||
/// Alignment depends on the current `self.byte_addr` instead of the slice pointer address
|
||||
fn block_align_mut<'b>(&self, buf: &'b mut [u8]) -> (&'b mut [u8], &'b mut [u8], &'b mut [u8]) {
|
||||
let head_len = BLOCK_SIZE - (self.byte_addr as usize % BLOCK_SIZE);
|
||||
if head_len > buf.len() {
|
||||
|
@ -95,14 +117,55 @@ impl<'a> SdReader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Invalidate the buffer, so later unaligned read/write would reload the buffer from SD card.
|
||||
fn invalidate_buffer(&mut self) {
|
||||
self.index = BLOCK_SIZE;
|
||||
}
|
||||
|
||||
pub fn set_base_offset(&mut self, offset: u32) {
|
||||
/// Set the base offset of the SD card, to transform from physical address to logical address.
|
||||
fn set_base_offset(&mut self, offset: u32) -> IoResult<u64> {
|
||||
self.offset = offset;
|
||||
self.byte_addr += offset;
|
||||
self.invalidate_buffer();
|
||||
self.seek(SeekFrom::Start(0))
|
||||
}
|
||||
|
||||
/// 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) -> IoResult<fatfs::FileSystem<Self>> {
|
||||
let mut buffer: [u8; 4] = [0; 4];
|
||||
self.seek(SeekFrom::Start(0x1FE))?;
|
||||
self.read_exact(&mut buffer[..2])?;
|
||||
// check MBR signature
|
||||
if buffer[0] != 0x55 || buffer[1] != 0xAA {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
"Incorrect signature for MBR sector.",
|
||||
));
|
||||
}
|
||||
// Read partition ID.
|
||||
self.seek(SeekFrom::Start(entry as u64 + 0x4))?;
|
||||
self.read_exact(&mut buffer[..1])?;
|
||||
match buffer[0] {
|
||||
0x01 | 0x04 | 0x06 | 0x0B => (),
|
||||
_ => {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
"No FAT partition found for the specified entry.",
|
||||
))
|
||||
}
|
||||
};
|
||||
// Read LBA
|
||||
self.seek(SeekFrom::Current(0x3))?;
|
||||
self.read_exact(&mut buffer)?;
|
||||
let mut lba: u32 = 0;
|
||||
// Little endian
|
||||
for i in 0..4 {
|
||||
lba |= (buffer[i] as u32) << (i * 8);
|
||||
}
|
||||
// Set to logical address
|
||||
self.set_base_offset(lba * BLOCK_SIZE as u32)?;
|
||||
// setup fatfs
|
||||
fatfs::FileSystem::new(self, fatfs::FsOptions::new())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,23 +177,25 @@ impl<'a> Read for SdReader<'a> {
|
|||
if b.len() > 0 {
|
||||
// invalidate internal buffer
|
||||
self.invalidate_buffer();
|
||||
self.sd
|
||||
.read_block(
|
||||
self.byte_addr / BLOCK_SIZE as u32,
|
||||
(b.len() / BLOCK_SIZE) as u16,
|
||||
b,
|
||||
)
|
||||
.map_err(cmd_error_to_io_error)?;
|
||||
if let Err(_) = self.sd.read_block(
|
||||
self.byte_addr / BLOCK_SIZE as u32,
|
||||
(b.len() / BLOCK_SIZE) as u16,
|
||||
b,
|
||||
) {
|
||||
// we have to allow partial read, as per the trait required
|
||||
return Ok(a.len());
|
||||
}
|
||||
}
|
||||
if let Err(_) = self.read_unaligned(c) {
|
||||
// we have to allow partial read, as per the trait required
|
||||
return Ok(a.len() + b.len());
|
||||
}
|
||||
self.read_unaligned(c)?;
|
||||
Ok(total_length)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BufRead for SdReader<'a> {
|
||||
fn fill_buf(&mut self) -> IoResult<&[u8]> {
|
||||
assert!(self.index <= BLOCK_SIZE, "Invalid index!");
|
||||
|
||||
if self.index == BLOCK_SIZE {
|
||||
// flush the buffer if it is dirty before overwriting it with new data
|
||||
if self.dirty {
|
||||
|
@ -146,8 +211,6 @@ impl<'a> BufRead for SdReader<'a> {
|
|||
}
|
||||
|
||||
fn consume(&mut self, amt: usize) {
|
||||
assert!(self.index + amt <= BLOCK_SIZE, "Invalid amt!");
|
||||
|
||||
self.index += amt;
|
||||
self.byte_addr += amt as u32;
|
||||
}
|
||||
|
@ -159,15 +222,17 @@ impl<'a> Write for SdReader<'a> {
|
|||
self.write_unaligned(a)?;
|
||||
if b.len() > 0 {
|
||||
self.invalidate_buffer();
|
||||
self.sd
|
||||
.write_block(
|
||||
self.byte_addr / BLOCK_SIZE as u32,
|
||||
(b.len() / BLOCK_SIZE) as u16,
|
||||
b,
|
||||
)
|
||||
.map_err(cmd_error_to_io_error)?;
|
||||
if let Err(_) = self.sd.write_block(
|
||||
self.byte_addr / BLOCK_SIZE as u32,
|
||||
(b.len() / BLOCK_SIZE) as u16,
|
||||
b,
|
||||
) {
|
||||
return Ok(a.len());
|
||||
}
|
||||
}
|
||||
if let Err(_) = self.write_unaligned(c) {
|
||||
return Ok(a.len() + b.len());
|
||||
}
|
||||
self.write_unaligned(c)?;
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
|
@ -186,11 +251,11 @@ impl<'a> Write for SdReader<'a> {
|
|||
impl<'a> Seek for SdReader<'a> {
|
||||
fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> {
|
||||
let raw_target = match pos {
|
||||
SeekFrom::Start(x) => x as i64,
|
||||
SeekFrom::Start(x) => self.offset as i64 + x as i64,
|
||||
SeekFrom::Current(x) => self.byte_addr as i64 + x,
|
||||
SeekFrom::End(_) => panic!("SD card does not support seek from end"),
|
||||
} + self.offset as i64;
|
||||
if raw_target < 0 || raw_target > core::u32::MAX as i64 {
|
||||
};
|
||||
if raw_target < self.offset as i64 || raw_target > core::u32::MAX as i64 {
|
||||
return Err(Error::new(ErrorKind::InvalidInput, "Invalid address"));
|
||||
}
|
||||
let target_byte_addr = raw_target as u32;
|
||||
|
@ -208,7 +273,7 @@ impl<'a> Seek for SdReader<'a> {
|
|||
// invalidate the buffer as we moved to a different block
|
||||
BLOCK_SIZE
|
||||
};
|
||||
Ok(self.byte_addr as u64)
|
||||
Ok((self.byte_addr - self.offset) as u64)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,3 +283,4 @@ impl<'a> Drop for SdReader<'a> {
|
|||
self.flush().unwrap_or(());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue