#![no_std]
extern crate alloc;
use alloc::string::String;
use alloc::vec::Vec;
use bit_field::BitField;
use core::hint::spin_loop;
use lazy_static::lazy_static;
use spin::Mutex;
use x86_64::instructions::port::{Port, PortReadOnly, PortWriteOnly};
pub type BlockIndex = u32;
pub const ATA_BLOCK_SIZE: usize = 512;
fn sleep_ticks(ticks: usize) {
for _ in 0..=ticks {
x86_64::instructions::hlt();
}
}
#[repr(u16)]
enum Command {
Read = 0x20,
Write = 0x30,
Identify = 0xEC,
}
#[allow(dead_code)]
#[repr(usize)]
enum Status {
ERR = 0,
IDX = 1,
CORR = 2,
DRQ = 3,
SRV = 4,
DF = 5,
RDY = 6,
BSY = 7,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Bus {
id: u8,
irq: u8,
data_register: Port<u16>,
error_register: PortReadOnly<u8>,
features_register: PortWriteOnly<u8>,
sector_count_register: Port<u8>,
lba0_register: Port<u8>,
lba1_register: Port<u8>,
lba2_register: Port<u8>,
drive_register: Port<u8>,
status_register: PortReadOnly<u8>,
command_register: PortWriteOnly<u8>,
alternate_status_register: PortReadOnly<u8>,
control_register: PortWriteOnly<u8>,
drive_blockess_register: PortReadOnly<u8>,
}
impl Bus {
pub fn new(id: u8, io_base: u16, ctrl_base: u16, irq: u8) -> Self {
Self {
id, irq,
data_register: Port::new(io_base + 0),
error_register: PortReadOnly::new(io_base + 1),
features_register: PortWriteOnly::new(io_base + 1),
sector_count_register: Port::new(io_base + 2),
lba0_register: Port::new(io_base + 3),
lba1_register: Port::new(io_base + 4),
lba2_register: Port::new(io_base + 5),
drive_register: Port::new(io_base + 6),
status_register: PortReadOnly::new(io_base + 7),
command_register: PortWriteOnly::new(io_base + 7),
alternate_status_register: PortReadOnly::new(ctrl_base + 0),
control_register: PortWriteOnly::new(ctrl_base + 0),
drive_blockess_register: PortReadOnly::new(ctrl_base + 1),
}
}
fn reset(&mut self) {
unsafe {
self.control_register.write(4); sleep_ticks(2);
self.control_register.write(0); sleep_ticks(2);
}
}
fn wait(&mut self) {
for _ in 0..4 { unsafe { self.alternate_status_register.read(); }
}
}
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 write_data(&mut self, data: u16) {
unsafe { self.data_register.write(data) }
}
fn busy_loop(&mut self) {
self.wait();
let start = 0;
while self.is_busy() {
if 0 - start > 1 { 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)
}
fn select_drive(&mut self, drive: u8) {
let drive_id = 0xA0 | (drive << 4);
unsafe {
self.drive_register.write(drive_id);
}
}
fn setup(&mut self, drive: u8, block: u32) {
let drive_id = 0xE0 | (drive << 4);
unsafe {
self.drive_register.write(drive_id | ((block.get_bits(24..28) as u8) & 0x0F));
self.sector_count_register.write(1);
self.lba0_register.write(block.get_bits(0..8) as u8);
self.lba1_register.write(block.get_bits(8..16) as u8);
self.lba2_register.write(block.get_bits(16..24) as u8);
}
}
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 {
return None;
}
self.busy_loop();
if self.lba1() != 0 || self.lba2() != 0 {
return None;
}
for i in 0.. {
if i == 256 {
self.reset();
return None;
}
if self.is_error() {
return None;
}
if self.is_ready() {
break;
}
}
let mut res = [0; 256];
for i in 0..256 {
res[i] = self.read_data();
}
Some(res)
}
pub fn read(&mut self, drive: u8, block: BlockIndex, buf: &mut [u8]) {
assert!(buf.len() == 512);
self.setup(drive, block);
self.write_command(Command::Read);
self.busy_loop();
for i in (0..256).step_by(2) {
let data = self.read_data();
buf[i + 0] = data.get_bits(0..8) as u8;
buf[i + 1] = data.get_bits(8..16) as u8;
}
}
pub fn write(&mut self, drive: u8, block: BlockIndex, buf: &[u8]) {
assert!(buf.len() == 512);
self.setup(drive, block);
self.write_command(Command::Write);
self.busy_loop();
for i in 0..256 {
let mut data = 0 as u16;
data.set_bits(0..8, buf[i * 2] as u16);
data.set_bits(8..16, buf[i * 2 + 1] as u16);
self.write_data(data);
}
self.busy_loop();
}
}
lazy_static! {
pub static ref BUSES: Mutex<Vec<Bus>> = Mutex::new(Vec::new());
}
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 list() -> Vec<(u8, u8, String, String, u32, String, u32)> {
let mut buses = BUSES.lock();
let mut res = Vec::new();
for bus in 0..2 {
for drive in 0..2 {
if let Some(buf) = buses[bus as usize].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((bus, drive, model, serial, size, unit, sectors));
}
}
}
res
}
pub fn indentify_drive(bus : u8, drive : u8) -> Option<(u8, u8, String, String, u32, String, u32)> {
let mut buses = BUSES.lock();
if let Some(buf) = buses[bus as usize].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);
Some((bus, drive, model, serial, size, unit, sectors))
} else {
None
}
}
pub fn read(bus: u8, drive: u8, block: BlockIndex, buf: &mut [u8]) {
let mut buses = BUSES.lock();
buses[bus as usize].read(drive, block, buf);
}
pub fn write(bus: u8, drive: u8, block: BlockIndex, buf : &[u8]) {
let mut buses = BUSES.lock();
buses[bus as usize].write
(drive, block, buf);
}
pub fn drive_is_present(bus : usize) -> bool {
unsafe {BUSES.lock()[bus].status_register.read() != 0xFF}
}
pub fn init() -> Result<(), ()> {
{
let mut buses = BUSES.lock();
buses.push(Bus::new(0, 0x1F0, 0x3F6, 14));
buses.push(Bus::new(1, 0x170, 0x376, 15));
}
Ok(())
}