mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-23 16:36:18 +04:00
Simplify IDE code.
This commit is contained in:
parent
81196729e4
commit
a42d6086c6
@ -5,267 +5,120 @@
|
|||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref DISK0: LockedIde = LockedIde(Mutex::new(DmaController::new(0)));
|
pub static ref DISK0: LockedIde = LockedIde(Mutex::new(IDE::new(0)));
|
||||||
pub static ref DISK1: LockedIde = LockedIde(Mutex::new(DmaController::new(1)));
|
pub static ref DISK1: LockedIde = LockedIde(Mutex::new(IDE::new(1)));
|
||||||
}
|
}
|
||||||
pub const BLOCK_SIZE: usize = 512;
|
pub const BLOCK_SIZE: usize = 512;
|
||||||
|
|
||||||
pub struct LockedIde(pub Mutex<DmaController>);
|
pub struct LockedIde(pub Mutex<IDE>);
|
||||||
|
|
||||||
pub struct DmaController {
|
pub struct IDE {
|
||||||
num: u8,
|
num: u8,
|
||||||
|
/// I/O Base
|
||||||
|
base: u16,
|
||||||
|
/// Control Base
|
||||||
|
ctrl: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DmaController
|
impl IDE {
|
||||||
{
|
pub fn new(num: u8) -> Self {
|
||||||
/// Read ATA DMA. Block size = 512 bytes.
|
let ide = match num {
|
||||||
pub fn read(&self, blockidx: u64, count: usize, dst: &mut [u32]) -> Result<usize, ()> {
|
0 => IDE { num: 0, base: 0x1f0, ctrl: 0x3f4 },
|
||||||
assert_eq!(dst.len(), count * SECTOR_SIZE);
|
1 => IDE { num: 1, base: 0x1f0, ctrl: 0x3f4 },
|
||||||
let dst = if count > MAX_DMA_SECTORS { &mut dst[..MAX_DMA_SECTORS * SECTOR_SIZE] } else { dst };
|
2 => IDE { num: 2, base: 0x170, ctrl: 0x374 },
|
||||||
//self.do_dma(blockidx, DMABuffer::new_mut(dst, 32), disk, false);
|
3 => IDE { num: 3, base: 0x170, ctrl: 0x374 },
|
||||||
self.ide_read_secs(self.num, blockidx, dst, count as u8)
|
_ => panic!("ide number should be 0,1,2,3"),
|
||||||
}
|
};
|
||||||
/// Write ATA DMA. Block size = 512 bytes.
|
ide.init();
|
||||||
pub fn write(&self, blockidx: u64, count: usize, dst: &[u32]) -> Result<usize, ()> {
|
|
||||||
assert_eq!(dst.len(), count * SECTOR_SIZE);
|
|
||||||
let dst = if count > MAX_DMA_SECTORS { &dst[..MAX_DMA_SECTORS * SECTOR_SIZE] } else { dst };
|
|
||||||
//println!("ide_write_secs: disk={},blockidx={},count={}",disk,blockidx,count);
|
|
||||||
self.ide_write_secs(self.num, blockidx, dst, count as u8)
|
|
||||||
}
|
|
||||||
/// Create structure and init
|
|
||||||
fn new(num: u8) -> Self {
|
|
||||||
assert!(num < MAX_IDE as u8);
|
|
||||||
let ide = DmaController { num };
|
|
||||||
ide.ide_init();
|
|
||||||
ide
|
ide
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ide_wait_ready(&self, iobase: u16, check_error: usize) -> usize {
|
/// Read ATA DMA. Block size = 512 bytes.
|
||||||
|
pub fn read(&self, sector: u64, count: usize, data: &mut [u32]) -> Result<(), ()> {
|
||||||
|
assert_eq!(data.len(), count * SECTOR_SIZE);
|
||||||
|
self.wait();
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut r = port::inb(iobase + ISA_STATUS);
|
self.select(sector, count as u8);
|
||||||
//println!("iobase:{} ready:{}",iobase,r);
|
port::outb(self.base + ISA_COMMAND, IDE_CMD_READ);
|
||||||
while (r & IDE_BSY) > 0 {
|
for i in 0..count {
|
||||||
r = port::inb(iobase + ISA_STATUS);
|
let ptr = &data[(i as usize) * SECTOR_SIZE];
|
||||||
//println!("busy");
|
if self.wait_error() {
|
||||||
}
|
return Err(());
|
||||||
/* nothing */
|
}
|
||||||
if check_error == 1 && (r & (IDE_DF | IDE_ERR)) != 0 {
|
asm!("rep insl" :: "{dx}"(self.base), "{rdi}"(ptr), "{cx}"(SECTOR_SIZE) : "rdi" : "volatile");
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
Ok(())
|
||||||
|
}
|
||||||
|
/// Write ATA DMA. Block size = 512 bytes.
|
||||||
|
pub fn write(&self, sector: u64, count: usize, data: &[u32]) -> Result<(), ()> {
|
||||||
|
assert_eq!(data.len(), count * SECTOR_SIZE);
|
||||||
|
self.wait();
|
||||||
|
unsafe {
|
||||||
|
self.select(sector, count as u8);
|
||||||
|
port::outb(self.base + ISA_COMMAND, IDE_CMD_WRITE);
|
||||||
|
for i in 0..count {
|
||||||
|
let ptr = &data[(i as usize) * SECTOR_SIZE];
|
||||||
|
if self.wait_error() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
asm!("rep outsl" :: "{dx}"(self.base), "{rsi}"(ptr), "{cx}"(SECTOR_SIZE) : "rsi" : "volatile");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ide_init(&self) {
|
fn wait(&self) {
|
||||||
//static_assert((SECTSIZE % 4) == 0);
|
while unsafe { port::inb(self.base + ISA_STATUS) } & IDE_BUSY != 0 {}
|
||||||
let ideno = self.num;
|
}
|
||||||
//println!("ideno:{}",ideno);
|
|
||||||
/* assume that no device here */
|
|
||||||
//ide_devices[ideno].valid = 0;
|
|
||||||
|
|
||||||
//let iobase = IO_BASE(ideno);
|
fn wait_error(&self) -> bool {
|
||||||
let iobase = CHANNELS[if ideno > 2 { 1 } else { 0 }].0;
|
self.wait();
|
||||||
|
let status = unsafe { port::inb(self.base + ISA_STATUS) };
|
||||||
|
status & (IDE_DF | IDE_ERR) != 0
|
||||||
|
}
|
||||||
|
|
||||||
/* wait device ready */
|
fn init(&self) {
|
||||||
self.ide_wait_ready(iobase, 0);
|
self.wait();
|
||||||
//println!("ide_wait_ready");
|
|
||||||
unsafe {
|
unsafe {
|
||||||
/* step1: select drive */
|
// step1: select drive
|
||||||
//println!("outb");
|
port::outb(self.base + ISA_SDH, (0xE0 | ((self.num & 1) << 4)) as u8);
|
||||||
port::outb(iobase + ISA_SDH, (0xE0 | ((ideno & 1) << 4)) as u8);
|
self.wait();
|
||||||
self.ide_wait_ready(iobase, 0);
|
|
||||||
|
|
||||||
/* step2: send ATA identify command */
|
// step2: send ATA identify command
|
||||||
//println!("outb");
|
port::outb(self.base + ISA_COMMAND, IDE_CMD_IDENTIFY);
|
||||||
port::outb(iobase + ISA_COMMAND, IDE_CMD_IDENTIFY);
|
self.wait();
|
||||||
self.ide_wait_ready(iobase, 0);
|
|
||||||
|
|
||||||
/* step3: polling */
|
// step3: polling
|
||||||
//println!("inb");
|
if port::inb(self.base + ISA_STATUS) == 0 || self.wait_error() {
|
||||||
if port::inb(iobase + ISA_STATUS) == 0 || self.ide_wait_ready(iobase, 1) != 0 {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//println!("insl");
|
// ???
|
||||||
let mut buffer: [u32; 128] = [0; 128];
|
let mut data = [0; SECTOR_SIZE];
|
||||||
for i in 0..buffer.len() {
|
asm!("rep insl" :: "{dx}"(self.base + ISA_DATA), "{rdi}"(data.as_ptr()), "{cx}"(SECTOR_SIZE) : "rdi" : "volatile");
|
||||||
buffer[i] = i as u32;
|
|
||||||
if i == 1 {
|
|
||||||
//println!("{:#x}",&buffer[i] as *const u32 as usize - ::consts::KERNEL_OFFSET)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//println!("insl {:#x}",&buffer as *const u32 as usize - ::consts::KERNEL_OFFSET);
|
|
||||||
|
|
||||||
//println!("insl {:#x}",buffer.as_ptr() as usize - ::consts::KERNEL_OFFSET);
|
|
||||||
//port::insl(iobase + ISA_DATA, &mut buffer);
|
|
||||||
let port = iobase + ISA_DATA;
|
|
||||||
//let buf=&mut buffer;
|
|
||||||
for i in 0..buffer.len() {
|
|
||||||
asm!("insl %dx, (%rdi)"
|
|
||||||
:: "{dx}"(port), "{rdi}"(&buffer[i])
|
|
||||||
: "rdi" : "volatile");
|
|
||||||
}
|
|
||||||
//println!("insl");
|
|
||||||
for i in 0..4 {
|
|
||||||
info!("ide init: {}", buffer[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* device is ok */
|
|
||||||
//ide_devices[ideno].valid = 1;
|
|
||||||
|
|
||||||
/* read identification space of the device */
|
|
||||||
/*let buffer[128];
|
|
||||||
insl(iobase + ISA_DATA, buffer, sizeof(buffer) / sizeof(unsigned int));
|
|
||||||
|
|
||||||
unsigned char *ident = (unsigned char *)buffer;
|
|
||||||
unsigned int sectors;
|
|
||||||
unsigned int cmdsets = *(unsigned int *)(ident + IDE_IDENT_CMDSETS);
|
|
||||||
/* device use 48-bits or 28-bits addressing */
|
|
||||||
if (cmdsets & (1 << 26)) {
|
|
||||||
sectors = *(unsigned int *)(ident + IDE_IDENT_MAX_LBA_EXT);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sectors = *(unsigned int *)(ident + IDE_IDENT_MAX_LBA);
|
|
||||||
}
|
|
||||||
ide_devices[ideno].sets = cmdsets;
|
|
||||||
ide_devices[ideno].size = sectors;
|
|
||||||
|
|
||||||
/* check if supports LBA */
|
|
||||||
assert((*(unsigned short *)(ident + IDE_IDENT_CAPABILITIES) & 0x200) != 0);
|
|
||||||
|
|
||||||
unsigned char *model = ide_devices[ideno].model, *data = ident + IDE_IDENT_MODEL;
|
|
||||||
unsigned int i, length = 40;
|
|
||||||
for (i = 0; i < length; i += 2) {
|
|
||||||
model[i] = data[i + 1], model[i + 1] = data[i];
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
model[i] = '\0';
|
|
||||||
} while (i -- > 0 && model[i] == ' ');
|
|
||||||
|
|
||||||
cprintf("ide %d: %10u(sectors), '%s'.\n", ideno, ide_devices[ideno].size, ide_devices[ideno].model);*/
|
|
||||||
|
|
||||||
// enable ide interrupt
|
|
||||||
//pic_enable(IRQ_IDE1);
|
|
||||||
//pic_enable(IRQ_IDE2);
|
|
||||||
|
|
||||||
info!("ide {} init end", self.num);
|
|
||||||
}
|
|
||||||
fn ide_read_secs<'a>(&'a self, ideno: u8, secno: u64, dst: &'a mut [u32], nsecs: u8) -> Result<usize, ()> {
|
|
||||||
//assert(nsecs <= MAX_NSECS && VALID_IDE(ideno));
|
|
||||||
//assert(secno < MAX_DISK_NSECS && secno + nsecs <= MAX_DISK_NSECS);
|
|
||||||
let iobase = CHANNELS[if ideno > 2 { 1 } else { 0 }].0;
|
|
||||||
let ioctrl = CHANNELS[if ideno > 2 { 1 } else { 0 }].1;
|
|
||||||
|
|
||||||
//ide_wait_ready(iobase, 0);
|
|
||||||
|
|
||||||
self.ide_wait_ready(iobase, 0);
|
|
||||||
|
|
||||||
let ret = 0;
|
|
||||||
// generate interrupt
|
|
||||||
unsafe {
|
|
||||||
port::outb(ioctrl + ISA_CTRL, 0);
|
|
||||||
port::outb(iobase + ISA_SECCNT, nsecs);
|
|
||||||
port::outb(iobase + ISA_SECTOR, (secno & 0xFF) as u8);
|
|
||||||
port::outb(iobase + ISA_CYL_LO, ((secno >> 8) & 0xFF) as u8);
|
|
||||||
port::outb(iobase + ISA_CYL_HI, ((secno >> 16) & 0xFF) as u8);
|
|
||||||
port::outb(iobase + ISA_SDH, 0xE0 | ((ideno & 1) << 4) | (((secno >> 24) & 0xF) as u8));
|
|
||||||
//port::outb(iobase + ISA_SDH, (0xE0 | ((ideno & 1) << 4)) as u8);
|
|
||||||
//self.ide_wait_ready(iobase, 0);
|
|
||||||
port::outb(iobase + ISA_COMMAND, IDE_CMD_READ);
|
|
||||||
//self.ide_wait_ready(iobase, 0);
|
|
||||||
// if port::inb(iobase + ISA_STATUS) == 0 || self.ide_wait_ready(iobase, 1) != 0 {
|
|
||||||
// println!("error?");
|
|
||||||
// }
|
|
||||||
for i in 0..nsecs {
|
|
||||||
//dst = dst + SECTSIZE;
|
|
||||||
let tmp = &mut dst[(i as usize) * SECTOR_SIZE..((i + 1) as usize) * SECTOR_SIZE];
|
|
||||||
if self.ide_wait_ready(iobase, 1) != 0 {
|
|
||||||
println!("wait ready error");
|
|
||||||
}
|
|
||||||
//self.ide_wait_ready(iobase, 1);
|
|
||||||
//port::insl(iobase, tmp);
|
|
||||||
let port = iobase;
|
|
||||||
//let buf=&mut buffer;
|
|
||||||
for i in 0..tmp.len() {
|
|
||||||
asm!("insl %dx, (%rdi)"
|
|
||||||
:: "{dx}"(port), "{rdi}"(&tmp[i])
|
|
||||||
: "rdi" : "volatile");
|
|
||||||
}
|
|
||||||
//println!("read :{}",i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(ret)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ide_write_secs<'a>(&'a self, ideno: u8, secno: u64, src: &'a [u32], nsecs: u8) -> Result<usize, ()> {
|
fn select(&self, sector: u64, count: u8) {
|
||||||
//assert(nsecs <= MAX_NSECS && VALID_IDE(ideno));
|
assert_ne!(count, 0);
|
||||||
//assert(secno < MAX_DISK_NSECS && secno + nsecs <= MAX_DISK_NSECS);
|
self.wait();
|
||||||
let iobase = CHANNELS[if ideno > 2 { 1 } else { 0 }].0;
|
|
||||||
let ioctrl = CHANNELS[if ideno > 2 { 1 } else { 0 }].1;
|
|
||||||
|
|
||||||
//ide_wait_ready(iobase, 0);
|
|
||||||
|
|
||||||
self.ide_wait_ready(iobase, 0);
|
|
||||||
|
|
||||||
let ret = 0;
|
|
||||||
// generate interrupt
|
|
||||||
unsafe {
|
unsafe {
|
||||||
port::outb(ioctrl + ISA_CTRL, 0);
|
// generate interrupt
|
||||||
port::outb(iobase + ISA_SECCNT, nsecs);
|
port::outb(self.ctrl + ISA_CTRL, 0);
|
||||||
port::outb(iobase + ISA_SECTOR, (secno & 0xFF) as u8);
|
port::outb(self.base + ISA_SECCNT, count);
|
||||||
port::outb(iobase + ISA_CYL_LO, ((secno >> 8) & 0xFF) as u8);
|
port::outb(self.base + ISA_SECTOR, (sector & 0xFF) as u8);
|
||||||
port::outb(iobase + ISA_CYL_HI, ((secno >> 16) & 0xFF) as u8);
|
port::outb(self.base + ISA_CYL_LO, ((sector >> 8) & 0xFF) as u8);
|
||||||
port::outb(iobase + ISA_SDH, 0xE0 | ((ideno & 1) << 4) | (((secno >> 24) & 0xF) as u8));
|
port::outb(self.base + ISA_CYL_HI, ((sector >> 16) & 0xFF) as u8);
|
||||||
port::outb(iobase + ISA_COMMAND, IDE_CMD_WRITE);
|
port::outb(self.base + ISA_SDH, 0xE0 | ((self.num & 1) << 4) | (((sector >> 24) & 0xF) as u8));
|
||||||
//println!("{}",nsecs);
|
|
||||||
for i in 0..nsecs {
|
|
||||||
//dst = dst + SECTSIZE;
|
|
||||||
// if ((ret = ide_wait_ready(iobase, 1)) != 0) {
|
|
||||||
// goto out;
|
|
||||||
// }
|
|
||||||
//port::insb(iobase, dst);
|
|
||||||
//println!("i={}",i);
|
|
||||||
let tmp = &src[(i as usize) * SECTOR_SIZE..((i + 1) as usize) * SECTOR_SIZE];
|
|
||||||
if self.ide_wait_ready(iobase, 1) != 0 {
|
|
||||||
println!("wait ready error");
|
|
||||||
}
|
|
||||||
//println!("write {}:{}",i,src[i as usize]);
|
|
||||||
//println!("outsl");
|
|
||||||
//port::outsl(iobase, tmp);
|
|
||||||
let port = iobase;
|
|
||||||
//let buf=&mut buffer;
|
|
||||||
for i in 0..tmp.len() {
|
|
||||||
asm!("outsl (%rsi), %dx"
|
|
||||||
:: "{dx}"(port), "{rsi}"(&tmp[i])
|
|
||||||
: "rsi");
|
|
||||||
}
|
|
||||||
//println!("write :{}",i);
|
|
||||||
// for i in 0..4 {
|
|
||||||
// println!("{}",src[i as usize]);
|
|
||||||
// }
|
|
||||||
//port::outb(iobase, src[i as usize]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(ret)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SECTOR_SIZE: usize = 128;
|
const SECTOR_SIZE: usize = 128;
|
||||||
//const MAX_DMA_SECTORS: usize = 0x2_0000 / SECTOR_SIZE; // Limited by sector count (and PRDT entries)
|
|
||||||
const MAX_DMA_SECTORS: usize = 0x1F_F000 / SECTOR_SIZE; // Limited by sector count (and PRDT entries)
|
const MAX_DMA_SECTORS: usize = 0x1F_F000 / SECTOR_SIZE; // Limited by sector count (and PRDT entries)
|
||||||
// 512 PDRT entries, assume maximum fragmentation = 512 * 4K max = 2^21 = 2MB per transfer
|
// 512 PDRT entries, assume maximum fragmentation = 512 * 4K max = 2^21 = 2MB per transfer
|
||||||
|
|
||||||
const HDD_PIO_W28: u8 = 0x30;
|
|
||||||
const HDD_PIO_R28: u8 = 0x20;
|
|
||||||
const HDD_PIO_W48: u8 = 0x34;
|
|
||||||
const HDD_PIO_R48: u8 = 0x24;
|
|
||||||
const HDD_IDENTIFY: u8 = 0xEC;
|
|
||||||
|
|
||||||
const HDD_DMA_R28: u8 = 0xC8;
|
|
||||||
const HDD_DMA_W28: u8 = 0xCA;
|
|
||||||
const HDD_DMA_R48: u8 = 0x25;
|
|
||||||
const HDD_DMA_W48: u8 = 0x35;
|
|
||||||
|
|
||||||
const ISA_DATA: u16 = 0x00;
|
const ISA_DATA: u16 = 0x00;
|
||||||
const ISA_ERROR: u16 = 0x01;
|
const ISA_ERROR: u16 = 0x01;
|
||||||
const ISA_PRECOMP: u16 = 0x01;
|
const ISA_PRECOMP: u16 = 0x01;
|
||||||
@ -278,7 +131,7 @@ const ISA_SDH: u16 = 0x06;
|
|||||||
const ISA_COMMAND: u16 = 0x07;
|
const ISA_COMMAND: u16 = 0x07;
|
||||||
const ISA_STATUS: u16 = 0x07;
|
const ISA_STATUS: u16 = 0x07;
|
||||||
|
|
||||||
const IDE_BSY: u8 = 0x80;
|
const IDE_BUSY: u8 = 0x80;
|
||||||
const IDE_DRDY: u8 = 0x40;
|
const IDE_DRDY: u8 = 0x40;
|
||||||
const IDE_DF: u8 = 0x20;
|
const IDE_DF: u8 = 0x20;
|
||||||
const IDE_DRQ: u8 = 0x08;
|
const IDE_DRQ: u8 = 0x08;
|
||||||
@ -288,33 +141,7 @@ const IDE_CMD_READ: u8 = 0x20;
|
|||||||
const IDE_CMD_WRITE: u8 = 0x30;
|
const IDE_CMD_WRITE: u8 = 0x30;
|
||||||
const IDE_CMD_IDENTIFY: u8 = 0xEC;
|
const IDE_CMD_IDENTIFY: u8 = 0xEC;
|
||||||
|
|
||||||
const IDE_IDENT_SECTORS: usize = 20;
|
|
||||||
const IDE_IDENT_MODEL: usize = 54;
|
|
||||||
const IDE_IDENT_CAPABILITIES: usize = 98;
|
|
||||||
const IDE_IDENT_CMDSETS: usize = 164;
|
|
||||||
const IDE_IDENT_MAX_LBA: usize = 120;
|
|
||||||
const IDE_IDENT_MAX_LBA_EXT: usize = 200;
|
|
||||||
|
|
||||||
const IO_BASE0: u16 = 0x1F0;
|
|
||||||
const IO_BASE1: u16 = 0x170;
|
|
||||||
const IO_CTRL0: u16 = 0x3F4;
|
|
||||||
const IO_CTRL1: u16 = 0x374;
|
|
||||||
|
|
||||||
const MAX_IDE: usize = 4;
|
|
||||||
const MAX_NSECS: usize = 128;
|
const MAX_NSECS: usize = 128;
|
||||||
//const MAX_DISK_NSECS 0x10000000U;
|
|
||||||
//const VALID_IDE(ideno) (((ideno) >= 0) && ((ideno) < MAX_IDE) && (ide_devices[ideno].valid))
|
|
||||||
|
|
||||||
struct Channels {
|
|
||||||
base: u16,
|
|
||||||
// I/O Base
|
|
||||||
ctrl: u16, // Control Base
|
|
||||||
}
|
|
||||||
|
|
||||||
const CHANNELS: [(u16, u16); 2] = [(IO_BASE0, IO_CTRL0), (IO_BASE1, IO_CTRL1)];
|
|
||||||
|
|
||||||
//const IO_BASE(ideno) (CHANNELS[(ideno) >> 1].base)
|
|
||||||
//const IO_CTRL(ideno) (CHANNELS[(ideno) >> 1].ctrl)
|
|
||||||
|
|
||||||
mod port {
|
mod port {
|
||||||
use x86_64::instructions::port::Port;
|
use x86_64::instructions::port::Port;
|
||||||
|
Loading…
Reference in New Issue
Block a user