diff --git a/srcs/cli/commands/debugfs.rs b/srcs/cli/commands/debugfs.rs index dff9b998..2df9ce4f 100644 --- a/srcs/cli/commands/debugfs.rs +++ b/srcs/cli/commands/debugfs.rs @@ -8,7 +8,7 @@ use crate::utils::path::Path; pub static ROOT_INODE: usize = 2; pub static CURRENTDIR_INODE: Mutex = Mutex::new(ROOT_INODE); pub static PWD: Mutex> = Mutex::new(None); -pub static DISKNO: Mutex = Mutex::new(-1); +pub static DISKNO: Mutex> = Mutex::new(None); fn help() { crate::kprintln!( @@ -55,7 +55,7 @@ fn rm(command: Vec) { return; } ext2::remove_file( - *DISKNO.lock() as u8, + DISKNO.lock().as_mut().unwrap(), command[1].as_str(), *CURRENTDIR_INODE.lock() ); @@ -67,7 +67,7 @@ fn stat(command: Vec) { return; } ext2::show_inode_info( - *DISKNO.lock() as u8, + DISKNO.lock().as_ref().unwrap(), command[1].as_str(), *CURRENTDIR_INODE.lock() ); @@ -79,7 +79,7 @@ fn mkdir(command: Vec) { return; } ext2::create_dir( - *DISKNO.lock() as u8, + DISKNO.lock().as_mut().unwrap(), command[1].as_str(), *CURRENTDIR_INODE.lock() ); @@ -91,7 +91,7 @@ fn touch(command: Vec) { return; } ext2::create_file( - *DISKNO.lock() as u8, + DISKNO.lock().as_mut().unwrap(), command[1].as_str(), *CURRENTDIR_INODE.lock() ); @@ -103,7 +103,7 @@ fn cat(command: Vec) { return; } let file_content = ext2::get_file_content( - *DISKNO.lock() as u8, + DISKNO.lock().as_ref().unwrap(), command[1].as_str(), *CURRENTDIR_INODE.lock() ); @@ -113,13 +113,13 @@ fn cat(command: Vec) { } fn test() { - let mut ext2 = ext2::Ext2::new(*DISKNO.lock() as u8) - .expect("Disk is not a ext2 filesystem."); + // let binding = DISKNO.lock(); + // let ext2 = binding.as_ref().unwrap(); // let mut dentry = crate::fs::ext2::inode::Dentry::default(); - - let _node = ext2.alloc_node(0); - let _block = ext2.alloc_block(0); - crate::dprintln!("Node {}", _node); + // + // let _node = ext2.alloc_node(0); + // let _block = ext2.alloc_block(0); + // crate::dprintln!("Node {}", _node); } fn ls(command: Vec) { @@ -128,8 +128,11 @@ fn ls(command: Vec) { _ => command[1].as_str() }; crate::dprintln!("Ls: {}", path); - let dentries = - ext2::list_dir(*DISKNO.lock() as u8, path, *CURRENTDIR_INODE.lock()); + let dentries = ext2::list_dir( + DISKNO.lock().as_ref().unwrap(), + path, + *CURRENTDIR_INODE.lock() + ); for i in dentries { crate::kprint!("{} ", i.name); @@ -143,8 +146,8 @@ fn cd(command: Vec) { _ => command[1].as_str() }; let path = Path::new(path); - let ext2 = ext2::Ext2::new(*DISKNO.lock() as u8) - .expect("Disk is not a ext2 filesystem."); + let binding = DISKNO.lock(); + let ext2 = binding.as_ref().unwrap(); let lookup = ext2.recurs_find(path.as_str(), *CURRENTDIR_INODE.lock()); match lookup { None => crate::kprintln!("Dir not found"), @@ -174,8 +177,8 @@ fn imap(command: Vec) { 1 => "/", _ => command[1].as_str() }; - let ext2 = ext2::Ext2::new(*DISKNO.lock() as u8) - .expect("Disk is not a ext2 filesystem."); + let binding = DISKNO.lock(); + let ext2 = binding.as_ref().unwrap(); let lookup = ext2.get_inode_of(path); match lookup { None => crate::kprintln!("File not found"), diff --git a/srcs/disk/ide.rs b/srcs/disk/ide.rs new file mode 100644 index 00000000..aba8bafa --- /dev/null +++ b/srcs/disk/ide.rs @@ -0,0 +1,34 @@ +use super::DiskIO; +use crate::pci::ide::IDEDevice; + +pub struct IDEDisk { + diskno: u8, + device: IDEDevice +} + +unsafe impl Send for IDEDisk {} + +impl IDEDisk { + pub const fn new(diskno: u8, device: IDEDevice) -> Self { + Self { diskno, device } + } +} + +impl DiskIO for IDEDisk { + fn read_sectors(&self, numsects: u8, lba: u32, edi: u32) -> Result<(), u8> { + self.device.read_sectors(numsects, lba, edi) + } + + fn write_sectors( + &mut self, + numsects: u8, + lba: u32, + edi: u32 + ) -> Result<(), u8> { + self.device.write_sectors(numsects, lba, edi) + } + + fn sector_size(&self) -> usize { + self.device.sector_size() as usize + } +} diff --git a/srcs/disk/mod.rs b/srcs/disk/mod.rs new file mode 100644 index 00000000..b805b722 --- /dev/null +++ b/srcs/disk/mod.rs @@ -0,0 +1,74 @@ +use crate::alloc::boxed::Box; +use crate::alloc::vec::Vec; +use crate::pci::ide::IDE; + +pub mod ide; +use ide::IDEDisk; + +pub trait DiskIO { + fn read_sectors(&self, numsects: u8, lba: u32, edi: u32) -> Result<(), u8>; + + fn write_sectors( + &mut self, + numsects: u8, + lba: u32, + edi: u32 + ) -> Result<(), u8>; + + fn sector_size(&self) -> usize; +} + +pub fn discover() -> Vec> { + let mut found_disks = Vec::>::new(); + + // Discover IDE disks + let binding = IDE.lock(); + for i in 0..4 { + let disk = binding.get_device(i); + match disk { + Some(x) => { + let idedisk = IDEDisk::new(i as u8, x.clone()); + let diskio = Box::new(idedisk); + found_disks.push(diskio); + }, + None => {} + } + } + + found_disks +} + +#[cfg(test)] +mod test { + + use super::ide::IDEDisk; + use super::DiskIO; + use crate::alloc::vec; + use crate::{sys_macros, IDE}; + + #[sys_macros::test_case] + fn idedisk_read_write_sector() { + let to_write = vec!['C' as u8; 512]; + let read_from = vec![0x0 as u8; 512]; + + let device = IDE.lock().get_device(1).unwrap().clone(); + let mut idedisk = IDEDisk::new(1, device); + let _ = idedisk.write_sectors(1, 0x0, to_write.as_ptr() as u32); + let _ = idedisk.read_sectors(1, 0x0, read_from.as_ptr() as u32); + + assert_eq!(to_write, read_from); + } + + #[sys_macros::test_case] + fn idedisk_read_write_multiple_sectors() { + let to_write = vec!['D' as u8; 1024]; + let read_from = vec![0x0 as u8; 1024]; + + let device = IDE.lock().get_device(1).unwrap().clone(); + let mut idedisk = IDEDisk::new(1, device); + let _ = idedisk.write_sectors(2, 0x0, to_write.as_ptr() as u32); + let _ = idedisk.read_sectors(2, 0x0, read_from.as_ptr() as u32); + + assert_eq!(to_write, read_from); + } +} diff --git a/srcs/fs/ext2/mod.rs b/srcs/fs/ext2/mod.rs index a5fc87af..1b3bc55d 100644 --- a/srcs/fs/ext2/mod.rs +++ b/srcs/fs/ext2/mod.rs @@ -1,8 +1,10 @@ use crate::alloc::vec; +use crate::disk::DiskIO; use crate::pci::ide::IDE; use crate::string::ToString; use crate::utils::math::roundup; use crate::utils::path::Path; +use alloc::boxed::Box; mod bitmap; pub mod block; @@ -13,32 +15,21 @@ pub mod inode; /// In the filesystem created to test it this means we read/write 16 sectors for each operations /// This is pretty ineffective and will probably need optimisation in later version pub struct Ext2 { - diskno: u8, sector_size: usize, + diskio: Box, pub sblock: block::BaseSuperblock } impl Ext2 { - pub fn new(diskno: u8) -> Result { - let sector_size = { - let binding = IDE.lock(); - let device = binding.get_device(diskno); - if device.is_none() { - return Err(1); - } - match device.unwrap().r#type { - x if x == ide::IDEType::ATA as u16 => ide::ata::SECTOR_SIZE, - x if x == ide::IDEType::ATAPI as u16 => ide::atapi::SECTOR_SIZE, - _ => { - panic!("Unrecognized disk.") - } - } - }; - Ok(Self { - diskno: diskno, - sector_size: sector_size as usize, - sblock: read_superblock(diskno, sector_size as usize)? - }) + pub fn new(mut diskio: Box) -> Result { + let sector_size = diskio.sector_size() as usize; + let sblock = read_superblock(&mut diskio)?; + let fs = Self { sector_size, diskio, sblock }; + if fs.is_valid() { + Ok(fs) + } else { + Err(0x01) + } } pub fn is_valid(&self) -> bool { @@ -114,12 +105,9 @@ impl Ext2 { let first_sector = (bsize * block_no as usize) / self.sector_size; let mut block: crate::vec::Vec = crate::vec::Vec::new(); for i in first_sector..first_sector + nb_sector { - IDE.lock().read_sectors( - self.diskno, - 1, - i as u32, - buffer.as_ptr() as u32 - ); + self.diskio + .read_sectors(1, i as u32, buffer.as_ptr() as u32) + .expect("Something went wrong in read_block"); let mut start = 0; if sector_per_block < 1.0 { start = (block_no as usize % (1.0 / sector_per_block) as usize) @@ -137,12 +125,13 @@ impl Ext2 { let sector_per_block = bsize / self.sector_size as usize; let sector_no = bsize / self.sector_size as usize; - IDE.lock().write_sectors( - self.diskno, - sector_no as u8, - block_no * sector_per_block as u32, - block.as_ptr() as u32 - ); + self.diskio + .write_sectors( + sector_no as u8, + block_no * sector_per_block as u32, + block.as_ptr() as u32 + ) + .expect("Something went wrong in write block"); } fn write_slice(&mut self, block_no: u32, offset: usize, slice: &[u8]) { @@ -513,9 +502,9 @@ impl Ext2 { use crate::pci::ide; pub fn read_superblock( - diskno: u8, - sector_size: usize + diskio: &mut Box ) -> Result { + let sector_size = diskio.sector_size(); // superblock is at index 1024 and 1024 bytes long let mut nb_sector = roundup(2048 / sector_size, 1) as usize; // sector_size > 2048 @@ -524,12 +513,7 @@ pub fn read_superblock( } let buffer: Vec = vec![0; nb_sector * sector_size]; - IDE.lock().read_sectors( - diskno, - nb_sector as u8, - 0, - buffer.as_ptr() as u32 - )?; + diskio.read_sectors(nb_sector as u8, 0, buffer.as_ptr() as u32)?; let mut sblock = block::BaseSuperblock::from(&buffer[1024..1024 + 84]); if sblock.version().0 >= 1 { sblock.set_extension(block::ExtendedSuperblock::from( @@ -539,9 +523,9 @@ pub fn read_superblock( Ok(sblock) } -pub fn is_ext2(diskno: u8) -> bool { - Ext2::new(diskno as u8).is_ok_and(|fs| fs.is_valid()) -} +// pub fn is_ext2(diskno: u8) -> bool { +// Ext2::new(diskno as u8).is_ok_and(|fs| fs.is_valid()) +// } use crate::vec::Vec; @@ -553,8 +537,8 @@ fn get_block_content(block: Vec, size: usize) -> Vec { /// Helper function to get content of a file. /// Does not yet check if found entry is really a file. /// Does not yet take into account file bigger than 4096 -pub fn get_file_content(diskno: u8, path: &str, inode: usize) -> Vec { - let ext2 = Ext2::new(diskno).expect("Disk is not a ext2 filesystem."); +pub fn get_file_content(ext2: &Ext2, path: &str, inode: usize) -> Vec { + // let ext2 = Ext2::new(diskno).expect("Disk is not a ext2 filesystem."); let opt = ext2.recurs_find(path, inode); match opt { None => Vec::new(), @@ -653,11 +637,11 @@ pub fn get_file_content(diskno: u8, path: &str, inode: usize) -> Vec { /// Helper function to list all entries in a directory /// Does not yet check if found entry is a directory or not pub fn list_dir( - diskno: u8, + ext2: &Ext2, path: &str, inode: usize ) -> crate::vec::Vec { - let ext2 = Ext2::new(diskno).expect("Disk is not a ext2 filesystem."); + // let ext2 = Ext2::new(diskno).expect("Disk is not a ext2 filesystem."); let inode = ext2.recurs_find(path, inode); return match inode { None => crate::vec::Vec::new(), @@ -680,8 +664,8 @@ pub fn list_dir( }; } -pub fn create_file(diskno: u8, path: &str, inode_no: usize) { - let mut ext2 = Ext2::new(diskno).expect("Disk is not a ext2 filesystem."); +pub fn create_file(ext2: &mut Ext2, path: &str, inode_no: usize) { + // let mut ext2 = Ext2::new(diskno).expect("Disk is not a ext2 filesystem."); let path = Path::new(path); let filename = path.file_name().unwrap(); let binding = path.parent().unwrap(); @@ -725,8 +709,8 @@ pub fn create_file(diskno: u8, path: &str, inode_no: usize) { } } -pub fn remove_file(diskno: u8, path: &str, inode_no: usize) { - let mut ext2 = Ext2::new(diskno).expect("Disk is not a ext2 filesystem."); +pub fn remove_file(ext2: &mut Ext2, path: &str, inode_no: usize) { + // let mut ext2 = Ext2::new(diskno).expect("Disk is not a ext2 filesystem."); let path = Path::new(path); let filename = path.file_name().unwrap(); let binding = path.parent().unwrap(); @@ -753,8 +737,8 @@ pub fn remove_file(diskno: u8, path: &str, inode_no: usize) { } /// Helper function to create a folder at a given path -pub fn create_dir(diskno: u8, path: &str, inode_no: usize) { - let mut ext2 = Ext2::new(diskno).expect("Disk is not a ext2 filesystem."); +pub fn create_dir(ext2: &mut Ext2, path: &str, inode_no: usize) { + // let mut ext2 = Ext2::new(diskno).expect("Disk is not a ext2 filesystem."); let path = Path::new(path); let new_dir = path.file_name().unwrap(); let binding = path.parent().unwrap(); @@ -826,8 +810,8 @@ pub fn create_dir(diskno: u8, path: &str, inode_no: usize) { } } -pub fn show_inode_info(diskno: u8, path: &str, inode_no: usize) { - let ext2 = Ext2::new(diskno).expect("Disk is not a ext2 filesystem."); +pub fn show_inode_info(ext2: &Ext2, path: &str, inode_no: usize) { + // let ext2 = Ext2::new(diskno).expect("Disk is not a ext2 filesystem."); let inode = ext2.recurs_find(&path, inode_no); match inode { None => { diff --git a/srcs/kinit.rs b/srcs/kinit.rs index 63393689..880b424d 100644 --- a/srcs/kinit.rs +++ b/srcs/kinit.rs @@ -76,6 +76,7 @@ mod interrupts; mod multiboot; #[macro_use] mod syscalls; +mod disk; mod io; mod pci; mod pic; diff --git a/srcs/kmain.rs b/srcs/kmain.rs index cb4fd78b..1f18d93e 100644 --- a/srcs/kmain.rs +++ b/srcs/kmain.rs @@ -33,21 +33,20 @@ mod poc { } use crate::cli::DISKNO; +use crate::disk; use crate::fs::ext2; #[no_mangle] pub extern "C" fn kmain() -> ! { - for i in 0..4 { - if ext2::is_ext2(i) { - *DISKNO.lock() = i as i8; - crate::kprintln!("Found ext2 filesystem on disk {}.", i); - break; + // Mounting first ext2 disk found to DISKNO + let disks = disk::discover(); + for i in disks { + if let Ok(ext) = ext2::Ext2::new(i) { + kprintln!("Found an ext2 fs"); + *DISKNO.lock() = Some(ext); } } - if *DISKNO.lock() == -1 { - todo!("No ext2 disk found."); - } - // poc::insertion_poc(); + kprintln!("Hello World of {}!", 42); change_color!(Color::Red, Color::White); let workspace_msg = string::String::from( diff --git a/srcs/pci/ide/ata.rs b/srcs/pci/ide/ata.rs index b8893e63..997150e8 100644 --- a/srcs/pci/ide/ata.rs +++ b/srcs/pci/ide/ata.rs @@ -1,4 +1,4 @@ -use super::{IDEChannelRegisters, IDEController, IDEDevice, IDE_IRQ_INVOKED}; +use super::{IDEChannelRegisters, IDEDevice, IDE_IRQ_INVOKED}; use crate::io; @@ -103,13 +103,17 @@ pub struct ATA {} impl ATA { pub fn access( direction: u8, - device: &mut IDEDevice, + device: &IDEDevice, lba: u32, numsects: u8, mut edi: u32 ) -> Result<(), u8> { - let binding = device.channel.as_mut().ok_or(1)?; - let channel: &mut IDEChannelRegisters = &mut binding.lock(); + let binding = match &device.channel { + Some(x) => x, + None => return Err(0x1) + }; + let bind = binding.lock(); + let mut channel = bind.borrow_mut(); let lba_mode: u8; // 0: CHS, 1: LBA28, 2: LBA48 let dma: u8; // 0: No DMA, 1: DMA let mut lba_io: [u8; 6] = [0; 6]; @@ -124,7 +128,7 @@ impl ATA { // Disable IRQ *IDE_IRQ_INVOKED.lock() = 0x0; channel.n_ien = 0x02; - IDEController::write(channel, ATAReg::CONTROL, channel.n_ien); + channel.write(ATAReg::CONTROL, 0x02); // (I) Select one from LBA28, LBA48 or CHS // Sure Drive should support LBA in this case or you @@ -168,38 +172,30 @@ impl ATA { dma = 0; // We don't support DMA // (III) Wait if the drive is busy - while (IDEController::read(channel, ATAReg::STATUS) & ATAStatus::BSY) - != 0 - {} + while (channel.read(ATAReg::STATUS) & ATAStatus::BSY) != 0 {} // (IV) Select Drive from the controller if lba_mode == 0 { // Drive & CHS - IDEController::write( - channel, - ATAReg::HDDEVSEL, - 0xa0 | ((slavebit as u8) << 4) | head - ); + channel + .write(ATAReg::HDDEVSEL, 0xa0 | ((slavebit as u8) << 4) | head); } else { // Drive & LBA - IDEController::write( - channel, - ATAReg::HDDEVSEL, - 0xe0 | ((slavebit as u8) << 4) | head - ); + channel + .write(ATAReg::HDDEVSEL, 0xe0 | ((slavebit as u8) << 4) | head); } // (V) Write Parameters if lba_mode == 2 { - IDEController::write(channel, ATAReg::SECCOUNT1, 0); - IDEController::write(channel, ATAReg::LBA3, lba_io[3]); - IDEController::write(channel, ATAReg::LBA4, lba_io[4]); - IDEController::write(channel, ATAReg::LBA5, lba_io[5]); + channel.write(ATAReg::SECCOUNT1, 0); + channel.write(ATAReg::LBA3, lba_io[3]); + channel.write(ATAReg::LBA4, lba_io[4]); + channel.write(ATAReg::LBA5, lba_io[5]); } - IDEController::write(channel, ATAReg::SECCOUNT0, numsects); - IDEController::write(channel, ATAReg::LBA0, lba_io[0]); - IDEController::write(channel, ATAReg::LBA1, lba_io[1]); - IDEController::write(channel, ATAReg::LBA2, lba_io[2]); + channel.write(ATAReg::SECCOUNT0, numsects); + channel.write(ATAReg::LBA0, lba_io[0]); + channel.write(ATAReg::LBA1, lba_io[1]); + channel.write(ATAReg::LBA2, lba_io[2]); // (VI) Select the command and send it // Routine that is followed: @@ -226,7 +222,7 @@ impl ATA { _ => todo!() }; // Send the command - IDEController::write(channel, ATAReg::COMMAND, cmd as u8); + channel.write(ATAReg::COMMAND, cmd as u8); if dma != 0 { if direction == 0 { @@ -239,7 +235,7 @@ impl ATA { // PIO Read for _ in 0..numsects { // Polling, set error and exit if there is - IDEController::polling(channel, 1)?; + channel.polling(1)?; io::insw(bus as u16, edi as *mut _, words); edi += words * 2; } @@ -247,12 +243,11 @@ impl ATA { // PIO Write for _ in 0..numsects { // Polling - IDEController::polling(channel, 0)?; + channel.polling(0)?; io::outsw(bus as u16, edi as *mut _, words); edi += words * 2; } - IDEController::write( - channel, + channel.write( ATAReg::COMMAND, [ ATACommand::CacheFlush, @@ -261,7 +256,7 @@ impl ATA { ][lba_mode as usize] as u8 ); // Polling - IDEController::polling(channel, 0)?; + channel.polling(0)?; } } Ok(()) diff --git a/srcs/pci/ide/atapi.rs b/srcs/pci/ide/atapi.rs index 7fd5a25c..4cdbfacb 100644 --- a/srcs/pci/ide/atapi.rs +++ b/srcs/pci/ide/atapi.rs @@ -21,8 +21,12 @@ pub struct ATAPI {} impl ATAPI { pub fn capacity(device: &mut IDEDevice, lba: u32) -> Result { - let binding = device.channel.as_mut().ok_or(1)?; - let channel: &mut IDEChannelRegisters = &mut binding.lock(); + let binding = match &device.channel { + Some(x) => x, + None => return Err(0x1) + }; + let bind = binding.lock(); + let mut channel = bind.borrow_mut(); let slavebit: u32 = device.drive as u32; let bus: u32 = channel.base as u32; let mut buffer: [u32; 2] = [0; 2]; @@ -30,7 +34,8 @@ impl ATAPI { // Enable IRQs *IDE_IRQ_INVOKED.lock() = 0; channel.n_ien = 0; - IDEController::write(channel, ATAReg::CONTROL, channel.n_ien); + let n_ien = channel.n_ien; + channel.write(ATAReg::CONTROL, n_ien); // (I) Setup SCSI Packet let packet: [u8; 12] = [ @@ -49,44 +54,40 @@ impl ATAPI { ]; // (II) Select the drive - IDEController::write(channel, ATAReg::HDDEVSEL, (slavebit << 4) as u8); + channel.write(ATAReg::HDDEVSEL, (slavebit << 4) as u8); // (III) Delay 400 nanoseconds for select to complete for _ in 0..4 { // Reading the Alternate Status port wastes 100ns - IDEController::read(channel, ATAReg::ALTSTATUS); + channel.read(ATAReg::ALTSTATUS); } // (IV) Inform the Controller that we use PIO mode - IDEController::write(channel, ATAReg::FEATURES, 0); + channel.write(ATAReg::FEATURES, 0); // (V) Tell the Controller the size of buffer (16 bytes will be returned) let size: usize = 0x0008; // Lower Byte of Sector size - IDEController::write(channel, ATAReg::LBA1, (size & 0xff) as u8); + channel.write(ATAReg::LBA1, (size & 0xff) as u8); // Upper Byte of Sector size - IDEController::write(channel, ATAReg::LBA2, (size >> 8) as u8); + channel.write(ATAReg::LBA2, (size >> 8) as u8); // (VI) Send the Packet Command - IDEController::write( - channel, - ATAReg::COMMAND, - ATACommand::Packet as u8 - ); + channel.write(ATAReg::COMMAND, ATACommand::Packet as u8); // (VII) Waiting for the driver to finish or return an error code - IDEController::polling(channel, 1)?; + channel.polling(1)?; // (VIII) Sending the packet data io::outsw(bus as u16, packet.as_ptr() as *const _, 6); // (IX) Receiving Data - IDEController::polling(channel, 1)?; + channel.polling(1)?; io::insw(bus as u16, buffer.as_mut_ptr() as *mut _, 4); // (X) Waiting for BSY & DRQ to clear loop { - if (IDEController::read(channel, ATAReg::STATUS) + if (channel.read(ATAReg::STATUS) & (ATAStatus::BSY | ATAStatus::DRQ)) == 0 { @@ -100,13 +101,17 @@ impl ATAPI { } pub fn read( - device: &mut IDEDevice, + device: &IDEDevice, lba: u32, numsects: u8, mut edi: u32 ) -> Result<(), u8> { - let binding = device.channel.as_mut().ok_or(1)?; - let channel: &mut IDEChannelRegisters = &mut binding.lock(); + let binding = match &device.channel { + Some(x) => x, + None => return Err(0x1) + }; + let bind = binding.lock(); + let mut channel = bind.borrow_mut(); let slavebit: u32 = device.drive as u32; let bus: u32 = channel.base as u32; // Sector Size @@ -116,7 +121,7 @@ impl ATAPI { // Enable IRQs *IDE_IRQ_INVOKED.lock() = 0; channel.n_ien = 0; - IDEController::write(channel, ATAReg::CONTROL, channel.n_ien); + channel.write(ATAReg::CONTROL, 0); // (I) Setup SCSI Packet let packet: [u8; 12] = [ @@ -135,32 +140,28 @@ impl ATAPI { ]; // (II) Select the drive - IDEController::write(channel, ATAReg::HDDEVSEL, (slavebit << 4) as u8); + channel.write(ATAReg::HDDEVSEL, (slavebit << 4) as u8); // (III) Delay 400 nanoseconds for select to complete for _ in 0..4 { // Reading the Alternate Status port wastes 100ns - IDEController::read(channel, ATAReg::ALTSTATUS); + channel.read(ATAReg::ALTSTATUS); } // (IV) Inform the Controller that we use PIO mode - IDEController::write(channel, ATAReg::FEATURES, 0); + channel.write(ATAReg::FEATURES, 0); // (V) Tell the Controller the size of buffer // Lower Byte of Sector size - IDEController::write(channel, ATAReg::LBA1, ((words * 2) & 0xff) as u8); + channel.write(ATAReg::LBA1, ((words * 2) & 0xff) as u8); // Upper Byte of Sector size - IDEController::write(channel, ATAReg::LBA2, ((words * 2) >> 8) as u8); + channel.write(ATAReg::LBA2, ((words * 2) >> 8) as u8); // (VI) Send the Packet Command - IDEController::write( - channel, - ATAReg::COMMAND, - ATACommand::Packet as u8 - ); + channel.write(ATAReg::COMMAND, ATACommand::Packet as u8); // (VII) Waiting for the driver to finish or return an error code - IDEController::polling(channel, 1)?; + channel.polling(1)?; // (VIII) Sending the packet data io::outsw(bus as u16, packet.as_ptr() as *const _, 6); @@ -168,7 +169,7 @@ impl ATAPI { // (IX) Receiving Data for _ in 0..numsects { IDEController::wait_irq(); - IDEController::polling(channel, 1)?; + channel.polling(1)?; io::insw(bus as u16, edi as *mut _, words); edi += words * 2; } @@ -178,7 +179,7 @@ impl ATAPI { // (XI) Waiting for BSY & DRQ to clear loop { - if (IDEController::read(channel, ATAReg::STATUS) + if (channel.read(ATAReg::STATUS) & (ATAStatus::BSY | ATAStatus::DRQ)) == 0 { @@ -190,8 +191,12 @@ impl ATAPI { } pub fn eject(device: &mut IDEDevice) -> Result<(), u8> { - let binding = device.channel.as_mut().ok_or(1)?; - let channel: &mut IDEChannelRegisters = &mut binding.lock(); + let binding = match &device.channel { + Some(x) => x, + None => return Err(0x1) + }; + let bind = binding.lock(); + let mut channel = bind.borrow_mut(); let slavebit: u32 = device.drive as u32; let bus: u32 = channel.base as u32; @@ -206,7 +211,7 @@ impl ATAPI { // Enable IRQs *IDE_IRQ_INVOKED.lock() = 0x0; channel.n_ien = 0x0; - IDEController::write(channel, ATAReg::CONTROL, channel.n_ien); + channel.write(ATAReg::CONTROL, 0x0); // (I) Setup SCSI Packet let packet: [u8; 12] = [ @@ -225,35 +230,27 @@ impl ATAPI { ]; // (II) Select the Drive - IDEController::write( - channel, - ATAReg::HDDEVSEL, - (slavebit << 4) as u8 - ); + channel.write(ATAReg::HDDEVSEL, (slavebit << 4) as u8); // (III) Delay 400 nanosecond for select to complete for _ in 0..4 { // Reading Alternate Status Port Wastes 100ns - IDEController::read(channel, ATAReg::ALTSTATUS); + channel.read(ATAReg::ALTSTATUS); } // (IV) Send the Packet Command - IDEController::write( - channel, - ATAReg::COMMAND, - ATACommand::Packet as u8 - ); + channel.write(ATAReg::COMMAND, ATACommand::Packet as u8); // (V) Waiting for the driver to finish or invoke an error // Polling and stop if error - IDEController::polling(channel, 1)?; + channel.polling(1)?; // (VI) Sending the packet data io::outsw(bus as u16, packet.as_ptr() as *const _, 6); IDEController::wait_irq(); // Polling and get error code - match IDEController::polling(channel, 1) { + match channel.polling(1) { Err(err) if err != 3 => return Err(err), _ => {} } diff --git a/srcs/pci/ide/channel.rs b/srcs/pci/ide/channel.rs new file mode 100644 index 00000000..8ec0c134 --- /dev/null +++ b/srcs/pci/ide/channel.rs @@ -0,0 +1,113 @@ +use super::ata::ATAChannel; +use super::{ATAReg, ATAStatus}; +use crate::io::{inb, insl, outb}; + +#[derive(Clone, Copy)] +pub struct IDEChannelRegisters { + pub r#type: ATAChannel, // 0 - Primary Channel, 1 - Secondary Channel + pub base: u16, // I/O Base + ctrl: u16, // ControlBase + bmide: u16, // Bus Master IDE + pub n_ien: u8 // nIEN (No Interrupt) +} + +impl IDEChannelRegisters { + pub const fn new( + channel: ATAChannel, + base: u16, + ctrl: u16, + bmide: u16, + n_ien: u8 + ) -> Self { + Self { r#type: channel, base, ctrl, bmide, n_ien } + } + + pub fn read(&mut self, reg: u8) -> u8 { + let mut result: u8 = 0; + if reg > 0x07 && reg < 0x0c { + self.write(ATAReg::CONTROL, 0x80 | self.n_ien); + } + if reg < 0x08 { + result = inb(self.base + reg as u16 - 0x00); + } else if reg < 0x0c { + result = inb(self.base + reg as u16 - 0x06); + } else if reg < 0x0e { + result = inb(self.ctrl + reg as u16 - 0x0a); + } else if reg < 0x16 { + result = inb(self.bmide + reg as u16 - 0x0e); + } + if reg > 0x07 && reg < 0x0c { + self.write(ATAReg::CONTROL, self.n_ien); + } + return result; + } + + pub fn read_buffer(&mut self, reg: u8, buffer: &mut [u32], quads: u32) { + if reg > 0x07 && reg < 0x0c { + self.write(ATAReg::CONTROL, 0x80 | self.n_ien); + } + if reg < 0x08 { + insl(self.base + reg as u16 - 0x00, buffer.as_mut_ptr(), quads); + } else if reg < 0x0c { + insl(self.base + reg as u16 - 0x06, buffer.as_mut_ptr(), quads); + } else if reg < 0x0e { + insl(self.ctrl + reg as u16 - 0x0a, buffer.as_mut_ptr(), quads); + } else if reg < 0x16 { + insl(self.bmide + reg as u16 - 0x0e, buffer.as_mut_ptr(), quads); + } + if reg > 0x07 && reg < 0x0c { + self.write(ATAReg::CONTROL, self.n_ien); + } + } + + pub fn write(&mut self, reg: u8, data: u8) { + if reg > 0x07 && reg < 0x0c { + self.write(ATAReg::CONTROL, 0x80 | self.n_ien); + } + if reg < 0x08 { + outb(self.base + reg as u16 - 0x00, data); + } else if reg < 0x0c { + outb(self.base + reg as u16 - 0x06, data); + } else if reg < 0x0e { + outb(self.ctrl + reg as u16 - 0x0a, data); + } else if reg < 0x16 { + outb(self.bmide + reg as u16 - 0x0e, data); + } + if reg > 0x07 && reg < 0x0c { + self.write(ATAReg::CONTROL, self.n_ien); + } + } + + pub fn polling(&mut self, advanced_check: u32) -> Result<(), u8> { + for _ in 0..4 { + self.read(ATAReg::ALTSTATUS); + } + + // (II) Wait for BSY to be cleared + while (self.read(ATAReg::STATUS) & ATAStatus::BSY as u8) != 0 { // Wait for BSY to be zero + } + + if advanced_check != 0 { + // Read Status Register + let state: u8 = self.read(ATAReg::STATUS); + + // (III) Check for errors + if (state & ATAStatus::ERR) != 0 { + return Err(2); + } + + // (IV) Check if device fault + if (state & ATAStatus::DF) != 0 { + return Err(1); + } + + // (V) Check DRQ + // BSY = 0; DF = 0; Err = 0; So we should check for DRQ now + if (state & ATAStatus::DRQ) == 0 { + return Err(3); + } + } + // No Error + Ok(()) + } +} diff --git a/srcs/pci/ide/device.rs b/srcs/pci/ide/device.rs new file mode 100644 index 00000000..c54be2cf --- /dev/null +++ b/srcs/pci/ide/device.rs @@ -0,0 +1,212 @@ +use super::ata::{self, ATADirection, ATAError, ATAReg, ATA}; +use super::atapi::{self, ATAPI}; +pub use super::channel::IDEChannelRegisters; +use super::IDEType; +use crate::kprintln; +use crate::utils::arcm::Arcm; +use core::cell::RefCell; +use core::ffi::CStr; + +#[derive(Clone)] +pub struct IDEDevice { + pub reserved: u8, // 0 (Empty) or 1 (This Drive really exists) + pub channel: Option>>, + pub drive: u8, // 0 (Master Drive) or 1 (Slave Drive) + pub r#type: u16, // 0: ATA, 1:ATAPI + pub signature: u16, // Drive Signature + pub capabilities: u16, // Features + pub command_sets: u32, // Command Sets Supported + pub size: u32, // Size in Sectors + pub model: [u8; 41] // Model in string +} + +impl IDEDevice { + pub const fn new() -> Self { + Self { + reserved: 0, + channel: None, + drive: 0, + r#type: 0, + signature: 0, + capabilities: 0, + command_sets: 0, + size: 0, + model: [0; 41] + } + } + + pub fn print_error(&self, mut err: u8) -> u8 { + if err == 0 { + return err; + } + kprintln!("IDE:"); + let binding = match &self.channel { + Some(x) => x, + None => { + kprintln!("- Channel non-initialized"); + return 23; + } + }; + let bind = binding.lock(); + let channel: &mut IDEChannelRegisters = &mut bind.borrow_mut(); + match err { + 1 => { + kprintln!("- Device Fault"); + err = 19; + }, + 2 => { + let st: u8 = channel.read(ATAReg::ERROR); + if (st & ATAError::AMNF) != 0 { + kprintln!("- No Address Mark Found"); + err = 7; + } + if (st & ATAError::ABRT) != 0 { + kprintln!("- Command Aborted"); + err = 20; + } + if ((st & ATAError::TK0NF) != 0) + | ((st & ATAError::MCR) != 0) + | ((st & ATAError::MC) != 0) + { + kprintln!("- No Media or Media Error"); + err = 3; + } + if (st & ATAError::IDNF) != 0 { + kprintln!("- ID mark not Found"); + err = 21; + } + if (st & ATAError::UNC) != 0 { + kprintln!("- Uncorrectable Data Error"); + err = 22; + } + if (st & ATAError::BBK) != 0 { + kprintln!("- Bad Sectors"); + err = 13; + } + }, + 3 => { + kprintln!("- Reads Nothing"); + err = 23; + }, + 4 => { + kprintln!("- Write Protected"); + err = 8; + }, + _ => {} + } + kprintln!( + " - [{} {}] {}", + ["Primary", "Secondary"][channel.r#type as usize], + ["Master", "Slave"][self.drive as usize], + CStr::from_bytes_until_nul(&self.model) + .unwrap() + .to_str() + .unwrap() + ); + err + } + + /// Read sector from a device + /// + /// Parameters: + /// + numsects: number of sectors to be read. If 0, the ATA controller will now we want 256 sectors + /// + lba: LBA address --> index of the sector, which allows us to acces disks up to 2TB + /// + edi: adress of the buffer we want to fill + pub fn read_sectors( + &self, + numsects: u8, + lba: u32, + edi: u32 + ) -> Result<(), u8> { + // 1- Check if the drive presents + if self.reserved == 0 { + // Drive not found + return Err(0x1); + // 2- Check if inputs are valid + } else if (lba + numsects as u32 > self.size) + && (self.r#type == IDEType::ATA as u16) + { + // Seeking to invalid position + return Err(0x2); + // 3- Read in PIO Mode through Polling & IRQs + } else { + if self.r#type == IDEType::ATA as u16 { + match ATA::access( + ATADirection::Read as u8, + self, + lba, + numsects, + edi + ) { + Ok(_) => {}, + Err(err) => return Err(self.print_error(err)) + } + } else if self.r#type == IDEType::ATAPI as u16 { + for i in 0..numsects { + match ATAPI::read( + self, + lba + i as u32, + 1, + edi + i as u32 * atapi::SECTOR_SIZE + ) { + Ok(_) => {}, + Err(err) => return Err(self.print_error(err)) + } + } + } + } + Ok(()) + } + + /// Write sector from a device + /// + /// Parameters: + /// + numsects: number of sectors to write. If 0, the ATA controller will now we want 256 sectors + /// + lba: LBA address --> index of the sector, which allows us to access disks up to 2TB + /// + edi: adress of the buffer we want to fill + pub fn write_sectors( + &mut self, + numsects: u8, + lba: u32, + edi: u32 + ) -> Result<(), u8> { + // 1- Check if the drive presents + if self.reserved == 0 { + // Drive not found + return Err(0x1); + // 2- Check if inputs are valid + } else if (lba + numsects as u32 > self.size) + && (self.r#type == IDEType::ATA as u16) + { + return Err(0x2); + // 3- Read in PIO Mode through Polling & IRQs + } else { + if self.r#type == IDEType::ATA as u16 { + match ATA::access( + ATADirection::Write as u8, + self, + lba, + numsects, + edi + ) { + Ok(_) => {}, + Err(err) => return Err(self.print_error(err)) + } + } else if self.r#type == IDEType::ATAPI as u16 { + // Write-Protected + return Err(0x4); + } + } + Ok(()) + } + + pub fn sector_size(&self) -> u32 { + match self.r#type { + x if x == IDEType::ATA as u16 => ata::SECTOR_SIZE, + x if x == IDEType::ATAPI as u16 => atapi::SECTOR_SIZE, + _ => { + panic!("Unrecognized disk.") + } + } + } +} diff --git a/srcs/pci/ide/mod.rs b/srcs/pci/ide/mod.rs index a05e18b7..09fbf1a1 100644 --- a/srcs/pci/ide/mod.rs +++ b/srcs/pci/ide/mod.rs @@ -1,26 +1,29 @@ use core::ffi::CStr; use core::mem::size_of; -use crate::io::{inb, insl, outb}; use crate::kprintln; use crate::spin::{KMutex, Mutex}; use crate::time::sleep; use crate::utils::arcm::Arcm; +use core::cell::RefCell; pub mod ata; pub mod atapi; +pub mod channel; +pub mod device; use ata::{ ATAChannel, ATACommand, ATADirection, - ATAError, ATAIdentify, ATAReg, ATAStatus, ATA }; use atapi::ATAPI; +use channel::IDEChannelRegisters; +pub use device::IDEDevice; static IDE_IRQ_INVOKED: KMutex = KMutex::::new(0); pub static IDE: Mutex = @@ -31,54 +34,12 @@ pub enum IDEType { ATAPI = 0x01 } -#[derive(Clone, Copy)] -struct IDEChannelRegisters { - r#type: ATAChannel, // 0 - Primary Channel, 1 - Secondary Channel - base: u16, // I/O Base - ctrl: u16, // ControlBase - bmide: u16, // Bus Master IDE - n_ien: u8 // nIEN (No Interrupt) -} - -impl IDEChannelRegisters { - const fn new(channel: ATAChannel) -> Self { - Self { r#type: channel, base: 0, ctrl: 0, bmide: 0, n_ien: 0 } - } -} - -pub struct IDEDevice { - reserved: u8, // 0 (Empty) or 1 (This Drive really exists) - channel: Option>, - drive: u8, // 0 (Master Drive) or 1 (Slave Drive) - pub r#type: u16, // 0: ATA, 1:ATAPI - signature: u16, // Drive Signature - capabilities: u16, // Features - command_sets: u32, // Command Sets Supported - size: u32, // Size in Sectors - model: [u8; 41] // Model in string -} - -impl IDEDevice { - const fn new() -> Self { - Self { - reserved: 0, - channel: None, - drive: 0, - r#type: 0, - signature: 0, - capabilities: 0, - command_sets: 0, - size: 0, - model: [0; 41] - } - } -} - pub struct IDEController { devices: [IDEDevice; 4] } impl IDEController { + /// Create a controller with default devices pub const fn new() -> Self { Self { devices: [ @@ -90,6 +51,11 @@ impl IDEController { } } + /// Obtain reference to an existing device. + /// + /// Actually return a reference to the device and should be clone afterward + /// However if the reference is never needed this function will probably + /// be change to return a clone of the device instead pub fn get_device(&self, num: u8) -> Option<&IDEDevice> { if num > 3 || self.devices[num as usize].reserved == 0 { return None; @@ -107,35 +73,33 @@ impl IDEController { ) -> Result<(), u8> { let mut ide_buf: [u8; 2048] = [0; 2048]; - let channels: [Arcm; 2] = [ - Arcm::new(IDEChannelRegisters::new(ATAChannel::Primary)), - Arcm::new(IDEChannelRegisters::new(ATAChannel::Secondary)) - ]; - // 1- Detect I/O Ports which interface IDE Controller - channels[ATAChannel::Primary as usize].lock().base = - (bar0 & 0xfffffffc) as u16; - channels[ATAChannel::Primary as usize].lock().ctrl = - (bar1 & 0xfffffffc) as u16; - channels[ATAChannel::Secondary as usize].lock().base = - (bar2 & 0xfffffffc) as u16; - channels[ATAChannel::Secondary as usize].lock().ctrl = - (bar3 & 0xfffffffc) as u16; - channels[ATAChannel::Primary as usize].lock().bmide = - ((bar4 & 0xfffffffc) + 0) as u16; - channels[ATAChannel::Secondary as usize].lock().bmide = - ((bar4 & 0xfffffffc) + 8) as u16; - - // 2- Disable IRQs - IDEController::write( - &channels[ATAChannel::Primary as usize].lock(), - ATAReg::CONTROL, - 2 + let primary = IDEChannelRegisters::new( + ATAChannel::Primary, + (bar0 & 0xfffffffc) as u16, + (bar1 & 0xfffffffc) as u16, + ((bar4 & 0xfffffffc) + 0) as u16, + 0 ); - IDEController::write( - &channels[ATAChannel::Secondary as usize].lock(), - ATAReg::CONTROL, - 2 + let secondary = IDEChannelRegisters::new( + ATAChannel::Secondary, + (bar2 & 0xfffffffc) as u16, + (bar3 & 0xfffffffc) as u16, + ((bar4 & 0xfffffffc) + 8) as u16, + 0 ); + let mut channels: [Arcm>; 2] = [ + Arcm::new(RefCell::new(primary)), + Arcm::new(RefCell::new(secondary)) + ]; + // 2- Disable IRQs + channels[ATAChannel::Primary as usize] + .lock() + .borrow_mut() + .write(ATAReg::CONTROL, 2); + channels[ATAChannel::Secondary as usize] + .lock() + .borrow_mut() + .write(ATAReg::CONTROL, 2); let mut count: usize = 0; // 3- Detect ATA-ATAPI Devices @@ -143,39 +107,29 @@ impl IDEController { for j in 0..2 { let mut err: u8 = 0; let mut r#type: u8 = IDEType::ATA as u8; - - // Assuming that no drive here - self.devices[count].reserved = 0; - // (I) Select Drive - IDEController::write( - &mut channels[i].lock(), - ATAReg::HDDEVSEL, - 0xa0 | (j << 4) - ); + channels[i] + .lock() + .borrow_mut() + .write(ATAReg::HDDEVSEL, 0xa0 | (j << 4)); sleep(1); // (II) Send ATA Identify Command - IDEController::write( - &mut channels[i].lock(), - ATAReg::COMMAND, - ATACommand::Identify as u8 - ); + channels[i] + .lock() + .borrow_mut() + .write(ATAReg::COMMAND, ATACommand::Identify as u8); sleep(1); // (III) Polling // If Status = 0, No Device - if IDEController::read(&mut channels[i].lock(), ATAReg::STATUS) - == 0 - { + if channels[i].lock().borrow_mut().read(ATAReg::STATUS) == 0 { continue; } loop { - let status: u8 = IDEController::read( - &mut channels[i].lock(), - ATAReg::STATUS - ); + let status: u8 = + channels[i].lock().borrow_mut().read(ATAReg::STATUS); if (status & ATAStatus::ERR) != 0 { err = 1; break; @@ -189,14 +143,10 @@ impl IDEController { // (IV) Probe for ATAPI Devices if err != 0 { - let cl: u8 = IDEController::read( - &mut channels[i].lock(), - ATAReg::LBA1 - ); - let ch: u8 = IDEController::read( - &mut channels[i].lock(), - ATAReg::LBA2 - ); + let cl: u8 = + channels[i].lock().borrow_mut().read(ATAReg::LBA1); + let ch: u8 = + channels[i].lock().borrow_mut().read(ATAReg::LBA2); if cl == 0x14 && ch == 0xeb { r#type = IDEType::ATAPI as u8; @@ -207,8 +157,7 @@ impl IDEController { continue; } - IDEController::write( - &mut channels[i].lock(), + channels[i].lock().borrow_mut().write( ATAReg::COMMAND, ATACommand::IdentifyPacket as u8 ); @@ -216,8 +165,7 @@ impl IDEController { } // (V) Read Identification Space of the Device - IDEController::read_buffer( - &mut channels[i].lock(), + channels[i].lock().borrow_mut().read_buffer( ATAReg::DATA, unsafe { ide_buf.align_to_mut::().1 }, 128 @@ -315,191 +263,28 @@ impl IDEController { *IDE_IRQ_INVOKED.lock() = 1; } - fn read(channel: &IDEChannelRegisters, reg: u8) -> u8 { - let mut result: u8 = 0; - if reg > 0x07 && reg < 0x0c { - IDEController::write( - channel, - ATAReg::CONTROL, - 0x80 | channel.n_ien - ); - } - if reg < 0x08 { - result = inb(channel.base + reg as u16 - 0x00); - } else if reg < 0x0c { - result = inb(channel.base + reg as u16 - 0x06); - } else if reg < 0x0e { - result = inb(channel.ctrl + reg as u16 - 0x0a); - } else if reg < 0x16 { - result = inb(channel.bmide + reg as u16 - 0x0e); - } - if reg > 0x07 && reg < 0x0c { - IDEController::write(channel, ATAReg::CONTROL, channel.n_ien); - } - return result; + fn read(channel: &mut IDEChannelRegisters, reg: u8) -> u8 { + channel.read(reg) } - fn write(channel: &IDEChannelRegisters, reg: u8, data: u8) { - if reg > 0x07 && reg < 0x0c { - IDEController::write( - channel, - ATAReg::CONTROL, - 0x80 | channel.n_ien - ); - } - if reg < 0x08 { - outb(channel.base + reg as u16 - 0x00, data); - } else if reg < 0x0c { - outb(channel.base + reg as u16 - 0x06, data); - } else if reg < 0x0e { - outb(channel.ctrl + reg as u16 - 0x0a, data); - } else if reg < 0x16 { - outb(channel.bmide + reg as u16 - 0x0e, data); - } - if reg > 0x07 && reg < 0x0c { - IDEController::write(channel, ATAReg::CONTROL, channel.n_ien); - } + fn write(channel: &mut IDEChannelRegisters, reg: u8, data: u8) { + channel.write(reg, data); } fn read_buffer( - channel: &IDEChannelRegisters, + channel: &mut IDEChannelRegisters, reg: u8, buffer: &mut [u32], quads: u32 ) { - if reg > 0x07 && reg < 0x0c { - IDEController::write( - channel, - ATAReg::CONTROL, - 0x80 | channel.n_ien - ); - } - if reg < 0x08 { - insl(channel.base + reg as u16 - 0x00, buffer.as_mut_ptr(), quads); - } else if reg < 0x0c { - insl(channel.base + reg as u16 - 0x06, buffer.as_mut_ptr(), quads); - } else if reg < 0x0e { - insl(channel.ctrl + reg as u16 - 0x0a, buffer.as_mut_ptr(), quads); - } else if reg < 0x16 { - insl(channel.bmide + reg as u16 - 0x0e, buffer.as_mut_ptr(), quads); - } - if reg > 0x07 && reg < 0x0c { - IDEController::write(channel, ATAReg::CONTROL, channel.n_ien); - } + channel.read_buffer(reg, buffer, quads); } fn polling( - channel: &IDEChannelRegisters, + channel: &mut IDEChannelRegisters, advanced_check: u32 ) -> Result<(), u8> { - // (I) Delay 400 nanosecond for BSY to be set - // Reading port wastes 100ns - for _ in 0..4 { - IDEController::read(channel, ATAReg::ALTSTATUS); - } - - // (II) Wait for BSY to be cleared - while (IDEController::read(channel, ATAReg::STATUS) - & ATAStatus::BSY as u8) - != 0 - { - // Wait for BSY to be zero - } - - if advanced_check != 0 { - // Read Status Register - let state: u8 = IDEController::read(channel, ATAReg::STATUS); - - // (III) Check for errors - if (state & ATAStatus::ERR) != 0 { - return Err(2); - } - - // (IV) Check if device fault - if (state & ATAStatus::DF) != 0 { - return Err(1); - } - - // (V) Check DRQ - // BSY = 0; DF = 0; Err = 0; So we should check for DRQ now - if (state & ATAStatus::DRQ) == 0 { - return Err(3); - } - } - // No Error - Ok(()) - } - - fn print_error(&mut self, drive: u8, mut err: u8) -> u8 { - let device: &IDEDevice = &self.devices[drive as usize]; - - if err == 0 { - return err; - } - kprintln!("IDE:"); - let binding = match &device.channel { - Some(x) => x, - None => { - kprintln!("- Channel non-initialized"); - return 23; - } - }; - let channel: &IDEChannelRegisters = &binding.lock(); - match err { - 1 => { - kprintln!("- Device Fault"); - err = 19; - }, - 2 => { - let st: u8 = IDEController::read(channel, ATAReg::ERROR); - if (st & ATAError::AMNF) != 0 { - kprintln!("- No Address Mark Found"); - err = 7; - } - if (st & ATAError::ABRT) != 0 { - kprintln!("- Command Aborted"); - err = 20; - } - if ((st & ATAError::TK0NF) != 0) - | ((st & ATAError::MCR) != 0) - | ((st & ATAError::MC) != 0) - { - kprintln!("- No Media or Media Error"); - err = 3; - } - if (st & ATAError::IDNF) != 0 { - kprintln!("- ID mark not Found"); - err = 21; - } - if (st & ATAError::UNC) != 0 { - kprintln!("- Uncorrectable Data Error"); - err = 22; - } - if (st & ATAError::BBK) != 0 { - kprintln!("- Bad Sectors"); - err = 13; - } - }, - 3 => { - kprintln!("- Reads Nothing"); - err = 23; - }, - 4 => { - kprintln!("- Write Protected"); - err = 8; - }, - _ => {} - } - kprintln!( - " - [{} {}] {}", - ["Primary", "Secondary"][channel.r#type as usize], - ["Master", "Slave"][device.drive as usize], - CStr::from_bytes_until_nul(&device.model) - .unwrap() - .to_str() - .unwrap() - ); - err + channel.polling(advanced_check) } /// Read sector from a drive @@ -539,7 +324,7 @@ impl IDEController { edi ) { Ok(_) => {}, - Err(err) => return Err(self.print_error(drive, err)) + Err(err) => return Err(device.print_error(err)) } } else if device.r#type == IDEType::ATAPI as u16 { for i in 0..numsects { @@ -550,7 +335,7 @@ impl IDEController { edi + i as u32 * atapi::SECTOR_SIZE ) { Ok(_) => {}, - Err(err) => return Err(self.print_error(drive, err)) + Err(err) => return Err(device.print_error(err)) } } } @@ -594,7 +379,7 @@ impl IDEController { edi ) { Ok(_) => {}, - Err(err) => return Err(self.print_error(drive, err)) + Err(err) => return Err(device.print_error(err)) } } else if device.r#type == IDEType::ATAPI as u16 { // Write-Protected @@ -616,12 +401,9 @@ mod test { let to_write = vec!['B' as u8; 512]; let read_from = vec![0x0 as u8; 512]; - let _ = IDE - .lock() - .write_sectors(1, 1, 0x0, to_write.as_ptr() as u32); - let _ = IDE - .lock() - .read_sectors(1, 1, 0x0, read_from.as_ptr() as u32); + let mut device = IDE.lock().get_device(1).unwrap().clone(); + let _ = device.write_sectors(1, 0x0, to_write.as_ptr() as u32); + let _ = device.read_sectors(1, 0x0, read_from.as_ptr() as u32); assert_eq!(to_write, read_from); } @@ -631,12 +413,9 @@ mod test { let to_write = vec!['A' as u8; 1024]; let read_from = vec![0x0 as u8; 1024]; - let _ = IDE - .lock() - .write_sectors(1, 2, 0x0, to_write.as_ptr() as u32); - let _ = IDE - .lock() - .read_sectors(1, 2, 0x0, read_from.as_ptr() as u32); + let mut device = IDE.lock().get_device(1).unwrap().clone(); + let _ = device.write_sectors(2, 0x0, to_write.as_ptr() as u32); + let _ = device.read_sectors(2, 0x0, read_from.as_ptr() as u32); assert_eq!(to_write, read_from); }