diff --git a/ostd/src/arch/riscv/mod.rs b/ostd/src/arch/riscv/mod.rs index 8574cdb5..b325d5db 100644 --- a/ostd/src/arch/riscv/mod.rs +++ b/ostd/src/arch/riscv/mod.rs @@ -32,6 +32,7 @@ pub(crate) unsafe fn late_init_on_bsp() { crate::boot::smp::boot_all_aps(); timer::init(); + let _ = pci::init(); } pub(crate) unsafe fn init_on_ap() { diff --git a/ostd/src/arch/riscv/pci.rs b/ostd/src/arch/riscv/pci.rs index 025e32ae..6332143f 100644 --- a/ostd/src/arch/riscv/pci.rs +++ b/ostd/src/arch/riscv/pci.rs @@ -1,8 +1,67 @@ // SPDX-License-Identifier: MPL-2.0 -//! PCI bus io port +//! PCI bus access -use super::device::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess}; +use spin::Once; -pub static PCI_ADDRESS_PORT: IoPort = unsafe { IoPort::new(0x0) }; -pub static PCI_DATA_PORT: IoPort = unsafe { IoPort::new(0x0) }; +use super::boot::DEVICE_TREE; +use crate::{bus::pci::PciDeviceLocation, io::IoMem, mm::VmIoOnce, prelude::*, Error}; + +static PCI_BASE_ADDR: Once = Once::new(); + +pub(crate) fn write32(location: &PciDeviceLocation, offset: u32, value: u32) -> Result<()> { + PCI_BASE_ADDR.get().ok_or(Error::IoError)?.write_once( + (encode_as_address_offset(location) | (offset & 0xfc)) as usize, + &value, + ) +} + +pub(crate) fn read32(location: &PciDeviceLocation, offset: u32) -> Result { + PCI_BASE_ADDR + .get() + .ok_or(Error::IoError)? + .read_once((encode_as_address_offset(location) | (offset & 0xfc)) as usize) +} + +pub(crate) fn has_pci_bus() -> bool { + PCI_BASE_ADDR.is_completed() +} + +pub(crate) fn init() -> Result<()> { + let pci = DEVICE_TREE + .get() + .unwrap() + .find_node("/soc/pci") + .ok_or(Error::IoError)?; + + let mut reg = pci.reg().ok_or(Error::IoError)?; + + let Ok(region) = reg.next() else { + warn!("PCI node should have exactly one `reg` property, but found zero `reg`s"); + return Err(Error::IoError); + }; + if reg.next().is_some() { + warn!( + "PCI node should have exactly one `reg` property, but found {} `reg`s", + reg.count() + 2 + ); + return Err(Error::IoError); + } + + PCI_BASE_ADDR.call_once(|| { + IoMem::acquire( + (region.starting_address as usize) + ..(region.starting_address as usize + region.size.unwrap()), + ) + .unwrap() + }); + + Ok(()) +} + +/// Encodes the bus, device, and function into an address offset in the PCI MMIO region. +fn encode_as_address_offset(location: &PciDeviceLocation) -> u32 { + ((location.bus as u32) << 16) + | ((location.device as u32) << 11) + | ((location.function as u32) << 8) +} diff --git a/ostd/src/arch/x86/pci.rs b/ostd/src/arch/x86/pci.rs index 00b66265..f54828d3 100644 --- a/ostd/src/arch/x86/pci.rs +++ b/ostd/src/arch/x86/pci.rs @@ -1,8 +1,35 @@ // SPDX-License-Identifier: MPL-2.0 -//! PCI bus io port +//! PCI bus access use super::device::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess}; +use crate::{bus::pci::PciDeviceLocation, prelude::*}; -pub static PCI_ADDRESS_PORT: IoPort = unsafe { IoPort::new(0x0CF8) }; -pub static PCI_DATA_PORT: IoPort = unsafe { IoPort::new(0x0CFC) }; +static PCI_ADDRESS_PORT: IoPort = unsafe { IoPort::new(0x0CF8) }; +static PCI_DATA_PORT: IoPort = unsafe { IoPort::new(0x0CFC) }; + +const BIT32_ALIGN_MASK: u32 = 0xFFFC; + +pub(crate) fn write32(location: &PciDeviceLocation, offset: u32, value: u32) -> Result<()> { + PCI_ADDRESS_PORT.write(encode_as_port(location) | (offset & BIT32_ALIGN_MASK)); + PCI_DATA_PORT.write(value.to_le()); + Ok(()) +} + +pub(crate) fn read32(location: &PciDeviceLocation, offset: u32) -> Result { + PCI_ADDRESS_PORT.write(encode_as_port(location) | (offset & BIT32_ALIGN_MASK)); + Ok(PCI_DATA_PORT.read().to_le()) +} + +pub(crate) fn has_pci_bus() -> bool { + true +} + +/// Encodes the bus, device, and function into a port address for use with the PCI I/O port. +fn encode_as_port(location: &PciDeviceLocation) -> u32 { + // 1 << 31: Configuration enable + (1 << 31) + | ((location.bus as u32) << 16) + | (((location.device as u32) & 0b11111) << 11) + | (((location.function as u32) & 0b111) << 8) +} diff --git a/ostd/src/bus/mod.rs b/ostd/src/bus/mod.rs index 58d237ee..f22a5836 100644 --- a/ostd/src/bus/mod.rs +++ b/ostd/src/bus/mod.rs @@ -16,8 +16,6 @@ pub enum BusProbeError { /// Initializes the bus pub(crate) fn init() { - #[cfg(target_arch = "x86_64")] pci::init(); - mmio::init(); } diff --git a/ostd/src/bus/pci/device_info.rs b/ostd/src/bus/pci/device_info.rs index c672e7ec..cc5d955e 100644 --- a/ostd/src/bus/pci/device_info.rs +++ b/ostd/src/bus/pci/device_info.rs @@ -5,7 +5,6 @@ use core::iter; use super::cfg_space::PciDeviceCommonCfgOffset; -use crate::arch::pci::{PCI_ADDRESS_PORT, PCI_DATA_PORT}; /// PCI device ID #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -70,15 +69,6 @@ impl PciDeviceLocation { const MAX_DEVICE: u8 = 31; const MIN_FUNCTION: u8 = 0; const MAX_FUNCTION: u8 = 7; - /// By encoding bus, device, and function into u32, user can access a PCI device in x86 by passing in this value. - #[inline(always)] - pub fn encode_as_x86_address_value(self) -> u32 { - // 1 << 31: Configuration enable - (1 << 31) - | ((self.bus as u32) << 16) - | (((self.device as u32) & 0b11111) << 11) - | (((self.function as u32) & 0b111) << 8) - } /// Returns an iterator that enumerates all possible PCI device locations. pub fn all() -> impl Iterator { @@ -130,9 +120,7 @@ impl PciDeviceLocation { (offset & 0b11) == 0, "misaligned PCI configuration dword u32 read" ); - PCI_ADDRESS_PORT - .write(self.encode_as_x86_address_value() | (offset & Self::BIT32_ALIGN_MASK) as u32); - PCI_DATA_PORT.read().to_le() + crate::arch::pci::read32(self, offset as u32).unwrap() } pub(super) fn write8(&self, offset: u16, val: u8) { @@ -160,9 +148,6 @@ impl PciDeviceLocation { (offset & 0b11) == 0, "misaligned PCI configuration dword u32 write" ); - - PCI_ADDRESS_PORT - .write(self.encode_as_x86_address_value() | (offset & Self::BIT32_ALIGN_MASK) as u32); - PCI_DATA_PORT.write(val.to_le()) + crate::arch::pci::write32(self, offset as u32, val).unwrap() } } diff --git a/ostd/src/bus/pci/mod.rs b/ostd/src/bus/pci/mod.rs index f2124521..500c5de5 100644 --- a/ostd/src/bus/pci/mod.rs +++ b/ostd/src/bus/pci/mod.rs @@ -59,12 +59,16 @@ mod device_info; pub use device_info::{PciDeviceId, PciDeviceLocation}; use self::{bus::PciBus, common_device::PciCommonDevice}; -use crate::sync::Mutex; +use crate::{arch::pci::has_pci_bus, sync::Mutex}; /// PCI bus instance pub static PCI_BUS: Mutex = Mutex::new(PciBus::new()); pub(crate) fn init() { + if !has_pci_bus() { + return; + } + let mut lock = PCI_BUS.lock(); for location in PciDeviceLocation::all() { let Some(device) = PciCommonDevice::new(location) else {