PCI driver WIP

This commit is contained in:
Jeremy Soller 2016-09-11 15:56:48 -06:00
parent f05cc96db1
commit c9a4b3882c
16 changed files with 400 additions and 7 deletions

View file

@ -25,6 +25,7 @@ clean:
cargo clean cargo clean
cargo clean --manifest-path libstd/Cargo.toml cargo clean --manifest-path libstd/Cargo.toml
cargo clean --manifest-path init/Cargo.toml cargo clean --manifest-path init/Cargo.toml
cargo clean --manifest-path drivers/pcid/Cargo.toml
rm -rf build rm -rf build
FORCE: FORCE:
@ -92,11 +93,12 @@ $(KBUILD)/librustc_unicode.rlib: rust/src/librustc_unicode/lib.rs $(KBUILD)/libc
$(KBUILD)/libcollections.rlib: rust/src/libcollections/lib.rs $(KBUILD)/libcore.rlib $(KBUILD)/liballoc.rlib $(KBUILD)/librustc_unicode.rlib $(KBUILD)/libcollections.rlib: rust/src/libcollections/lib.rs $(KBUILD)/libcore.rlib $(KBUILD)/liballoc.rlib $(KBUILD)/librustc_unicode.rlib
$(KRUSTC) $(KRUSTCFLAGS) -o $@ $< $(KRUSTC) $(KRUSTCFLAGS) -o $@ $<
$(KBUILD)/libkernel.a: $(KBUILD)/libcore.rlib $(KBUILD)/liballoc.rlib $(KBUILD)/libcollections.rlib $(BUILD)/init kernel/** FORCE $(KBUILD)/libkernel.a: kernel/** $(KBUILD)/libcore.rlib $(KBUILD)/liballoc.rlib $(KBUILD)/libcollections.rlib $(BUILD)/init $(BUILD)/pcid FORCE
$(KCARGO) rustc $(KCARGOFLAGS) -o $@ $(KCARGO) rustc $(KCARGOFLAGS) -o $@
$(KBUILD)/kernel: $(KBUILD)/libkernel.a $(KBUILD)/kernel: $(KBUILD)/libkernel.a
$(LD) --gc-sections -z max-page-size=0x1000 -T arch/$(ARCH)/src/linker.ld -o $@ $< $(LD) --gc-sections -z max-page-size=0x1000 -T arch/$(ARCH)/src/linker.ld -o $@ $<
strip $@
# Userspace recipes # Userspace recipes
$(BUILD)/libcore.rlib: rust/src/libcore/lib.rs $(BUILD)/libcore.rlib: rust/src/libcore/lib.rs
@ -121,3 +123,8 @@ $(BUILD)/libstd.rlib: libstd/Cargo.toml libstd/src/** $(BUILD)/libcore.rlib $(BU
$(BUILD)/init: init/Cargo.toml init/src/*.rs $(BUILD)/libstd.rlib $(BUILD)/init: init/Cargo.toml init/src/*.rs $(BUILD)/libstd.rlib
$(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@ $(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@
strip $@
$(BUILD)/pcid: drivers/pcid/Cargo.toml drivers/pcid/src/** $(BUILD)/libstd.rlib
$(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@
strip $@

6
drivers/pcid/Cargo.toml Normal file
View file

@ -0,0 +1,6 @@
[package]
name = "pcid"
version = "0.1.0"
[dependencies.syscall]
path = "../../syscall/"

73
drivers/pcid/src/main.rs Normal file
View file

@ -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();
}

View file

@ -0,0 +1,18 @@
#[derive(Debug)]
pub enum PciBar {
None,
Memory(u32),
Port(u16)
}
impl From<u32> 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)
}
}
}

View file

@ -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<Self::Item> {
if self.num < 32 {
let dev = PciDev {
bus: self.bus,
num: self.num as u8
};
self.num += 1;
Some(dev)
} else {
None
}
}
}

View file

@ -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<u8> 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)
}
}
}

View file

@ -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<Self::Item> {
if self.num < 8 {
let func = PciFunc {
dev: self.dev,
num: self.num as u8
};
self.num += 1;
Some(func)
} else {
None
}
}
}

View file

@ -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<PciHeader> {
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)
}
}

View file

@ -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::<PciHeader>()/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::<PciHeader>()/4) as &mut [u32] }
}
}

View file

@ -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<Self::Item> {
if self.num < 256 {
let bus = PciBus {
pci: self.pci,
num: self.num as u8
};
self.num += 1;
Some(bus)
} else {
None
}
}
}

View file

@ -1,6 +1,3 @@
[package] [package]
name = "init" name = "init"
version = "0.1.0" version = "0.1.0"
[[bin]]
name = "init"

View file

@ -3,8 +3,8 @@ use std::io::{BufRead, BufReader};
use std::thread; use std::thread;
pub fn main() { pub fn main() {
let mut file = File::open("initfs:etc/init.rc").expect("failed to open init.rc"); let file = File::open("initfs:etc/init.rc").expect("failed to open init.rc");
let mut reader = BufReader::new(file); let reader = BufReader::new(file);
for line in reader.lines() { for line in reader.lines() {
println!("{}", line.expect("failed to read init.rc")); println!("{}", line.expect("failed to read init.rc"));

View file

@ -121,7 +121,7 @@ pub extern fn userspace_init() {
assert_eq!(syscall::open(b"debug:", 0), Ok(1)); assert_eq!(syscall::open(b"debug:", 0), Ok(1));
assert_eq!(syscall::open(b"debug:", 0), Ok(2)); assert_eq!(syscall::open(b"debug:", 0), Ok(2));
syscall::exec(b"initfs:bin/init", &[]).expect("failed to execute initfs:init"); syscall::exec(b"initfs:bin/pcid", &[]).expect("failed to execute initfs:init");
panic!("initfs:init returned") panic!("initfs:init returned")
} }

View file

@ -19,6 +19,7 @@ impl InitFsScheme {
let mut files: BTreeMap<&'static [u8], &'static [u8]> = BTreeMap::new(); let mut files: BTreeMap<&'static [u8], &'static [u8]> = BTreeMap::new();
files.insert(b"bin/init", include_bytes!("../../build/userspace/init")); files.insert(b"bin/init", include_bytes!("../../build/userspace/init"));
files.insert(b"bin/pcid", include_bytes!("../../build/userspace/pcid"));
files.insert(b"etc/init.rc", b"echo testing\n"); files.insert(b"etc/init.rc", b"echo testing\n");
InitFsScheme { InitFsScheme {

View file

@ -32,6 +32,8 @@ pub enum Call {
GetPid = 20, GetPid = 20,
/// Set process break /// Set process break
Brk = 45, Brk = 45,
/// Set process I/O privilege level
Iopl = 110,
/// Yield to scheduler /// Yield to scheduler
SchedYield = 158 SchedYield = 158
} }
@ -49,6 +51,7 @@ impl Call {
11 => Ok(Call::Exec), 11 => Ok(Call::Exec),
20 => Ok(Call::GetPid), 20 => Ok(Call::GetPid),
45 => Ok(Call::Brk), 45 => Ok(Call::Brk),
110 => Ok(Call::Iopl),
158 => Ok(Call::SchedYield), 158 => Ok(Call::SchedYield),
_ => Err(Error::NoCall) _ => Err(Error::NoCall)
} }
@ -106,6 +109,7 @@ pub fn handle(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize) -> Re
Call::Exec => exec(convert_slice(b as *const u8, c)?, convert_slice(d as *const [usize; 2], e)?), Call::Exec => exec(convert_slice(b as *const u8, c)?, convert_slice(d as *const [usize; 2], e)?),
Call::GetPid => getpid(), Call::GetPid => getpid(),
Call::Brk => brk(b), Call::Brk => brk(b),
Call::Iopl => iopl(b),
Call::SchedYield => sched_yield() Call::SchedYield => sched_yield()
} }
} }

View file

@ -105,6 +105,11 @@ pub fn getpid() -> Result<usize> {
Ok(context.id) Ok(context.id)
} }
pub fn iopl(_level: usize) -> Result<usize> {
//TODO
Ok(0)
}
pub fn sched_yield() -> Result<usize> { pub fn sched_yield() -> Result<usize> {
unsafe { context::switch(); } unsafe { context::switch(); }
Ok(0) Ok(0)