From 8c29ffea06eae6e1d14a90f43010eb680d4b416f Mon Sep 17 00:00:00 2001 From: pjht Date: Tue, 1 Nov 2022 12:45:49 -0500 Subject: [PATCH] Initial commit --- .cargo/config.toml | 9 + .gitignore | 1 + Cargo.lock | 367 ++++++++++++++++++++++++++++++++++ Cargo.toml | 23 +++ rust-toolchain.toml | 2 + src/ata.rs | 412 +++++++++++++++++++++++++++++++++++++++ src/main.rs | 91 +++++++++ x86_64-unknown-none.json | 15 ++ 8 files changed, 920 insertions(+) create mode 100644 .cargo/config.toml create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 rust-toolchain.toml create mode 100644 src/ata.rs create mode 100644 src/main.rs create mode 100644 x86_64-unknown-none.json diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..62d96b1 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,9 @@ +[unstable] +build-std-features = ["compiler-builtins-mem"] +build-std = ["core", "compiler_builtins", "alloc"] + +[build] +target = "x86_64-unknown-none.json" + +[install] +root = "../kernel/sysroot" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..82dfe70 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,367 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bit_field" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + +[[package]] +name = "core2" +version = "0.4.0" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "derive-try-from-primitive" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302ccf094df1151173bb6f5a2282fcd2f45accd5eae1bdf82dcbfefbc501ad5c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dev_driver_rpc" +version = "0.1.0" +dependencies = [ + "postcard", + "serde", + "spin", + "std", +] + +[[package]] +name = "elfloader" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a249d6a9d50f3bf5a3cb7bfd75e84989cad89c6c77b5996c8b084e844146ff04" +dependencies = [ + "bitflags", + "log", + "xmas-elf", +] + +[[package]] +name = "file_rpc" +version = "0.1.0" +dependencies = [ + "postcard", + "serde", + "spin", + "std", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "libc" +version = "0.2.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" + +[[package]] +name = "linked_list_allocator" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "636c3bc929db632724303109c88d5d559a2a60f62243bb041387f03fa081d94a" +dependencies = [ + "spinning_top", +] + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "once_cell" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" + +[[package]] +name = "postcard" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c2b180dc0bade59f03fd005cb967d3f1e5f69b13922dad0cd6e047cb8af2363" +dependencies = [ + "cobs", + "serde", +] + +[[package]] +name = "proc-macro2" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "spin" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spinning_top" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75adad84ee84b521fb2cca2d4fd0f1dab1d8d026bda3c5bea4ca63b5f9f9293c" +dependencies = [ + "lock_api", +] + +[[package]] +name = "std" +version = "0.1.0" +dependencies = [ + "core2", + "crossbeam-queue", + "derive-try-from-primitive", + "elfloader", + "hashbrown", + "linked_list_allocator", + "postcard", + "serde", + "spin", + "x86_64 0.14.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "test_proc" +version = "0.1.0" +dependencies = [ + "bitflags", + "dev_driver_rpc", + "file_rpc", + "postcard", + "serde", + "spin", + "std", + "tap", + "x86_64 0.14.10 (git+https://github.com/pjht/x86_64)", +] + +[[package]] +name = "unicode-ident" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "volatile" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ca98349dda8a60ae74e04fd90c7fb4d6a4fbe01e6d3be095478aa0b76f6c0c" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "x86_64" +version = "0.14.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "100555a863c0092238c2e0e814c1096c1e5cf066a309c696a87e907b5f8c5d69" +dependencies = [ + "bit_field", + "bitflags", + "rustversion", + "volatile", +] + +[[package]] +name = "x86_64" +version = "0.14.10" +source = "git+https://github.com/pjht/x86_64#5d941e68fa70779e07576d42a9f49bc89afdb9ed" +dependencies = [ + "bit_field", + "bitflags", + "rustversion", + "volatile", +] + +[[package]] +name = "xmas-elf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d29b4d8e7beaceb4e77447ba941a7600d23d0319ab52da0461abea214832d5a" +dependencies = [ + "zero", +] + +[[package]] +name = "zero" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1e99ce5 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "test_proc" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dev_driver_rpc = { version = "0.1.0", path = "../dev_driver_rpc" } +postcard = { version = "1.0.2", default-features = false, features = ["alloc"] } +serde = { version = "1.0.144", default-features = false, features = ["alloc", "derive"] } +std = { path = "../std" } +bitflags = "1.3.2" +spin = "0.9.4" +tap = "1.0.1" +x86_64 = { git = "https://github.com/pjht/x86_64", features = ["experimental"] } +file_rpc = { version = "0.1.0", path = "../file_rpc" } + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..5d56faf --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/src/ata.rs b/src/ata.rs new file mode 100644 index 0000000..1df8ece --- /dev/null +++ b/src/ata.rs @@ -0,0 +1,412 @@ +use std::cmp::Ordering; + +use bitflags::bitflags; +use spin::{Lazy, Mutex}; +use std::io::{self, Read, Seek}; +use tap::Tap; +use x86_64::instructions::port::{ + PortRead, PortSafe, PortSafeReadOnly, PortSafeWriteOnly, PortWrite, +}; + +bitflags! { + pub struct RawError: u8 { + const AMNF = 0b0000_0001; + const TKZNF = 0b0000_0010; + const ABRT = 0b0000_0100; + const MCR = 0b0000_1000; + const IDNF = 0b0001_0000; + const MC = 0b0010_0000; + const UNC = 0b0100_0000; + const BBK = 0b1000_0000; + } +} + +impl From for Error { + fn from(err: RawError) -> Self { + if err.contains(RawError::AMNF) { + Self::AddressMarkNotFound + } else if err.contains(RawError::TKZNF) { + Self::TrackZeroNotFound + } else if err.contains(RawError::ABRT) { + Self::AbortedCommand + } else if err.contains(RawError::MCR) { + Self::MediaChangeRequest + } else if err.contains(RawError::IDNF) { + Self::IDMarkNotFound + } else if err.contains(RawError::MC) { + Self::MediaChanged + } else if err.contains(RawError::UNC) { + Self::UncorrectableData + } else if err.contains(RawError::BBK) { + Self::BadBlock + } else { + Self::Generic + } + } +} + +impl PortRead for RawError { + unsafe fn read_from_port(port: u16) -> Self { + unsafe { Self::from_bits_unchecked(u8::read_from_port(port)) } + } +} + +impl PortWrite for RawError { + unsafe fn write_to_port(port: u16, value: Self) { + unsafe { u8::write_to_port(port, value.bits) }; + } +} + +bitflags! { + pub struct Status: u8 { + const ERR = 0b0000_0001; + const DRQ = 0b0000_1000; + const SRV = 0b0001_0000; + const DF = 0b0010_0000; + const RDY = 0b0100_0000; + const BSY = 0b1000_0000; + } +} + +impl PortRead for Status { + unsafe fn read_from_port(port: u16) -> Self { + unsafe { Self::from_bits_unchecked(u8::read_from_port(port)) } + } +} + +impl PortWrite for Status { + unsafe fn write_to_port(port: u16, value: Self) { + unsafe { u8::write_to_port(port, value.bits) }; + } +} + +bitflags! { + pub struct DeviceControl: u8 { + const N_IEN = 0b0000_0010; + const SRST = 0b0000_0100; + const HOB = 0b1000_0000; + } +} + +impl PortRead for DeviceControl { + unsafe fn read_from_port(port: u16) -> Self { + unsafe { Self::from_bits_unchecked(u8::read_from_port(port)) } + } +} + +impl PortWrite for DeviceControl { + unsafe fn write_to_port(port: u16, value: Self) { + unsafe { u8::write_to_port(port, value.bits) }; + } +} + +bitflags! { + #[repr(transparent)] + pub struct DriveHead: u8 { + const DT0 = 0b0000_0001; + const DT1 = 0b0000_0010; + const DT2 = 0b0000_0100; + const DT3 = 0b0000_1000; + const DRV = 0b0001_0000; + const LBA = 0b0100_0000; + } +} + +impl DriveHead { + fn set_head_block(&mut self, data: u8) { + assert!(data < 16); + self.bits = (self.bits & 0xF0) | data; + } +} + +impl PortRead for DriveHead { + unsafe fn read_from_port(port: u16) -> Self { + unsafe { Self::from_bits_unchecked(u8::read_from_port(port)) } + } +} + +impl PortWrite for DriveHead { + unsafe fn write_to_port(port: u16, value: Self) { + unsafe { u8::write_to_port(port, value.bits) }; + } +} + +#[repr(u8)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum DriveNumber { + Master = 0, + Slave = 1, +} + +#[repr(u8)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(unused)] +enum Command { + Identify = 0xEC, + IdentifyPacket = 0xA1, + ReadSectors = 0x20, + WriteSectors = 0x30, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Error { + NonexistentDrive, + Generic, + AbortedCommand, + TrackZeroNotFound, + AddressMarkNotFound, + MediaChangeRequest, + IDMarkNotFound, + MediaChanged, + UncorrectableData, + BadBlock, +} + +impl From for io::Error { + fn from(_: Error) -> Self { + Self::new(io::ErrorKind::Other, "ATA read error") + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[allow(clippy::upper_case_acronyms)] +pub enum DriveKind { + ATA, + ATAPI, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum IdentifyError { + SATADrive, + Error(Error), +} + +impl From for IdentifyError { + fn from(err: Error) -> Self { + Self::Error(err) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Bus { + data: PortSafe, + error: PortSafeReadOnly, + sector_count: PortSafe, + sector_num_lba_lo: PortSafe, + cyl_low_lba_mid: PortSafe, + cyl_high_lba_hi: PortSafe, + drive_head: PortSafe, + status: PortSafeReadOnly, + command: PortSafeWriteOnly, + selected_drive: Option, // None represents the initial state with an unknown drive selected +} + +impl Bus { + /// SAFETY + /// io_base must be a valid base for the ATA bus's IO registers + const unsafe fn new(io_base: u16) -> Self { + unsafe { + Self { + data: PortSafe::new(io_base), + error: PortSafeReadOnly::new(io_base + 1), + sector_count: PortSafe::new(io_base + 2), + sector_num_lba_lo: PortSafe::new(io_base + 3), + cyl_low_lba_mid: PortSafe::new(io_base + 4), + cyl_high_lba_hi: PortSafe::new(io_base + 5), + drive_head: PortSafe::new(io_base + 6), + status: PortSafeReadOnly::new(io_base + 7), + command: PortSafeWriteOnly::new(io_base + 7), + selected_drive: None, + } + } + } + + pub fn select(&mut self, drive: DriveNumber, lba: bool, data: u8) { + if self.selected_drive != Some(drive) { + self.drive_head.write(DriveHead::empty().tap_mut(|v| { + v.set(DriveHead::DRV, drive == DriveNumber::Slave); + v.set(DriveHead::LBA, lba); + v.set_head_block(data); + })); + for _ in 0..14 { + self.status.read(); + } + self.selected_drive = Some(drive); + } + } + + pub fn read_data(&mut self) -> Result<[u16; 256], Error> { + self.poll()?; + let mut arr = [0; 256]; + arr.fill_with(|| self.data.read()); + Ok(arr) + } + + fn poll(&mut self) -> Result<(), Error> { + while self.status.read().contains(Status::BSY) {} + while !(self.status.read().intersects(Status::DRQ | Status::ERR)) {} + self.error() + } + + fn send_command(&mut self, command: Command) { + self.command.write(command as u8); + } + + pub fn identify(&mut self) -> Result<(DriveKind, [u16; 256]), IdentifyError> { + self.command.write(Command::Identify as u8); + if self.status.read().bits() == 0 { + return Err(IdentifyError::Error(Error::NonexistentDrive)); + }; + self.poll()?; + if self.status.read().contains(Status::ERR) { + if self.cyl_low_lba_mid.read() == 0x14 && self.cyl_high_lba_hi.read() == 0xEB { + self.command.write(Command::IdentifyPacket as u8); + if self.status.read().bits() == 0 { + return Err(IdentifyError::Error(Error::NonexistentDrive)); + }; + Ok((DriveKind::ATAPI, self.read_data()?)) + } else { + Err(IdentifyError::SATADrive) + } + } else { + Ok((DriveKind::ATA, self.read_data()?)) + } + } + + fn error(&mut self) -> Result<(), Error> { + if self.status.read().contains(Status::ERR) { + panic!("Drive Error: {:?}", Error::from(self.error.read())); + Err(self.error.read().into()) + } else { + Ok(()) + } + } +} + +#[allow(unused)] +// SAFETY +// This is safe because 0x1F0 is the standard primary bus base address +static PRIMARY_BUS: Mutex = Mutex::new(unsafe { Bus::new(0x1F0) }); +#[allow(unused)] +// SAFETY +// This is safe because 0x170 is the standard secondary bus base address +static SECONDARY_BUS: Mutex = Mutex::new(unsafe { Bus::new(0x170) }); + +#[allow(unused)] +pub static PRIMARY_MASTER: Lazy> = + Lazy::new(|| Device::new(&PRIMARY_BUS, DriveNumber::Master)); +#[allow(unused)] +pub static PRIMARY_SLAVE: Lazy> = + Lazy::new(|| Device::new(&PRIMARY_BUS, DriveNumber::Slave)); +#[allow(unused)] +pub static SECONDARY_MASTER: Lazy> = + Lazy::new(|| Device::new(&SECONDARY_BUS, DriveNumber::Master)); +#[allow(unused)] +pub static SECONDARY_SLAVE: Lazy> = + Lazy::new(|| Device::new(&SECONDARY_BUS, DriveNumber::Slave)); + +#[derive(Copy, Clone, Debug)] +pub struct Device { + bus: &'static Mutex, + drive_number: DriveNumber, + lba: bool, + pos: u64, + len: u64, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum NewDeviceError { + IdentifyError(IdentifyError), + ATAPIDevice, +} + +impl Device { + fn new(bus: &'static Mutex, drive_number: DriveNumber) -> Result { + bus.lock().select(drive_number, true, 0); + let id_result = bus + .lock() + .identify() + .map_err(NewDeviceError::IdentifyError)?; + if let (DriveKind::ATA, ident_data) = id_result { + Ok(Self { + bus, + drive_number, + lba: true, + pos: 0, + len: (u64::from(ident_data[60]) * 512), + }) + } else { + Err(NewDeviceError::ATAPIDevice) + } + } + + fn select(&self, data: u8) { + self.bus.lock().select(self.drive_number, self.lba, data); + } +} + +impl Read for Device { + #[allow(clippy::similar_names)] + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let avail_len = u64::min(u64::min(self.len - self.pos, buf.len() as u64), 512 * 250); + if avail_len == 0 { + return Ok(0); + } + let sector = self.pos / 512; + assert!(sector < 0x1_0000_0000_0000); + let offset = (self.pos % 512) as usize; + let length = avail_len as usize + offset; + let num_sectors = length.div_ceil(512); + assert!(num_sectors < 256); + if sector < 0x1000_0000 { + self.select(((sector & 0xF00_0000) >> 24) as u8); + let mut bus = self.bus.lock(); + bus.sector_count.write(num_sectors as u8); + bus.sector_num_lba_lo.write(sector as u8); + bus.cyl_low_lba_mid.write((sector >> 8) as u8); + bus.cyl_high_lba_hi.write((sector >> 16) as u8); + bus.send_command(Command::ReadSectors); + } else { + unimplemented!(); + } + let mut byte_num = 0; + let mut i = 0; + for _ in 0..num_sectors { + for byte in self + .bus + .lock() + .read_data()? + .into_iter() + .flat_map(u16::to_le_bytes) + { + if byte_num >= offset && byte_num < (offset + buf.len()) { + buf[i] = byte; + i += 1; + } + byte_num += 1; + } + } + self.pos += avail_len as u64; + Ok(avail_len as usize) + } +} + +impl Seek for Device { + fn seek(&mut self, pos: io::SeekFrom) -> io::Result { + match pos { + io::SeekFrom::Start(x) => self.pos = x, + io::SeekFrom::End(_) => { + return Err(io::Error::new( + io::ErrorKind::Other, + "End seek not implemented yet", + )) + } + io::SeekFrom::Current(x) => match x.cmp(&0) { + Ordering::Equal => (), + Ordering::Greater => self.pos += x.unsigned_abs(), + Ordering::Less => self.pos -= x.unsigned_abs(), + }, + }; + Ok(self.pos) + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..a548139 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,91 @@ +#![no_std] +#![no_main] +#![feature(int_roundings)] +#![deny(unsafe_op_in_unsafe_fn)] + +mod ata; + +use ata::{ + Device, NewDeviceError, PRIMARY_MASTER, PRIMARY_SLAVE, SECONDARY_MASTER, SECONDARY_SLAVE, +}; +use dev_driver_rpc::Server as DevServer; +use file_rpc::Server as FileServer; +use std::{ + io::{self, Read, Seek, SeekFrom}, + ipc, + prelude::*, +}; + +struct Serv; + +fn get_drive_from_number(num: u64) -> Result { + match num { + 0 => *PRIMARY_MASTER, + 1 => *PRIMARY_SLAVE, + 2 => *SECONDARY_MASTER, + 3 => *SECONDARY_SLAVE, + _ => panic!(), + } +} + +impl DevServer for Serv { + fn open(&self, path: &str) -> Result { + match path { + "sda" => { + if PRIMARY_MASTER.is_ok() { + Ok(0) + } else { + Err(io::ErrorKind::NotFound.into()) + } + } + "sdb" => { + if PRIMARY_SLAVE.is_ok() { + Ok(1) + } else { + Err(io::ErrorKind::NotFound.into()) + } + } + "sdc" => { + if SECONDARY_MASTER.is_ok() { + Ok(2) + } else { + Err(io::ErrorKind::NotFound.into()) + } + } + "sdd" => { + if SECONDARY_SLAVE.is_ok() { + Ok(3) + } else { + Err(io::ErrorKind::NotFound.into()) + } + } + _ => Err(io::ErrorKind::NotFound.into()), + } + } +} +impl FileServer for Serv { + fn read(&self, fd: u64, pos: u64, len: usize) -> Result, io::Error> { + let mut buf = Vec::new(); + buf.resize(len, 0); + let mut drive = get_drive_from_number(fd).unwrap(); + // dbg!(pos, len); + drive.seek(SeekFrom::Start(pos))?; + drive.read(&mut buf)?; + // dbg!(&buf[0..usize::min(len, 16)]); + Ok(buf) + } + + fn write(&self, _fd: u64, _pos: u64, _data: &[u8]) -> Result<(), io::Error> { + todo!() + } + + fn close(&self, _fd: u64) {} +} + +main!({ + dev_driver_rpc::register_server(Box::new(Serv)); + file_rpc::register_server(Box::new(Serv)); + loop { + ipc::process_messages() + } +}); diff --git a/x86_64-unknown-none.json b/x86_64-unknown-none.json new file mode 100644 index 0000000..7d2110d --- /dev/null +++ b/x86_64-unknown-none.json @@ -0,0 +1,15 @@ +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float" +}