mirror of
https://github.com/rcore-os/rCore.git
synced 2025-01-18 17:07:04 +04:00
Add IDE back for mips, remove mipssim
This commit is contained in:
parent
100db70184
commit
a16a9e238b
2
kernel/Cargo.lock
generated
2
kernel/Cargo.lock
generated
@ -709,7 +709,7 @@ checksum = "3a385d94f3f62e60445a0adb9ff8d9621faa272234530d4c0f848ec98f88e316"
|
||||
[[package]]
|
||||
name = "trapframe"
|
||||
version = "0.4.3"
|
||||
source = "git+https://github.com/rcore-os/trapframe-rs?rev=063a844#063a844654aaf37af2ef2afac305b4b025407441"
|
||||
source = "git+https://github.com/rcore-os/trapframe-rs?rev=e58d975#e58d9755f181de24431b5ff9437f396ac71e8429"
|
||||
dependencies = [
|
||||
"raw-cpuid",
|
||||
"x86_64",
|
||||
|
@ -27,8 +27,7 @@ nographic = []
|
||||
consolegraphic = []
|
||||
board_raspi3 = ["bcm2837"]
|
||||
# for qemu machine
|
||||
board_malta = ["link_user"]
|
||||
board_mipssim = ["link_user"]
|
||||
board_malta = []
|
||||
# for x86 PC
|
||||
board_pc = ["link_user"]
|
||||
# Hard link user program
|
||||
@ -70,7 +69,7 @@ rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "517af47"
|
||||
rlibc = "1.0"
|
||||
smoltcp = { git = "https://github.com/rcore-os/smoltcp", rev = "5bd87c7c", default-features = false, features = ["alloc", "log", "ethernet", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
|
||||
spin = "0.5"
|
||||
trapframe = { git = "https://github.com/rcore-os/trapframe-rs", rev = "063a844" }
|
||||
trapframe = { git = "https://github.com/rcore-os/trapframe-rs", rev = "e58d975" }
|
||||
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "dfa70e14" }
|
||||
volatile = "0.2"
|
||||
woke = "0.0.2"
|
||||
|
@ -65,11 +65,6 @@ ifeq ($(ARCH), mipsel)
|
||||
DTB := src/arch/$(ARCH)/board/$(BOARD)/device.dtb
|
||||
endif
|
||||
|
||||
# mipssim does not support SMP
|
||||
ifeq ($(BOARD), mipssim)
|
||||
SMP := 1
|
||||
endif
|
||||
|
||||
### qemu options ###
|
||||
qemu_opts := \
|
||||
-smp cores=$(SMP)
|
||||
@ -157,15 +152,10 @@ else ifeq ($(ARCH), mipsel)
|
||||
ifeq ($(BOARD), malta)
|
||||
qemu_opts += \
|
||||
-machine $(BOARD) -device VGA \
|
||||
-hda $(USER_QCOW2) \
|
||||
-serial null -serial null -serial mon:stdio \
|
||||
-kernel $(kernel_img)
|
||||
endif
|
||||
ifeq ($(BOARD), mipssim)
|
||||
qemu_opts += \
|
||||
-machine $(BOARD) \
|
||||
-serial mon:stdio \
|
||||
-kernel $(kernel_img)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef D
|
||||
@ -302,7 +292,7 @@ ifeq ($(ARCH), $(filter $(ARCH), riscv32 riscv64))
|
||||
$(sysroot)/lib/rustlib/src/rust/src/libcore/sync/atomic.rs \
|
||||
src/arch/riscv/atomic.patch
|
||||
else ifeq ($(ARCH), mipsel)
|
||||
@for file in context entry trap ; do \
|
||||
@for file in entry ; do \
|
||||
$(hostcc) -Dboard_$(BOARD) -E src/arch/$(ARCH)/boot/$${file}.S -o src/arch/$(ARCH)/boot/$${file}.gen.s ; \
|
||||
done
|
||||
$(hostcc) -Dboard_$(BOARD) -E src/arch/$(ARCH)/boot/linker.ld.S -o src/arch/$(ARCH)/boot/linker.ld
|
||||
|
@ -1,3 +1,3 @@
|
||||
/// board specific constants
|
||||
pub const MEMORY_END: usize = 0x8400_0000;
|
||||
pub const MEMORY_END: usize = 0x8800_0000;
|
||||
pub const KERNEL_HEAP_SIZE: usize = 0x0200_0000;
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::drivers::block::ide;
|
||||
use crate::drivers::bus::pci;
|
||||
use crate::drivers::gpu::fb::{self, FramebufferInfo};
|
||||
use mips::registers::cp0;
|
||||
@ -42,4 +43,5 @@ pub fn init_driver() {
|
||||
screen_size: 800 * 600,
|
||||
};
|
||||
fb::init(fb_info);
|
||||
ide::init();
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
/// board specific constants
|
||||
pub const MEMORY_END: usize = 0x8800_0000;
|
||||
pub const KERNEL_HEAP_SIZE: usize = 0x00a0_0000;
|
@ -1,36 +0,0 @@
|
||||
/dts-v1/;
|
||||
|
||||
|
||||
/ {
|
||||
model = "qemu mipssim";
|
||||
compatible = "qemu,mipssim";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
chosen {
|
||||
stdio = &uart0;
|
||||
};
|
||||
|
||||
aliases { };
|
||||
|
||||
cpu_intc: interrupt-controller {
|
||||
compatible = "mti,cpu-interrupt-controller";
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
};
|
||||
|
||||
main_memory: memory@0 {
|
||||
device_type = "memory";
|
||||
reg = <0x00000000 0x10000000>;
|
||||
};
|
||||
|
||||
uart0: serial@bfd003f8 {
|
||||
compatible = "ns16550a";
|
||||
reg = <0xbfd003f8 0x8>;
|
||||
clock-frequency = <1843200>;
|
||||
/* attached to the MIPS CPU INT2 pin, ie interrupt 4 */
|
||||
interrupt-parent = <&cpu_intc>;
|
||||
interrupts = <4>;
|
||||
};
|
||||
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
pub mod consts;
|
||||
#[path = "../../../../drivers/serial/uart16550.rs"]
|
||||
pub mod serial;
|
||||
|
||||
/// Device tree bytes
|
||||
pub static DTB: &'static [u8] = include_bytes!("device.dtb");
|
||||
|
||||
/// Initialize serial port first
|
||||
pub fn init_serial_early() {
|
||||
serial::init(0xbfd003f8);
|
||||
println!("Hello QEMU MIPSSIM!");
|
||||
}
|
||||
|
||||
/// Initialize other board drivers
|
||||
pub fn init_driver() {
|
||||
// TODO: add possibly more drivers
|
||||
// timer::init();
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
#include "regdef.h"
|
||||
|
||||
.set noat
|
||||
.set noreorder
|
||||
|
||||
.section .text.context
|
||||
.globl switch_context
|
||||
.extern _root_page_table_ptr
|
||||
.extern _cur_kstack_ptr
|
||||
.extern _cur_tls
|
||||
|
||||
switch_context:
|
||||
// save from's registers
|
||||
addi sp, sp, (-4*16)
|
||||
sw sp, 0(a0)
|
||||
sw ra, 0(sp)
|
||||
sw s0, 4*4(sp)
|
||||
sw s1, 5*4(sp)
|
||||
sw s2, 6*4(sp)
|
||||
sw s3, 7*4(sp)
|
||||
sw s4, 8*4(sp)
|
||||
sw s5, 9*4(sp)
|
||||
sw s6, 10*4(sp)
|
||||
sw s7, 11*4(sp)
|
||||
sw s8, 12*4(sp)
|
||||
sw gp, 13*4(sp)
|
||||
// sw ra, 12*4(sp)
|
||||
// sw sp, 13*4(sp)
|
||||
|
||||
// save page table address
|
||||
la s0, _root_page_table_ptr
|
||||
lw s1, 0(s0)
|
||||
sw s1, 4(sp)
|
||||
|
||||
// save TLS
|
||||
la s2, _cur_tls
|
||||
lw s1, 0(s2)
|
||||
sw s1, 2*4(sp)
|
||||
|
||||
// restore to's registers
|
||||
lw sp, 0(a1)
|
||||
|
||||
// restore page table address
|
||||
lw s1, 4(sp)
|
||||
sw s1, 0(s0)
|
||||
|
||||
// restore TLS
|
||||
lw s1, 2*4(sp)
|
||||
sw s1, 0(s2)
|
||||
mtc0 s1, $4, 2 // cp0.user_local
|
||||
|
||||
lw ra, 0(sp)
|
||||
lw s0, 4*4(sp)
|
||||
lw s1, 5*4(sp)
|
||||
lw s2, 6*4(sp)
|
||||
lw s3, 7*4(sp)
|
||||
lw s4, 8*4(sp)
|
||||
lw s5, 9*4(sp)
|
||||
lw s6, 10*4(sp)
|
||||
lw s7, 11*4(sp)
|
||||
lw s8, 12*4(sp)
|
||||
lw gp, 13*4(sp)
|
||||
addi sp, sp, (4*16)
|
||||
|
||||
sw zero, 0(a1)
|
||||
jr ra
|
||||
nop
|
@ -38,3 +38,14 @@ bootstack:
|
||||
.space 4096 * 16 * 8
|
||||
.global bootstacktop
|
||||
bootstacktop:
|
||||
|
||||
.align 12 #PGSHIFT
|
||||
.global _root_page_table_buffer
|
||||
_root_page_table_buffer:
|
||||
.space 1024 * 64 # 64KB
|
||||
.global _root_page_table_ptr
|
||||
_root_page_table_ptr:
|
||||
.space 4 # 4bytes
|
||||
.global _cur_tls
|
||||
_cur_tls:
|
||||
.space 4 # 4bytes
|
||||
|
@ -1,199 +0,0 @@
|
||||
#include "regdef.h"
|
||||
|
||||
.set noat
|
||||
.set noreorder
|
||||
.section .text.ebase
|
||||
.globl trap_entry
|
||||
|
||||
.org 0x0
|
||||
trap_entry:
|
||||
# +0x000: TLB-miss vector
|
||||
b general_trap_vec
|
||||
|
||||
# +0x180: general vector
|
||||
.org 0x180
|
||||
general_trap_vec:
|
||||
move k1, sp # save stack pointer to k1
|
||||
mfc0 k0, $12 # read cp0.status
|
||||
andi k0, k0, 0x10 # extract cp0.status.ksu
|
||||
beq k0, zero, trap_from_kernel
|
||||
nop # delayslot
|
||||
|
||||
trap_from_user:
|
||||
# load kstack, we can use k0 to store something
|
||||
# la k0, kernel_stack
|
||||
# la sp, kernel_stack_top
|
||||
la k0, _cur_kstack_ptr
|
||||
lw sp, 0(k0)
|
||||
|
||||
trap_from_kernel:
|
||||
/*
|
||||
* k0 is damaged
|
||||
* k1 = old stack pointer
|
||||
* sp = kernel stack */
|
||||
|
||||
#define TRAPFRAME_SIZE 176
|
||||
|
||||
# align stack pointer
|
||||
andi k0, sp, 0xf
|
||||
beqz k0, sp_aligned
|
||||
nop
|
||||
|
||||
la k0, 0xfffffff0
|
||||
and k0, sp, k0
|
||||
sw sp, -TRAPFRAME_SIZE(k0)
|
||||
move sp, k0
|
||||
|
||||
sp_aligned:
|
||||
# allocate 38 / 70 words for trapframe + 6 extra words
|
||||
|
||||
addiu sp, sp, -TRAPFRAME_SIZE
|
||||
|
||||
# save general registers
|
||||
sw ra, 160(sp)
|
||||
sw fp, 156(sp)
|
||||
sw k1, 152(sp) # k1 = old sp
|
||||
sw gp, 148(sp)
|
||||
sw k1, 144(sp) # real k1 is damaged
|
||||
sw k0, 140(sp) # real k0 is damaged
|
||||
sw t9, 136(sp)
|
||||
sw t8, 132(sp)
|
||||
sw s7, 128(sp)
|
||||
sw s6, 124(sp)
|
||||
sw s5, 120(sp)
|
||||
sw s4, 116(sp)
|
||||
sw s3, 112(sp)
|
||||
sw s2, 108(sp)
|
||||
sw s1, 104(sp)
|
||||
sw s0, 100(sp)
|
||||
sw t7, 96(sp)
|
||||
sw t6, 92(sp)
|
||||
sw t5, 88(sp)
|
||||
sw t4, 84(sp)
|
||||
sw t3, 80(sp)
|
||||
sw t2, 76(sp)
|
||||
sw t1, 72(sp)
|
||||
sw t0, 68(sp)
|
||||
sw a3, 64(sp)
|
||||
sw a2, 60(sp)
|
||||
sw a1, 56(sp)
|
||||
sw a0, 52(sp)
|
||||
sw v1, 48(sp)
|
||||
sw v0, 44(sp)
|
||||
sw AT, 40(sp)
|
||||
nop
|
||||
|
||||
# save hi/lo
|
||||
mflo t1
|
||||
sw t1, 36(sp)
|
||||
mfhi t0
|
||||
sw t0, 32(sp)
|
||||
|
||||
# save special registers
|
||||
mfc0 t0, $8 # cp0.vaddr
|
||||
sw t0, 28(sp)
|
||||
|
||||
mfc0 t1, $14 # cp0.epc
|
||||
sw t1, 24(sp)
|
||||
|
||||
mfc0 t0, $13 # cp0.cause
|
||||
sw t0, 20(sp)
|
||||
|
||||
mfc0 t1, $12 # cp0.status
|
||||
sw t1, 16(sp)
|
||||
|
||||
# support nested interrupt
|
||||
la t0, ~0x1b # reset status.ksu, status.exl, status.ie
|
||||
and t1, t1, t0
|
||||
mtc0 t1, $12 # cp0.status
|
||||
|
||||
# prepare to call rust_trap
|
||||
ori a0, sp, 0 /* set argument (trapframe) */
|
||||
jal rust_trap
|
||||
nop
|
||||
|
||||
.globl trap_return
|
||||
trap_return:
|
||||
# restore special registers
|
||||
lw t1, 16(sp)
|
||||
ori t1, t1, 0x2 # status.exl
|
||||
nop
|
||||
mtc0 t1, $12 # cp0.status
|
||||
|
||||
lw k0, 24(sp)
|
||||
mtc0 k0, $14 # cp0.epc
|
||||
|
||||
lw t0, 32(sp)
|
||||
mthi t0
|
||||
lw t1, 36(sp)
|
||||
mtlo t1
|
||||
|
||||
# restore general registers
|
||||
lw AT, 40(sp)
|
||||
lw v0, 44(sp)
|
||||
lw v1, 48(sp)
|
||||
lw a0, 52(sp)
|
||||
lw a1, 56(sp)
|
||||
lw a2, 60(sp)
|
||||
lw a3, 64(sp)
|
||||
lw t0, 68(sp)
|
||||
lw t1, 72(sp)
|
||||
lw t2, 76(sp)
|
||||
lw t3, 80(sp)
|
||||
lw t4, 84(sp)
|
||||
lw t5, 88(sp)
|
||||
lw t6, 92(sp)
|
||||
lw t7, 96(sp)
|
||||
lw s0, 100(sp)
|
||||
lw s1, 104(sp)
|
||||
lw s2, 108(sp)
|
||||
lw s3, 112(sp)
|
||||
lw s4, 116(sp)
|
||||
lw s5, 120(sp)
|
||||
lw s6, 124(sp)
|
||||
lw s7, 128(sp)
|
||||
lw t8, 132(sp)
|
||||
lw t9, 136(sp)
|
||||
|
||||
# lw k0, 140(sp)
|
||||
# lw k1, 144(sp)
|
||||
lw gp, 148(sp)
|
||||
lw fp, 156(sp)
|
||||
lw ra, 160(sp)
|
||||
|
||||
# save kernel stack
|
||||
lw k0, 0(sp)
|
||||
addiu k1, sp, TRAPFRAME_SIZE
|
||||
movn k1, k0, k0
|
||||
|
||||
la k0, _cur_kstack_ptr
|
||||
sw k1, 0(k0)
|
||||
nop
|
||||
|
||||
// restore stack
|
||||
lw sp, 152(sp)
|
||||
|
||||
eret
|
||||
nop
|
||||
|
||||
.section .bss.stack
|
||||
.align 12 #PGSHIFT
|
||||
.global kernel_stack
|
||||
kernel_stack:
|
||||
.space 1024 * 16 # 16KB for kernel stack
|
||||
.global kernel_stack_top
|
||||
kernel_stack_top:
|
||||
|
||||
.align 12 #PGSHIFT
|
||||
.global _root_page_table_buffer
|
||||
_root_page_table_buffer:
|
||||
.space 1024 * 64 # 64KB
|
||||
.global _root_page_table_ptr
|
||||
_root_page_table_ptr:
|
||||
.space 4 # 4bytes
|
||||
.global _cur_kstack_ptr
|
||||
_cur_kstack_ptr:
|
||||
.space 4 # 4bytes
|
||||
.global _cur_tls
|
||||
_cur_tls:
|
||||
.space 4 # 4bytes
|
@ -37,6 +37,7 @@ fn init_frame_allocator() {
|
||||
|
||||
/// Transform memory area `[start, end)` to integer range for `FrameAllocator`
|
||||
fn to_range(start: usize, end: usize) -> Range<usize> {
|
||||
info!("frame allocator: start {:#x} end {:#x}", start, end);
|
||||
let page_start = (start - MEMORY_OFFSET) / PAGE_SIZE;
|
||||
let page_end = (end - MEMORY_OFFSET - 1) / PAGE_SIZE + 1;
|
||||
assert!(page_start < page_end, "illegal range for frame allocator");
|
||||
|
@ -17,10 +17,6 @@ use mips::registers::cp0;
|
||||
#[path = "board/malta/mod.rs"]
|
||||
pub mod board;
|
||||
|
||||
#[cfg(feature = "board_mipssim")]
|
||||
#[path = "board/mipssim/mod.rs"]
|
||||
pub mod board;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_main() -> ! {
|
||||
// unsafe { cpu::set_cpu_id(hartid); }
|
||||
@ -70,6 +66,4 @@ fn others_main() -> ! {
|
||||
|
||||
const BOOT_CPU_ID: u32 = 0;
|
||||
|
||||
global_asm!(include_str!("boot/context.gen.s"));
|
||||
global_asm!(include_str!("boot/entry.gen.s"));
|
||||
global_asm!(include_str!("boot/trap.gen.s"));
|
||||
|
252
kernel/src/drivers/block/ide.rs
Normal file
252
kernel/src/drivers/block/ide.rs
Normal file
@ -0,0 +1,252 @@
|
||||
//! ATA IO code, handling device multiplexing and IO operations
|
||||
//!
|
||||
//! Borrow from Rucore project. Thanks GWord!
|
||||
//! Port from ucore C code.
|
||||
//! Currently used in MIPS
|
||||
|
||||
use crate::drivers::{block::BlockDriver, DeviceType, Driver};
|
||||
use crate::drivers::{BLK_DRIVERS, DRIVERS};
|
||||
use crate::sync::SpinNoIrqLock as Mutex;
|
||||
use alloc::string::String;
|
||||
use alloc::sync::Arc;
|
||||
use core::slice;
|
||||
|
||||
pub const BLOCK_SIZE: usize = 512;
|
||||
|
||||
pub struct IDE {
|
||||
num: u8,
|
||||
/// I/O Base
|
||||
base: u16,
|
||||
/// Control Base
|
||||
ctrl: u16,
|
||||
}
|
||||
|
||||
pub struct IDEDriver(Mutex<IDE>);
|
||||
|
||||
impl Driver for IDEDriver {
|
||||
fn try_handle_interrupt(&self, _irq: Option<usize>) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn device_type(&self) -> DeviceType {
|
||||
DeviceType::Block
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
format!("ide")
|
||||
}
|
||||
|
||||
fn as_block(&self) -> Option<&dyn BlockDriver> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockDriver for IDEDriver {
|
||||
fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool {
|
||||
let mut driver = self.0.lock();
|
||||
let buf = unsafe { slice::from_raw_parts_mut(buf.as_ptr() as *mut u32, BLOCK_SIZE / 4) };
|
||||
driver.read(block_id as u64, 1, buf).is_ok()
|
||||
}
|
||||
|
||||
fn write_block(&self, block_id: usize, buf: &[u8]) -> bool {
|
||||
if buf.len() < BLOCK_SIZE {
|
||||
return false;
|
||||
}
|
||||
let mut driver = self.0.lock();
|
||||
let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *mut u32, BLOCK_SIZE / 4) };
|
||||
driver.write(block_id as u64, 1, buf).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl IDE {
|
||||
pub fn new(num: u8) -> Self {
|
||||
let ide = match num {
|
||||
0 => IDE {
|
||||
num: 0,
|
||||
base: 0x1f0,
|
||||
ctrl: 0x3f4,
|
||||
},
|
||||
1 => IDE {
|
||||
num: 1,
|
||||
base: 0x1f0,
|
||||
ctrl: 0x3f4,
|
||||
},
|
||||
2 => IDE {
|
||||
num: 2,
|
||||
base: 0x170,
|
||||
ctrl: 0x374,
|
||||
},
|
||||
3 => IDE {
|
||||
num: 3,
|
||||
base: 0x170,
|
||||
ctrl: 0x374,
|
||||
},
|
||||
_ => panic!("ide number should be 0,1,2,3"),
|
||||
};
|
||||
ide.init();
|
||||
ide
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
self.select(sector, count as u8);
|
||||
port::outb(self.base + ISA_COMMAND, IDE_CMD_READ);
|
||||
for i in 0..count {
|
||||
let ptr = &mut data[(i as usize) * SECTOR_SIZE];
|
||||
if self.wait_error() {
|
||||
return Err(());
|
||||
}
|
||||
insl(self.base, ptr, SECTOR_SIZE);
|
||||
}
|
||||
}
|
||||
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(());
|
||||
}
|
||||
outsl(self.base, ptr, SECTOR_SIZE);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn wait(&self) {
|
||||
while unsafe { port::inb(self.base + ISA_STATUS) } & IDE_BUSY != 0 {}
|
||||
}
|
||||
|
||||
fn wait_error(&self) -> bool {
|
||||
self.wait();
|
||||
let status = unsafe { port::inb(self.base + ISA_STATUS) };
|
||||
status & (IDE_DF | IDE_ERR) != 0
|
||||
}
|
||||
|
||||
fn init(&self) {
|
||||
self.wait();
|
||||
unsafe {
|
||||
// step1: select drive
|
||||
port::outb(self.base + ISA_SDH, (0xE0 | ((self.num & 1) << 4)) as u8);
|
||||
self.wait();
|
||||
|
||||
// step2: send ATA identify command
|
||||
port::outb(self.base + ISA_COMMAND, IDE_CMD_IDENTIFY);
|
||||
self.wait();
|
||||
|
||||
// step3: polling
|
||||
if port::inb(self.base + ISA_STATUS) == 0 || self.wait_error() {
|
||||
return;
|
||||
}
|
||||
|
||||
// ???
|
||||
let mut data = [0; SECTOR_SIZE];
|
||||
insl(self.base + ISA_DATA, data.as_mut_ptr(), SECTOR_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
fn select(&self, sector: u64, count: u8) {
|
||||
assert_ne!(count, 0);
|
||||
self.wait();
|
||||
unsafe {
|
||||
// generate interrupt
|
||||
port::outb(self.ctrl + ISA_CTRL, 0);
|
||||
port::outb(self.base + ISA_SECCNT, count);
|
||||
port::outb(self.base + ISA_SECTOR, (sector & 0xFF) as u8);
|
||||
port::outb(self.base + ISA_CYL_LO, ((sector >> 8) & 0xFF) as u8);
|
||||
port::outb(self.base + ISA_CYL_HI, ((sector >> 16) & 0xFF) as u8);
|
||||
port::outb(
|
||||
self.base + ISA_SDH,
|
||||
0xE0 | ((self.num & 1) << 4) | (((sector >> 24) & 0xF) as u8),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const SECTOR_SIZE: usize = 128;
|
||||
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 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_BUSY: 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 MAX_NSECS: usize = 128;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
unsafe fn insl(addr: u16, data: *mut u32, len: usize) {
|
||||
llvm_asm!("rep insl" :: "{dx}"(addr), "{rdi}"(data), "{cx}"(SECTOR_SIZE) : "rdi" : "volatile");
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
unsafe fn insl(addr: u16, data: *mut u32, len: usize) {
|
||||
for i in 0..len {
|
||||
*data.add(i) = port::inl(addr);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
unsafe fn outsl(addr: u16, data: *const u32, len: usize) {
|
||||
llvm_asm!("rep insl" :: "{dx}"(addr), "{rdi}"(data), "{cx}"(SECTOR_SIZE) : "rdi" : "volatile");
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
unsafe fn outsl(addr: u16, data: *const u32, len: usize) {
|
||||
for i in 0..len {
|
||||
port::outl(addr, *data.add(i));
|
||||
}
|
||||
}
|
||||
|
||||
// MIPS
|
||||
mod port {
|
||||
const PCI_BASE: usize = 0xb8000000;
|
||||
pub unsafe fn inb(port: u16) -> u8 {
|
||||
crate::util::read(port as usize + PCI_BASE)
|
||||
}
|
||||
|
||||
pub unsafe fn outb(port: u16, value: u8) {
|
||||
crate::util::write(port as usize + PCI_BASE, value)
|
||||
}
|
||||
|
||||
pub unsafe fn inl(port: u16) -> u32 {
|
||||
crate::util::read(port as usize + PCI_BASE)
|
||||
}
|
||||
|
||||
pub unsafe fn outl(port: u16, value: u32) {
|
||||
crate::util::write(port as usize + PCI_BASE, value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
let ide = IDE::new(0);
|
||||
let driver = Arc::new(IDEDriver(Mutex::new(ide)));
|
||||
DRIVERS.write().push(driver.clone());
|
||||
BLK_DRIVERS.write().push(driver.clone());
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
use super::Driver;
|
||||
|
||||
pub mod ahci;
|
||||
pub mod ide;
|
||||
pub mod virtio_blk;
|
||||
|
||||
pub trait BlockDriver: Driver {
|
||||
|
Loading…
Reference in New Issue
Block a user