//! Simple wrapper around a FAT32 image exposed to the kernel. //! //! Implements a minimal disk backend and exposes a global FILE_SYSTEM used by //! the kernel to load user binaries. use core::fmt::Debug; use alloc::boxed::Box; use bffs::{Fat32FileSystem, ReadSeek, entry::DirEntry, file::File}; use io::{IoBase, Read, Seek, Write}; use crate::virtual_fs::{VirtualFileSystem, VirtualNode}; const DISK_ADDR: *const u8 = 0xA000_0000 as *const _; #[derive(Debug)] /// Simple disk backend that reads from a fixed memory region. /// /// The `Disk` struct provides `Read` and `Seek` implementations over a /// contiguous in-memory image exposed at DISK_ADDR. pub struct Disk { pos: u64, size: u64, } impl Disk { /// Create a new `Disk` representing an in-memory image of `size` bytes. pub fn new(size: u64) -> Self { Self { pos: 0, size } } } impl IoBase for Disk { type Error = (); } impl Seek for Disk { fn seek(&mut self, pos: io::SeekFrom) -> Result { match pos { io::SeekFrom::Start(pos) => self.pos = pos, io::SeekFrom::End(_) => unimplemented!(), io::SeekFrom::Current(pos) => self.pos = (self.pos as i64 + pos) as u64, } Ok(self.pos) } } impl Read for Disk { /// Read bytes from the in-memory disk image into `buf`. fn read(&mut self, buf: &mut [u8]) -> Result { if self.pos >= self.size { return Ok(0); } let size = usize::min(buf.len(), (self.size - self.pos) as usize); unsafe { core::ptr::copy_nonoverlapping( DISK_ADDR.byte_add(self.pos as usize), buf.as_mut_ptr(), size, ); } self.pos += size as u64; Ok(size) } } #[derive(Debug)] pub struct Fat32VirtualNode<'a, T> { kind: Fat32VirtualNodeType<'a, T>, _entry: DirEntry<'a, T>, } #[derive(Debug)] enum Fat32VirtualNodeType<'a, T> { Dir, File(File<'a, T>), } impl<'a, T: ReadSeek> Fat32VirtualNode<'a, T> { pub unsafe fn new(entry: DirEntry<'a, T>) -> Self { let kind = if entry.is_dir() { Fat32VirtualNodeType::Dir } else { Fat32VirtualNodeType::File(entry.to_file()) }; Self { kind, _entry: entry, } } } impl VirtualNode for Fat32VirtualNode<'_, T> {} impl IoBase for Fat32VirtualNode<'_, T> { type Error = (); } impl Seek for Fat32VirtualNode<'_, T> { fn seek(&mut self, pos: io::SeekFrom) -> Result { match &mut self.kind { Fat32VirtualNodeType::Dir => todo!(), Fat32VirtualNodeType::File(file) => file.seek(pos).map_err(|_| ()), } } } impl Read for Fat32VirtualNode<'_, T> { fn read(&mut self, buf: &mut [u8]) -> Result { match &mut self.kind { Fat32VirtualNodeType::Dir => unimplemented!(), Fat32VirtualNodeType::File(file) => file.read(buf).map_err(|_| ()), } } } impl Write for Fat32VirtualNode<'_, T> { fn write(&mut self, _buf: &[u8]) -> Result { todo!() } fn flush(&mut self) -> Result<(), Self::Error> { todo!() } } impl VirtualFileSystem for Fat32FileSystem { fn open(&mut self, path: &bffs::path::Path) -> Result, ()> { let entry = self.open_entry(path).unwrap(); Ok(Box::new(unsafe { Fat32VirtualNode::new(entry) })) } }