diff --git a/crates/filesystem/src/lib.rs b/crates/filesystem/src/lib.rs index c0be029c..7b1255ee 100644 --- a/crates/filesystem/src/lib.rs +++ b/crates/filesystem/src/lib.rs @@ -104,13 +104,14 @@ struct DirectoryEntryData { const _: () = assert!(size_of::() == 8); +#[derive(Debug)] pub struct DirectoryEntryRef<'a> { - inode_num: u32, - rec_len: u16, - name_len: u8, - file_type: u8, - name: &'a [u8], - dir_offset: usize, + pub inode_num: u32, + pub rec_len: u16, + pub name_len: u8, + pub file_type: u8, + pub name: &'a [u8], + pub dir_offset: usize, } impl DirectoryEntryData { @@ -258,24 +259,24 @@ const _: () = assert!(size_of::() == 32); #[repr(C)] #[derive(Copy, Clone, Debug)] pub struct INode { - i_mode: u16, - i_uid: u16, - i_size: u32, - i_atime: u32, - i_ctime: u32, - i_mtime: u32, - i_dtime: u32, - i_gid: u16, - i_links_count: u16, - i_blocks: u32, - i_flags: u32, - i_osd1: u32, - i_block: [u32; 15], // 12 direct, single, double, triple - i_generation: u32, - i_file_acl: u32, - i_dir_acl: u32, - i_faddr: u32, - i_osd2: [u8; 12], + pub i_mode: u16, + pub i_uid: u16, + pub i_size: u32, + pub i_atime: u32, + pub i_ctime: u32, + pub i_mtime: u32, + pub i_dtime: u32, + pub i_gid: u16, + pub i_links_count: u16, + pub i_blocks: u32, + pub i_flags: u32, + pub i_osd1: u32, + pub i_block: [u32; 15], // 12 direct, single, double, triple + pub i_generation: u32, + pub i_file_acl: u32, + pub i_dir_acl: u32, + pub i_faddr: u32, + pub i_osd2: [u8; 12], } const _: () = assert!(size_of::() == 128); @@ -351,8 +352,8 @@ const UNALLOCATED_BLOCK_SLOT: u32 = 0; #[derive(Debug)] pub struct INodeWrapper { - inode: INode, - _inode_num: u32, + pub inode: INode, + pub _inode_num: u32, } unsafe impl bytemuck::Zeroable for DirectoryEntryData {} diff --git a/crates/kernel/examples/ext2.rs b/crates/kernel/examples/ext2.rs new file mode 100644 index 00000000..11cec83f --- /dev/null +++ b/crates/kernel/examples/ext2.rs @@ -0,0 +1,57 @@ +#![no_std] +#![no_main] + +extern crate alloc; +extern crate kernel; + +use device::{discover_compatible, find_device_addr, sdcard}; +use filesystem::BlockDevice; +use fs::ext2::Ext2File; +use kernel::{device::sdcard::SD, sync::SpinLock, *}; + +#[no_mangle] +extern "Rust" fn kernel_main(tree: device_tree::DeviceTree) { + println!("| starting kernel_main"); + + // Should use this on hardware + // let sdcard = discover_compatible(&tree, b"brcm,bcm2711-emmc2") + // .unwrap() + // .next() + // .unwrap(); + // The bcm2835-sdhci requires additional gpio pin initialization which could possibly conflict with other drivers that need those pinss + let sdcard = discover_compatible(&tree, b"brcm,bcm2835-sdhci") + .unwrap() + .next() + .unwrap(); + let (sdcard_addr, _) = find_device_addr(sdcard).unwrap().unwrap(); + let sdcard_base = unsafe { memory::map_device(sdcard_addr) }.as_ptr(); + println!("| SD Card controller addr: {:#010x}", sdcard_addr as usize); + println!("| SD Card controller base: {:#010x}", sdcard_base as usize); + let sdcard = unsafe { sdcard::bcm2711_emmc2_driver::init(sdcard_base) }; + unsafe { SD.init(SpinLock::new(sdcard)) }; + println!("| initialized SD Card"); + + let block_device = SD.get(); + println!("Initializing ext2 filesystem"); + let mut fs = filesystem::Ext2::new(block_device).unwrap(); + + println!("Reading root dir"); + let root = fs.get_root_inode_wrapper(); + root.borrow_mut().get_dir_entries(&mut fs, |entry| { + let filename = core::str::from_utf8(entry.name).unwrap(); + println!("- {:?}: {:?}", filename, entry); + core::ops::ControlFlow::<()>::Continue(()) + }, None).unwrap(); + + println!("Creating 'example-file.txt'"); + fs.create_file(&mut *root.borrow_mut(), b"example-file.txt").unwrap(); + + println!("Re-reading root dir"); + root.borrow_mut().get_dir_entries(&mut fs, |entry| { + let filename = core::str::from_utf8(entry.name).unwrap(); + println!("- {:?}: {:?}", filename, entry); + core::ops::ControlFlow::<()>::Continue(()) + }, None).unwrap(); + + println!("Done with test"); +} diff --git a/crates/kernel/examples/sd.rs b/crates/kernel/examples/sd.rs index b14e061d..258918c7 100644 --- a/crates/kernel/examples/sd.rs +++ b/crates/kernel/examples/sd.rs @@ -6,6 +6,7 @@ extern crate kernel; use device::{discover_compatible, find_device_addr, sdcard}; use filesystem::BlockDevice; +use fs::ext2::Ext2File; use kernel::{device::sdcard::SD, sync::SpinLock, *}; #[no_mangle] @@ -72,4 +73,13 @@ extern "Rust" fn kernel_main(tree: device_tree::DeviceTree) { println!("{:?}", buf1024); assert_eq!(buf1024[0..512], buf0); assert_eq!(buf1024[512..1024], buf0); + + let block_device = SD.get(); + let mut fs = filesystem::Ext2::new(block_device).unwrap(); + + let root = fs.get_root_inode_wrapper(); + root.borrow_mut().get_dir_entries(&mut fs, |entry| { + println!("entry: {:?}", entry); + core::ops::ControlFlow::<()>::Continue(()) + }, None).unwrap(); } diff --git a/crates/kernel/scripts/run-usb.sh b/crates/kernel/scripts/run-usb.sh index c6cfd04e..ac98f84f 100755 --- a/crates/kernel/scripts/run-usb.sh +++ b/crates/kernel/scripts/run-usb.sh @@ -1,7 +1,8 @@ #!/usr/bin/env bash set -ex -QEMU_DISPLAY="default" QEMU_DEVICES="-usb -device usb-kbd -device usb-mouse -device usb-net,netdev=net0 -netdev user,id=net0,hostfwd=tcp::2222-:22 -object filter-dump,id=f1,netdev=net0,file=net0.pcap" "$(dirname "$0")/run.sh" +QEMU_DISPLAY="default" QEMU_DEVICES="-usb -device usb-kbd -device usb-mouse" "$(dirname "$0")/run.sh" +#QEMU_DISPLAY="default" QEMU_DEVICES="-usb -device usb-kbd -device usb-mouse -device usb-net,netdev=net0 -netdev user,id=net0,hostfwd=tcp::2222-:22 -object filter-dump,id=f1,netdev=net0,file=net0.pcap" "$(dirname "$0")/run.sh" # QEMU_DISPLAY="default" QEMU_DEVICES="-usb -device usb-kbd -device usb-mouse -device usb-net,netdev=net0 -netdev tap,id=net0,ifname=tap0,script=no,downscript=no -object filter-dump,id=f1,netdev=net0,file=net0.pcap" "$(dirname "$0")/run.sh" # QEMU_DISPLAY="default" QEMU_DEVICES="-usb -device usb-kbd -device usb-mouse -device usb-net,netdev=net0 -netdev bridge,id=net0,br=br0 -object filter-dump,id=f1,netdev=net0,file=net0.pcap" "$(dirname "$0")/run.sh" diff --git a/crates/kernel/scripts/run.sh b/crates/kernel/scripts/run.sh index d0dab554..f5ea2eb3 100755 --- a/crates/kernel/scripts/run.sh +++ b/crates/kernel/scripts/run.sh @@ -5,7 +5,7 @@ set -e # Check if sdcard.img exists, create it if not if [ ! -f sdcard.img ]; then echo "Creating SD card image" - qemu-img create -f raw sdcard.img 32M + mkfs.ext2 -q -b 4096 -i 4096 -I 128 -r 0 -t ext2 -d ../init/fs sdcard.img 32m echo "SD card image created" fi @@ -58,3 +58,5 @@ qemu-system-aarch64 \ # -netdev user,id=net0,hostfwd=tcp::2222-:22 \ # -object filter-dump,id=f1,netdev=net0,file=net0.pcap \ # -trace enable=net* \ + +rm -f sdcard.img diff --git a/crates/kernel/src/device/sdcard.rs b/crates/kernel/src/device/sdcard.rs index f8196103..cdfcf0c9 100644 --- a/crates/kernel/src/device/sdcard.rs +++ b/crates/kernel/src/device/sdcard.rs @@ -1,12 +1,10 @@ #![allow(dead_code, nonstandard_style)] -pub static SD: UnsafeInit> = unsafe { UnsafeInit::uninit() }; - // SDHCI driver for raspberry pi 4b // TODO: -// Rest of PR fixes -// Better error handling -// Assert test in sd.rs in /examples +// spin_sleep() timing validation +// cleanup error handling +// cleanup comments // https://github.com/jncronin/rpi-boot/blob/master/emmc.c // https://github.com/rsta2/circle/blob/master/addon/SDCard/emmc.cpp @@ -21,6 +19,8 @@ use filesystem::BlockDevice; // use super::{gpio, GPIO}; use super::{mailbox, MAILBOX}; +pub static SD: UnsafeInit> = unsafe { UnsafeInit::uninit() }; + #[derive(Debug, Copy, Clone)] pub struct SdScr { pub scr: [u32; 2], @@ -521,6 +521,8 @@ impl bcm2711_emmc2_driver { panic!("Cannot init SD card"); } + println!("| SD capacity is {:?} Bytes", driver.get_capacity()); + driver } @@ -1310,7 +1312,6 @@ impl bcm2711_emmc2_driver { } self.emmc.capacity = (nSize << nShift) as u64 * SD_BLOCK_SIZE as u64; - println!("SD capacity is {:?} Bytes", self.emmc.capacity); if let Err(e) = self.issue_command(SELECT_CARD, self.emmc.card_rca << 16, 500000) { println!("Error sending CMD7"); @@ -1395,7 +1396,7 @@ impl bcm2711_emmc2_driver { let old_irpt_mask = self.reg(IRPT_MASK).read(); let new_irpt_mask = old_irpt_mask & !(1 << 8); self.reg(IRPT_MASK).write(new_irpt_mask); - + self.issue_command(STOP_TRANSMISSION, 0, 500000); if self.issue_command(SET_BUS_WIDTH, 2, 500000).is_err() { println!("Switch to 4-bit data mode failed"); } else { @@ -1407,7 +1408,7 @@ impl bcm2711_emmc2_driver { } println!( - "Found a valid {:#?} SD Card", + "| Found a valid {:#?} SD Card", SD_VERSIONS[(*self.emmc.scr).sd_version as usize] ); @@ -1430,7 +1431,7 @@ impl bcm2711_emmc2_driver { let vendor = ver >> 24; let slot_status = ver & 0xff; println!( - "SD version: {:#?}, vendor: {:#010x}, slot status: {:#010x}", + "| SD version: {:#?}, vendor: {:#010x}, slot status: {:#010x}", SD_VERSIONS[sdversion as usize], vendor, slot_status ); @@ -1453,12 +1454,16 @@ impl bcm2711_emmc2_driver { fn ensure_data_mode(&mut self) -> Result<(), SdCardError> { if self.emmc.card_rca == CARD_RCA_INVALID { + println!("Card rca invalid, resetting"); let ret = self.card_reset(); if ret.is_err() { + println!("Card reset failed"); return ret; } } + + if let Err(e) = self.issue_command(SEND_STATUS, self.emmc.card_rca << 16, 500000) { self.emmc.card_rca = CARD_RCA_INVALID; println!("ensure_data_mode() error sending CMD13"); @@ -1482,12 +1487,14 @@ impl bcm2711_emmc2_driver { } let _ = self.reset_dat(); } else if cur_state != 4 { + println!("Card not in data mode resetting, cur_state: {:#010x}", cur_state); let ret = self.card_reset(); if ret.is_err() { return ret; } } if cur_state != 4 { + println!("Card still not in data mode, cur_state: {:#010x}", cur_state); if let Err(e) = self.issue_command(SEND_STATUS, self.emmc.card_rca << 16, 500000) { self.emmc.card_rca = CARD_RCA_INVALID; println!("ensure_data_mode() error sending CMD13"); @@ -1497,7 +1504,7 @@ impl bcm2711_emmc2_driver { cur_state = (status >> 9) & 0xf; if cur_state != 4 { self.emmc.card_rca = CARD_RCA_INVALID; - sderror!("Unable to initialize SD card to date mode") + sderror!("Unable to initialize SD card to data mode") } } Ok(()) @@ -1562,6 +1569,7 @@ impl bcm2711_emmc2_driver { self.emmc.card_rca = CARD_RCA_INVALID; return Err(SdCardError::Error); } + self.issue_command(STOP_TRANSMISSION, 0, 500000)?; Ok(()) } @@ -1574,9 +1582,7 @@ impl bcm2711_emmc2_driver { } fn do_write(&mut self, buf: &[u8], block_no: u32) -> Result { - if self.ensure_data_mode().is_err() { - return Err(SdCardError::Error); - } + self.ensure_data_mode()?; let ptr = buf.as_ptr() as *mut u8; let tmp: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(ptr, buf.len()) }; self.do_data_command(true, tmp, block_no)?; @@ -1631,6 +1637,28 @@ impl bcm2711_emmc2_driver { &self.emmc.id } + pub fn read_sector( + &mut self, + index: u64, + buffer: &mut [u8; filesystem::SECTOR_SIZE], + ) -> Result<(), filesystem::BlockDeviceError> { + self.seek(index * filesystem::SECTOR_SIZE as u64); + self.read(buffer) + .map_err(|_| filesystem::BlockDeviceError::Unknown)?; + Ok(()) + } + + pub fn write_sector( + &mut self, + index: u64, + buffer: &[u8; filesystem::SECTOR_SIZE], + ) -> Result<(), filesystem::BlockDeviceError> { + self.seek(index * filesystem::SECTOR_SIZE as u64); + self.write(buffer) + .map_err(|_| filesystem::BlockDeviceError::Unknown)?; + Ok(()) + } + pub fn read_sectors( &mut self, index: u64, @@ -1653,16 +1681,13 @@ impl bcm2711_emmc2_driver { } } -impl BlockDevice for bcm2711_emmc2_driver { +impl BlockDevice for &SpinLock { fn read_sector( &mut self, index: u64, buffer: &mut [u8; filesystem::SECTOR_SIZE], ) -> Result<(), filesystem::BlockDeviceError> { - self.seek(index * filesystem::SECTOR_SIZE as u64); - self.read(buffer) - .map_err(|_| filesystem::BlockDeviceError::Unknown)?; - Ok(()) + self.lock().read_sector(index, buffer) } fn write_sector( @@ -1670,10 +1695,23 @@ impl BlockDevice for bcm2711_emmc2_driver { index: u64, buffer: &[u8; filesystem::SECTOR_SIZE], ) -> Result<(), filesystem::BlockDeviceError> { - self.seek(index * filesystem::SECTOR_SIZE as u64); - self.write(buffer) - .map_err(|_| filesystem::BlockDeviceError::Unknown)?; - Ok(()) + self.lock().write_sector(index, buffer) + } + + fn read_sectors( + &mut self, + start_index: u64, + buffer: &mut [u8], + ) -> Result<(), filesystem::BlockDeviceError> { + self.lock().read_sectors(start_index, buffer) + } + + fn write_sectors( + &mut self, + start_index: u64, + buffer: &[u8], + ) -> Result<(), filesystem::BlockDeviceError> { + self.lock().write_sectors(start_index, buffer) } } diff --git a/crates/kernel/src/fs/ext2.rs b/crates/kernel/src/fs/ext2.rs new file mode 100644 index 00000000..a46d722c --- /dev/null +++ b/crates/kernel/src/fs/ext2.rs @@ -0,0 +1,63 @@ +#![allow(dead_code, nonstandard_style)] + +use crate::process; + +use filesystem::{*}; +use alloc::sync::{Arc, Weak}; +use process::fd::{FileDescriptor, boxed_future}; + +use crate::{device::sdcard::bcm2711_emmc2_driver, sync::SpinLock}; + +pub struct Ext2File { + pub ext2: Arc>>, + pub inode_wrapper: Arc>, +} + +impl FileDescriptor for Ext2File { + fn is_same_file(&self, other: &dyn FileDescriptor) -> bool { + if let Some(other) = other.as_any().downcast_ref::() { + // Note: removed the Arc::ptr_eq check for ext2, lmk if this is a problem + let self_inode_num = self.inode_wrapper.lock()._inode_num; + let other_inode_num = other.inode_wrapper.lock()._inode_num; + + self_inode_num == other_inode_num + } else { + false + } + } + + fn kind(&self) -> crate::process::fd::FileKind { + match self.inode_wrapper.lock().inode.i_mode & 0xF000 { + i_mode::EXT2_S_IFDIR => crate::process::fd::FileKind::Directory, + i_mode::EXT2_S_IFREG => crate::process::fd::FileKind::Regular, + i_mode::EXT2_S_IFLNK => crate::process::fd::FileKind::SymbolicLink, + _ => crate::process::fd::FileKind::Other, + } + + } + + fn read<'a>(&'a self, offset: u64, buf: &'a mut [u8]) -> crate::process::fd::SmallFuture<'a, crate::process::fd::FileDescResult> { + if self.inode_wrapper.lock().is_dir() { + todo!() + } else { + todo!() + } + } + + fn write<'a>(&'a self, offset: u64, buf: &'a [u8]) -> crate::process::fd::SmallFuture<'a, crate::process::fd::FileDescResult> { + todo!() + } + + fn size<'a>(&'a self) -> crate::process::fd::SmallFuture<'a, crate::process::fd::FileDescResult> { + let size = self.inode_wrapper.lock().size(); + crate::process::fd::boxed_future(async move { Ok(size).into() }) + } + + fn mmap_page(&self, offset: u64) -> crate::process::fd::SmallFuture> { + todo!() + } + + fn as_any(&self) -> &dyn core::any::Any { + self + } +} \ No newline at end of file diff --git a/crates/kernel/src/fs/mod.rs b/crates/kernel/src/fs/mod.rs index e12735d0..51eddcc1 100644 --- a/crates/kernel/src/fs/mod.rs +++ b/crates/kernel/src/fs/mod.rs @@ -1 +1,2 @@ pub mod initfs; +pub mod ext2;