diff --git a/ostd/src/arch/riscv/mod.rs b/ostd/src/arch/riscv/mod.rs index 507f60213..82b90ad85 100644 --- a/ostd/src/arch/riscv/mod.rs +++ b/ostd/src/arch/riscv/mod.rs @@ -34,12 +34,13 @@ pub(crate) unsafe fn late_init_on_bsp() { // in the boot context of the BSP, with no timer-related operations having // been performed. unsafe { timer::init() }; - let _ = pci::init(); // SAFETY: // 1. All the system device memory have been removed from the builder. // 2. RISC-V platforms do not have port I/O. unsafe { crate::io::init(io_mem_builder) }; + + 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 5d8c3aed8..c131d0e1e 100644 --- a/ostd/src/arch/riscv/pci.rs +++ b/ostd/src/arch/riscv/pci.rs @@ -6,58 +6,69 @@ use log::warn; use spin::Once; use super::boot::DEVICE_TREE; -use crate::{bus::pci::PciDeviceLocation, io::IoMem, mm::VmIoOnce, prelude::*, Error}; +use crate::{ + bus::pci::PciDeviceLocation, + io::{IoMem, IoMemAllocatorBuilder}, + mm::{CachePolicy, PageFlags, VmIoOnce}, + prelude::*, + Error, +}; -static PCI_BASE_ADDR: Once = Once::new(); +static PCI_ECAM_CFG_SPACE: Once = Once::new(); pub(crate) fn write32(location: &PciDeviceLocation, offset: u32, value: u32) -> Result<()> { - PCI_BASE_ADDR.get().ok_or(Error::IoError)?.write_once( + PCI_ECAM_CFG_SPACE.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 + PCI_ECAM_CFG_SPACE .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() + PCI_ECAM_CFG_SPACE.is_completed() } -pub(crate) fn init() -> Result<()> { - let pci = DEVICE_TREE +pub(crate) fn init() { + // We follow the Linux's PCI device tree to obtain the register information + // about the PCI bus. See also the specification at + // . + // + // TODO: Support multiple PCIe segment groups instead of assuming only one + // PCIe segment group is in use. + let Some(pci) = DEVICE_TREE .get() .unwrap() - .find_node("/soc/pci") - .ok_or(Error::IoError)?; - - let mut reg = pci.reg().ok_or(Error::IoError)?; + .find_compatible(&["pci-host-ecam-generic"]) + else { + warn!("No generic PCI host controller node found in the device tree"); + return; + }; + let Some(mut reg) = pci.reg() else { + warn!("PCI node should have exactly one `reg` property, but found zero `reg`s"); + return; + }; let Some(region) = reg.next() else { warn!("PCI node should have exactly one `reg` property, but found zero `reg`s"); - return Err(Error::IoError); + return; }; 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); + return; } - PCI_BASE_ADDR.call_once(|| { - IoMem::acquire( - (region.starting_address as usize) - ..(region.starting_address as usize + region.size.unwrap()), - ) - .unwrap() - }); - - Ok(()) + let addr_start = region.starting_address as usize; + let addr_end = addr_start.checked_add(region.size.unwrap()).unwrap(); + PCI_ECAM_CFG_SPACE.call_once(|| IoMem::acquire(addr_start..addr_end).unwrap()); } pub(crate) const MSIX_DEFAULT_MSG_ADDR: u32 = 0x2400_0000; @@ -68,7 +79,9 @@ pub(crate) fn construct_remappable_msix_address(remapping_index: u32) -> u32 { /// 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) + // We only support ECAM here for RISC-V platforms. Offsets are from + // . + ((location.bus as u32) << 20) + | ((location.device as u32) << 15) + | ((location.function as u32) << 12) }