pci.rs 4.2 KB

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