1 use crate::arch::io::PortIOArch;
2 use crate::arch::{CurrentPortIOArch, TraitPciArch};
3 use crate::driver::acpi::acpi_manager;
4 use crate::driver::pci::ecam::{pci_ecam_root_info_manager, EcamRootInfo};
5 use crate::driver::pci::pci::{
6 pci_init, BusDeviceFunction, PciAddr, PciCam, PciError, PORT_PCI_CONFIG_ADDRESS,
7 PORT_PCI_CONFIG_DATA,
8 };
9 use crate::driver::pci::root::{pci_root_manager, PciRoot};
10 use crate::init::initcall::INITCALL_SUBSYS;
11 use crate::mm::PhysAddr;
12
13 use acpi::mcfg::Mcfg;
14 use log::warn;
15 use system_error::SystemError;
16 use unified_init::macros::unified_init;
17
18 pub struct X86_64PciArch;
19
20 impl X86_64PciArch {
21 /// # 在早期引导阶段直接访问PCI配置空间的函数
22 /// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/pci/early.c?fi=read_pci_config_byte#19
read_config_early(bus: u8, slot: u8, func: u8, offset: u8) -> u823 fn read_config_early(bus: u8, slot: u8, func: u8, offset: u8) -> u8 {
24 unsafe {
25 CurrentPortIOArch::out32(
26 PORT_PCI_CONFIG_ADDRESS,
27 0x80000000
28 | ((bus as u32) << 16)
29 | ((slot as u32) << 11)
30 | ((func as u32) << 8)
31 | offset as u32,
32 );
33 }
34 let value = unsafe { CurrentPortIOArch::in8(PORT_PCI_CONFIG_DATA + (offset & 3) as u16) };
35 return value;
36 }
37 }
38
39 impl TraitPciArch for X86_64PciArch {
read_config(bus_device_function: &BusDeviceFunction, offset: u8) -> u3240 fn read_config(bus_device_function: &BusDeviceFunction, offset: u8) -> u32 {
41 // 构造pci配置空间地址
42 let address = ((bus_device_function.bus as u32) << 16)
43 | ((bus_device_function.device as u32) << 11)
44 | ((bus_device_function.function as u32 & 7) << 8)
45 | (offset & 0xfc) as u32
46 | (0x80000000);
47 let ret = unsafe {
48 CurrentPortIOArch::out32(PORT_PCI_CONFIG_ADDRESS, address);
49 let temp = CurrentPortIOArch::in32(PORT_PCI_CONFIG_DATA);
50 temp
51 };
52 return ret;
53 }
54
write_config(bus_device_function: &BusDeviceFunction, offset: u8, data: u32)55 fn write_config(bus_device_function: &BusDeviceFunction, offset: u8, data: u32) {
56 let address = ((bus_device_function.bus as u32) << 16)
57 | ((bus_device_function.device as u32) << 11)
58 | ((bus_device_function.function as u32 & 7) << 8)
59 | (offset & 0xfc) as u32
60 | (0x80000000);
61 unsafe {
62 CurrentPortIOArch::out32(PORT_PCI_CONFIG_ADDRESS, address);
63 // 写入数据
64 CurrentPortIOArch::out32(PORT_PCI_CONFIG_DATA, data);
65 }
66 }
67
address_pci_to_physical(pci_address: PciAddr) -> PhysAddr68 fn address_pci_to_physical(pci_address: PciAddr) -> PhysAddr {
69 return PhysAddr::new(pci_address.data());
70 }
71 }
72
73 #[unified_init(INITCALL_SUBSYS)]
x86_64_pci_init() -> Result<(), SystemError>74 fn x86_64_pci_init() -> Result<(), SystemError> {
75 if discover_ecam_root().is_err() {
76 // ecam初始化失败,使用portio访问pci配置空间
77 // 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/pci/broadcom_bus.c#27
78 let bus_begin = X86_64PciArch::read_config_early(0, 0, 0, 0x44);
79 let bus_end = X86_64PciArch::read_config_early(0, 0, 0, 0x45);
80
81 if !pci_root_manager().has_root(bus_begin as u16) {
82 let root = PciRoot::new(None, PciCam::Portiocam, bus_begin, bus_end);
83 pci_root_manager().add_pci_root(root.unwrap());
84 } else {
85 warn!("x86_64_pci_init(): pci_root_manager {}", bus_begin);
86 }
87 }
88 pci_init();
89
90 return Ok(());
91 }
92
93 /// # discover_ecam_root - 发现使用ECAM的PCI root device
94 ///
95 /// 该函数用于从ACPI管理器获取MCFG表,并从中发现使用ECAM的PCI root device。
96 /// 然后,本函数将这些信息添加到pci_ecam_root_info_manager
97 ///
98 /// ## 返回值
99 ///
100 /// - Ok(()): 成功发现并添加了所有ECAM根信息
101 /// - Err(PciError): 在获取ACPI管理器表或发现MCFG表时发生错误
discover_ecam_root() -> Result<(), PciError>102 fn discover_ecam_root() -> Result<(), PciError> {
103 let mcfg = acpi_manager()
104 .tables()
105 .expect("get acpi_manager table error")
106 .find_table::<Mcfg>()
107 .map_err(|_| PciError::McfgTableNotFound)?;
108 for mcfg_entry in mcfg.entries() {
109 pci_ecam_root_info_manager().add_ecam_root_info(EcamRootInfo::new(
110 mcfg_entry.pci_segment_group,
111 mcfg_entry.bus_number_start,
112 mcfg_entry.bus_number_end,
113 PhysAddr::new(mcfg_entry.base_address as usize),
114 ));
115 }
116
117 Ok(())
118 }
119