Debugging ATA
This commit is contained in:
parent
08597721f8
commit
eadab15759
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -6,6 +6,7 @@ version = 3
|
||||||
name = "KarxOS"
|
name = "KarxOS"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bit_field",
|
||||||
"bootloader",
|
"bootloader",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"linked_list_allocator",
|
"linked_list_allocator",
|
||||||
|
|
|
@ -12,6 +12,7 @@ x86_64 = "0.14.2"
|
||||||
pic8259 = "0.10.1"
|
pic8259 = "0.10.1"
|
||||||
pc-keyboard = "0.5.0"
|
pc-keyboard = "0.5.0"
|
||||||
linked_list_allocator = "0.9.0"
|
linked_list_allocator = "0.9.0"
|
||||||
|
bit_field = "0.10.0"
|
||||||
|
|
||||||
[dependencies.lazy_static]
|
[dependencies.lazy_static]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
|
|
170
src/ata.rs
170
src/ata.rs
|
@ -4,6 +4,8 @@ use core::hint::spin_loop;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use x86_64::instructions::port::{Port, PortReadOnly, PortWriteOnly};
|
use x86_64::instructions::port::{Port, PortReadOnly, PortWriteOnly};
|
||||||
|
use bit_field::BitField;
|
||||||
|
use crate::println;
|
||||||
|
|
||||||
// Commands to send to the drives
|
// Commands to send to the drives
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
|
@ -72,16 +74,174 @@ impl Bus {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
|
use crate::clock::nanowait;
|
||||||
|
unsafe {
|
||||||
|
self.control_register.write(4);
|
||||||
|
nanowait(5);
|
||||||
|
self.control_register.write(0);
|
||||||
|
nanowait(2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait(&mut self) {
|
||||||
|
for _ in 0..4 {
|
||||||
|
unsafe {
|
||||||
|
self.alternate_status_register.read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn select_drive(&mut self, drive: u8) {
|
||||||
|
let drive_id = 0xA0 | (drive << 4);
|
||||||
|
unsafe {
|
||||||
|
self.drive_register.write(drive_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_command(&mut self, cmd: Command) {
|
||||||
|
unsafe {
|
||||||
|
self.command_register.write(cmd as u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn status(&mut self) -> u8 {
|
||||||
|
unsafe {
|
||||||
|
self.status_register.read()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lba1(&mut self) -> u8 {
|
||||||
|
unsafe {
|
||||||
|
self.lba1_register.read()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lba2(&mut self) -> u8 {
|
||||||
|
unsafe {
|
||||||
|
self.lba2_register.read()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_data(&mut self) -> u16 {
|
||||||
|
unsafe { self.data_register.read() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn busy_loop(&mut self) {
|
||||||
|
self.wait();
|
||||||
|
let start = crate::clock::uptime();
|
||||||
|
while self.is_busy() {
|
||||||
|
if crate::clock::uptime() - start > 1.0 {
|
||||||
|
return self.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_loop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_busy(&mut self) -> bool {
|
||||||
|
self.status().get_bit(Status::BSY as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_error(&mut self) -> bool {
|
||||||
|
self.status().get_bit(Status::ERR as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ready(&mut self) -> bool {
|
||||||
|
self.status().get_bit(Status::RDY as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn identify_drive(&mut self, drive: u8) -> Option<[u16; 256]> {
|
||||||
|
self.reset();
|
||||||
|
self.wait();
|
||||||
|
self.select_drive(drive);
|
||||||
|
unsafe {
|
||||||
|
self.sector_count_register.write(0);
|
||||||
|
self.lba0_register.write(0);
|
||||||
|
self.lba1_register.write(0);
|
||||||
|
self.lba2_register.write(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.write_command(Command::Identify);
|
||||||
|
|
||||||
|
if self.status() == 0 {
|
||||||
|
println!("status 0");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.busy_loop();
|
||||||
|
|
||||||
|
if self.lba1() != 0 || self.lba2() != 0 {
|
||||||
|
println!("lba thingies");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0.. {
|
||||||
|
if i == 256 {
|
||||||
|
println!("i 256");
|
||||||
|
self.reset();
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if self.is_error() {
|
||||||
|
println!("Is error");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if self.is_ready() {
|
||||||
|
println!("ready");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut res = [0; 256];
|
||||||
|
for i in 0..256 {
|
||||||
|
res[i] = self.read_data();
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(res)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref BUSES: Mutex<Vec<Bus>> = Mutex::new(Vec::new());
|
pub static ref BUS: Mutex<Bus> = Mutex::new(Bus::new(0, 0x170, 0x376, 15));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
fn disk_size(sectors: u32) -> (u32, String) {
|
||||||
let mut buses = BUSES.lock();
|
let bytes = sectors * 512;
|
||||||
buses.push(Bus::new(0, 0x1f0, 0x3f6, 14));
|
if bytes >> 20 < 1000 {
|
||||||
buses.push(Bus::new(1, 0x170, 0x376, 15));
|
(bytes >> 20, String::from("MB"))
|
||||||
|
} else {
|
||||||
|
(bytes >> 30, String::from("GB"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn info() -> Vec<(u8, String, String, u32, String)> {
|
||||||
|
let mut bus = BUS.lock();
|
||||||
|
let mut res = Vec::new();
|
||||||
|
for drive in 0..2 {
|
||||||
|
if let Some(buf) = bus.identify_drive(drive) {
|
||||||
|
let mut serial = String::new();
|
||||||
|
for i in 10..20 {
|
||||||
|
for &b in &buf[i].to_be_bytes() {
|
||||||
|
serial.push(b as char);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serial = serial.trim().into();
|
||||||
|
let mut model = String::new();
|
||||||
|
for i in 27..47 {
|
||||||
|
for &b in &buf[i].to_be_bytes() {
|
||||||
|
model.push(b as char);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model = model.trim().into();
|
||||||
|
let sectors = (buf[61] as u32) << 16 | (buf[60] as u32);
|
||||||
|
let (size, unit) = disk_size(sectors);
|
||||||
|
res.push((drive, model, serial, size, unit));
|
||||||
|
} else {
|
||||||
|
println!("No drive found!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
|
use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
|
||||||
|
use core::hint::spin_loop;
|
||||||
use x86_64::instructions::port::Port;
|
use x86_64::instructions::port::Port;
|
||||||
|
|
||||||
static CLOCKS_PER_NANOSECOND: AtomicU64 = AtomicU64::new(0);
|
static CLOCKS_PER_NANOSECOND: AtomicU64 = AtomicU64::new(0);
|
||||||
|
@ -46,6 +47,14 @@ pub fn sleep(seconds: f64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn nanowait(nanoseconds: u64) {
|
||||||
|
let start = rdtsc();
|
||||||
|
let delta = nanoseconds * CLOCKS_PER_NANOSECOND.load(Ordering::Relaxed);
|
||||||
|
while rdtsc() - start < delta {
|
||||||
|
spin_loop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pit_interrupt_handler() {
|
pub fn pit_interrupt_handler() {
|
||||||
PIT_TICKS.fetch_add(1, Ordering::Relaxed);
|
PIT_TICKS.fetch_add(1, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ lazy_static! {
|
||||||
.set_handler_fn(double_fault_handler)
|
.set_handler_fn(double_fault_handler)
|
||||||
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
|
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
|
||||||
}
|
}
|
||||||
|
idt.page_fault.set_handler_fn(page_fault_handler);
|
||||||
idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler);
|
idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler);
|
||||||
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
|
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
|
||||||
idt
|
idt
|
||||||
|
@ -37,6 +38,16 @@ extern "x86-interrupt" fn double_fault_handler(
|
||||||
) -> ! {
|
) -> ! {
|
||||||
panic!("EXCEPTION : DOUBLE FAULT\n{:#?}", stack_frame);
|
panic!("EXCEPTION : DOUBLE FAULT\n{:#?}", stack_frame);
|
||||||
}
|
}
|
||||||
|
extern "x86-interrupt" fn page_fault_handler(
|
||||||
|
stack_frame: InterruptStackFrame,
|
||||||
|
error_code: x86_64::structures::idt::PageFaultErrorCode,
|
||||||
|
) {
|
||||||
|
println!("EXCEPTION : PAGE FAULT");
|
||||||
|
println!("Accessed Address: {:?}", x86_64::registers::control::Cr2::read());
|
||||||
|
println!("Error Code: {:?}", error_code);
|
||||||
|
println!("{:#?}", stack_frame);
|
||||||
|
x86_64::instructions::interrupts::enable_and_hlt();
|
||||||
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||||
crate::clock::pit_interrupt_handler();
|
crate::clock::pit_interrupt_handler();
|
||||||
|
|
13
src/main.rs
13
src/main.rs
|
@ -17,6 +17,7 @@ mod shell;
|
||||||
mod vga_buffer;
|
mod vga_buffer;
|
||||||
|
|
||||||
use bootloader::BootInfo;
|
use bootloader::BootInfo;
|
||||||
|
use bootloader::entry_point;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
@ -35,6 +36,10 @@ fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
|
||||||
fn init() {
|
fn init() {
|
||||||
gdt::init_gdt();
|
gdt::init_gdt();
|
||||||
interrupts::init();
|
interrupts::init();
|
||||||
|
unsafe {
|
||||||
|
interrupts::PICS.lock().initialize();
|
||||||
|
}
|
||||||
|
x86_64::instructions::interrupts::enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! status {
|
macro_rules! status {
|
||||||
|
@ -47,8 +52,9 @@ macro_rules! status {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
entry_point!(main);
|
||||||
pub extern "C" fn _start(boot_info: &'static BootInfo) {
|
|
||||||
|
fn main(boot_info: &'static BootInfo) -> ! {
|
||||||
use memory::BootInfoFrameAllocator;
|
use memory::BootInfoFrameAllocator;
|
||||||
use x86_64::VirtAddr;
|
use x86_64::VirtAddr;
|
||||||
use crate::vga_buffer::{change_color, Color}; // For status! macro
|
use crate::vga_buffer::{change_color, Color}; // For status! macro
|
||||||
|
@ -68,7 +74,8 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) {
|
||||||
status!("Initialized heap");
|
status!("Initialized heap");
|
||||||
|
|
||||||
// Must be initialized AFTER the heap!
|
// Must be initialized AFTER the heap!
|
||||||
ata::init();
|
println!("{:#?}", ata::info());
|
||||||
|
println!("{:#?}", ata::info());
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
print!("Welcome to ");
|
print!("Welcome to ");
|
||||||
|
|
Loading…
Reference in a new issue