forked from koniifer/ableos
stolen code
This commit is contained in:
parent
a0c9587e5c
commit
25e87735e6
13
Cargo.lock
generated
13
Cargo.lock
generated
|
@ -66,6 +66,7 @@ dependencies = [
|
||||||
"wasmi",
|
"wasmi",
|
||||||
"watson",
|
"watson",
|
||||||
"x86_64",
|
"x86_64",
|
||||||
|
"x86_ata",
|
||||||
"y-compositor-protocol",
|
"y-compositor-protocol",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1148,6 +1149,18 @@ dependencies = [
|
||||||
"volatile 0.4.4",
|
"volatile 0.4.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x86_ata"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bit_field",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"serde",
|
||||||
|
"spin 0.9.2",
|
||||||
|
"x86_64",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xshell"
|
name = "xshell"
|
||||||
version = "0.1.17"
|
version = "0.1.17"
|
||||||
|
|
|
@ -29,6 +29,10 @@ run-args = [
|
||||||
# "-machine", "pcspk-audiodev=0",
|
# "-machine", "pcspk-audiodev=0",
|
||||||
|
|
||||||
|
|
||||||
|
"-hdb",
|
||||||
|
"../img.ext2",
|
||||||
|
|
||||||
|
|
||||||
"-qmp",
|
"-qmp",
|
||||||
"unix:../qmp-sock,server,nowait",
|
"unix:../qmp-sock,server,nowait",
|
||||||
|
|
||||||
|
@ -128,6 +132,7 @@ git = "https://git.ablecorp.us:443/able/externc-libm.git"
|
||||||
riscv = "*"
|
riscv = "*"
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||||
|
x86_ata = { path = "../x86_ata" }
|
||||||
bootloader = { version = "0.9.8", features = ["map_physical_memory"] }
|
bootloader = { version = "0.9.8", features = ["map_physical_memory"] }
|
||||||
cpuio = { git = "https://git.ablecorp.us/ondra05/cpuio.git" }
|
cpuio = { git = "https://git.ablecorp.us/ondra05/cpuio.git" }
|
||||||
pic8259 = "0.10.1"
|
pic8259 = "0.10.1"
|
||||||
|
|
|
@ -247,6 +247,7 @@ pub fn bsod(src: BSODSource) -> ! {
|
||||||
BSODSource::DoubleFault(_) => "https://git.ablecorp.us/able/ableos/wiki/Double-Faults",
|
BSODSource::DoubleFault(_) => "https://git.ablecorp.us/able/ableos/wiki/Double-Faults",
|
||||||
BSODSource::Panic(_) => {
|
BSODSource::Panic(_) => {
|
||||||
//
|
//
|
||||||
|
trace!("panic");
|
||||||
"https://git.ablecorp.us/able/ableos/wiki/"
|
"https://git.ablecorp.us/able/ableos/wiki/"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -47,6 +47,17 @@ pub fn kernel_main() -> ! {
|
||||||
|
|
||||||
drop(ipc_service);
|
drop(ipc_service);
|
||||||
|
|
||||||
|
use x86_ata::{init, list, read, ATA_BLOCK_SIZE};
|
||||||
|
// 1. Initialise ATA Subsystem. (Perform Once, on boot)
|
||||||
|
init().expect("Failed To Start ATA...");
|
||||||
|
let mut buffer: [u8; ATA_BLOCK_SIZE] = [0; ATA_BLOCK_SIZE];
|
||||||
|
// FIXME: Calls to read panic the kernel
|
||||||
|
// read(0, 0, 0, &mut buffer);
|
||||||
|
|
||||||
|
// for abc in list() {
|
||||||
|
// trace!("{:?}", abc);
|
||||||
|
// }
|
||||||
|
|
||||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||||
let mut scheduler = SCHEDULER.lock();
|
let mut scheduler = SCHEDULER.lock();
|
||||||
// comment this out to resume normal use
|
// comment this out to resume normal use
|
||||||
|
|
25
x86_ata/Cargo.toml
Normal file
25
x86_ata/Cargo.toml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
[package]
|
||||||
|
name = "x86_ata"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "*"
|
||||||
|
[dependencies.bit_field]
|
||||||
|
version = "0.10.0"
|
||||||
|
|
||||||
|
[dependencies.lazy_static]
|
||||||
|
features = ["spin_no_std"]
|
||||||
|
version = "1.4.0"
|
||||||
|
|
||||||
|
[dependencies.serde]
|
||||||
|
default-features = false
|
||||||
|
version = "1.0.126"
|
||||||
|
|
||||||
|
[dependencies.spin]
|
||||||
|
version = "0.9.0"
|
||||||
|
|
||||||
|
[dependencies.x86_64]
|
||||||
|
version = "0.14.3"
|
380
x86_ata/src/lib.rs
Normal file
380
x86_ata/src/lib.rs
Normal file
|
@ -0,0 +1,380 @@
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
/// Implementation Courtesy of MOROS.
|
||||||
|
/// Currently Only Supports ATA-PIO, with 24-bit LBA Addressing.
|
||||||
|
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 log::trace;
|
||||||
|
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); // Set SRST bit
|
||||||
|
sleep_ticks(2);
|
||||||
|
self.control_register.write(0); // Then clear it
|
||||||
|
sleep_ticks(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait(&mut self) {
|
||||||
|
for _ in 0..4 {
|
||||||
|
// Wait about 4 x 100 ns
|
||||||
|
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 {
|
||||||
|
// Hanged
|
||||||
|
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) {
|
||||||
|
// Drive #0 (primary) = 0xA0
|
||||||
|
// Drive #1 (secondary) = 0xB0
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read A single, 512-byte long slice from a given block
|
||||||
|
/// panics if buf isn't EXACTLY 512 Bytes long;
|
||||||
|
/// Example:
|
||||||
|
/// ```rust
|
||||||
|
/// // Read A Single block from a disk
|
||||||
|
/// pub fn read_single() {
|
||||||
|
/// use x86_ata::{init, ATA_BLOCK_SIZE, read};
|
||||||
|
/// // 1. Initialise ATA Subsystem. (Perform Once, on boot)
|
||||||
|
/// init().expect("Failed To Start ATA...");
|
||||||
|
/// // 2. Create a temporary buffer of size 512.
|
||||||
|
/// let mut buffer: [u8;ATA_BLOCK_SIZE] = [0; ATA_BLOCK_SIZE];
|
||||||
|
/// // 3. Pass the buffer over to the Subsystem, to be filled.
|
||||||
|
/// read(0, 0, 0, &mut buffer);
|
||||||
|
/// }
|
||||||
|
|
||||||
|
pub fn read(&mut self, drive: u8, block: BlockIndex, buf: &mut [u8]) {
|
||||||
|
assert!(buf.len() == 512);
|
||||||
|
trace!("Reading Block 0x{:8X}", block);
|
||||||
|
// trace!("{:?}", self);
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
//log!("Read[{:08X}][{:02X}]: 0x{:04X}\n", block, i, data);
|
||||||
|
buf[i + 0] = data.get_bits(0..8) as u8;
|
||||||
|
buf[i + 1] = data.get_bits(8..16) as u8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write A single, 512-byte long slice to a given block
|
||||||
|
/// panics if buf isn't EXACTLY 512 Bytes long;
|
||||||
|
/// Example:
|
||||||
|
/// ```rust
|
||||||
|
/// // Read A Single block from a disk
|
||||||
|
/// pub fn write_single() {
|
||||||
|
/// use x86_ata::{init, ATA_BLOCK_SIZE, write};
|
||||||
|
/// // 1. Initialise ATA Subsystem. (Perform Once, on boot)
|
||||||
|
/// init().expect("Failed To Start ATA...");
|
||||||
|
/// // 2. Create a temporary buffer of size 512.
|
||||||
|
/// let buffer: [u8;ATA_BLOCK_SIZE] = [0; ATA_BLOCK_SIZE];
|
||||||
|
/// // 3. Pass the buffer over to the Subsystem, to be filled.
|
||||||
|
/// write(0, 0, 0, &buffer);
|
||||||
|
/// }
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
//log!("Data: 0x{:04X} | {}{} \n", data, buf[i * 2] as char, buf[i * 2 + 1] as char);
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Identify a specific drive on a bus, format: (bus, drive, model, serial. size, unit, sectors)
|
||||||
|
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();
|
||||||
|
trace!("Reading Block 0x{:08X}\n", block);
|
||||||
|
buses[bus as usize].read(drive, block, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(bus: u8, drive: u8, block: BlockIndex, buf: &[u8]) {
|
||||||
|
let mut buses = BUSES.lock();
|
||||||
|
//log!("Writing Block 0x{:08X}\n", block);
|
||||||
|
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(())
|
||||||
|
}
|
Loading…
Reference in a new issue