Debugging ATA

This commit is contained in:
Yash Karandikar 2021-09-26 13:14:30 -05:00
parent 08597721f8
commit eadab15759
6 changed files with 197 additions and 8 deletions

1
Cargo.lock generated
View file

@ -6,6 +6,7 @@ version = 3
name = "KarxOS"
version = "0.1.0"
dependencies = [
"bit_field",
"bootloader",
"lazy_static",
"linked_list_allocator",

View file

@ -12,6 +12,7 @@ x86_64 = "0.14.2"
pic8259 = "0.10.1"
pc-keyboard = "0.5.0"
linked_list_allocator = "0.9.0"
bit_field = "0.10.0"
[dependencies.lazy_static]
version = "1.0"

View file

@ -4,6 +4,8 @@ use core::hint::spin_loop;
use lazy_static::lazy_static;
use spin::Mutex;
use x86_64::instructions::port::{Port, PortReadOnly, PortWriteOnly};
use bit_field::BitField;
use crate::println;
// Commands to send to the drives
#[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! {
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() {
let mut buses = BUSES.lock();
buses.push(Bus::new(0, 0x1f0, 0x3f6, 14));
buses.push(Bus::new(1, 0x170, 0x376, 15));
fn disk_size(sectors: u32) -> (u32, String) {
let bytes = sectors * 512;
if bytes >> 20 < 1000 {
(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
}

View file

@ -1,4 +1,5 @@
use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
use core::hint::spin_loop;
use x86_64::instructions::port::Port;
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() {
PIT_TICKS.fetch_add(1, Ordering::Relaxed);
}

View file

@ -15,6 +15,7 @@ lazy_static! {
.set_handler_fn(double_fault_handler)
.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::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
idt
@ -37,6 +38,16 @@ extern "x86-interrupt" fn double_fault_handler(
) -> ! {
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) {
crate::clock::pit_interrupt_handler();

View file

@ -17,6 +17,7 @@ mod shell;
mod vga_buffer;
use bootloader::BootInfo;
use bootloader::entry_point;
use core::panic::PanicInfo;
extern crate alloc;
@ -35,6 +36,10 @@ fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
fn init() {
gdt::init_gdt();
interrupts::init();
unsafe {
interrupts::PICS.lock().initialize();
}
x86_64::instructions::interrupts::enable();
}
macro_rules! status {
@ -47,8 +52,9 @@ macro_rules! status {
}
}
#[no_mangle]
pub extern "C" fn _start(boot_info: &'static BootInfo) {
entry_point!(main);
fn main(boot_info: &'static BootInfo) -> ! {
use memory::BootInfoFrameAllocator;
use x86_64::VirtAddr;
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");
// Must be initialized AFTER the heap!
ata::init();
println!("{:#?}", ata::info());
println!("{:#?}", ata::info());
println!();
print!("Welcome to ");