Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 37 additions & 6 deletions kernel/src/arch/x86_64/pci/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,40 @@ 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::{
pci_init, BusDeviceFunction, PciAddr, PciError, PORT_PCI_CONFIG_ADDRESS, PORT_PCI_CONFIG_DATA,
pci_init, BusDeviceFunction, PciAddr, PciCam, PciError, PORT_PCI_CONFIG_ADDRESS,
PORT_PCI_CONFIG_DATA,
};
use crate::include::bindings::bindings::{io_in32, io_out32};
use crate::driver::pci::root::{pci_root_manager, PciRoot};
use crate::include::bindings::bindings::{io_in32, io_in8, io_out32};
use crate::init::initcall::INITCALL_SUBSYS;

use crate::mm::PhysAddr;

use acpi::mcfg::Mcfg;
use log::error;
use log::{error, warn};
use system_error::SystemError;
use unified_init::macros::unified_init;

pub struct X86_64PciArch;

impl X86_64PciArch {
/// # 在早期引导阶段直接访问PCI配置空间的函数
/// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/pci/early.c?fi=read_pci_config_byte#19
fn read_config_early(bus: u8, slot: u8, func: u8, offset: u8) -> u8 {
unsafe {
io_out32(
PORT_PCI_CONFIG_ADDRESS,
0x80000000
| ((bus as u32) << 16)
| ((slot as u32) << 11)
| ((func as u32) << 8)
| offset as u32,
);
}
let value = unsafe { io_in8(PORT_PCI_CONFIG_DATA + (offset & 3) as u16) };
return value;
}
}

