commit 4b3bc6ac114b7964fd073d4b2f7d3f7edce339e3 Author: Jeremy Soller Date: Sun Sep 11 15:56:48 2016 -0600 PCI driver WIP diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml new file mode 100644 index 0000000000..e6b63183f3 --- /dev/null +++ b/pcid/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "pcid" +version = "0.1.0" + +[dependencies.syscall] +path = "../../syscall/" diff --git a/pcid/src/main.rs b/pcid/src/main.rs new file mode 100644 index 0000000000..e23df8da6b --- /dev/null +++ b/pcid/src/main.rs @@ -0,0 +1,73 @@ +#![feature(asm)] + +extern crate syscall; + +use syscall::iopl; + +use pci::{Pci, PciBar, PciClass}; + +mod pci; + +fn enumerate_pci() { + println!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV"); + + let pci = Pci::new(); + for bus in pci.buses() { + for dev in bus.devs() { + for func in dev.funcs() { + if let Some(header) = func.header() { + println!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", + bus.num, dev.num, func.num, + header.vendor_id, header.device_id, + header.class, header.subclass, header.interface, header.revision, + PciClass::from(header.class)); + + for i in 0..header.bars.len() { + match PciBar::from(header.bars[i]) { + PciBar::None => (), + PciBar::Memory(address) => println!(" BAR {} {:>08X}", i, address), + PciBar::Port(address) => println!(" BAR {} {:>04X}", i, address) + } + } + + match PciClass::from(header.class) { + PciClass::Storage => match header.subclass { + 0x01 => { + println!(" + IDE"); + }, + 0x06 => { + println!(" + SATA"); + }, + _ => () + }, + PciClass::SerialBus => match header.subclass { + 0x03 => match header.interface { + 0x00 => { + println!(" + UHCI"); + }, + 0x10 => { + println!(" + OHCI"); + }, + 0x20 => { + println!(" + EHCI"); + }, + 0x30 => { + println!(" + XHCI"); + }, + _ => () + }, + _ => () + }, + _ => () + } + } + } + } + } +} + +fn main() { + unsafe { iopl(3).unwrap() }; + + enumerate_pci(); +} diff --git a/pcid/src/pci/bar.rs b/pcid/src/pci/bar.rs new file mode 100644 index 0000000000..190fa05d2d --- /dev/null +++ b/pcid/src/pci/bar.rs @@ -0,0 +1,18 @@ +#[derive(Debug)] +pub enum PciBar { + None, + Memory(u32), + Port(u16) +} + +impl From for PciBar { + fn from(bar: u32) -> Self { + if bar & 0xFFFFFFFC == 0 { + PciBar::None + } else if bar & 1 == 0 { + PciBar::Memory(bar & 0xFFFFFFF0) + } else { + PciBar::Port((bar & 0xFFFC) as u16) + } + } +} diff --git a/pcid/src/pci/bus.rs b/pcid/src/pci/bus.rs new file mode 100644 index 0000000000..120fa458f9 --- /dev/null +++ b/pcid/src/pci/bus.rs @@ -0,0 +1,46 @@ +use super::{Pci, PciDev}; + +pub struct PciBus<'pci> { + pub pci: &'pci Pci, + pub num: u8 +} + +impl<'pci> PciBus<'pci> { + pub fn devs(&'pci self) -> PciBusIter<'pci> { + PciBusIter::new(self) + } + + pub unsafe fn read(&self, dev: u8, func: u8, offset: u8) -> u32 { + self.pci.read(self.num, dev, func, offset) + } +} + +pub struct PciBusIter<'pci> { + bus: &'pci PciBus<'pci>, + num: u32 +} + +impl<'pci> PciBusIter<'pci> { + pub fn new(bus: &'pci PciBus<'pci>) -> Self { + PciBusIter { + bus: bus, + num: 0 + } + } +} + +impl<'pci> Iterator for PciBusIter<'pci> { + type Item = PciDev<'pci>; + fn next(&mut self) -> Option { + if self.num < 32 { + let dev = PciDev { + bus: self.bus, + num: self.num as u8 + }; + self.num += 1; + Some(dev) + } else { + None + } + } +} diff --git a/pcid/src/pci/class.rs b/pcid/src/pci/class.rs new file mode 100644 index 0000000000..21f7f69bbe --- /dev/null +++ b/pcid/src/pci/class.rs @@ -0,0 +1,50 @@ +#[derive(Debug)] +pub enum PciClass { + Legacy, + Storage, + Network, + Display, + Multimedia, + Memory, + Bridge, + SimpleComms, + Peripheral, + Input, + Docking, + Processor, + SerialBus, + Wireless, + IntelligentIo, + SatelliteComms, + Cryptography, + SignalProc, + Reserved(u8), + Unknown +} + +impl From for PciClass { + fn from(class: u8) -> PciClass { + match class { + 0x00 => PciClass::Legacy, + 0x01 => PciClass::Storage, + 0x02 => PciClass::Network, + 0x03 => PciClass::Display, + 0x04 => PciClass::Multimedia, + 0x05 => PciClass::Memory, + 0x06 => PciClass::Bridge, + 0x07 => PciClass::SimpleComms, + 0x08 => PciClass::Peripheral, + 0x09 => PciClass::Input, + 0x0A => PciClass::Docking, + 0x0B => PciClass::Processor, + 0x0C => PciClass::SerialBus, + 0x0D => PciClass::Wireless, + 0x0E => PciClass::IntelligentIo, + 0x0F => PciClass::SatelliteComms, + 0x10 => PciClass::Cryptography, + 0x11 => PciClass::SignalProc, + 0xFF => PciClass::Unknown, + reserved => PciClass::Reserved(reserved) + } + } +} diff --git a/pcid/src/pci/dev.rs b/pcid/src/pci/dev.rs new file mode 100644 index 0000000000..05088886e8 --- /dev/null +++ b/pcid/src/pci/dev.rs @@ -0,0 +1,46 @@ +use super::{PciBus, PciFunc}; + +pub struct PciDev<'pci> { + pub bus: &'pci PciBus<'pci>, + pub num: u8 +} + +impl<'pci> PciDev<'pci> { + pub fn funcs(&'pci self) -> PciDevIter<'pci> { + PciDevIter::new(self) + } + + pub unsafe fn read(&self, func: u8, offset: u8) -> u32 { + self.bus.read(self.num, func, offset) + } +} + +pub struct PciDevIter<'pci> { + dev: &'pci PciDev<'pci>, + num: u32 +} + +impl<'pci> PciDevIter<'pci> { + pub fn new(dev: &'pci PciDev<'pci>) -> Self { + PciDevIter { + dev: dev, + num: 0 + } + } +} + +impl<'pci> Iterator for PciDevIter<'pci> { + type Item = PciFunc<'pci>; + fn next(&mut self) -> Option { + if self.num < 8 { + let func = PciFunc { + dev: self.dev, + num: self.num as u8 + }; + self.num += 1; + Some(func) + } else { + None + } + } +} diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs new file mode 100644 index 0000000000..578e5c61be --- /dev/null +++ b/pcid/src/pci/func.rs @@ -0,0 +1,30 @@ +use std::ops::DerefMut; + +use super::{PciDev, PciHeader}; + +pub struct PciFunc<'pci> { + pub dev: &'pci PciDev<'pci>, + pub num: u8 +} + +impl<'pci> PciFunc<'pci> { + pub fn header(&self) -> Option { + if unsafe { self.read(0) } != 0xFFFFFFFF { + let mut header = PciHeader::default(); + { + let dwords = header.deref_mut(); + dwords.iter_mut().fold(0usize, |offset, dword| { + *dword = unsafe { self.read(offset as u8) }; + offset + 4 + }); + } + Some(header) + } else { + None + } + } + + pub unsafe fn read(&self, offset: u8) -> u32 { + self.dev.read(self.num, offset) + } +} diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs new file mode 100644 index 0000000000..2cc335e388 --- /dev/null +++ b/pcid/src/pci/header.rs @@ -0,0 +1,43 @@ +use std::ops::{Deref, DerefMut}; +use std::{slice, mem}; + +#[derive(Debug, Default)] +#[repr(packed)] +pub struct PciHeader { + pub vendor_id: u16, + pub device_id: u16, + pub command: u16, + pub status: u16, + pub revision: u8, + pub interface: u8, + pub subclass: u8, + pub class: u8, + pub cache_line_size: u8, + pub latency_timer: u8, + pub header_type: u8, + pub bist: u8, + pub bars: [u32; 6], + pub cardbus_cis_ptr: u32, + pub subsystem_vendor_id: u16, + pub subsystem_id: u16, + pub expansion_rom_bar: u32, + pub capabilities: u8, + pub reserved: [u8; 7], + pub interrupt_line: u8, + pub interrupt_pin: u8, + pub min_grant: u8, + pub max_latency: u8 +} + +impl Deref for PciHeader { + type Target = [u32]; + fn deref(&self) -> &[u32] { + unsafe { slice::from_raw_parts(self as *const PciHeader as *const u32, mem::size_of::()/4) as &[u32] } + } +} + +impl DerefMut for PciHeader { + fn deref_mut(&mut self) -> &mut [u32] { + unsafe { slice::from_raw_parts_mut(self as *mut PciHeader as *mut u32, mem::size_of::()/4) as &mut [u32] } + } +} diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs new file mode 100644 index 0000000000..0d760ef446 --- /dev/null +++ b/pcid/src/pci/mod.rs @@ -0,0 +1,67 @@ +pub use self::bar::PciBar; +pub use self::bus::{PciBus, PciBusIter}; +pub use self::class::PciClass; +pub use self::dev::{PciDev, PciDevIter}; +pub use self::func::PciFunc; +pub use self::header::PciHeader; + +mod bar; +mod bus; +mod class; +mod dev; +mod func; +mod header; + +pub struct Pci; + +impl Pci { + pub fn new() -> Self { + Pci + } + + pub fn buses<'pci>(&'pci self) -> PciIter<'pci> { + PciIter::new(self) + } + + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + pub unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 { + let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC); + let value: u32; + asm!("mov dx, 0xCF8 + out dx, eax + mov dx, 0xCFC + in eax, dx" + : "={eax}"(value) : "{eax}"(address) : "dx" : "intel", "volatile"); + value + } +} + +pub struct PciIter<'pci> { + pci: &'pci Pci, + num: u32 +} + +impl<'pci> PciIter<'pci> { + pub fn new(pci: &'pci Pci) -> Self { + PciIter { + pci: pci, + num: 0 + } + } +} + +impl<'pci> Iterator for PciIter<'pci> { + type Item = PciBus<'pci>; + fn next(&mut self) -> Option { + if self.num < 256 { + let bus = PciBus { + pci: self.pci, + num: self.num as u8 + }; + self.num += 1; + Some(bus) + } else { + None + } + } +}