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 23 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 { 40 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 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 68 fn address_pci_to_physical(pci_address: PciAddr) -> PhysAddr { 69 return PhysAddr::new(pci_address.data()); 70 } 71 } 72 73 #[unified_init(INITCALL_SUBSYS)] 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表时发生错误 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