From 1c80b95fe4d0cfd76b45c1cf5b3d2c901ba2d3e8 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Thu, 24 May 2018 00:25:27 +0800 Subject: [PATCH] Add IDE driver. No longer link img. --- Makefile | 4 +- src/arch/x86_64/driver/ide.rs | 317 ++++++++++++++++++++++++++++++++++ src/arch/x86_64/driver/mod.rs | 1 + src/fs.rs | 50 ++++-- 4 files changed, 356 insertions(+), 16 deletions(-) create mode 100644 src/arch/x86_64/driver/ide.rs diff --git a/Makefile b/Makefile index 6cd1215..836f35f 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/src/arch/x86_64/driver/ide.rs b/src/arch/x86_64/driver/ide.rs new file mode 100644 index 0000000..0ef0da7 --- /dev/null +++ b/src/arch/x86_64/driver/ide.rs @@ -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); + +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 { + 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 { + 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 { + //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 { + //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) \ No newline at end of file diff --git a/src/arch/x86_64/driver/mod.rs b/src/arch/x86_64/driver/mod.rs index decb194..42819d0 100644 --- a/src/arch/x86_64/driver/mod.rs +++ b/src/arch/x86_64/driver/mod.rs @@ -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!(); diff --git a/src/fs.rs b/src/fs.rs index 92ec3c2..27d897f 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -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(); } \ No newline at end of file