Add IDE driver. No longer link img.

master
WangRunji 7 years ago
parent 90c14cc8fa
commit 1c80b95fe4

@ -23,11 +23,11 @@ assembly_object_files := $(patsubst $(boot_src)/%.asm, \
build/arch/$(arch)/boot/%.o, $(assembly_source_files))
user_image_files := $(wildcard user/*.img)
user_object_files := $(patsubst user/%.img, build/user/%.o, $(user_image_files))
qemu_opts := -cdrom $(iso) -smp 4 -serial mon:stdio
SFSIMG := user/ucore32.img
qemu_opts := -cdrom $(iso) -smp 4 -serial mon:stdio -drive file=$(SFSIMG),media=disk,cache=writeback
features := use_apic
LOG ?= debug
link_user = 1
ifdef link_user
features := $(features) link_user_program

@ -0,0 +1,317 @@
//! ATA IO code, handling device multiplexing and IO operations
//!
//! Borrow from Rucore project. Thanks GWord!
//! Port from ucore C code.
use x86_64::instructions::port;
use spin::Mutex;
lazy_static! {
pub static ref DISK0: LockedIde = LockedIde(Mutex::new(DmaController::new(0)));
}
pub const BLOCK_SIZE: usize = 512;
pub struct LockedIde(pub Mutex<DmaController>);
pub struct DmaController {
num: u8,
}
impl DmaController
{
/// Read ATA DMA. Block size = 512 bytes.
pub fn read(&self, blockidx: u64, count: usize, dst: &mut [u32]) -> Result<usize, ()> {
assert_eq!(dst.len(), count * SECTOR_SIZE);
let dst = if count > MAX_DMA_SECTORS { &mut dst[..MAX_DMA_SECTORS * SECTOR_SIZE] } else { dst };
//self.do_dma(blockidx, DMABuffer::new_mut(dst, 32), disk, false);
self.ide_read_secs(self.num, blockidx, dst, count as u8)
}
/// Write ATA DMA. Block size = 512 bytes.
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
}
fn ide_wait_ready(&self, iobase: u16, check_error: usize) -> usize {
unsafe {
let mut r = port::inb(iobase + ISA_STATUS);
//println!("iobase:{} ready:{}",iobase,r);
while (r & IDE_BSY) > 0 {
r = port::inb(iobase + ISA_STATUS);
//println!("busy");
}
/* nothing */
if check_error == 1 && (r & (IDE_DF | IDE_ERR)) != 0 {
return 1;
}
}
return 0;
}
fn ide_init(&self) {
//static_assert((SECTSIZE % 4) == 0);
let ideno = self.num;
//println!("ideno:{}",ideno);
/* assume that no device here */
//ide_devices[ideno].valid = 0;
//let iobase = IO_BASE(ideno);
let iobase = CHANNELS[if ideno > 2 { 1 } else { 0 }].0;
/* wait device ready */
self.ide_wait_ready(iobase, 0);
//println!("ide_wait_ready");
unsafe {
/* step1: select drive */
//println!("outb");
port::outb(iobase + ISA_SDH, (0xE0 | ((ideno & 1) << 4)) as u8);
self.ide_wait_ready(iobase, 0);
/* step2: send ATA identify command */
//println!("outb");
port::outb(iobase + ISA_COMMAND, IDE_CMD_IDENTIFY);
self.ide_wait_ready(iobase, 0);
/* step3: polling */
//println!("inb");
if port::inb(iobase + ISA_STATUS) == 0 || self.ide_wait_ready(iobase, 1) != 0 {
return;
}
//println!("insl");
let mut buffer: [u32; 128] = [0; 128];
for i in 0..buffer.len() {
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 {
println!("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, ()> {
//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_COMMAND, IDE_CMD_WRITE);
//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 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)
// 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_ERROR: u16 = 0x01;
const ISA_PRECOMP: u16 = 0x01;
const ISA_CTRL: u16 = 0x02;
const ISA_SECCNT: u16 = 0x02;
const ISA_SECTOR: u16 = 0x03;
const ISA_CYL_LO: u16 = 0x04;
const ISA_CYL_HI: u16 = 0x05;
const ISA_SDH: u16 = 0x06;
const ISA_COMMAND: u16 = 0x07;
const ISA_STATUS: u16 = 0x07;
const IDE_BSY: u8 = 0x80;
const IDE_DRDY: u8 = 0x40;
const IDE_DF: u8 = 0x20;
const IDE_DRQ: u8 = 0x08;
const IDE_ERR: u8 = 0x01;
const IDE_CMD_READ: u8 = 0x20;
const IDE_CMD_WRITE: u8 = 0x30;
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_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)

@ -6,6 +6,7 @@ pub mod serial;
pub mod pic;
pub mod keyboard;
pub mod pit;
pub mod ide;
pub fn init(mut page_map: impl FnMut(usize)) -> acpi::AcpiResult {
assert_has_not_been_called!();

@ -1,7 +1,28 @@
use simple_filesystem::*;
use alloc::boxed::Box;
use arch::driver::ide;
use spin::Mutex;
use process;
pub fn load_sfs() {
// let slice = unsafe { MemBuf::new(_binary_user_ucore32_img_start, _binary_user_ucore32_img_end) };
let sfs = SimpleFileSystem::open(Box::new(&ide::DISK0)).unwrap();
let root = sfs.root_inode();
let files = root.borrow().list().unwrap();
trace!("Loading programs: {:?}", files);
// for name in files.iter().filter(|&f| f != "." && f != "..") {
for name in files.iter().filter(|&f| f == "sleep") {
static mut BUF: [u8; 64 << 12] = [0; 64 << 12];
let file = root.borrow().lookup(name.as_str()).unwrap();
let len = file.borrow().read_at(0, unsafe { &mut BUF }).unwrap();
process::add_user_process(name, unsafe { &BUF[..len] });
}
process::print();
}
#[cfg(feature = "link_user_program")]
extern {
fn _binary_user_ucore32_img_start();
fn _binary_user_ucore32_img_end();
@ -30,20 +51,21 @@ impl Device for MemBuf {
}
}
pub fn load_sfs() {
let slice = unsafe { MemBuf::new(_binary_user_ucore32_img_start, _binary_user_ucore32_img_end) };
let sfs = SimpleFileSystem::open(Box::new(slice)).unwrap();
let root = sfs.root_inode();
let files = root.borrow().list().unwrap();
trace!("Loading programs: {:?}", files);
use core::slice;
// for name in files.iter().filter(|&f| f != "." && f != "..") {
for name in files.iter().filter(|&f| f == "sleep") {
static mut BUF: [u8; 64 << 12] = [0; 64 << 12];
let file = root.borrow().lookup(name.as_str()).unwrap();
let len = file.borrow().read_at(0, unsafe { &mut BUF }).unwrap();
process::add_user_process(name, unsafe { &BUF[..len] });
impl BlockedDevice for &'static ide::DISK0 {
fn block_size_log2(&self) -> u8 {
debug_assert_eq!(ide::BLOCK_SIZE, 512);
9
}
fn read_at(&mut self, block_id: usize, buf: &mut [u8]) -> bool {
assert!(buf.len() >= ide::BLOCK_SIZE);
let buf = unsafe { slice::from_raw_parts_mut(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) };
self.0.lock().read(block_id as u64, 1, buf).is_ok()
}
fn write_at(&mut self, block_id: usize, buf: &[u8]) -> bool {
assert!(buf.len() >= ide::BLOCK_SIZE);
let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) };
self.0.lock().write(block_id as u64, 1, buf).is_ok()
}
process::print();
}
Loading…
Cancel
Save