diff --git a/Makefile b/Makefile index 1c0676d..7b4e165 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ FORCE: # Emulation QEMU=qemu-system-$(ARCH) -QEMUFLAGS=-serial mon:stdio -d guest_errors +QEMUFLAGS=-serial mon:stdio -d cpu_reset -d guest_errors ifeq ($(ARCH),arm) LD=$(ARCH)-none-eabi-ld QEMUFLAGS+=-cpu arm1176 -machine integratorcp diff --git a/drivers/ahcid/src/ahci/dma.rs b/drivers/ahcid/src/ahci/dma.rs new file mode 100644 index 0000000..91258b8 --- /dev/null +++ b/drivers/ahcid/src/ahci/dma.rs @@ -0,0 +1,76 @@ +use std::{mem, ptr}; +use std::ops::{Deref, DerefMut}; + +use syscall::{self, Result}; + +struct PhysBox { + address: usize, + size: usize +} + +impl PhysBox { + fn new(size: usize) -> Result { + let address = unsafe { syscall::physalloc(size)? }; + Ok(PhysBox { + address: address, + size: size + }) + } +} + +impl Drop for PhysBox { + fn drop(&mut self) { + let _ = unsafe { syscall::physfree(self.address, self.size) }; + } +} + +pub struct Dma { + phys: PhysBox, + virt: *mut T +} + +impl Dma { + pub fn new(value: T) -> Result> { + let phys = PhysBox::new(mem::size_of::())?; + let virt = unsafe { syscall::physmap(phys.address, phys.size, syscall::MAP_WRITE)? } as *mut T; + unsafe { ptr::write(virt, value); } + Ok(Dma { + phys: phys, + virt: virt + }) + } + + pub fn zeroed() -> Result> { + let phys = PhysBox::new(mem::size_of::())?; + let virt = unsafe { syscall::physmap(phys.address, phys.size, syscall::MAP_WRITE)? } as *mut T; + unsafe { ptr::write_bytes(virt as *mut u8, 0, phys.size); } + Ok(Dma { + phys: phys, + virt: virt + }) + } + + pub fn physical(&self) -> usize { + self.phys.address + } +} + +impl Deref for Dma { + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.virt } + } +} + +impl DerefMut for Dma { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.virt } + } +} + +impl Drop for Dma { + fn drop(&mut self) { + unsafe { drop(ptr::read(self.virt)); } + let _ = unsafe { syscall::physunmap(self.virt as usize) }; + } +} diff --git a/drivers/ahcid/src/ahci/hba.rs b/drivers/ahcid/src/ahci/hba.rs index f7ca720..a76b4b4 100644 --- a/drivers/ahcid/src/ahci/hba.rs +++ b/drivers/ahcid/src/ahci/hba.rs @@ -1,11 +1,13 @@ use io::{Io, Mmio}; use std::mem::size_of; +use std::ops::DerefMut; use std::{ptr, u32}; -use syscall::{physalloc, physmap, physunmap, virttophys, MAP_WRITE}; +use syscall::{virttophys, MAP_WRITE}; use syscall::error::{Error, Result, EIO}; +use super::dma::Dma; use super::fis::{FisType, FisRegH2D}; const ATA_CMD_READ_DMA_EXT: u8 = 0x25; @@ -72,49 +74,42 @@ impl HbaPort { } } - pub fn init(&mut self) { + pub fn init(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], fb: &mut Dma<[u8; 256]>) { self.stop(); - let clb_phys = unsafe { physalloc(size_of::()).unwrap() }; - self.clb.write(clb_phys as u64); + self.clb.write(clb.physical() as u64); + self.fb.write(fb.physical() as u64); - let fb = unsafe { physalloc(256).unwrap() }; - self.fb.write(fb as u64); - - let clb = unsafe { physmap(clb_phys, size_of::(), MAP_WRITE).unwrap() } as *mut HbaCmdHeader; for i in 0..32 { - let cmdheader = unsafe { &mut *clb.offset(i) }; - let ctba = unsafe { physalloc(size_of::()).unwrap() }; - cmdheader.ctba.write(ctba as u64); + let cmdheader = &mut clb[i]; + cmdheader.ctba.write(ctbas[i].physical() as u64); cmdheader.prdtl.write(0); } - unsafe { physunmap(clb as usize).unwrap(); } self.start(); } - pub unsafe fn identify(&mut self, port: usize) -> Option { + pub unsafe fn identify(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { self.is.write(u32::MAX); - let dest_phys = physalloc(256).unwrap(); - let dest = physmap(dest_phys, 256, MAP_WRITE).unwrap() as *mut u16; + let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap(); if let Some(slot) = self.slot() { - { - let clb = unsafe { physmap(self.clb.read() as usize, size_of::(), MAP_WRITE).unwrap() } as *mut HbaCmdHeader; - let cmdheader = &mut *clb.offset(slot as isize); - cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); - cmdheader.prdtl.write(1); + let cmdheader = &mut clb[slot as usize]; + cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); + cmdheader.prdtl.write(1); - let ctba = unsafe { physmap(cmdheader.ctba.read() as usize, size_of::(), MAP_WRITE).unwrap() } as *mut HbaCmdTable; - ptr::write_bytes(ctba as *mut u8, 0, size_of::()); - let cmdtbl = &mut *(ctba); + { + let cmdtbl = &mut ctbas[slot as usize]; + ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::()); let prdt_entry = &mut cmdtbl.prdt_entry[0]; - prdt_entry.dba.write(dest_phys as u64); + prdt_entry.dba.write(dest.physical() as u64); prdt_entry.dbc.write(512 | 1); + } - let cmdfis = &mut *(cmdtbl.cfis.as_ptr() as *mut FisRegH2D); + { + let cmdfis = &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D); cmdfis.fis_type.write(FisType::RegH2D as u8); cmdfis.pm.write(1 << 7); @@ -122,9 +117,6 @@ impl HbaPort { cmdfis.device.write(0); cmdfis.countl.write(1); cmdfis.counth.write(0); - - unsafe { physunmap(ctba as usize).unwrap(); } - unsafe { physunmap(clb as usize).unwrap(); } } while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {} @@ -143,7 +135,7 @@ impl HbaPort { let mut serial = String::new(); for word in 10..20 { - let d = *dest.offset(word); + let d = dest[word]; let a = ((d >> 8) as u8) as char; if a != '\0' { serial.push(a); @@ -156,7 +148,7 @@ impl HbaPort { let mut firmware = String::new(); for word in 23..27 { - let d = *dest.offset(word); + let d = dest[word]; let a = ((d >> 8) as u8) as char; if a != '\0' { firmware.push(a); @@ -169,7 +161,7 @@ impl HbaPort { let mut model = String::new(); for word in 27..47 { - let d = *dest.offset(word); + let d = dest[word]; let a = ((d >> 8) as u8) as char; if a != '\0' { model.push(a); @@ -180,20 +172,20 @@ impl HbaPort { } } - let mut sectors = (*dest.offset(100) as u64) | - ((*dest.offset(101) as u64) << 16) | - ((*dest.offset(102) as u64) << 32) | - ((*dest.offset(103) as u64) << 48); + let mut sectors = (dest[100] as u64) | + ((dest[101] as u64) << 16) | + ((dest[102] as u64) << 32) | + ((dest[103] as u64) << 48); let lba_bits = if sectors == 0 { - sectors = (*dest.offset(60) as u64) | ((*dest.offset(61) as u64) << 16); + sectors = (dest[60] as u64) | ((dest[61] as u64) << 16); 28 } else { 48 }; - println!(" + Port {}: Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", - port, serial.trim(), firmware.trim(), model.trim(), lba_bits, sectors / 2048); + println!(" + Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", + serial.trim(), firmware.trim(), model.trim(), lba_bits, sectors / 2048); Some(sectors * 512) } else { @@ -353,14 +345,14 @@ pub struct HbaMem { } #[repr(packed)] -struct HbaPrdtEntry { +pub struct HbaPrdtEntry { dba: Mmio, // Data base address rsv0: Mmio, // Reserved dbc: Mmio, // Byte count, 4M max, interrupt = 1 } #[repr(packed)] -struct HbaCmdTable { +pub struct HbaCmdTable { // 0x00 cfis: [Mmio; 64], // Command FIS @@ -375,7 +367,7 @@ struct HbaCmdTable { } #[repr(packed)] -struct HbaCmdHeader { +pub struct HbaCmdHeader { // DW0 cfl: Mmio, /* Command FIS length in DWORDS, 2 ~ 16, atapi: 4, write - host to device: 2, prefetchable: 1 */ pm: Mmio, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier diff --git a/drivers/ahcid/src/ahci/mod.rs b/drivers/ahcid/src/ahci/mod.rs index c3b4219..52e8c30 100644 --- a/drivers/ahcid/src/ahci/mod.rs +++ b/drivers/ahcid/src/ahci/mod.rs @@ -2,8 +2,10 @@ use io::Io; use syscall::error::Result; -use self::hba::{HbaMem, HbaPort, HbaPortType}; +use self::dma::Dma; +use self::hba::{HbaMem, HbaCmdTable, HbaCmdHeader, HbaPort, HbaPortType}; +pub mod dma; pub mod fis; pub mod hba; @@ -17,17 +19,17 @@ impl Ahci { let ret: Vec = (0..32) .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) .filter_map(|i| { - let mut disk = AhciDisk::new(base, i, irq); - let port_type = disk.port.probe(); + let port = &mut unsafe { &mut *(base as *mut HbaMem) }.ports[i]; + let port_type = port.probe(); println!("{}: {:?}", i, port_type); match port_type { HbaPortType::SATA => { - disk.port.init(); - if let Some(size) = unsafe { disk.port.identify(i) } { - disk.size = size; - Some(disk) - } else { - None + match AhciDisk::new(port) { + Ok(disk) => Some(disk), + Err(err) => { + println!("{}: {}", i, err); + None + } } } _ => None, @@ -41,29 +43,38 @@ impl Ahci { pub struct AhciDisk { port: &'static mut HbaPort, - port_index: usize, - irq: u8, size: u64, + clb: Dma<[HbaCmdHeader; 32]>, + ctbas: [Dma; 32], + fb: Dma<[u8; 256]> } impl AhciDisk { - fn new(base: usize, port_index: usize, irq: u8) -> Self { - AhciDisk { - port: &mut unsafe { &mut *(base as *mut HbaMem) }.ports[port_index], - port_index: port_index, - irq: irq, - size: 0 - } - } + fn new(port: &'static mut HbaPort) -> Result { + let mut clb = Dma::zeroed()?; + let mut ctbas = [ + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + ]; + let mut fb = Dma::zeroed()?; - fn name(&self) -> String { - format!("AHCI Port {}", self.port_index) - } + port.init(&mut clb, &mut ctbas, &mut fb); - fn on_irq(&mut self, irq: u8) { - if irq == self.irq { - //debugln!("AHCI IRQ"); - } + let size = unsafe { port.identify(&mut clb, &mut ctbas).unwrap_or(0) }; + + Ok(AhciDisk { + port: port, + size: size, + clb: clb, + ctbas: ctbas, + fb: fb + }) } fn size(&self) -> u64 { diff --git a/drivers/ahcid/src/main.rs b/drivers/ahcid/src/main.rs index 5f7b1a1..7a919ae 100644 --- a/drivers/ahcid/src/main.rs +++ b/drivers/ahcid/src/main.rs @@ -1,4 +1,5 @@ #![feature(asm)] +#![feature(question_mark)] #[macro_use] extern crate bitflags; @@ -27,9 +28,9 @@ fn main() { } let address = unsafe { physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; - { - ahci::Ahci::disks(address, irq); + ahci::Ahci::disks(address, irq); + loop { + let _ = syscall::sched_yield(); } - unsafe { physunmap(address).expect("ahcid: failed to unmap address") }; }); }