impl TraitPciArch for X86_64PciArch {
fn read_config(bus_device_function: &BusDeviceFunction, offset: u8) -> u32 {
// 构造pci配置空间地址
Expand Down Expand Up @@ -51,8 +72,18 @@ impl TraitPciArch for X86_64PciArch {

#[unified_init(INITCALL_SUBSYS)]
fn x86_64_pci_init() -> Result<(), SystemError> {
if let Err(e) = discover_ecam_root() {
error!("x86_64_pci_init(): discover_ecam_root error: {:?}", e);
if discover_ecam_root().is_err() {
// ecam初始化失败,使用portio访问pci配置空间
// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/pci/broadcom_bus.c#27
let bus_begin = X86_64PciArch::read_config_early(0, 0, 0, 0x44);
let bus_end = X86_64PciArch::read_config_early(0, 0, 0, 0x45);

if !pci_root_manager().has_root(bus_begin as u16) {
let root = PciRoot::new(None, PciCam::Portiocam, bus_begin, bus_end);
pci_root_manager().add_pci_root(root.unwrap());
} else {
warn!("x86_64_pci_init(): pci_root_manager {}", bus_begin);
}
}
pci_init();

Expand Down
24 changes: 14 additions & 10 deletions kernel/src/driver/pci/ecam.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,32 @@ pub fn pci_ecam_root_info_manager() -> &'static EcamRootInfoManager {
}

/// Ecam pci root info
#[derive(Clone, Copy)]
#[derive(Clone, Debug, Copy)]
pub struct EcamRootInfo {
pub segement_group_number: SegmentGroupNumber,
/// 段组号
pub segment_group_number: SegmentGroupNumber,
/// 该分组中的最小bus
pub bus_begin: u8,
/// 该分组中的最大bus
pub bus_end: u8,
/// 物理基地址
pub physical_address_base: PhysAddr,
}

impl EcamRootInfo {
pub fn new(
segement_group_number: SegmentGroupNumber,
segment_group_number: SegmentGroupNumber,
bus_begin: u8,
bus_end: u8,
physical_address_base: PhysAddr,
) -> Self {
Self {
segement_group_number,
let ecam_root_info = Self {
segment_group_number,
bus_begin,
bus_end,
physical_address_base,
}
};
return ecam_root_info;
}
}

Expand All @@ -48,11 +53,10 @@ impl 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) {
if !pci_root_manager().has_root(ecam_root_info.segment_group_number) {
let root = PciRoot::new(
ecam_root_info.segement_group_number,
Some(ecam_root_info),
PciCam::Ecam,
ecam_root_info.physical_address_base,
ecam_root_info.bus_begin,
ecam_root_info.bus_end,
);
Expand All @@ -66,7 +70,7 @@ impl EcamRootInfoManager {
} else {
warn!(
"add_ecam_root_info(): root {} already exists",
ecam_root_info.segement_group_number
ecam_root_info.segment_group_number
);
}
}
Expand Down
3 changes: 3 additions & 0 deletions kernel/src/driver/pci/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,8 @@ impl PciDeviceStructure for PciDeviceStructurePciToCardbusBridge {
/// 用于访问PCI设备的功能配置空间的一组机制。
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum PciCam {
/// PortIO配置访问机制
Portiocam,
/// PCI内存映射配置访问机制
///
/// 为每个设备功能提供256字节的配置空间访问。
Expand All @@ -653,6 +655,7 @@ impl PciCam {
/// Returns the total size in bytes of the memory-mapped region.
pub const fn size(self) -> u32 {
match self {
Self::Portiocam => 0x100000,
Self::MmioCam => 0x1000000,
Self::Ecam => 0x10000000,
}
Expand Down
105 changes: 64 additions & 41 deletions kernel/src/driver/pci/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ use alloc::sync::Arc;
use hashbrown::HashMap;

use crate::{
arch::{PciArch, TraitPciArch},
libs::spinlock::{SpinLock, SpinLockGuard},
mm::{
mmio_buddy::{mmio_pool, MMIOSpaceGuard},
page::PAGE_2M_SIZE,
PhysAddr,
},
};

use super::pci::{
BusDeviceFunction, ExternalCapabilityIterator, PciCam, PciError, SegmentGroupNumber,
use super::{
ecam::EcamRootInfo,
pci::{BusDeviceFunction, ExternalCapabilityIterator, PciCam, PciError, SegmentGroupNumber},
};

lazy_static! {
Expand All @@ -28,13 +29,14 @@ pub fn pci_root_manager() -> &'static PciRootManager {
/// 代表一个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 ecam_root_info: Option<EcamRootInfo>,
pub mmio_guard: Option<Arc<MMIOSpaceGuard>>, //映射后的虚拟地址,为方便访问数据这里转化成指针
/// 配置空间访问机制
pub cam: PciCam,
/// bus起始位置
pub bus_begin: u8,
/// bus结束位置
pub bus_end: u8,
}

///线程间共享需要,该结构体只需要在初始化时写入数据,无需读写锁保证线程安全
Expand All @@ -43,11 +45,15 @@ 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
)
if let Some(ecam_root_info) = &self.ecam_root_info {
write!(
f,
"PCI Eacm Root with segment:{}, bus begin at {}, bus end at {}, physical address at {:?},mapped at {:?}",
ecam_root_info.segment_group_number, ecam_root_info.bus_begin, ecam_root_info.bus_end, ecam_root_info.physical_address_base, self.mmio_guard
)
} else {
write!(f, "PCI Root cam is {:?}", self.cam,)
}
}
}

Expand All @@ -69,27 +75,28 @@ impl PciRoot {
///
/// - 成功执行后,结构体的内部状态将被初始化为包含映射后的虚拟地址。
pub fn new(
segment_group_number: SegmentGroupNumber,
ecam_root_info: Option<EcamRootInfo>,
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,
ecam_root_info,
mmio_guard: None,
segment_group_number,
cam,
bus_begin,
bus_end,
cam,
};
pci_root.map()?;

if ecam_root_info.is_some() {
pci_root.map()?;
}

Ok(Arc::new(pci_root))
}
/// @brief 完成物理地址到虚拟地址的映射,并将虚拟地址加入mmio_base变量
/// @return 返回错误或Ok(0)

/// # 完成物理地址到虚拟地址的映射,并将虚拟地址加入mmio_base变量
/// ## return 返回错误或Ok(0)
fn map(&mut self) -> Result<u8, PciError> {
//debug!("bus_begin={},bus_end={}", self.bus_begin,self.bus_end);
let bus_number = (self.bus_end - self.bus_begin) as u32 + 1;
Expand All @@ -104,7 +111,7 @@ impl PciRoot {
self.mmio_guard = Some(space_guard.clone());

assert!(space_guard
.map_phys(self.physical_address_base, size)
.map_phys(self.ecam_root_info.unwrap().physical_address_base, size)
.is_ok());
}
return Ok(0);
Expand All @@ -129,18 +136,20 @@ impl PciRoot {
/// - 此函数计算出的地址需要是字对齐的(即地址与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
let bdf = ((bus_device_function.bus - self.ecam_root_info.unwrap().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::Portiocam => 4,
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设备中相应位置的寄存器值。
Expand All @@ -154,12 +163,16 @@ impl PciRoot {
///
/// - `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()
if self.ecam_root_info.is_some() {
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()
}
} else {
PciArch::read_config(&bus_device_function, register_offset as u8)
}
}

Expand All @@ -178,16 +191,21 @@ impl PciRoot {
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)
if self.ecam_root_info.is_some() {
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)
}
} else {
PciArch::write_config(&bus_device_function, register_offset as u8, data);
}
}

/// 返回迭代器,遍历pcie设备的external_capabilities
#[allow(dead_code)]
pub fn external_capabilities(
Expand Down Expand Up @@ -233,9 +251,14 @@ impl PciRootManager {
/// - `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);

if let Some(ecam_root_info) = pci_root.ecam_root_info {
inner
.pci_root
.insert(ecam_root_info.segment_group_number, pci_root);
} else {
inner.pci_root.insert(pci_root.bus_begin as u16, pci_root);
}
}

/// # 检查是否存在PciRoot - 检查PciRootManager中是否存在指定segment_group_number的PciRoot
Expand Down