diff --git a/Makefile b/Makefile index 18e48ab..6895056 100644 --- a/Makefile +++ b/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 $@ diff --git a/drivers/pcid/Cargo.toml b/drivers/pcid/Cargo.toml new file mode 100644 index 0000000..e6b6318 --- /dev/null +++ b/drivers/pcid/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "pcid" +version = "0.1.0" + +[dependencies.syscall] +path = "../../syscall/" diff --git a/drivers/pcid/src/main.rs b/drivers/pcid/src/main.rs new file mode 100644 index 0000000..e23df8d --- /dev/null +++ b/drivers/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/drivers/pcid/src/pci/bar.rs b/drivers/pcid/src/pci/bar.rs new file mode 100644 index 0000000..190fa05 --- /dev/null +++ b/drivers/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/drivers/pcid/src/pci/bus.rs b/drivers/pcid/src/pci/bus.rs new file mode 100644 index 0000000..120fa45 --- /dev/null +++ b/drivers/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/drivers/pcid/src/pci/class.rs b/drivers/pcid/src/pci/class.rs new file mode 100644 index 0000000..21f7f69 --- /dev/null +++ b/drivers/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/drivers/pcid/src/pci/dev.rs b/drivers/pcid/src/pci/dev.rs new file mode 100644 index 0000000..0508888 --- /dev/null +++ b/drivers/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/drivers/pcid/src/pci/func.rs b/drivers/pcid/src/pci/func.rs new file mode 100644 index 0000000..578e5c6 --- /dev/null +++ b/drivers/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/drivers/pcid/src/pci/header.rs b/drivers/pcid/src/pci/header.rs new file mode 100644 index 0000000..2cc335e --- /dev/null +++ b/drivers/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/drivers/pcid/src/pci/mod.rs b/drivers/pcid/src/pci/mod.rs new file mode 100644 index 0000000..0d760ef --- /dev/null +++ b/drivers/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 + } + } +} diff --git a/init/Cargo.toml b/init/Cargo.toml index cc77b50..cd1a1ed 100644 --- a/init/Cargo.toml +++ b/init/Cargo.toml @@ -1,6 +1,3 @@ [package] name = "init" version = "0.1.0" - -[[bin]] -name = "init" diff --git a/init/src/main.rs b/init/src/main.rs index 48b1c76..899d587 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -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")); diff --git a/kernel/lib.rs b/kernel/lib.rs index e32d088..c26a057 100644 --- a/kernel/lib.rs +++ b/kernel/lib.rs @@ -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") } diff --git a/kernel/scheme/initfs.rs b/kernel/scheme/initfs.rs index 38fefc4..cedca68 100644 --- a/kernel/scheme/initfs.rs +++ b/kernel/scheme/initfs.rs @@ -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 { diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index 91f4388..7d05149 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -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() } } diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index f357d36..452edc2 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -105,6 +105,11 @@ pub fn getpid() -> Result { Ok(context.id) } +pub fn iopl(_level: usize) -> Result { + //TODO + Ok(0) +} + pub fn sched_yield() -> Result { unsafe { context::switch(); } Ok(0)