Documentation and added mounting function

This commit is contained in:
pca006132 2020-06-12 10:32:14 +08:00
parent 7238e69f10
commit 5bb051d1f0
2 changed files with 98 additions and 50 deletions

View File

@ -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")
}

View File

@ -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(());
}
}