PCI driver WIP
This commit is contained in:
parent
f05cc96db1
commit
c9a4b3882c
9
Makefile
9
Makefile
|
@ -25,6 +25,7 @@ clean:
|
|||
cargo clean
|
||||
cargo clean --manifest-path libstd/Cargo.toml
|
||||
cargo clean --manifest-path init/Cargo.toml
|
||||
cargo clean --manifest-path drivers/pcid/Cargo.toml
|
||||
rm -rf build
|
||||
|
||||
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
|
||||
$(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 $@
|
||||
|
||||
$(KBUILD)/kernel: $(KBUILD)/libkernel.a
|
||||
$(LD) --gc-sections -z max-page-size=0x1000 -T arch/$(ARCH)/src/linker.ld -o $@ $<
|
||||
strip $@
|
||||
|
||||
# Userspace recipes
|
||||
$(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
|
||||
$(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
6
drivers/pcid/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "pcid"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies.syscall]
|
||||
path = "../../syscall/"
|
73
drivers/pcid/src/main.rs
Normal file
73
drivers/pcid/src/main.rs
Normal 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();
|
||||
}
|
18
drivers/pcid/src/pci/bar.rs
Normal file
18
drivers/pcid/src/pci/bar.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
46
drivers/pcid/src/pci/bus.rs
Normal file
46
drivers/pcid/src/pci/bus.rs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
50
drivers/pcid/src/pci/class.rs
Normal file
50
drivers/pcid/src/pci/class.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
46
drivers/pcid/src/pci/dev.rs
Normal file
46
drivers/pcid/src/pci/dev.rs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
30
drivers/pcid/src/pci/func.rs
Normal file
30
drivers/pcid/src/pci/func.rs
Normal 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)
|
||||
}
|
||||
}
|
43
drivers/pcid/src/pci/header.rs
Normal file
43
drivers/pcid/src/pci/header.rs
Normal 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] }
|
||||
}
|
||||
}
|
67
drivers/pcid/src/pci/mod.rs
Normal file
67
drivers/pcid/src/pci/mod.rs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,3 @@
|
|||
[package]
|
||||
name = "init"
|
||||
version = "0.1.0"
|
||||
|
||||
[[bin]]
|
||||
name = "init"
|
||||
|
|
|
@ -3,8 +3,8 @@ use std::io::{BufRead, BufReader};
|
|||
use std::thread;
|
||||
|
||||
pub fn main() {
|
||||
let mut file = File::open("initfs:etc/init.rc").expect("failed to open init.rc");
|
||||
let mut reader = BufReader::new(file);
|
||||
let file = File::open("initfs:etc/init.rc").expect("failed to open init.rc");
|
||||
let reader = BufReader::new(file);
|
||||
|
||||
for line in reader.lines() {
|
||||
println!("{}", line.expect("failed to read init.rc"));
|
||||
|
|
|
@ -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(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")
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ impl InitFsScheme {
|
|||
let mut files: BTreeMap<&'static [u8], &'static [u8]> = BTreeMap::new();
|
||||
|
||||
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");
|
||||
|
||||
InitFsScheme {
|
||||
|
|
|
@ -32,6 +32,8 @@ pub enum Call {
|
|||
GetPid = 20,
|
||||
/// Set process break
|
||||
Brk = 45,
|
||||
/// Set process I/O privilege level
|
||||
Iopl = 110,
|
||||
/// Yield to scheduler
|
||||
SchedYield = 158
|
||||
}
|
||||
|
@ -49,6 +51,7 @@ impl Call {
|
|||
11 => Ok(Call::Exec),
|
||||
20 => Ok(Call::GetPid),
|
||||
45 => Ok(Call::Brk),
|
||||
110 => Ok(Call::Iopl),
|
||||
158 => Ok(Call::SchedYield),
|
||||
_ => 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::GetPid => getpid(),
|
||||
Call::Brk => brk(b),
|
||||
Call::Iopl => iopl(b),
|
||||
Call::SchedYield => sched_yield()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,6 +105,11 @@ pub fn getpid() -> Result<usize> {
|
|||
Ok(context.id)
|
||||
}
|
||||
|
||||
pub fn iopl(_level: usize) -> Result<usize> {
|
||||
//TODO
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn sched_yield() -> Result<usize> {
|
||||
unsafe { context::switch(); }
|
||||
Ok(0)
|
||||
|
|
Loading…
Reference in a new issue