//! 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::{ cell::{LazyCell, UnsafeCell}, ops::Deref, }; use bffs::{ io::{IoBase, Read, Seek}, path::Path, Fat32FileSystem, }; use hashbrown::HashMap; const DISK_ADDR: *const u8 = 0x9000_0000 as *const _; /// Lazy holder for the kernel's filesystem instance. /// /// The inner `UnsafeCell` allows one-time initialization at early boot while /// exposing a shared `&'static` reference through `Deref` once initialized. pub struct FSTemp(UnsafeCell>>); unsafe impl Sync for FSTemp {} impl FSTemp { /// Initialize the global filesystem from the in-memory disk image. /// /// Safety: must be called exactly once during early kernel initialization /// before any other filesystem operations occur. pub unsafe fn init(&self) { unsafe { *self.0.get() = Some(Fat32FileSystem::new(Disk::new(1024 * 1024 * 16)).unwrap()); } } } impl Deref for FSTemp { type Target = Fat32FileSystem; fn deref(&self) -> &Self::Target { unsafe { (&*self.0.get()).as_ref().unwrap_unchecked() } } } pub static FILE_SYSTEM: FSTemp = FSTemp(UnsafeCell::new(None)); #[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: bffs::io::SeekFrom) -> Result> { match pos { bffs::io::SeekFrom::Start(pos) => self.pos = pos, bffs::io::SeekFrom::End(_) => unimplemented!(), bffs::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) } } pub struct KernelFDTable(LazyCell>>); unsafe impl Sync for KernelFDTable {} pub static KERNEL_FILE_DESCRIPTOR_TABLE: KernelFDTable = KernelFDTable(LazyCell::new(HashMap::new));