Make AHCI driver read bytes
This commit is contained in:
parent
f714d4858a
commit
ba83ca3939
116
drivers/ahcid/src/ahci/disk.rs
Normal file
116
drivers/ahcid/src/ahci/disk.rs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
use syscall::error::{Error, EIO, Result};
|
||||||
|
|
||||||
|
use super::dma::Dma;
|
||||||
|
use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader};
|
||||||
|
|
||||||
|
pub struct Disk {
|
||||||
|
id: usize,
|
||||||
|
port: &'static mut HbaPort,
|
||||||
|
size: u64,
|
||||||
|
clb: Dma<[HbaCmdHeader; 32]>,
|
||||||
|
ctbas: [Dma<HbaCmdTable>; 32],
|
||||||
|
fb: Dma<[u8; 256]>,
|
||||||
|
buf: Dma<[u8; 256 * 512]>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Disk {
|
||||||
|
pub fn new(id: usize, port: &'static mut HbaPort) -> Result<Self> {
|
||||||
|
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()?;
|
||||||
|
let buf = Dma::zeroed()?;
|
||||||
|
|
||||||
|
port.init(&mut clb, &mut ctbas, &mut fb);
|
||||||
|
|
||||||
|
let size = unsafe { port.identify(&mut clb, &mut ctbas).unwrap_or(0) };
|
||||||
|
|
||||||
|
Ok(Disk {
|
||||||
|
id: id,
|
||||||
|
port: port,
|
||||||
|
size: size,
|
||||||
|
clb: clb,
|
||||||
|
ctbas: ctbas,
|
||||||
|
fb: fb,
|
||||||
|
buf: buf
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> usize {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> u64 {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
|
||||||
|
let sectors = buffer.len()/512;
|
||||||
|
if sectors > 0 {
|
||||||
|
let mut sector: usize = 0;
|
||||||
|
while sectors - sector >= 255 {
|
||||||
|
if let Err(err) = self.port.ata_dma(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf) {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), 255 * 512); }
|
||||||
|
|
||||||
|
sector += 255;
|
||||||
|
}
|
||||||
|
if sector < sectors {
|
||||||
|
if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf) {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), (sectors - sector) * 512); }
|
||||||
|
|
||||||
|
sector += sectors - sector;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(sector * 512)
|
||||||
|
} else {
|
||||||
|
println!("Invalid request");
|
||||||
|
Err(Error::new(EIO))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
|
||||||
|
let sectors = (buffer.len() + 511)/512;
|
||||||
|
if sectors > 0 {
|
||||||
|
let mut sector: usize = 0;
|
||||||
|
while sectors - sector >= 255 {
|
||||||
|
unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), 255 * 512); }
|
||||||
|
|
||||||
|
if let Err(err) = self.port.ata_dma(block + sector as u64, 255, true, &mut self.clb, &mut self.ctbas, &mut self.buf) {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
sector += 255;
|
||||||
|
}
|
||||||
|
if sector < sectors {
|
||||||
|
unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), (sectors - sector) * 512); }
|
||||||
|
|
||||||
|
if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, true, &mut self.clb, &mut self.ctbas, &mut self.buf) {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
sector += sectors - sector;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(sector * 512)
|
||||||
|
} else {
|
||||||
|
println!("Invalid request");
|
||||||
|
Err(Error::new(EIO))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ use std::mem::size_of;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::{ptr, u32};
|
use std::{ptr, u32};
|
||||||
|
|
||||||
use syscall::{virttophys, MAP_WRITE};
|
|
||||||
use syscall::error::{Error, Result, EIO};
|
use syscall::error::{Error, Result, EIO};
|
||||||
|
|
||||||
use super::dma::Dma;
|
use super::dma::Dma;
|
||||||
|
@ -218,37 +217,34 @@ impl HbaPort {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ata_dma_small(&mut self, block: u64, sectors: usize, mut buf: usize, write: bool) -> Result<usize> {
|
pub fn ata_dma(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma<HbaCmdTable>; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result<usize> {
|
||||||
if buf >= 0x80000000 {
|
println!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}", (self as *mut HbaPort) as usize, block, sectors, write);
|
||||||
buf -= 0x80000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: PRDTL for files larger than 4MB
|
assert!(sectors > 0 && sectors < 256);
|
||||||
let entries = 1;
|
|
||||||
|
|
||||||
if buf > 0 && sectors > 0 {
|
self.is.write(u32::MAX);
|
||||||
self.is.write(u32::MAX);
|
|
||||||
|
|
||||||
if let Some(slot) = self.slot() {
|
if let Some(slot) = self.slot() {
|
||||||
println!("Slot {}", slot);
|
println!("Slot {}", slot);
|
||||||
|
|
||||||
let clb = self.clb.read() as usize;
|
let cmdheader = &mut clb[slot as usize];
|
||||||
let cmdheader = unsafe { &mut *(clb as *mut HbaCmdHeader).offset(slot as isize) };
|
|
||||||
|
|
||||||
cmdheader.cfl.write(((size_of::<FisRegH2D>() / size_of::<u32>()) as u8));
|
cmdheader.cfl.write(((size_of::<FisRegH2D>() / size_of::<u32>()) as u8));
|
||||||
cmdheader.cfl.writef(1 << 6, write);
|
cmdheader.cfl.writef(1 << 6, write);
|
||||||
|
|
||||||
cmdheader.prdtl.write(entries);
|
cmdheader.prdtl.write(1);
|
||||||
|
|
||||||
let ctba = cmdheader.ctba.read() as usize;
|
{
|
||||||
unsafe { ptr::write_bytes(ctba as *mut u8, 0, size_of::<HbaCmdTable>()) };
|
let cmdtbl = &mut ctbas[slot as usize];
|
||||||
let cmdtbl = unsafe { &mut *(ctba as *mut HbaCmdTable) };
|
unsafe { ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::<HbaCmdTable>()) };
|
||||||
|
|
||||||
let prdt_entry = &mut cmdtbl.prdt_entry[0];
|
let prdt_entry = &mut cmdtbl.prdt_entry[0];
|
||||||
prdt_entry.dba.write(buf as u64);
|
prdt_entry.dba.write(buf.physical() as u64);
|
||||||
prdt_entry.dbc.write(((sectors * 512) as u32) | 1);
|
prdt_entry.dbc.write(((sectors * 512) as u32) | 1);
|
||||||
|
}
|
||||||
|
|
||||||
let cmdfis = unsafe { &mut *(cmdtbl.cfis.as_ptr() as *mut FisRegH2D) };
|
{
|
||||||
|
let cmdfis = unsafe { &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D) };
|
||||||
|
|
||||||
cmdfis.fis_type.write(FisType::RegH2D as u8);
|
cmdfis.fis_type.write(FisType::RegH2D as u8);
|
||||||
cmdfis.pm.write(1 << 7);
|
cmdfis.pm.write(1 << 7);
|
||||||
|
@ -270,57 +266,27 @@ impl HbaPort {
|
||||||
|
|
||||||
cmdfis.countl.write(sectors as u8);
|
cmdfis.countl.write(sectors as u8);
|
||||||
cmdfis.counth.write((sectors >> 8) as u8);
|
cmdfis.counth.write((sectors >> 8) as u8);
|
||||||
|
}
|
||||||
|
|
||||||
println!("Busy Wait");
|
println!("Busy Wait");
|
||||||
while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {}
|
while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {}
|
||||||
|
|
||||||
self.ci.writef(1 << slot, true);
|
self.ci.writef(1 << slot, true);
|
||||||
|
|
||||||
println!("Completion Wait");
|
|
||||||
while self.ci.readf(1 << slot) {
|
|
||||||
if self.is.readf(HBA_PORT_IS_TFES) {
|
|
||||||
return Err(Error::new(EIO));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
println!("Completion Wait");
|
||||||
|
while self.ci.readf(1 << slot) {
|
||||||
if self.is.readf(HBA_PORT_IS_TFES) {
|
if self.is.readf(HBA_PORT_IS_TFES) {
|
||||||
return Err(Error::new(EIO));
|
return Err(Error::new(EIO));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(sectors * 512)
|
|
||||||
} else {
|
|
||||||
println!("No Command Slots");
|
|
||||||
Err(Error::new(EIO))
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
println!("Invalid request");
|
|
||||||
Err(Error::new(EIO))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ata_dma(&mut self, block: u64, sectors: usize, buf: usize, write: bool) -> Result<usize> {
|
if self.is.readf(HBA_PORT_IS_TFES) {
|
||||||
println!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} BUF: {:X} WRITE: {}", (self as *mut HbaPort) as usize, block, sectors, buf, write);
|
return Err(Error::new(EIO));
|
||||||
|
|
||||||
if sectors > 0 {
|
|
||||||
let physical_address = try!(unsafe { virttophys(buf) });
|
|
||||||
|
|
||||||
let mut sector: usize = 0;
|
|
||||||
while sectors - sector >= 255 {
|
|
||||||
if let Err(err) = self.ata_dma_small(block + sector as u64, 255, physical_address + sector * 512, write) {
|
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
sector += 255;
|
|
||||||
}
|
|
||||||
if sector < sectors {
|
|
||||||
if let Err(err) = self.ata_dma_small(block + sector as u64, sectors - sector, physical_address + sector * 512, write) {
|
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(sectors * 512)
|
Ok(sectors * 512)
|
||||||
} else {
|
} else {
|
||||||
println!("Invalid request");
|
println!("No Command Slots");
|
||||||
Err(Error::new(EIO))
|
Err(Error::new(EIO))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,91 +1,37 @@
|
||||||
use io::Io;
|
use io::Io;
|
||||||
|
|
||||||
use syscall::error::Result;
|
use self::disk::Disk;
|
||||||
|
use self::hba::{HbaMem, HbaPortType};
|
||||||
use self::dma::Dma;
|
|
||||||
use self::hba::{HbaMem, HbaCmdTable, HbaCmdHeader, HbaPort, HbaPortType};
|
|
||||||
|
|
||||||
|
pub mod disk;
|
||||||
pub mod dma;
|
pub mod dma;
|
||||||
pub mod fis;
|
pub mod fis;
|
||||||
pub mod hba;
|
pub mod hba;
|
||||||
|
|
||||||
pub struct Ahci;
|
pub fn disks(base: usize, irq: u8) -> Vec<Disk> {
|
||||||
|
println!(" + AHCI on: {:X} IRQ: {}", base as usize, irq);
|
||||||
|
|
||||||
impl Ahci {
|
let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read();
|
||||||
pub fn disks(base: usize, irq: u8) -> Vec<AhciDisk> {
|
let ret: Vec<Disk> = (0..32)
|
||||||
println!(" + AHCI on: {:X} IRQ: {}", base as usize, irq);
|
.filter(|&i| pi & 1 << i as i32 == 1 << i as i32)
|
||||||
|
.filter_map(|i| {
|
||||||
let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read();
|
let port = &mut unsafe { &mut *(base as *mut HbaMem) }.ports[i];
|
||||||
let ret: Vec<AhciDisk> = (0..32)
|
let port_type = port.probe();
|
||||||
.filter(|&i| pi & 1 << i as i32 == 1 << i as i32)
|
println!("{}: {:?}", i, port_type);
|
||||||
.filter_map(|i| {
|
match port_type {
|
||||||
let port = &mut unsafe { &mut *(base as *mut HbaMem) }.ports[i];
|
HbaPortType::SATA => {
|
||||||
let port_type = port.probe();
|
match Disk::new(i, port) {
|
||||||
println!("{}: {:?}", i, port_type);
|
Ok(disk) => Some(disk),
|
||||||
match port_type {
|
Err(err) => {
|
||||||
HbaPortType::SATA => {
|
println!("{}: {}", i, err);
|
||||||
match AhciDisk::new(port) {
|
None
|
||||||
Ok(disk) => Some(disk),
|
|
||||||
Err(err) => {
|
|
||||||
println!("{}: {}", i, err);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => None,
|
|
||||||
}
|
}
|
||||||
})
|
_ => None,
|
||||||
.collect();
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
ret
|
ret
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AhciDisk {
|
|
||||||
port: &'static mut HbaPort,
|
|
||||||
size: u64,
|
|
||||||
clb: Dma<[HbaCmdHeader; 32]>,
|
|
||||||
ctbas: [Dma<HbaCmdTable>; 32],
|
|
||||||
fb: Dma<[u8; 256]>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AhciDisk {
|
|
||||||
fn new(port: &'static mut HbaPort) -> Result<Self> {
|
|
||||||
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()?;
|
|
||||||
|
|
||||||
port.init(&mut clb, &mut ctbas, &mut fb);
|
|
||||||
|
|
||||||
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 {
|
|
||||||
self.size
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
|
|
||||||
self.port.ata_dma(block, buffer.len() / 512, buffer.as_ptr() as usize, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
|
|
||||||
self.port.ata_dma(block, buffer.len() / 512, buffer.as_ptr() as usize, true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,28 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let address = unsafe { physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") };
|
let address = unsafe { physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") };
|
||||||
ahci::Ahci::disks(address, irq);
|
{
|
||||||
loop {
|
let mut disks = ahci::disks(address, irq);
|
||||||
let _ = syscall::sched_yield();
|
for mut disk in disks.iter_mut() {
|
||||||
|
let mut sector = [0; 512];
|
||||||
|
println!("Read disk {} size {} MB", disk.id(), disk.size()/1024/1024);
|
||||||
|
match disk.read(0, &mut sector) {
|
||||||
|
Ok(count) => {
|
||||||
|
println!("{}", count);
|
||||||
|
for i in 0..512 {
|
||||||
|
print!("{:X} ", sector[i]);
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
println!("{}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loop {
|
||||||
|
let _ = syscall::sched_yield();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
unsafe { let _ = physunmap(address); }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue