ableos/ableos/src/devices/pci/piix.rs

132 lines
3.8 KiB
Rust

use x86_64::structures::paging::{FrameAllocator, FrameDeallocator};
// FIXME: platform agnostic paging stuff
use x86_64::structures::paging::{PhysFrame, Size4KiB, mapper::MapToError, Mapper, Page};
use x86_64::VirtAddr;
use crate::arch::memory::BootInfoFrameAllocator;
use super::{PciDeviceInfo, check_device};
const PRDT_START: u64 = 0x_ffff_ffff_0000_0000;
const BUFFER_START: u64 = 0x_ffff_ffff_0000_1000;
pub struct Piix {
device_info: PciDeviceInfo,
prdt_frame: Option<PhysFrame>,
buffer_frames: Option<Vec<PhysFrame>>,
}
impl Piix {
pub fn new(bus: u8, device: u8) -> Option<Self> {
let device_info = check_device(bus, device)?;
trace!("device_info: {device_info}");
Some(Self {
device_info,
prdt_frame: None,
buffer_frames: None,
})
}
pub fn allocate_dma_frame(
&mut self,
mapper: &mut impl Mapper<Size4KiB>,
frame_allocator: &mut BootInfoFrameAllocator,
) -> Result<(), MapToError<Size4KiB>> {
use x86_64::structures::paging::PageTableFlags as Flags;
let prdt_frame = frame_allocator.allocate_frame()
.ok_or(MapToError::FrameAllocationFailed)?;
let buffer_frames = {
let mut frame = frame_allocator.allocate_frame()
.ok_or(MapToError::FrameAllocationFailed)?;
while !frame.start_address().is_aligned(0x10000u64) {
unsafe {
frame_allocator.deallocate_frame(frame);
}
frame = frame_allocator.allocate_frame()
.ok_or(MapToError::FrameAllocationFailed)?;
}
let mut frames = Vec::with_capacity(16);
frames.push(frame);
for _ in 0..15 {
let frame = frame_allocator.allocate_frame()
.ok_or(MapToError::FrameAllocationFailed)?;;
frames.push(frame);
}
frames
};
let flags = Flags::NO_CACHE | Flags::PRESENT | Flags::WRITABLE;
unsafe {
mapper.map_to(
Page::containing_address(VirtAddr::new(PRDT_START)),
prdt_frame,
flags,
frame_allocator,
)?.flush();
for (i, frame) in buffer_frames.iter().enumerate() {
mapper.map_to(
Page::containing_address(VirtAddr::new(BUFFER_START + i as u64 * 0x1000)),
*frame,
flags,
frame_allocator,
)?.flush()
}
}
trace!("prdt_frame: {prdt_frame:?}");
trace!("buffer_frames: {buffer_frames:?}");
self.prdt_frame = Some(prdt_frame);
self.buffer_frames = Some(buffer_frames);
Ok(())
}
pub fn read(&self) {
// bus master interface base address
let bmiba = self.device_info.bars[4] as *mut BusMasterInterface;
// bmiba.bmidtpp = prdt;
}
}
#[derive(Copy, Clone, Debug)]
#[repr(C, packed)]
struct BusMasterInterface {
/// Bus Master IDE Command (primary)
pub bmicp: u8,
/// Reserved
pub _0: u8,
/// Bus Master IDE Status (primary)
pub bmisp: u8,
/// Reserved
pub _1: u8,
/// Bus Master IDE Descriptor Table Pointer (primary)
pub bmidtpp: u32,
/// Bus Master IDE Command (secondary)
pub bmics: u8,
/// Reserved
pub _2: u8,
/// Bus Master IDE Status (secondary)
pub bmiss: u8,
/// Reserved
pub _3: u8,
/// Bus Master IDE Descriptor Table Pointer (secondary)
pub bmidtps: u32,
}
#[repr(C, packed)]
struct PhysRegionDescriptor {
/// Pointer to the data buffer
pub data_buffer: u32,
/// Byte count, 64K maximum per PRD transfer
pub byte_count: u16,
/// Reserved byte
pub _0: u8,
/// MSB marks end of transfer
pub eot: u8,
}