From 11c56091716b21cc04a1d30e9de03bf036c1e200 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sat, 30 Mar 2019 23:43:20 +0800 Subject: [PATCH] refactor PCI mod using pci crate --- kernel/Cargo.lock | 10 + kernel/Cargo.toml | 1 + kernel/src/drivers/bus/pci.rs | 435 ++++++++++------------------------ kernel/src/syscall/custom.rs | 4 +- 4 files changed, 139 insertions(+), 311 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index e945a93..d2dd79e 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -247,6 +247,14 @@ name = "pc-keyboard" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pci" +version = "0.0.1" +source = "git+https://github.com/rcore-os/pci-rs#30f2e83aa51dd313957f3fd6c3b233d3c905a4d0" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pulldown-cmark" version = "0.0.3" @@ -311,6 +319,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pci 0.0.1 (git+https://github.com/rcore-os/pci-rs)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)", "rcore-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)", @@ -611,6 +620,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "931fb7a4cf34610cf6cbe58d52a8ca5ef4c726d4e2e178abd0dc13a6551c6d73" "checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" "checksum pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c48392db76c4e9a69e0b3be356c5f97ebb7b14413c5e4fd0af4755dbf86e2fce" +"checksum pci 0.0.1 (git+https://github.com/rcore-os/pci-rs)" = "" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 63f4969..1665f77 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -44,6 +44,7 @@ volatile = "0.2" heapless = "0.4" console-traits = "0.3" buddy_system_allocator = "0.1" +pci = { git = "https://github.com/rcore-os/pci-rs" } device_tree = { git = "https://github.com/rcore-os/device_tree-rs" } isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers" } lazy_static = { version = "1.3", features = ["spin_no_std"] } diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index 9985d0d..c5d9661 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -1,318 +1,142 @@ -use crate::drivers::net::*; use crate::drivers::block::*; +use crate::drivers::net::*; use crate::drivers::{Driver, DRIVERS, NET_DRIVERS}; use alloc::collections::BTreeMap; use alloc::string::String; use alloc::sync::Arc; use core::cmp::Ordering; +use pci::*; use spin::Mutex; use x86_64::instructions::port::Port; -const PCI_VENDOR: u32 = 0x00; -const PCI_DEVICE: u32 = 0x02; -const PCI_COMMAND: u32 = 0x04; -const PCI_STATUS: u32 = 0x06; -const PCI_SUBCLASS: u32 = 0x0a; -const PCI_CLASS: u32 = 0x0b; -const PCI_HEADER: u32 = 0x0e; -const PCI_BAR0: u32 = 0x10; // first -const PCI_BAR5: u32 = 0x24; // last -const PCI_CAP_PTR: u32 = 0x34; -const PCI_INTERRUPT_LINE: u32 = 0x3c; -const PCI_INTERRUPT_PIN: u32 = 0x3d; - -const PCI_MSI_CTRL_CAP: u32 = 0x00; -const PCI_MSI_ADDR: u32 = 0x04; -const PCI_MSI_UPPER_ADDR: u32 = 0x08; -const PCI_MSI_DATA: u32 = 0x0C; - -const PCI_CAP_ID_MSI: u32 = 0x05; - -const PCI_ADDR_PORT: u16 = 0xcf8; -const PCI_DATA_PORT: u16 = 0xcfc; - -const PCI_BASE_ADDRESS_SPACE: u32 = 0x01; -const PCI_BASE_ADDRESS_SPACE_IO: u32 = 0x01; -const PCI_BASE_ADDRESS_SPACE_MEMORY: u32 = 0x00; - -const PCI_BASE_ADDRESS_MEM_TYPE_MASK: u32 = 0x06; -const PCI_BASE_ADDRESS_MEM_TYPE_32: u32 = 0x00; -const PCI_BASE_ADDRESS_MEM_TYPE_1M: u32 = 0x02; -const PCI_BASE_ADDRESS_MEM_TYPE_64: u32 = 0x04; -const PCI_BASE_ADDRESS_MEM_PREFETCH: u32 = 0x08; -const PCI_BASE_ADDRESS_MEM_MASK: u32 = 0xfffffff0; - -#[derive(Copy, Clone)] -pub struct PciTag(u32); - -impl Ord for PciTag { - fn cmp(&self, other: &PciTag) -> Ordering { - self.0.cmp(&other.0) - } -} - -impl PartialOrd for PciTag { - fn partial_cmp(&self, other: &PciTag) -> Option { - Some(self.cmp(other)) - } -} +const PCI_COMMAND: u16 = 0x04; +const PCI_CAP_PTR: u16 = 0x34; +const PCI_INTERRUPT_LINE: u16 = 0x3c; +const PCI_INTERRUPT_PIN: u16 = 0x3d; -impl Eq for PciTag {} +const PCI_MSI_CTRL_CAP: u16 = 0x00; +const PCI_MSI_ADDR: u16 = 0x04; +const PCI_MSI_UPPER_ADDR: u16 = 0x08; +const PCI_MSI_DATA: u16 = 0x0C; -impl PartialEq for PciTag { - fn eq(&self, other: &PciTag) -> bool { - self.0 == other.0 - } -} - -impl PciTag { - pub fn new(bus: u32, dev: u32, func: u32) -> PciTag { - assert!(bus < 256); - assert!(dev < 32); - assert!(func < 8); - PciTag(bus << 16 | dev << 11 | func << 8) - } +const PCI_CAP_ID_MSI: u8 = 0x05; - pub fn bus(&self) -> u32 { - (self.0 >> 16) & 0xFF - } +struct PortOpsImpl; - pub fn dev(&self) -> u32 { - (self.0 >> 11) & 0x1F +impl PortOps for PortOpsImpl { + unsafe fn read8(&self, port: u16) -> u8 { + Port::new(port).read() } - - pub fn func(&self) -> u32 { - (self.0 >> 8) & 0x7 + unsafe fn read16(&self, port: u16) -> u16 { + Port::new(port).read() } - - // biscuit/src/pci/pci.go Pci_read - pub unsafe fn read(&self, reg: u32, width: u32) -> u32 { - // spans in one reg - assert_eq!(reg / 4, (reg + width - 1) / 4); - - let enable = 1 << 31; - let rsh = reg % 4; - let r = reg - rsh; - let t = enable | self.0 | r; - - let mut pci_addr: Port = Port::new(PCI_ADDR_PORT); - let mut pci_data: Port = Port::new(PCI_DATA_PORT); - - pci_addr.write(t); - let d = pci_data.read(); - pci_addr.write(0); - - let ret = d >> (rsh * 8); - let m = if width < 4 { - (1 << (8 * width)) - 1 - } else { - 0xffffffff - }; - - return ret & m; + unsafe fn read32(&self, port: u16) -> u32 { + Port::new(port).read() } - - pub unsafe fn write(&self, reg: u32, val: u32) { - assert_eq!(reg & 3, 0); - - let enable = 1 << 31; - let t = enable | self.0 | reg; - - let mut pci_addr: Port = Port::new(PCI_ADDR_PORT); - let mut pci_data: Port = Port::new(PCI_DATA_PORT); - - pci_addr.write(t); - pci_data.write(val); - pci_addr.write(0); + unsafe fn write8(&self, port: u16, val: u8) { + Port::new(port).write(val); } - - // biscuit/src/pci/pci.go Pci_bar_mem - // linux/drivers/pci/probe.c pci_read_bases - // return (addr, len) - pub unsafe fn get_bar_mem(&self, bar_number: u32) -> Option<(usize, usize)> { - assert!(bar_number <= 6); - let bar = PCI_BAR0 + 4 * bar_number; - let mut base_lo = self.read(bar, 4); - self.write(bar, 0xffffffff); - let mut max_base_lo = self.read(bar, 4); - self.write(bar, base_lo); - - let mut base; - let mut max_base; - let mut address_mark; - - // memory instead of io - assert!(base_lo & PCI_BASE_ADDRESS_SPACE == PCI_BASE_ADDRESS_SPACE_MEMORY); - match base_lo & PCI_BASE_ADDRESS_MEM_TYPE_MASK { - PCI_BASE_ADDRESS_MEM_TYPE_32 => { - base = (base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize; - max_base = (max_base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize; - address_mark = PCI_BASE_ADDRESS_MEM_MASK as usize; - } - PCI_BASE_ADDRESS_MEM_TYPE_64 => { - base = (base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize; - max_base = (max_base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize; - - let base_hi = self.read(bar + 4, 4); - self.write(bar + 4, 0xffffffff); - let max_base_hi = self.read(bar + 4, 4); - self.write(bar + 4, base_hi); - base |= (base_hi as usize) << 32; - max_base |= (max_base_hi as usize) << 32; - address_mark = !0; - } - _ => unimplemented!("pci bar mem type"), - } - - if max_base == 0 { - return None; - } - - // linux/drivers/pci/probe.c pci_size - let mut size = max_base & address_mark; - if size == 0 { - return None; - } - size = (size & !(size - 1)) - 1; - - debug!( - "device memory address from {:#X} to {:#X}", - base, - base + size - ); - return Some((base as usize, size as usize)); + unsafe fn write16(&self, port: u16, val: u16) { + Port::new(port).write(val); } - - // returns a tuple of (vid, did, next) - pub fn probe(&self) -> Option<(u32, u32, bool)> { - unsafe { - // To lookup vendor and device, please see https://pci-ids.ucw.cz/read/PC/ - let v = self.read(PCI_VENDOR, 2); - if v == 0xffff { - return None; - } - let d = self.read(PCI_DEVICE, 2); - let mf = self.read(PCI_HEADER, 1); - - // To lookup class and subclass, please see https://pci-ids.ucw.cz/read/PD/ - let cl = self.read(PCI_CLASS, 1); - let scl = self.read(PCI_SUBCLASS, 1); - let line = self.read(PCI_INTERRUPT_LINE, 1); - let pin = self.read(PCI_INTERRUPT_PIN, 1); - info!( - "{:02x}:{:02x}.{}: {:#x} {:#x} ({} {}) irq {}:{}", - self.bus(), - self.dev(), - self.func(), - v, - d, - cl, - scl, - line, - pin - ); - - return Some((v, d, mf & 0x80 != 0)); - } + unsafe fn write32(&self, port: u16, val: u32) { + Port::new(port).write(val); } +} - /// Enable the pci tag and its interrupt - /// Return assigned MSI interrupt number when applicable - pub unsafe fn enable(&self) -> Option { - // 23 and lower are used - static mut MSI_IRQ: u32 = 23; - - let orig = self.read(PCI_COMMAND, 2); - // IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable - self.write(PCI_COMMAND, orig | 0x40f); - - // find MSI cap - let mut msi_found = false; - let mut cap_ptr = self.read(PCI_CAP_PTR, 1); - let mut assigned_irq = None; - while cap_ptr > 0 { - let cap_id = self.read(cap_ptr, 1); - if cap_id == PCI_CAP_ID_MSI { - // The manual Volume 3 Chapter 10.11 Message Signalled Interrupts - // 0 is (usually) the apic id of the bsp. - self.write(cap_ptr + PCI_MSI_ADDR, 0xfee00000 | (0 << 12)); - MSI_IRQ += 1; - let irq = MSI_IRQ; - assigned_irq = Some(irq); - // we offset all our irq numbers by 32 - self.write(cap_ptr + PCI_MSI_DATA, irq + 32); - - // enable MSI interrupt, assuming 64bit for now - let orig_ctrl = self.read(cap_ptr + PCI_MSI_CTRL_CAP, 4); - self.write(cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000); - debug!( - "MSI control {:#b}, enabling MSI interrupts", - orig_ctrl >> 16 - ); - msi_found = true; - break; - } - debug!( - "PCI device has cap id {} at {:#X}", - self.read(cap_ptr, 1), - cap_ptr - ); - cap_ptr = self.read(cap_ptr + 1, 1); - } - - if !msi_found { - // Use PCI legacy interrupt instead - // IO Space | MEM Space | Bus Mastering | Special Cycles - self.write(PCI_COMMAND, orig | 0xf); - let line = self.read(PCI_INTERRUPT_LINE, 1); - let pin = self.read(PCI_INTERRUPT_PIN, 1); +/// Enable the pci device and its interrupt +/// Return assigned MSI interrupt number when applicable +unsafe fn enable(loc: Location) -> Option { + let ops = &PortOpsImpl; + let am = CSpaceAccessMethod::IO; + + // 23 and lower are used + static mut MSI_IRQ: u32 = 23; + + let orig = am.read16(ops, loc, PCI_COMMAND); + // IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable + am.write32(ops, loc, PCI_COMMAND, (orig | 0x40f) as u32); + + // find MSI cap + let mut msi_found = false; + let mut cap_ptr = am.read8(ops, loc, PCI_CAP_PTR) as u16; + let mut assigned_irq = None; + while cap_ptr > 0 { + let cap_id = am.read8(ops, loc, cap_ptr); + if cap_id == PCI_CAP_ID_MSI { + // The manual Volume 3 Chapter 10.11 Message Signalled Interrupts + // 0 is (usually) the apic id of the bsp. + am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000 | (0 << 12)); + MSI_IRQ += 1; + let irq = MSI_IRQ; + assigned_irq = Some(irq); + // we offset all our irq numbers by 32 + am.write32(ops, loc, cap_ptr + PCI_MSI_DATA, irq + 32); + + // enable MSI interrupt, assuming 64bit for now + let orig_ctrl = am.read32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP); + am.write32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000); debug!( - "MSI not found, using PCI interrupt line {} pin {}", - line, pin + "MSI control {:#b}, enabling MSI interrupts", + orig_ctrl >> 16 ); + msi_found = true; + break; } + debug!("PCI device has cap id {} at {:#X}", cap_id, cap_ptr); + cap_ptr = am.read8(ops, loc, cap_ptr + 1) as u16; + } - assigned_irq + if !msi_found { + // Use PCI legacy interrupt instead + // IO Space | MEM Space | Bus Mastering | Special Cycles + am.write32(ops, loc, PCI_COMMAND, (orig | 0xf) as u32); + debug!("MSI not found, using PCI interrupt"); } + + assigned_irq } -pub fn init_driver(name: String, vid: u32, did: u32, tag: PciTag) { - if vid == 0x8086 { - if did == 0x100e || did == 0x100f || did == 0x10d3 { +pub fn init_driver(dev: &PCIDevice) { + match (dev.id.vendor_id, dev.id.device_id) { + (0x8086, 0x100e) | (0x8086, 0x100f) | (0x8086, 0x10d3) => { // 0x100e // 82540EM Gigabit Ethernet Controller // 0x100f // 82545EM Gigabit Ethernet Controller (Copper) // 0x10d3 // 82574L Gigabit Network Connection - if let Some((addr, len)) = unsafe { tag.get_bar_mem(0) } { - unsafe { - tag.enable(); - } - e1000::e1000_init(addr, len); + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { + let _ = unsafe { enable(dev.loc) }; + e1000::e1000_init(addr as usize, len as usize); } - } else if did == 0x10fb { + } + (0x8086, 0x10fb) => { // 82599ES 10-Gigabit SFI/SFP+ Network Connection - if let Some((addr, len)) = unsafe { tag.get_bar_mem(0) } { - let irq = unsafe { tag.enable() }; - PCI_DRIVERS - .lock() - .insert(tag, ixgbe::ixgbe_init(name, irq, addr, len)); + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { + let name = format!("enp{}s{}f{}", dev.loc.bus, dev.loc.device, dev.loc.function); + let irq = unsafe { enable(dev.loc) }; + PCI_DRIVERS.lock().insert( + dev.loc, + ixgbe::ixgbe_init(name, irq, addr as usize, len as usize), + ); } - } else if did == 0x2922 { + } + (0x8086, 0x2922) => { // 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode] - if let Some((addr, len)) = unsafe { tag.get_bar_mem(5) } { - let irq = unsafe { tag.enable() }; + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[5] { + let irq = unsafe { enable(dev.loc) }; PCI_DRIVERS .lock() - .insert(tag, ahci::ahci_init(irq, addr, len)); + .insert(dev.loc, ahci::ahci_init(irq, addr as usize, len as usize)); } } + _ => {} } } -pub fn detach_driver(tag: &PciTag) -> bool { - match PCI_DRIVERS.lock().remove(tag) { +pub fn detach_driver(loc: &Location) -> bool { + match PCI_DRIVERS.lock().remove(loc) { Some(driver) => { DRIVERS .write() @@ -327,51 +151,44 @@ pub fn detach_driver(tag: &PciTag) -> bool { } pub fn init() { - for bus in 0..256 { - for dev in 0..32 { - let tag = PciTag::new(bus, dev, 0); - if let Some((vid, did, next)) = tag.probe() { - let name = format!("enp{}s{}f0", bus, dev); - init_driver(name, vid, did, tag); - if next { - for func in 1..8 { - let tag = PciTag::new(bus, dev, func); - if let Some((vid, did, _)) = tag.probe() { - let name = format!("enp{}s{}f{}", bus, dev, func); - init_driver(name, vid, did, tag); - } - } - } - } - } + let mut pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) }; + for dev in pci_iter { + info!( + "pci: {:02x}:{:02x}.{} {:#x} {:#x} ({} {}) irq: {}:{:?}", + dev.loc.bus, + dev.loc.device, + dev.loc.function, + dev.id.vendor_id, + dev.id.device_id, + dev.id.class, + dev.id.subclass, + dev.pic_interrupt_line, + dev.interrupt_pin, + ); + init_driver(&dev); } } -pub fn find_device(vendor: u32, product: u32) -> Option { - for bus in 0..256 { - for dev in 0..32 { - let tag = PciTag::new(bus, dev, 0); - if let Some((vid, did, next)) = tag.probe() { - if vid == vendor && did == product { - return Some(tag); - } - if next { - for func in 1..8 { - let tag = PciTag::new(bus, dev, func); - if let Some((vid, did, _)) = tag.probe() { - if vid == vendor && did == product { - return Some(tag); - } - } - } - } - } +pub fn find_device(vendor: u16, product: u16) -> Option { + let mut pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) }; + for dev in pci_iter { + if dev.id.vendor_id == vendor && dev.id.device_id == product { + return Some(dev.loc); } } None } +pub fn get_bar0_mem(loc: Location) -> Option<(usize, usize)> { + unsafe { probe_function(&PortOpsImpl, loc, CSpaceAccessMethod::IO) } + .and_then(|dev| dev.bars[0]) + .map(|bar| match bar { + BAR::Memory(addr, len, _, _) => (addr as usize, len as usize), + _ => unimplemented!(), + }) +} + lazy_static! { - pub static ref PCI_DRIVERS: Arc>>> = - Arc::new(Mutex::new(BTreeMap::new())); + pub static ref PCI_DRIVERS: Mutex>> = + Mutex::new(BTreeMap::new()); } diff --git a/kernel/src/syscall/custom.rs b/kernel/src/syscall/custom.rs index 94ef99a..e21fa12 100644 --- a/kernel/src/syscall/custom.rs +++ b/kernel/src/syscall/custom.rs @@ -13,13 +13,13 @@ pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult { vendor, product ); - let tag = pci::find_device(vendor as u32, product as u32).ok_or(SysError::ENOENT)?; + let tag = pci::find_device(vendor as u16, product as u16).ok_or(SysError::ENOENT)?; if pci::detach_driver(&tag) { info!("Kernel driver detached"); } // Get BAR0 memory - let (base, len) = unsafe { tag.get_bar_mem(0) }.ok_or(SysError::ENOENT)?; + let (base, len) = pci::get_bar0_mem(tag).ok_or(SysError::ENOENT)?; let mut proc = process(); let virt_addr = proc.vm.find_free_area(0, len);