From 3ae815c56ff353ab3963081d9d7ee1949e9e8093 Mon Sep 17 00:00:00 2001 From: longjin Date: Sat, 20 Apr 2024 12:25:52 +0000 Subject: [PATCH] =?UTF-8?q?pci:=20=E6=B7=BB=E5=8A=A0pci=20root=20manager?= =?UTF-8?q?=E6=9D=A5=E7=AE=A1=E7=90=86pci=20root.=20pci:=20=E4=BD=BF?= =?UTF-8?q?=E5=BE=97riscv=E8=83=BD=E5=A4=9F=E6=AD=A3=E5=B8=B8=E6=89=AB?= =?UTF-8?q?=E6=8F=8Fpci=E8=AE=BE=E5=A4=87.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/arch/mod.rs | 6 +- kernel/src/arch/riscv64/pci/mod.rs | 29 ++- kernel/src/arch/riscv64/pci/pci_host_ecam.rs | 75 ++++++ kernel/src/arch/x86_64/init/mod.rs | 3 - kernel/src/arch/x86_64/pci/pci.rs | 53 ++-- kernel/src/driver/net/e1000e/e1000e.rs | 5 - kernel/src/driver/open_firmware/fdt.rs | 14 + kernel/src/driver/pci/ecam.rs | 71 +++++ kernel/src/driver/pci/mod.rs | 2 + kernel/src/driver/pci/pci.rs | 167 +----------- kernel/src/driver/pci/pci_irq.rs | 3 +- kernel/src/driver/pci/root.rs | 256 +++++++++++++++++++ kernel/src/driver/virtio/transport_pci.rs | 3 +- kernel/src/mm/mmio_buddy.rs | 5 +- kernel/src/mm/page.rs | 3 + kernel/src/syscall/mod.rs | 9 +- 16 files changed, 490 insertions(+), 214 deletions(-) create mode 100644 kernel/src/arch/riscv64/pci/pci_host_ecam.rs create mode 100644 kernel/src/driver/pci/ecam.rs create mode 100644 kernel/src/driver/pci/root.rs diff --git a/kernel/src/arch/mod.rs b/kernel/src/arch/mod.rs index cc6469ec1..4deb88437 100644 --- a/kernel/src/arch/mod.rs +++ b/kernel/src/arch/mod.rs @@ -1,5 +1,5 @@ use crate::{ - driver::pci::pci::{BusDeviceFunction, PciAddr, PciError, PciRoot, SegmentGroupNumber}, + driver::pci::pci::{BusDeviceFunction, PciAddr}, mm::PhysAddr, }; @@ -31,8 +31,4 @@ pub trait TraitPciArch { /// @param address PCI域地址 /// @return usize 转换结果 fn address_pci_to_physical(pci_address: PciAddr) -> PhysAddr; - /// @brief 获取Segement的root地址,x86_64架构为acpi mcfg表中读取 - /// @param segement 组id - /// @return Result 转换结果或出错原因 - fn ecam_root(segement: SegmentGroupNumber) -> Result; } diff --git a/kernel/src/arch/riscv64/pci/mod.rs b/kernel/src/arch/riscv64/pci/mod.rs index bd8bff385..43245143d 100644 --- a/kernel/src/arch/riscv64/pci/mod.rs +++ b/kernel/src/arch/riscv64/pci/mod.rs @@ -1,8 +1,21 @@ +use system_error::SystemError; +use unified_init::macros::unified_init; + use crate::{ arch::TraitPciArch, - driver::pci::pci::{BusDeviceFunction, PciAddr, PciError, PciRoot, SegmentGroupNumber}, + driver::{ + open_firmware::fdt::open_firmware_fdt_driver, + pci::pci::{pci_init, BusDeviceFunction, PciAddr, PciError, SegmentGroupNumber}, + }, + init::{boot_params, initcall::INITCALL_SUBSYS}, + kwarn, + mm::PhysAddr, }; +use self::pci_host_ecam::pci_host_ecam_driver_init; + +mod pci_host_ecam; + pub struct RiscV64PciArch; impl TraitPciArch for RiscV64PciArch { fn read_config(bus_device_function: &BusDeviceFunction, offset: u8) -> u32 { @@ -14,10 +27,16 @@ impl TraitPciArch for RiscV64PciArch { } fn address_pci_to_physical(pci_address: PciAddr) -> crate::mm::PhysAddr { - unimplemented!("RiscV64PciArch::address_pci_to_physical") + return PhysAddr::new(pci_address.data()); } +} - fn ecam_root(segement: SegmentGroupNumber) -> Result { - unimplemented!("RiscV64PciArch::ecam_root") - } +#[unified_init(INITCALL_SUBSYS)] +fn riscv_pci_init() -> Result<(), SystemError> { + let fdt = open_firmware_fdt_driver().fdt_ref()?; + + pci_host_ecam_driver_init(&fdt)?; + pci_init(); + + return Ok(()); } diff --git a/kernel/src/arch/riscv64/pci/pci_host_ecam.rs b/kernel/src/arch/riscv64/pci/pci_host_ecam.rs new file mode 100644 index 000000000..7c38057fd --- /dev/null +++ b/kernel/src/arch/riscv64/pci/pci_host_ecam.rs @@ -0,0 +1,75 @@ +use fdt::{node::FdtNode, Fdt}; +use system_error::SystemError; + +use crate::{ + driver::{ + open_firmware::fdt::open_firmware_fdt_driver, + pci::ecam::{pci_ecam_root_info_manager, EcamRootInfo}, + }, + kdebug, + mm::PhysAddr, +}; + +// static PCI_ECAM_HOST + +pub(super) fn pci_host_ecam_driver_init(fdt: &Fdt<'_>) -> Result<(), SystemError> { + let do_check = |node: FdtNode| -> Result<(), SystemError> { + let reg = node + .reg() + .ok_or(SystemError::EINVAL)? + .next() + .ok_or(SystemError::EINVAL)?; + let paddr = reg.starting_address as usize; + let size = reg.size.unwrap_or(0); + let bus_range: &[u8] = node.property("bus-range").ok_or(SystemError::EINVAL)?.value; + + let (bus_begin, bus_end) = match bus_range.len() { + 8 => ( + u32::from_be_bytes(bus_range[0..4].try_into().unwrap()), + u32::from_be_bytes(bus_range[4..8].try_into().unwrap()), + ), + _ => panic!("Unexpected bus-range length"), + }; + + let segement_group_number: &[u8] = node + .property("linux,pci-domain") + .ok_or(SystemError::EINVAL)? + .value; + + let segement_group_number = match segement_group_number.len() { + 4 => u32::from_be_bytes(segement_group_number[0..4].try_into().unwrap()), + _ => panic!("Unexpected linux,pci-domain length"), + }; + + kdebug!( + "pci_host_ecam_driver_init(): {} paddr: {:#x} size: {:#x} bus-range: {}-{} segement_group_number: {}", + node.name, + paddr, + size, + bus_begin, + bus_end, + segement_group_number + ); + + pci_ecam_root_info_manager().add_ecam_root_info(EcamRootInfo::new( + segement_group_number.try_into().unwrap(), + bus_begin as u8, + bus_end as u8, + PhysAddr::new(paddr), + )); + + Ok(()) + }; + + for node in open_firmware_fdt_driver().find_node_by_compatible(&fdt, "pci-host-ecam-generic") { + if let Err(err) = do_check(node) { + kdebug!( + "pci_host_ecam_driver_init(): check {} error: {:?}", + node.name, + err + ); + } + } + + return Ok(()); +} diff --git a/kernel/src/arch/x86_64/init/mod.rs b/kernel/src/arch/x86_64/init/mod.rs index 5a2deef0f..fb6250a5f 100644 --- a/kernel/src/arch/x86_64/init/mod.rs +++ b/kernel/src/arch/x86_64/init/mod.rs @@ -5,7 +5,6 @@ use x86::dtables::DescriptorTablePointer; use crate::{ arch::{interrupt::trap::arch_trap_init, process::table::TSSManager}, - driver::pci::pci::pci_init, init::init::start_kernel, kdebug, mm::{MemoryManagementArch, PhysAddr}, @@ -88,8 +87,6 @@ pub fn early_setup_arch() -> Result<(), SystemError> { /// 架构相关的初始化 #[inline(never)] pub fn setup_arch() -> Result<(), SystemError> { - // todo: 将来pci接入设备驱动模型之后,删掉这里。 - pci_init(); return Ok(()); } diff --git a/kernel/src/arch/x86_64/pci/pci.rs b/kernel/src/arch/x86_64/pci/pci.rs index a3a6df994..7a1d47950 100644 --- a/kernel/src/arch/x86_64/pci/pci.rs +++ b/kernel/src/arch/x86_64/pci/pci.rs @@ -1,13 +1,17 @@ use crate::arch::TraitPciArch; use crate::driver::acpi::acpi_manager; +use crate::driver::pci::ecam::{pci_ecam_root_info_manager, EcamRootInfo}; use crate::driver::pci::pci::{ - BusDeviceFunction, PciAddr, PciCam, PciError, PciRoot, SegmentGroupNumber, - PORT_PCI_CONFIG_ADDRESS, PORT_PCI_CONFIG_DATA, + pci_init, BusDeviceFunction, PciAddr, PciError, PORT_PCI_CONFIG_ADDRESS, PORT_PCI_CONFIG_DATA, }; use crate::include::bindings::bindings::{io_in32, io_out32}; +use crate::init::initcall::INITCALL_SUBSYS; +use crate::kerror; use crate::mm::PhysAddr; use acpi::mcfg::Mcfg; +use system_error::SystemError; +use unified_init::macros::unified_init; pub struct X86_64PciArch; impl TraitPciArch for X86_64PciArch { @@ -42,25 +46,32 @@ impl TraitPciArch for X86_64PciArch { fn address_pci_to_physical(pci_address: PciAddr) -> PhysAddr { return PhysAddr::new(pci_address.data()); } +} - fn ecam_root(segement: SegmentGroupNumber) -> Result { - let mcfg = acpi_manager() - .tables() - .expect("get acpi_manager table error") - .find_table::() - .map_err(|_| PciError::McfgTableNotFound)?; - for mcfg_entry in mcfg.entries() { - if mcfg_entry.pci_segment_group == segement { - return Ok(PciRoot { - physical_address_base: PhysAddr::new(mcfg_entry.base_address as usize), - mmio_guard: None, - segement_group_number: segement, - bus_begin: mcfg_entry.bus_number_start, - bus_end: mcfg_entry.bus_number_end, - cam: PciCam::Ecam, - }); - } - } - return Err(PciError::SegmentNotFound); +#[unified_init(INITCALL_SUBSYS)] +fn x86_64_pci_init() -> Result<(), SystemError> { + if let Err(e) = discover_ecam_root() { + kerror!("x86_64_pci_init(): discover_ecam_root error: {:?}", e); } + pci_init(); + + return Ok(()); +} + +fn discover_ecam_root() -> Result<(), PciError> { + let mcfg = acpi_manager() + .tables() + .expect("get acpi_manager table error") + .find_table::() + .map_err(|_| PciError::McfgTableNotFound)?; + for mcfg_entry in mcfg.entries() { + pci_ecam_root_info_manager().add_ecam_root_info(EcamRootInfo::new( + mcfg_entry.pci_segment_group, + mcfg_entry.bus_number_start, + mcfg_entry.bus_number_end, + PhysAddr::new(mcfg_entry.base_address as usize), + )); + } + + Ok(()) } diff --git a/kernel/src/driver/net/e1000e/e1000e.rs b/kernel/src/driver/net/e1000e/e1000e.rs index fc2cc5172..c2a27806d 100644 --- a/kernel/src/driver/net/e1000e/e1000e.rs +++ b/kernel/src/driver/net/e1000e/e1000e.rs @@ -587,11 +587,6 @@ impl Drop for E1000EDevice { } } -#[no_mangle] -pub extern "C" fn rs_e1000e_init() { - e1000e_init(); -} - pub fn e1000e_init() { match e1000e_probe() { Ok(_code) => { diff --git a/kernel/src/driver/open_firmware/fdt.rs b/kernel/src/driver/open_firmware/fdt.rs index b7014ff34..c1f59276c 100644 --- a/kernel/src/driver/open_firmware/fdt.rs +++ b/kernel/src/driver/open_firmware/fdt.rs @@ -381,6 +381,20 @@ impl OpenFirmwareFdtDriver { return mem_block_manager().reserve_block(base, size); } + + pub fn find_node_by_compatible<'b>( + &self, + fdt: &'b Fdt<'b>, + compatible: &'b str, + ) -> impl Iterator> + 'b { + // compatible = compatible.trim(); + let r = fdt.all_nodes().filter(move |x| { + x.compatible() + .is_some_and(|x| x.all().any(|x| x == compatible)) + }); + + return r; + } } #[allow(dead_code)] diff --git a/kernel/src/driver/pci/ecam.rs b/kernel/src/driver/pci/ecam.rs new file mode 100644 index 000000000..de1529c9c --- /dev/null +++ b/kernel/src/driver/pci/ecam.rs @@ -0,0 +1,71 @@ +use crate::mm::PhysAddr; + +use super::{ + pci::{PciCam, SegmentGroupNumber}, + root::{pci_root_manager, PciRoot}, +}; + +#[inline(always)] +pub fn pci_ecam_root_info_manager() -> &'static EcamRootInfoManager { + &EcamRootInfoManager +} + +/// Ecam pci root info +#[derive(Clone, Copy)] +pub struct EcamRootInfo { + pub segement_group_number: SegmentGroupNumber, + pub bus_begin: u8, + pub bus_end: u8, + pub physical_address_base: PhysAddr, +} + +impl EcamRootInfo { + pub fn new( + segement_group_number: SegmentGroupNumber, + bus_begin: u8, + bus_end: u8, + physical_address_base: PhysAddr, + ) -> Self { + Self { + segement_group_number, + bus_begin, + bus_end, + physical_address_base, + } + } +} + +pub struct EcamRootInfoManager; + +impl EcamRootInfoManager { + /// # add_ecam_root_info - 向EcamRootInfoManager添加EcamRootInfo + /// + /// 将一个新的EcamRootInfo添加到EcamRootInfoManager中。 + /// + /// ## 参数 + /// + /// - `ecam_root_info`: EcamRootInfo - 要添加的EcamRootInfo实例 + pub fn add_ecam_root_info(&self, ecam_root_info: EcamRootInfo) { + if !pci_root_manager().has_root(ecam_root_info.segement_group_number) { + let root = PciRoot::new( + ecam_root_info.segement_group_number, + PciCam::Ecam, + ecam_root_info.physical_address_base, + ecam_root_info.bus_begin, + ecam_root_info.bus_end, + ); + + if let Err(err) = root { + kerror!("add_ecam_root_info(): failed to create PciRoot: {:?}", err); + return; + } + + pci_root_manager().add_pci_root(root.unwrap()); + } else { + kwarn!( + "add_ecam_root_info(): root {} already exists", + ecam_root_info.segement_group_number + ); + } + } +} diff --git a/kernel/src/driver/pci/mod.rs b/kernel/src/driver/pci/mod.rs index da14fd1ff..9973b1225 100644 --- a/kernel/src/driver/pci/mod.rs +++ b/kernel/src/driver/pci/mod.rs @@ -1,3 +1,5 @@ +pub mod ecam; #[allow(clippy::module_inception)] pub mod pci; pub mod pci_irq; +pub mod root; diff --git a/kernel/src/driver/pci/pci.rs b/kernel/src/driver/pci/pci.rs index 82404f5de..2e6cb53c3 100644 --- a/kernel/src/driver/pci/pci.rs +++ b/kernel/src/driver/pci/pci.rs @@ -2,14 +2,14 @@ // 目前仅支持单主桥单Segment use super::pci_irq::{IrqType, PciIrqError}; +use super::root::{pci_root_0, PciRoot}; use crate::arch::{PciArch, TraitPciArch}; use crate::exception::IrqNumber; -use crate::include::bindings::bindings::PAGE_2M_SIZE; use crate::libs::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use crate::mm::mmio_buddy::{mmio_pool, MMIOSpaceGuard}; -use crate::mm::{PhysAddr, VirtAddr}; +use crate::mm::VirtAddr; use crate::{kdebug, kerror, kinfo, kwarn}; use alloc::sync::Arc; use alloc::vec::Vec; @@ -21,23 +21,8 @@ use core::{ fmt::{self, Debug, Display, Formatter}, }; // PCI_DEVICE_LINKEDLIST 添加了读写锁的全局链表,里面存储了检索到的PCI设备结构体 -// PCI_ROOT_0 Segment为0的全局PciRoot lazy_static! { pub static ref PCI_DEVICE_LINKEDLIST: PciDeviceLinkedList = PciDeviceLinkedList::new(); - pub static ref PCI_ROOT_0: Option = { - match PciRoot::new(0, PciCam::Ecam) { - Ok(root) => Some(root), - Err(err) => { - kerror!("Pci_root init failed because of error: {}", err); - None - } - } - }; -} - -#[inline(always)] -pub fn pci_root_0() -> &'static PciRoot { - PCI_ROOT_0.as_ref().unwrap() } /// PCI域地址 @@ -600,18 +585,6 @@ impl PciDeviceStructure for PciDeviceStructurePciToCardbusBridge { } } -/// 代表一个PCI segement greoup. -#[derive(Clone, Debug)] -pub struct PciRoot { - pub physical_address_base: PhysAddr, //物理地址,acpi获取 - pub mmio_guard: Option>, //映射后的虚拟地址,为方便访问数据这里转化成指针 - pub segement_group_number: SegmentGroupNumber, //segement greoup的id - pub bus_begin: u8, //该分组中的最小bus - pub bus_end: u8, //该分组中的最大bus - /// 配置空间访问机制 - pub cam: PciCam, -} - /// PCI配置空间访问机制 /// /// 用于访问PCI设备的功能配置空间的一组机制。 @@ -637,142 +610,6 @@ impl PciCam { } } -///线程间共享需要,该结构体只需要在初始化时写入数据,无需读写锁保证线程安全 -unsafe impl Send for PciRoot {} -unsafe impl Sync for PciRoot {} -///实现PciRoot的Display trait,自定义输出 -impl Display for PciRoot { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!( - f, - "PCI Root with segement:{}, bus begin at {}, bus end at {}, physical address at {:?},mapped at {:?}", - self.segement_group_number, self.bus_begin, self.bus_end, self.physical_address_base, self.mmio_guard - ) - } -} - -impl PciRoot { - /// 此函数用于初始化一个PciRoot结构体实例, - /// 该结构体基于ECAM根的物理地址,将其映射到虚拟地址 - /// - /// ## 参数 - /// - /// - segment_group_number: ECAM根的段组号。 - /// - cam: PCI配置空间访问机制 - /// - /// ## 返回值 - /// - /// - Ok(Self): 初始化成功,返回一个新的结构体实例。 - /// - Err(PciError): 初始化过程中发生错误,返回错误信息。 - /// - /// ## 副作用 - /// - /// - 成功执行后,结构体的内部状态将被初始化为包含映射后的虚拟地址。 - pub fn new(segment_group_number: SegmentGroupNumber, cam: PciCam) -> Result { - assert_eq!(cam, PciCam::Ecam); - let mut pci_root = PciArch::ecam_root(segment_group_number)?; - pci_root.map()?; - Ok(pci_root) - } - /// @brief 完成物理地址到虚拟地址的映射,并将虚拟地址加入mmio_base变量 - /// @return 返回错误或Ok(0) - fn map(&mut self) -> Result { - //kdebug!("bus_begin={},bus_end={}", self.bus_begin,self.bus_end); - let bus_number = (self.bus_end - self.bus_begin) as u32 + 1; - let bus_number_double = (bus_number - 1) / 2 + 1; //一个bus占据1MB空间,计算全部bus占据空间相对于2MB空间的个数 - - let size = (bus_number_double as usize) * (PAGE_2M_SIZE as usize); - unsafe { - let space_guard = mmio_pool() - .create_mmio(size) - .map_err(|_| PciError::CreateMmioError)?; - let space_guard = Arc::new(space_guard); - self.mmio_guard = Some(space_guard.clone()); - - assert!(space_guard - .map_phys(self.physical_address_base, size) - .is_ok()); - } - return Ok(0); - } - - /// # cam_offset - 获得要操作的寄存器相对于mmio_offset的偏移量 - /// - /// 此函数用于计算一个PCI设备中特定寄存器相对于该设备的MMIO基地址的偏移量。 - /// - /// ## 参数 - /// - /// - `bus_device_function`: BusDeviceFunction,用于标识在同一组中的PCI设备。 - /// - `register_offset`: u16,寄存器在设备中的偏移量。 - /// - /// ## 返回值 - /// - /// - `u32`: 成功时,返回要操作的寄存器相对于mmio_offset的偏移量。 - /// - /// ## Panic - /// - /// - 此函数在参数有效性方面进行了断言,如果传入的`bus_device_function`无效,将panic。 - /// - 此函数计算出的地址需要是字对齐的(即地址与0x3对齐)。如果不是,将panic。 - fn cam_offset(&self, bus_device_function: BusDeviceFunction, register_offset: u16) -> u32 { - assert!(bus_device_function.valid()); - let bdf = ((bus_device_function.bus - self.bus_begin) as u32) << 8 - | (bus_device_function.device as u32) << 3 - | bus_device_function.function as u32; - let address = - bdf << match self.cam { - PciCam::MmioCam => 8, - PciCam::Ecam => 12, - } | register_offset as u32; - // Ensure that address is word-aligned. - assert!(address & 0x3 == 0); - address - } - /// @brief 通过bus_device_function和offset读取相应位置寄存器的值(32位) - /// @param bus_device_function 在同一个group中pci设备的唯一标识符 - /// @param register_offset 寄存器在设备中的offset - /// @return u32 寄存器读值结果 - pub fn read_config(&self, bus_device_function: BusDeviceFunction, register_offset: u16) -> u32 { - let address = self.cam_offset(bus_device_function, register_offset); - unsafe { - // Right shift to convert from byte offset to word offset. - ((self.mmio_guard.as_ref().unwrap().vaddr().data() as *mut u32) - .add((address >> 2) as usize)) - .read_volatile() - } - } - - /// @brief 通过bus_device_function和offset写入相应位置寄存器值(32位) - /// @param bus_device_function 在同一个group中pci设备的唯一标识符 - /// @param register_offset 寄存器在设备中的offset - /// @param data 要写入的值 - pub fn write_config( - &self, - bus_device_function: BusDeviceFunction, - register_offset: u16, - data: u32, - ) { - let address = self.cam_offset(bus_device_function, register_offset); - // Safe because both the `mmio_base` and the address offset are properly aligned, and the - // resulting pointer is within the MMIO range of the CAM. - unsafe { - // Right shift to convert from byte offset to word offset. - ((self.mmio_guard.as_ref().unwrap().vaddr().data() as *mut u32) - .add((address >> 2) as usize)) - .write_volatile(data) - } - } - /// @brief 返回迭代器,遍历pcie设备的external_capabilities - pub fn external_capabilities( - &self, - bus_device_function: BusDeviceFunction, - ) -> ExternalCapabilityIterator { - ExternalCapabilityIterator { - root: self, - bus_device_function, - next_capability_offset: Some(0x100), - } - } -} /// Gets the capabilities 'pointer' for the device function, if any. /// @brief 获取第一个capability 的offset /// @param bus_device_function PCI设备的唯一标识 diff --git a/kernel/src/driver/pci/pci_irq.rs b/kernel/src/driver/pci/pci_irq.rs index d0ffb1004..2246f0c9c 100644 --- a/kernel/src/driver/pci/pci_irq.rs +++ b/kernel/src/driver/pci/pci_irq.rs @@ -8,7 +8,8 @@ use alloc::sync::Arc; use alloc::vec::Vec; use system_error::SystemError; -use super::pci::{pci_root_0, PciDeviceStructure, PciDeviceStructureGeneralDevice, PciError}; +use super::pci::{PciDeviceStructure, PciDeviceStructureGeneralDevice, PciError}; +use super::root::pci_root_0; use crate::arch::msi::{arch_msi_message_address, arch_msi_message_data}; use crate::driver::base::device::DeviceId; diff --git a/kernel/src/driver/pci/root.rs b/kernel/src/driver/pci/root.rs new file mode 100644 index 000000000..56b173075 --- /dev/null +++ b/kernel/src/driver/pci/root.rs @@ -0,0 +1,256 @@ +use core::fmt::Formatter; + +use alloc::sync::Arc; +use hashbrown::HashMap; + +use crate::{ + libs::spinlock::{SpinLock, SpinLockGuard}, + mm::{ + mmio_buddy::{mmio_pool, MMIOSpaceGuard}, + page::PAGE_2M_SIZE, + PhysAddr, + }, +}; + +use super::pci::{ + BusDeviceFunction, ExternalCapabilityIterator, PciCam, PciError, SegmentGroupNumber, +}; + +lazy_static! { + static ref PCI_ROOT_MANAGER: PciRootManager = PciRootManager::new(); +} + +#[inline(always)] +pub fn pci_root_manager() -> &'static PciRootManager { + &PCI_ROOT_MANAGER +} + +/// 代表一个PCI segement greoup. +#[derive(Clone, Debug)] +pub struct PciRoot { + pub physical_address_base: PhysAddr, //物理地址,acpi获取 + pub mmio_guard: Option>, //映射后的虚拟地址,为方便访问数据这里转化成指针 + pub segment_group_number: SegmentGroupNumber, //segement greoup的id + pub bus_begin: u8, //该分组中的最小bus + pub bus_end: u8, //该分组中的最大bus + /// 配置空间访问机制 + pub cam: PciCam, +} + +///线程间共享需要,该结构体只需要在初始化时写入数据,无需读写锁保证线程安全 +unsafe impl Send for PciRoot {} +unsafe impl Sync for PciRoot {} +///实现PciRoot的Display trait,自定义输出 +impl core::fmt::Display for PciRoot { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + write!( + f, + "PCI Root with segement:{}, bus begin at {}, bus end at {}, physical address at {:?},mapped at {:?}", + self.segment_group_number, self.bus_begin, self.bus_end, self.physical_address_base, self.mmio_guard + ) + } +} + +impl PciRoot { + /// 此函数用于初始化一个PciRoot结构体实例, + /// 该结构体基于ECAM根的物理地址,将其映射到虚拟地址 + /// + /// ## 参数 + /// + /// - segment_group_number: ECAM根的段组号。 + /// - cam: PCI配置空间访问机制 + /// + /// ## 返回值 + /// + /// - Ok(Self): 初始化成功,返回一个新的结构体实例。 + /// - Err(PciError): 初始化过程中发生错误,返回错误信息。 + /// + /// ## 副作用 + /// + /// - 成功执行后,结构体的内部状态将被初始化为包含映射后的虚拟地址。 + pub fn new( + segment_group_number: SegmentGroupNumber, + cam: PciCam, + phys_base: PhysAddr, + bus_begin: u8, + bus_end: u8, + ) -> Result, PciError> { + assert_eq!(cam, PciCam::Ecam); + let mut pci_root = Self { + physical_address_base: phys_base, + mmio_guard: None, + segment_group_number, + bus_begin, + bus_end, + cam, + }; + pci_root.map()?; + + Ok(Arc::new(pci_root)) + } + /// @brief 完成物理地址到虚拟地址的映射,并将虚拟地址加入mmio_base变量 + /// @return 返回错误或Ok(0) + fn map(&mut self) -> Result { + //kdebug!("bus_begin={},bus_end={}", self.bus_begin,self.bus_end); + let bus_number = (self.bus_end - self.bus_begin) as u32 + 1; + let bus_number_double = (bus_number - 1) / 2 + 1; //一个bus占据1MB空间,计算全部bus占据空间相对于2MB空间的个数 + + let size = (bus_number_double as usize) * PAGE_2M_SIZE; + unsafe { + let space_guard = mmio_pool() + .create_mmio(size) + .map_err(|_| PciError::CreateMmioError)?; + let space_guard = Arc::new(space_guard); + self.mmio_guard = Some(space_guard.clone()); + + assert!(space_guard + .map_phys(self.physical_address_base, size) + .is_ok()); + } + return Ok(0); + } + + /// # cam_offset - 获得要操作的寄存器相对于mmio_offset的偏移量 + /// + /// 此函数用于计算一个PCI设备中特定寄存器相对于该设备的MMIO基地址的偏移量。 + /// + /// ## 参数 + /// + /// - `bus_device_function`: BusDeviceFunction,用于标识在同一组中的PCI设备。 + /// - `register_offset`: u16,寄存器在设备中的偏移量。 + /// + /// ## 返回值 + /// + /// - `u32`: 成功时,返回要操作的寄存器相对于mmio_offset的偏移量。 + /// + /// ## Panic + /// + /// - 此函数在参数有效性方面进行了断言,如果传入的`bus_device_function`无效,将panic。 + /// - 此函数计算出的地址需要是字对齐的(即地址与0x3对齐)。如果不是,将panic。 + fn cam_offset(&self, bus_device_function: BusDeviceFunction, register_offset: u16) -> u32 { + assert!(bus_device_function.valid()); + let bdf = ((bus_device_function.bus - self.bus_begin) as u32) << 8 + | (bus_device_function.device as u32) << 3 + | bus_device_function.function as u32; + let address = + bdf << match self.cam { + PciCam::MmioCam => 8, + PciCam::Ecam => 12, + } | register_offset as u32; + // Ensure that address is word-aligned. + assert!(address & 0x3 == 0); + address + } + /// @brief 通过bus_device_function和offset读取相应位置寄存器的值(32位) + /// @param bus_device_function 在同一个group中pci设备的唯一标识符 + /// @param register_offset 寄存器在设备中的offset + /// @return u32 寄存器读值结果 + pub fn read_config(&self, bus_device_function: BusDeviceFunction, register_offset: u16) -> u32 { + let address = self.cam_offset(bus_device_function, register_offset); + unsafe { + // Right shift to convert from byte offset to word offset. + ((self.mmio_guard.as_ref().unwrap().vaddr().data() as *mut u32) + .add((address >> 2) as usize)) + .read_volatile() + } + } + + /// @brief 通过bus_device_function和offset写入相应位置寄存器值(32位) + /// @param bus_device_function 在同一个group中pci设备的唯一标识符 + /// @param register_offset 寄存器在设备中的offset + /// @param data 要写入的值 + pub fn write_config( + &self, + bus_device_function: BusDeviceFunction, + register_offset: u16, + data: u32, + ) { + let address = self.cam_offset(bus_device_function, register_offset); + // Safe because both the `mmio_base` and the address offset are properly aligned, and the + // resulting pointer is within the MMIO range of the CAM. + unsafe { + // Right shift to convert from byte offset to word offset. + ((self.mmio_guard.as_ref().unwrap().vaddr().data() as *mut u32) + .add((address >> 2) as usize)) + .write_volatile(data) + } + } + /// 返回迭代器,遍历pcie设备的external_capabilities + #[allow(dead_code)] + pub fn external_capabilities( + &self, + bus_device_function: BusDeviceFunction, + ) -> ExternalCapabilityIterator { + ExternalCapabilityIterator { + root: self, + bus_device_function, + next_capability_offset: Some(0x100), + } + } +} + +#[inline(always)] +pub fn pci_root_0() -> Arc { + pci_root_manager().get_pci_root(0).unwrap() +} + +pub struct PciRootManager { + inner: SpinLock, +} + +struct InnerPciRootManager { + pci_root: HashMap>, +} + +impl PciRootManager { + pub fn new() -> Self { + Self { + inner: SpinLock::new(InnerPciRootManager { + pci_root: HashMap::new(), + }), + } + } + + pub fn add_pci_root(&self, pci_root: Arc) { + let mut inner = self.inner.lock(); + inner + .pci_root + .insert(pci_root.segment_group_number, pci_root); + } + + pub fn has_root(&self, segement_group_number: SegmentGroupNumber) -> bool { + self.inner + .lock() + .pci_root + .contains_key(&segement_group_number) + } + + pub fn get_pci_root(&self, segement_group_number: SegmentGroupNumber) -> Option> { + self.inner + .lock() + .pci_root + .get(&segement_group_number) + .cloned() + } + + #[allow(dead_code)] + pub fn iter(&self) -> PciRootIterator<'_> { + PciRootIterator { + inner: self.inner.lock(), + index: 0, + } + } +} + +pub struct PciRootIterator<'a> { + inner: SpinLockGuard<'a, InnerPciRootManager>, + index: usize, +} + +impl<'a> Iterator for PciRootIterator<'a> { + type Item = Arc; + + fn next(&mut self) -> Option { + self.inner.pci_root.values().nth(self.index).cloned() + } +} diff --git a/kernel/src/driver/virtio/transport_pci.rs b/kernel/src/driver/virtio/transport_pci.rs index 66e855f09..ca7b12239 100644 --- a/kernel/src/driver/virtio/transport_pci.rs +++ b/kernel/src/driver/virtio/transport_pci.rs @@ -2,11 +2,12 @@ use crate::driver::base::device::DeviceId; use crate::driver::pci::pci::{ - pci_root_0, BusDeviceFunction, PciDeviceStructure, PciDeviceStructureGeneralDevice, PciError, + BusDeviceFunction, PciDeviceStructure, PciDeviceStructureGeneralDevice, PciError, PciStandardDeviceBar, PCI_CAP_ID_VNDR, }; use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqSpecificMsg, PciInterrupt, PciIrqMsg, IRQ}; +use crate::driver::pci::root::pci_root_0; use crate::driver::virtio::irq::virtio_irq_manager; use crate::exception::irqdata::IrqHandlerData; use crate::exception::irqdesc::{IrqHandler, IrqReturn}; diff --git a/kernel/src/mm/mmio_buddy.rs b/kernel/src/mm/mmio_buddy.rs index 88eac5297..9d7ff2e0e 100644 --- a/kernel/src/mm/mmio_buddy.rs +++ b/kernel/src/mm/mmio_buddy.rs @@ -3,7 +3,6 @@ use crate::mm::kernel_mapper::KernelMapper; use crate::mm::page::{PAGE_1G_SHIFT, PAGE_4K_SHIFT}; use crate::process::ProcessManager; use crate::{ - include::bindings::bindings::PAGE_4K_SIZE, kdebug, mm::{MMArch, MemoryManagementArch}, }; @@ -14,7 +13,7 @@ use core::mem::MaybeUninit; use core::sync::atomic::{AtomicBool, Ordering}; use system_error::SystemError; -use super::page::PageFlags; +use super::page::{PageFlags, PAGE_4K_SIZE}; use super::{PhysAddr, VirtAddr}; // 最大的伙伴块的幂 @@ -495,7 +494,7 @@ impl MmioBuddyMemPool { // 对齐要申请的空间大小 // 如果要申请的空间大小小于4k,则分配4k if size_exp < PAGE_4K_SHIFT as u32 { - new_size = PAGE_4K_SIZE as usize; + new_size = PAGE_4K_SIZE; size_exp = PAGE_4K_SHIFT as u32; } else if (new_size & (!(1 << size_exp))) != 0 { // 向左对齐空间大小 diff --git a/kernel/src/mm/page.rs b/kernel/src/mm/page.rs index a6af66fc0..bc203c587 100644 --- a/kernel/src/mm/page.rs +++ b/kernel/src/mm/page.rs @@ -27,6 +27,9 @@ pub const PAGE_4K_SHIFT: usize = 12; pub const PAGE_2M_SHIFT: usize = 21; pub const PAGE_1G_SHIFT: usize = 30; +pub const PAGE_4K_SIZE: usize = 1 << PAGE_4K_SHIFT; +pub const PAGE_2M_SIZE: usize = 1 << PAGE_2M_SHIFT; + /// 全局物理页信息管理器 pub static mut PAGE_MANAGER: Option> = None; diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index ab4a9d9aa..02dfb1217 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -10,7 +10,7 @@ use crate::{ filesystem::vfs::syscall::{PosixStatfs, PosixStatx}, ipc::shm::{ShmCtlCmd, ShmFlags, ShmId, ShmKey}, libs::{futex::constant::FutexFlag, rand::GRandFlags}, - mm::syscall::MremapFlags, + mm::{page::PAGE_4K_SIZE, syscall::MremapFlags}, net::syscall::MsgHdr, process::{ fork::KernelCloneArgs, @@ -32,7 +32,6 @@ use crate::{ syscall::{ModeType, PosixKstat}, MAX_PATHLEN, }, - include::bindings::bindings::PAGE_4K_SIZE, kinfo, libs::align::page_align_up, mm::{verify_area, MemoryManagementArch, VirtAddr}, @@ -261,8 +260,8 @@ impl Syscall { // 权限校验 if frame.is_from_user() && (verify_area(virt_path_ptr, MAX_PATHLEN).is_err() - || verify_area(virt_argv_ptr, PAGE_4K_SIZE as usize).is_err()) - || verify_area(virt_env_ptr, PAGE_4K_SIZE as usize).is_err() + || verify_area(virt_argv_ptr, PAGE_4K_SIZE).is_err()) + || verify_area(virt_env_ptr, PAGE_4K_SIZE).is_err() { Err(SystemError::EFAULT) } else { @@ -422,7 +421,7 @@ impl Syscall { let virt_optlen = VirtAddr::new(optlen as usize); let security_check = || { // 验证optval的地址是否合法 - if verify_area(virt_optval, PAGE_4K_SIZE as usize).is_err() { + if verify_area(virt_optval, PAGE_4K_SIZE).is_err() { // 地址空间超出了用户空间的范围,不合法 return Err(SystemError::EFAULT); }