mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
pci: 添加pci root manager来管理pci root,并使得riscv能够正常扫描pci设备. (#745)
* pci: 添加pci root manager来管理pci root. pci: 使得riscv能够正常扫描pci设备. * doc: 添加注释
This commit is contained in:
parent
2709e017d0
commit
370472f728
@ -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<PciRoot, PciError> 转换结果或出错原因
|
||||
fn ecam_root(segement: SegmentGroupNumber) -> Result<PciRoot, PciError>;
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
||||
fn ecam_root(segement: SegmentGroupNumber) -> Result<PciRoot, PciError> {
|
||||
unimplemented!("RiscV64PciArch::ecam_root")
|
||||
return PhysAddr::new(pci_address.data());
|
||||
}
|
||||
}
|
||||
|
||||
#[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(());
|
||||
}
|
||||
|
73
kernel/src/arch/riscv64/pci/pci_host_ecam.rs
Normal file
73
kernel/src/arch/riscv64/pci/pci_host_ecam.rs
Normal file
@ -0,0 +1,73 @@
|
||||
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,
|
||||
};
|
||||
|
||||
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(());
|
||||
}
|
@ -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(());
|
||||
}
|
||||
|
||||
|
@ -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,41 @@ 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<PciRoot, PciError> {
|
||||
let mcfg = acpi_manager()
|
||||
.tables()
|
||||
.expect("get acpi_manager table error")
|
||||
.find_table::<Mcfg>()
|
||||
.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(());
|
||||
}
|
||||
|
||||
/// # discover_ecam_root - 发现使用ECAM的PCI root device
|
||||
///
|
||||
/// 该函数用于从ACPI管理器获取MCFG表,并从中发现使用ECAM的PCI root device。
|
||||
/// 然后,本函数将这些信息添加到pci_ecam_root_info_manager
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - Ok(()): 成功发现并添加了所有ECAM根信息
|
||||
/// - Err(PciError): 在获取ACPI管理器表或发现MCFG表时发生错误
|
||||
fn discover_ecam_root() -> Result<(), PciError> {
|
||||
let mcfg = acpi_manager()
|
||||
.tables()
|
||||
.expect("get acpi_manager table error")
|
||||
.find_table::<Mcfg>()
|
||||
.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(())
|
||||
}
|
||||
|
@ -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) => {
|
||||
|
@ -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<Item = fdt::node::FdtNode<'b, 'b>> + '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)]
|
||||
|
71
kernel/src/driver/pci/ecam.rs
Normal file
71
kernel/src/driver/pci/ecam.rs
Normal file
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
pub mod ecam;
|
||||
#[allow(clippy::module_inception)]
|
||||
pub mod pci;
|
||||
pub mod pci_irq;
|
||||
pub mod root;
|
||||
|
@ -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<PciRoot> = {
|
||||
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<Arc<MMIOSpaceGuard>>, //映射后的虚拟地址,为方便访问数据这里转化成指针
|
||||
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<Self, PciError> {
|
||||
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<u8, PciError> {
|
||||
//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设备的唯一标识
|
||||
|
@ -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;
|
||||
|
303
kernel/src/driver/pci/root.rs
Normal file
303
kernel/src/driver/pci/root.rs
Normal file
@ -0,0 +1,303 @@
|
||||
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<Arc<MMIOSpaceGuard>>, //映射后的虚拟地址,为方便访问数据这里转化成指针
|
||||
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<Arc<Self>, 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<u8, PciError> {
|
||||
//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
|
||||
}
|
||||
/// # read_config - 通过bus_device_function和offset读取相应位置寄存器的值(32位)
|
||||
///
|
||||
/// 此函数用于通过指定的bus_device_function和register_offset读取PCI设备中相应位置的寄存器值。
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `bus_device_function`: 在同一个group中pci设备的唯一标识符
|
||||
/// - `register_offset`: 寄存器在设备中的offset
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - `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()
|
||||
}
|
||||
}
|
||||
|
||||
/// # write_config - 通过bus_device_function和offset写入相应位置寄存器值(32位)
|
||||
///
|
||||
/// 此函数用于通过指定的bus_device_function和register_offset,向PCI设备写入一个32位的寄存器值。
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `bus_device_function`: 在同一个group中pci设备的唯一标识符
|
||||
/// - `register_offset`: 寄存器在设备中的offset
|
||||
/// - `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<PciRoot> {
|
||||
pci_root_manager().get_pci_root(0).unwrap()
|
||||
}
|
||||
|
||||
pub struct PciRootManager {
|
||||
inner: SpinLock<InnerPciRootManager>,
|
||||
}
|
||||
|
||||
struct InnerPciRootManager {
|
||||
pci_root: HashMap<SegmentGroupNumber, Arc<PciRoot>>,
|
||||
}
|
||||
|
||||
impl PciRootManager {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: SpinLock::new(InnerPciRootManager {
|
||||
pci_root: HashMap::new(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// # 添加PciRoot - 向PciRootManager中添加一个PciRoot
|
||||
///
|
||||
/// 向PciRootManager中添加一个新的PciRoot,通过其segment_group_number进行标识。
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `pci_root`: Arc<PciRoot>,要添加的PciRoot的Arc指针
|
||||
pub fn add_pci_root(&self, pci_root: Arc<PciRoot>) {
|
||||
let mut inner = self.inner.lock();
|
||||
inner
|
||||
.pci_root
|
||||
.insert(pci_root.segment_group_number, pci_root);
|
||||
}
|
||||
|
||||
/// # 检查是否存在PciRoot - 检查PciRootManager中是否存在指定segment_group_number的PciRoot
|
||||
///
|
||||
/// 检查PciRootManager中是否存在segment_group_number对应的PciRoot。
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `segement_group_number`: SegmentGroupNumber,要检查的segment_group_number。
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - `true`: 如果存在对应的PciRoot。
|
||||
/// - `false`: 如果不存在对应的PciRoot。
|
||||
pub fn has_root(&self, segement_group_number: SegmentGroupNumber) -> bool {
|
||||
self.inner
|
||||
.lock()
|
||||
.pci_root
|
||||
.contains_key(&segement_group_number)
|
||||
}
|
||||
|
||||
/// # 获取PciRoot - 从PciRootManager中获取指定segment_group_number的PciRoot
|
||||
///
|
||||
/// 从PciRootManager中获取segment_group_number对应的PciRoot。
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `segement_group_number`: SegmentGroupNumber,要获取的PciRoot的segment_group_number。
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - `Some(Arc<PciRoot>)`: 如果找到对应的PciRoot,返回其引用。
|
||||
/// - `None`: 如果没有找到对应的PciRoot。
|
||||
pub fn get_pci_root(&self, segement_group_number: SegmentGroupNumber) -> Option<Arc<PciRoot>> {
|
||||
self.inner
|
||||
.lock()
|
||||
.pci_root
|
||||
.get(&segement_group_number)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
/// # PciRoot迭代器 - 创建一个新的PciRoot迭代器
|
||||
///
|
||||
/// 创建一个新的迭代器,用于遍历PciRootManager中的所有PciRoot。
|
||||
#[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<PciRoot>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.inner.pci_root.values().nth(self.index).cloned()
|
||||
}
|
||||
}
|
@ -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};
|
||||
|
@ -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 {
|
||||
// 向左对齐空间大小
|
||||
|
@ -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<SpinLock<PageManager>> = None;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user