forked from koniifer/ableos
working IDE DMA implementation
This commit is contained in:
parent
998a1d30cf
commit
f140938ee6
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -54,6 +54,7 @@ dependencies = [
|
||||||
"rdrand",
|
"rdrand",
|
||||||
"riscv",
|
"riscv",
|
||||||
"rkyv",
|
"rkyv",
|
||||||
|
"seq-macro",
|
||||||
"serde",
|
"serde",
|
||||||
"spin 0.9.4",
|
"spin 0.9.4",
|
||||||
"toml",
|
"toml",
|
||||||
|
@ -648,6 +649,12 @@ version = "4.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "seq-macro"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0772c5c30e1a0d91f6834f8e545c69281c099dfa9a3ac58d96a9fd629c8d4898"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.141"
|
version = "1.0.141"
|
||||||
|
|
|
@ -78,7 +78,7 @@ versioning = { git = "https://git.ablecorp.us/able/aos_userland" }
|
||||||
pc-keyboard = "0.5"
|
pc-keyboard = "0.5"
|
||||||
# mini-backtrace = "0.1"
|
# mini-backtrace = "0.1"
|
||||||
clparse = { git = "https://git.ablecorp.us/able/core_utils", default-features = false }
|
clparse = { git = "https://git.ablecorp.us/able/core_utils", default-features = false }
|
||||||
|
seq-macro = "0.3"
|
||||||
|
|
||||||
[dependencies.linked_list_allocator]
|
[dependencies.linked_list_allocator]
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
|
|
@ -6,10 +6,16 @@
|
||||||
|
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
use crate::{arch::gdt, println, rhai_shell::KEYBUFF};
|
use crate::{
|
||||||
|
arch::gdt,
|
||||||
|
devices::pci::{PciDevice, PCI_DEVICES},
|
||||||
|
println,
|
||||||
|
rhai_shell::KEYBUFF,
|
||||||
|
};
|
||||||
use cpuio::outb;
|
use cpuio::outb;
|
||||||
use pic8259::ChainedPics;
|
use pic8259::ChainedPics;
|
||||||
use qrcode::QrCode;
|
use qrcode::QrCode;
|
||||||
|
use seq_macro::seq;
|
||||||
use spin::Lazy;
|
use spin::Lazy;
|
||||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||||
|
|
||||||
|
@ -30,6 +36,9 @@ pub enum InterruptIndex {
|
||||||
/// Mouse offset
|
/// Mouse offset
|
||||||
Mouse = 44,
|
Mouse = 44,
|
||||||
|
|
||||||
|
/// Disk offset
|
||||||
|
Disk = 46,
|
||||||
|
|
||||||
// SecondInterrupt = PIC_2_OFFSET,
|
// SecondInterrupt = PIC_2_OFFSET,
|
||||||
Cmos = 0x70,
|
Cmos = 0x70,
|
||||||
}
|
}
|
||||||
|
@ -47,9 +56,9 @@ static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
||||||
reset_pit_for_cpu();
|
reset_pit_for_cpu();
|
||||||
let mut idt = InterruptDescriptorTable::new();
|
let mut idt = InterruptDescriptorTable::new();
|
||||||
|
|
||||||
for int in 32..=255 {
|
seq!(N in 32..=255 {
|
||||||
idt[int].set_handler_fn(undefined_handler);
|
idt[N].set_handler_fn(undefined_handler_~N);
|
||||||
}
|
});
|
||||||
|
|
||||||
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -68,12 +77,21 @@ static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
||||||
idt
|
idt
|
||||||
});
|
});
|
||||||
|
|
||||||
extern "x86-interrupt" fn undefined_handler(stack_frame: InterruptStackFrame) {
|
seq!(N in 32..=255 {
|
||||||
error!("{:?}", stack_frame);
|
extern "x86-interrupt" fn undefined_handler_~N(stack_frame: InterruptStackFrame) {
|
||||||
}
|
error!("INT {}: {:?}", N, stack_frame);
|
||||||
|
unsafe {
|
||||||
|
PICS.lock()
|
||||||
|
.notify_end_of_interrupt(N);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
extern "x86-interrupt" fn software_int_handler(stack_frame: InterruptStackFrame) {
|
extern "x86-interrupt" fn software_int_handler(stack_frame: InterruptStackFrame) {
|
||||||
trace!("EXCEPTION: SOFTWARE INT\n{:#?}", stack_frame);
|
trace!("EXCEPTION: SOFTWARE INT\n{:#?}", stack_frame);
|
||||||
|
unsafe {
|
||||||
|
PICS.lock().notify_end_of_interrupt(54);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
|
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
|
use serde::de::value;
|
||||||
use x86_64::instructions::port::Port;
|
use x86_64::instructions::port::Port;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -24,7 +25,7 @@ pub const INTEL_PIIX4_IDE: DeviceID = DeviceID::new(IntelCorp, 0x7111);
|
||||||
// Display_VGA (0x0300)
|
// Display_VGA (0x0300)
|
||||||
pub const VMWARE_SVGA2: DeviceID = DeviceID::new(VMWareInc, 0x0405);
|
pub const VMWARE_SVGA2: DeviceID = DeviceID::new(VMWareInc, 0x0405);
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
/// A struct containing info about a PCI device.
|
/// A struct containing info about a PCI device.
|
||||||
pub struct PciDeviceInfo {
|
pub struct PciDeviceInfo {
|
||||||
pub header_type: u8,
|
pub header_type: u8,
|
||||||
|
@ -44,18 +45,29 @@ impl PciDeviceInfo {
|
||||||
/// Get the bar, 0-indexed
|
/// Get the bar, 0-indexed
|
||||||
pub fn bar(&self, bar: u8) -> u32 {
|
pub fn bar(&self, bar: u8) -> u32 {
|
||||||
assert!(bar < 6);
|
assert!(bar < 6);
|
||||||
unsafe { self.io_read(0, 0x10 + bar * 4) }
|
unsafe { self.read(0, 0x10 + bar * 4) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the interrupt pin
|
/// Get the interrupt pin
|
||||||
pub fn interrupt_pin(&self) -> u8 {
|
pub fn interrupt_pin(&self) -> u8 {
|
||||||
let last_row = unsafe { self.io_read(0, 0x3C) };
|
let last_row = unsafe { self.read(0, 0x3C) };
|
||||||
((last_row >> 8) & 0xFF) as u8
|
((last_row >> 8) & 0xFF) as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read from IO space
|
/// Enable bus mastering. This allows the PCI device to do DMA
|
||||||
pub unsafe fn io_read(&self, func: u8, offset: u8) -> u32 {
|
pub fn enable_bus_mastering(&self) {
|
||||||
pci_io_read(self.bus, self.device, func, offset)
|
let command = unsafe { self.read(0, 4) } | 1 << 2;
|
||||||
|
unsafe { self.write(0, 4, command) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read from configuration space
|
||||||
|
pub unsafe fn read(&self, func: u8, offset: u8) -> u32 {
|
||||||
|
pci_config_read(self.bus, self.device, func, offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write to IO space
|
||||||
|
pub unsafe fn write(&self, func: u8, offset: u8, value: u32) {
|
||||||
|
pci_config_write(self.bus, self.device, func, offset, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +128,7 @@ pub fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let reg2 = unsafe { pci_io_read(bus, device, 0, 0x8) };
|
let reg2 = unsafe { pci_config_read(bus, device, 0, 0x8) };
|
||||||
let class = ((reg2 >> 16) & 0x0000FFFF) as u16;
|
let class = ((reg2 >> 16) & 0x0000FFFF) as u16;
|
||||||
let pci_class = PciFullClass::from_u16(class);
|
let pci_class = PciFullClass::from_u16(class);
|
||||||
let header_type = get_header_type(bus, device, 0);
|
let header_type = get_header_type(bus, device, 0);
|
||||||
|
@ -134,7 +146,7 @@ pub fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn pci_io_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
|
unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
|
||||||
let bus = bus as u32;
|
let bus = bus as u32;
|
||||||
let device = device as u32;
|
let device = device as u32;
|
||||||
let func = func as u32;
|
let func = func as u32;
|
||||||
|
@ -144,23 +156,39 @@ unsafe fn pci_io_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
|
||||||
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc) | 0x80000000) as u32;
|
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc) | 0x80000000) as u32;
|
||||||
|
|
||||||
// write address
|
// write address
|
||||||
Port::<u32>::new(0xCF8).write(address);
|
Port::new(0xCF8).write(address);
|
||||||
|
|
||||||
// read data
|
// read data
|
||||||
Port::<u32>::new(0xCFC).read()
|
Port::new(0xCFC).read()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) {
|
||||||
|
let bus = bus as u32;
|
||||||
|
let device = device as u32;
|
||||||
|
let func = func as u32;
|
||||||
|
let offset = offset as u32;
|
||||||
|
// construct address param
|
||||||
|
let address =
|
||||||
|
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc) | 0x80000000) as u32;
|
||||||
|
|
||||||
|
// write address
|
||||||
|
Port::new(0xCF8).write(address);
|
||||||
|
|
||||||
|
// write data
|
||||||
|
Port::new(0xCFC).write(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_header_type(bus: u8, device: u8, function: u8) -> u8 {
|
fn get_header_type(bus: u8, device: u8, function: u8) -> u8 {
|
||||||
assert!(device < 32);
|
assert!(device < 32);
|
||||||
assert!(function < 8);
|
assert!(function < 8);
|
||||||
let res = unsafe { pci_io_read(bus, device, function, 0x0C) };
|
let res = unsafe { pci_config_read(bus, device, function, 0x0C) };
|
||||||
((res >> 16) & 0xFF) as u8
|
((res >> 16) & 0xFF) as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_ids(bus: u8, device: u8, function: u8) -> (u16, u16) {
|
fn get_ids(bus: u8, device: u8, function: u8) -> (u16, u16) {
|
||||||
assert!(device < 32);
|
assert!(device < 32);
|
||||||
assert!(function < 8);
|
assert!(function < 8);
|
||||||
let res = unsafe { pci_io_read(bus, device, function, 0) };
|
let res = unsafe { pci_config_read(bus, device, function, 0) };
|
||||||
let dev_id = ((res >> 16) & 0xFFFF) as u16;
|
let dev_id = ((res >> 16) & 0xFFFF) as u16;
|
||||||
let vnd_id = (res & 0xFFFF) as u16;
|
let vnd_id = (res & 0xFFFF) as u16;
|
||||||
(dev_id, vnd_id)
|
(dev_id, vnd_id)
|
||||||
|
|
|
@ -9,30 +9,48 @@ pub mod device;
|
||||||
pub mod vendors;
|
pub mod vendors;
|
||||||
|
|
||||||
// MassStorage_IDE (0x0101)
|
// MassStorage_IDE (0x0101)
|
||||||
pub mod piix;
|
pub mod piix_ide;
|
||||||
|
|
||||||
|
use alloc::sync::Arc;
|
||||||
pub use class::*;
|
pub use class::*;
|
||||||
pub use device::*;
|
pub use device::*;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use spin::Mutex;
|
||||||
use x86_64::structures::paging::{Mapper, Size4KiB};
|
use x86_64::structures::paging::{Mapper, Size4KiB};
|
||||||
|
|
||||||
use crate::arch::memory::BootInfoFrameAllocator;
|
use crate::arch::memory::BootInfoFrameAllocator;
|
||||||
|
|
||||||
use self::piix::Piix;
|
use self::piix_ide::PiixIde;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref PCI_DEVICES: Mutex<Vec<Arc<Mutex<PciDevice>>>> = Default::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum PciDevice {
|
||||||
|
// MassStorage_IDE (0x0101)
|
||||||
|
PiixIde(PiixIde),
|
||||||
|
// Variant so that we aren't about irrefutable if-let patterns
|
||||||
|
// FIXME: remove as soon as we have other variants
|
||||||
|
_0,
|
||||||
|
}
|
||||||
|
|
||||||
/// Enumerate PCI devices and run initialisation routines on ones we support
|
/// Enumerate PCI devices and run initialisation routines on ones we support
|
||||||
pub fn init(mapper: &mut impl Mapper<Size4KiB>, frame_allocator: &mut BootInfoFrameAllocator) {
|
pub fn init(mapper: &mut impl Mapper<Size4KiB>, frame_allocator: &mut BootInfoFrameAllocator) {
|
||||||
for bus in 0..=255 {
|
for bus in 0..=255 {
|
||||||
for device in 0..32 {
|
for device in 0..32 {
|
||||||
if let Some(device_info) = device::check_device(bus, device) {
|
if let Some(device_info) = device::check_device(bus, device) {
|
||||||
|
trace!("{device_info}");
|
||||||
match device_info.device_id {
|
match device_info.device_id {
|
||||||
// FIXME: Unknown class
|
// FIXME: Unknown class
|
||||||
S3INC_TRIO64V2 => {}
|
S3INC_TRIO64V2 => {}
|
||||||
|
|
||||||
// MassStorage_IDE (0x0101)
|
// MassStorage_IDE (0x0101)
|
||||||
INTEL_PIIX3_IDE | INTEL_PIIX4_IDE => {
|
INTEL_PIIX3_IDE | INTEL_PIIX4_IDE => {
|
||||||
let mut piix = Piix::new(bus, device).unwrap();
|
let mut piix = PiixIde::new(bus, device).unwrap();
|
||||||
piix.allocate_dma_frame(mapper, frame_allocator).unwrap();
|
piix.allocate_dma_frame(mapper, frame_allocator).unwrap();
|
||||||
piix.read().unwrap();
|
let mut devices = PCI_DEVICES.lock();
|
||||||
|
devices.push(Arc::new(Mutex::new(PciDevice::PiixIde(piix))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display_VGA (0x0300)
|
// Display_VGA (0x0300)
|
||||||
|
|
|
@ -4,10 +4,11 @@
|
||||||
* SPDX-License-Identifier: MPL-2.0
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use core::mem;
|
||||||
use core::num::TryFromIntError;
|
use core::num::TryFromIntError;
|
||||||
|
|
||||||
use x86_64::instructions::interrupts;
|
|
||||||
use x86_64::instructions::port::Port;
|
use x86_64::instructions::port::Port;
|
||||||
|
use x86_64::instructions::{hlt, interrupts};
|
||||||
use x86_64::structures::paging::{FrameAllocator, FrameDeallocator};
|
use x86_64::structures::paging::{FrameAllocator, FrameDeallocator};
|
||||||
// FIXME: platform agnostic paging stuff
|
// FIXME: platform agnostic paging stuff
|
||||||
use x86_64::structures::paging::{mapper::MapToError, Mapper, Page, PhysFrame, Size4KiB};
|
use x86_64::structures::paging::{mapper::MapToError, Mapper, Page, PhysFrame, Size4KiB};
|
||||||
|
@ -16,8 +17,11 @@ use x86_64::VirtAddr;
|
||||||
use crate::arch::memory::BootInfoFrameAllocator;
|
use crate::arch::memory::BootInfoFrameAllocator;
|
||||||
use crate::devices::pci::check_device;
|
use crate::devices::pci::check_device;
|
||||||
|
|
||||||
const PRDT_START: u64 = 0x_ffff_ffff_0000_0000;
|
use super::PciDeviceInfo;
|
||||||
const BUFFER_START: u64 = 0x_ffff_ffff_0000_1000;
|
|
||||||
|
// FIXME: un-hardcode these
|
||||||
|
const PRDT_START: u64 = 0xffff_ffff_0000_0000;
|
||||||
|
const BUFFER_START: u64 = 0xffff_ffff_0000_1000;
|
||||||
|
|
||||||
/// Bus Master IDE Command
|
/// Bus Master IDE Command
|
||||||
const BMIC_OFFSET: u16 = 0;
|
const BMIC_OFFSET: u16 = 0;
|
||||||
|
@ -38,6 +42,18 @@ const SECONDARY_COMMAND: u16 = 0x0170;
|
||||||
/// Data register offset
|
/// Data register offset
|
||||||
const DATA_OFFSET: u16 = 0;
|
const DATA_OFFSET: u16 = 0;
|
||||||
|
|
||||||
|
/// Sector count register offset
|
||||||
|
const SECCOUNT_OFFSET: u16 = 2;
|
||||||
|
|
||||||
|
/// LBA0 register offset
|
||||||
|
const LBA0_OFFSET: u16 = 3;
|
||||||
|
|
||||||
|
/// LBA1 register offset
|
||||||
|
const LBA1_OFFSET: u16 = 4;
|
||||||
|
|
||||||
|
/// LBA2 register offset
|
||||||
|
const LBA2_OFFSET: u16 = 5;
|
||||||
|
|
||||||
/// Drive/Head register offset
|
/// Drive/Head register offset
|
||||||
const DRIVE_HEAD_OFFSET: u16 = 6;
|
const DRIVE_HEAD_OFFSET: u16 = 6;
|
||||||
|
|
||||||
|
@ -56,19 +72,23 @@ const ALT_STATUS_OFFSET: u16 = 2;
|
||||||
/// ATA identification command
|
/// ATA identification command
|
||||||
const CMD_IDENTIFY: u8 = 0xEC;
|
const CMD_IDENTIFY: u8 = 0xEC;
|
||||||
|
|
||||||
pub struct Piix {
|
/// ATA read using LBA48 DMA command
|
||||||
|
const CMD_READ_DMA_EXT: u8 = 0x25;
|
||||||
|
|
||||||
|
pub struct PiixIde {
|
||||||
|
device_info: PciDeviceInfo,
|
||||||
ide_devices: Vec<IdeDevice>,
|
ide_devices: Vec<IdeDevice>,
|
||||||
prdt_frame: Option<PhysFrame>,
|
prdt_frame: Option<PhysFrame>,
|
||||||
buffer_frames: Option<Vec<PhysFrame>>,
|
buffer_frames: Option<Vec<PhysFrame>>,
|
||||||
bmiba: u16,
|
bmiba: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Piix {
|
impl PiixIde {
|
||||||
// FIXME: make this return a Result
|
// FIXME: make this return a Result
|
||||||
pub fn new(bus: u8, device: u8) -> Option<Self> {
|
pub fn new(bus: u8, device: u8) -> Option<Self> {
|
||||||
let device_info = check_device(bus, device)?;
|
let device_info = check_device(bus, device)?;
|
||||||
trace!("device_info: {device_info}");
|
device_info.enable_bus_mastering();
|
||||||
let idetim = unsafe { device_info.io_read(0, 0x40) };
|
let idetim = unsafe { device_info.read(0, 0x40) };
|
||||||
trace!("idetim: {idetim:b}");
|
trace!("idetim: {idetim:b}");
|
||||||
// FIXME: enable the right bits in idetim (and sidetim) to use fast timings
|
// FIXME: enable the right bits in idetim (and sidetim) to use fast timings
|
||||||
|
|
||||||
|
@ -160,6 +180,7 @@ impl Piix {
|
||||||
let bmiba = device_info.bar(4) & 0xFFFFFFFC;
|
let bmiba = device_info.bar(4) & 0xFFFFFFFC;
|
||||||
|
|
||||||
Some(Self {
|
Some(Self {
|
||||||
|
device_info,
|
||||||
ide_devices,
|
ide_devices,
|
||||||
prdt_frame: None,
|
prdt_frame: None,
|
||||||
buffer_frames: None,
|
buffer_frames: None,
|
||||||
|
@ -177,6 +198,7 @@ impl Piix {
|
||||||
let prdt_frame = frame_allocator
|
let prdt_frame = frame_allocator
|
||||||
.allocate_frame()
|
.allocate_frame()
|
||||||
.ok_or(MapToError::FrameAllocationFailed)?;
|
.ok_or(MapToError::FrameAllocationFailed)?;
|
||||||
|
|
||||||
let buffer_frames = {
|
let buffer_frames = {
|
||||||
let mut frame = frame_allocator
|
let mut frame = frame_allocator
|
||||||
.allocate_frame()
|
.allocate_frame()
|
||||||
|
@ -231,7 +253,7 @@ impl Piix {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&self) -> Result<(), TryFromIntError> {
|
pub fn read(&mut self) -> Result<(), TryFromIntError> {
|
||||||
// prepare PRD table
|
// prepare PRD table
|
||||||
let prd = PRDT_START as *mut PhysRegionDescriptor;
|
let prd = PRDT_START as *mut PhysRegionDescriptor;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -243,19 +265,51 @@ impl Piix {
|
||||||
(*prd).byte_count = 512;
|
(*prd).byte_count = 512;
|
||||||
// this is the end of table
|
// this is the end of table
|
||||||
(*prd).eot = 1 << 7;
|
(*prd).eot = 1 << 7;
|
||||||
|
// this byte is reserved, we should probably set it to 0
|
||||||
|
(*prd)._0 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.load_prdt(Channel::Primary);
|
self.load_prdt(Channel::Primary);
|
||||||
self.stop(Channel::Primary);
|
self.stop(Channel::Primary);
|
||||||
self.set_read(Channel::Primary);
|
self.set_read(Channel::Primary);
|
||||||
self.clear_status(Channel::Primary);
|
self.clear_bmi_status(Channel::Primary);
|
||||||
select_drive(Drive::Master, Channel::Primary);
|
select_drive(Drive::Master, Channel::Primary);
|
||||||
|
set_lba(Channel::Primary, 0, 1);
|
||||||
|
ata_send_command(CMD_READ_DMA_EXT, Channel::Primary);
|
||||||
|
self.start(Channel::Primary);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let status = self.bmi_status(Channel::Primary);
|
||||||
|
trace!("read status: 0b{status:b}");
|
||||||
|
|
||||||
|
// Bit 2 (INT) set?
|
||||||
|
if (status >> 2) & 1 == 1 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: error handling
|
||||||
|
|
||||||
|
// Stop DMA
|
||||||
|
self.stop(Channel::Primary);
|
||||||
|
|
||||||
|
// Clear the interrupt bit
|
||||||
|
self.clear_bmi_status(Channel::Primary);
|
||||||
|
|
||||||
|
for i in 0..512 {
|
||||||
|
let addr = (BUFFER_START + i) as *mut u8;
|
||||||
|
trace!("byte {i}: {}", *addr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn device_info(&self) -> PciDeviceInfo {
|
||||||
|
self.device_info
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn load_prdt(&self, channel: Channel) {
|
unsafe fn load_prdt(&self, channel: Channel) {
|
||||||
let addr = if channel.secondary() {
|
let addr = if channel.secondary() {
|
||||||
BMI_SECONDARY
|
BMI_SECONDARY
|
||||||
|
@ -273,6 +327,21 @@ impl Piix {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn start(&self, channel: Channel) {
|
||||||
|
let addr = if channel.secondary() {
|
||||||
|
BMI_SECONDARY
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
} + self.bmiba
|
||||||
|
+ BMIC_OFFSET;
|
||||||
|
let mut port: Port<u8> = Port::new(addr);
|
||||||
|
let mut bmic = port.read();
|
||||||
|
// start transfer
|
||||||
|
bmic |= 1;
|
||||||
|
// write the new bmic
|
||||||
|
port.write(bmic);
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn stop(&self, channel: Channel) {
|
unsafe fn stop(&self, channel: Channel) {
|
||||||
let addr = if channel.secondary() {
|
let addr = if channel.secondary() {
|
||||||
BMI_SECONDARY
|
BMI_SECONDARY
|
||||||
|
@ -318,7 +387,18 @@ impl Piix {
|
||||||
port.write(bmic);
|
port.write(bmic);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn clear_status(&self, channel: Channel) {
|
unsafe fn bmi_status(&self, channel: Channel) -> u8 {
|
||||||
|
let addr = if channel.secondary() {
|
||||||
|
BMI_SECONDARY
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
} + self.bmiba
|
||||||
|
+ BMIS_OFFSET;
|
||||||
|
let mut port = Port::new(addr);
|
||||||
|
port.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn clear_bmi_status(&self, channel: Channel) {
|
||||||
let addr = if channel.secondary() {
|
let addr = if channel.secondary() {
|
||||||
BMI_SECONDARY
|
BMI_SECONDARY
|
||||||
} else {
|
} else {
|
||||||
|
@ -341,14 +421,15 @@ unsafe fn select_drive(drive: Drive, channel: Channel) {
|
||||||
PRIMARY_COMMAND
|
PRIMARY_COMMAND
|
||||||
} + DRIVE_HEAD_OFFSET;
|
} + DRIVE_HEAD_OFFSET;
|
||||||
let mut port: Port<u8> = Port::new(addr);
|
let mut port: Port<u8> = Port::new(addr);
|
||||||
let mut drive_command = port.read();
|
// FIXME: CHS support
|
||||||
if drive.slave() {
|
let drive_command = if drive.slave() {
|
||||||
// mark bit 4
|
// slave & LBA
|
||||||
drive_command |= 1 << 4;
|
0b11110000
|
||||||
} else {
|
} else {
|
||||||
// clear bit 4
|
// master & LBA
|
||||||
drive_command &= !(1 << 4);
|
0b11100000
|
||||||
}
|
};
|
||||||
|
|
||||||
// write the new drive/head register
|
// write the new drive/head register
|
||||||
port.write(drive_command);
|
port.write(drive_command);
|
||||||
ata_delay(channel);
|
ata_delay(channel);
|
||||||
|
@ -361,7 +442,7 @@ unsafe fn ata_send_command(command: u8, channel: Channel) -> u8 {
|
||||||
} else {
|
} else {
|
||||||
PRIMARY_COMMAND
|
PRIMARY_COMMAND
|
||||||
} + COMMAND_STATUS_OFFSET;
|
} + COMMAND_STATUS_OFFSET;
|
||||||
let mut port: Port<u8> = Port::new(addr);
|
let mut port = Port::new(addr);
|
||||||
port.write(command);
|
port.write(command);
|
||||||
ata_delay(channel);
|
ata_delay(channel);
|
||||||
port.read()
|
port.read()
|
||||||
|
@ -380,6 +461,37 @@ unsafe fn ata_delay(channel: Channel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set LBA and sector count registers. sector_count of 0 means 65536 sectors
|
||||||
|
unsafe fn set_lba(channel: Channel, lba: u64, sector_count: u16) {
|
||||||
|
// FIXME: CHS and LBA24 support
|
||||||
|
assert!(lba < 0xFFFFFFFFFFFF);
|
||||||
|
|
||||||
|
let command_block = if channel.secondary() {
|
||||||
|
SECONDARY_COMMAND
|
||||||
|
} else {
|
||||||
|
PRIMARY_COMMAND
|
||||||
|
};
|
||||||
|
let mut seccount = Port::new(command_block + SECCOUNT_OFFSET);
|
||||||
|
let mut lba0 = Port::new(command_block + LBA0_OFFSET);
|
||||||
|
let mut lba1 = Port::new(command_block + LBA1_OFFSET);
|
||||||
|
let mut lba2 = Port::new(command_block + LBA2_OFFSET);
|
||||||
|
|
||||||
|
let lba_bytes = lba.to_le_bytes();
|
||||||
|
let sector_count_bytes = sector_count.to_le_bytes();
|
||||||
|
|
||||||
|
// write the new LBA & sector count registers
|
||||||
|
// if LBA48 {
|
||||||
|
seccount.write(sector_count_bytes[1]);
|
||||||
|
lba0.write(lba_bytes[3]);
|
||||||
|
lba1.write(lba_bytes[4]);
|
||||||
|
lba2.write(lba_bytes[5]);
|
||||||
|
// }
|
||||||
|
seccount.write(sector_count_bytes[0]);
|
||||||
|
lba0.write(lba_bytes[0]);
|
||||||
|
lba1.write(lba_bytes[1]);
|
||||||
|
lba2.write(lba_bytes[2]);
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn read_dword_buffer(port: u16, buffer: *mut u32, mut count: u32) {
|
unsafe fn read_dword_buffer(port: u16, buffer: *mut u32, mut count: u32) {
|
||||||
// FIXME: this assumes x86-64
|
// FIXME: this assumes x86-64
|
||||||
interrupts::without_interrupts(|| {
|
interrupts::without_interrupts(|| {
|
||||||
|
@ -398,6 +510,7 @@ struct IdeDevice {
|
||||||
pub channel: Channel,
|
pub channel: Channel,
|
||||||
pub drive: Drive,
|
pub drive: Drive,
|
||||||
pub size: u64, // in sectors
|
pub size: u64, // in sectors
|
||||||
|
// FIXME: model
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
use crate::arch::drivers::sysinfo::master;
|
use crate::arch::drivers::sysinfo::master;
|
||||||
use crate::arch::interrupts::{reset_pit_for_cpu, set_pit_2};
|
use crate::arch::interrupts::{reset_pit_for_cpu, set_pit_2};
|
||||||
|
use crate::devices::pci::{PciDevice, PCI_DEVICES};
|
||||||
use crate::filesystem;
|
use crate::filesystem;
|
||||||
use crate::filesystem::vfs::VFS;
|
use crate::filesystem::vfs::VFS;
|
||||||
use crate::systeminfo::{KERNEL_VERSION, RELEASE_TYPE};
|
use crate::systeminfo::{KERNEL_VERSION, RELEASE_TYPE};
|
||||||
|
@ -112,6 +113,24 @@ pub fn scratchpad() {
|
||||||
BANNER_WIDTH
|
BANNER_WIDTH
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let piix_ide_device = {
|
||||||
|
let pci_devices = PCI_DEVICES.lock();
|
||||||
|
pci_devices
|
||||||
|
.iter()
|
||||||
|
.find_map(|device_ref| {
|
||||||
|
let device = device_ref.lock();
|
||||||
|
if let PciDevice::PiixIde(_) = &*device {
|
||||||
|
Some(device_ref.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
let mut piix_ide_device = piix_ide_device.lock();
|
||||||
|
if let PciDevice::PiixIde(device) = &mut *piix_ide_device {
|
||||||
|
device.read().unwrap()
|
||||||
|
}
|
||||||
real_shell();
|
real_shell();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue