EDKII枚举PCI的PORT
时间: 2023-10-31 19:58:28 浏览: 134
PCI设备枚举
3星 · 编辑精心推荐
在 EDKII 中,可以使用 UEFI 的标准 PCI 配置空间来枚举 PCI 设备。具体步骤如下:
1. 获取 PCI 根桥的 `EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL` 接口指针。
```c
EFI_STATUS Status;
EFI_HANDLE* HandleBuffer;
UINTN HandleCount;
Status = gBS->LocateHandleBuffer(
ByProtocol,
&gEfiPciRootBridgeIoProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR(Status)) {
// 错误处理
}
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL* PciRootBridgeIo;
Status = gBS->HandleProtocol(
HandleBuffer[0],
&gEfiPciRootBridgeIoProtocolGuid,
&PciRootBridgeIo
);
if (EFI_ERROR(Status)) {
// 错误处理
}
```
2. 枚举 PCI 总线上的所有设备和函数。
```c
for (UINT8 Bus = 0; Bus <= 0xFF; Bus++) {
for (UINT8 Device = 0; Device <= 0x1F; Device++) {
for (UINT8 Function = 0; Function <= 0x07; Function++) {
UINT64 Address = EFI_PCI_ADDRESS(Bus, Device, Function, 0);
UINT16 VendorId;
PciRootBridgeIo->Pci.Read(PciRootBridgeIo, EfiPciWidthUint16, Address + PCI_VENDOR_ID_OFFSET, 1, &VendorId);
// 判断该设备是否存在
if (VendorId != 0xFFFF) {
// TODO: 处理该设备
}
}
}
}
```
3. 对于存在的设备,可以根据需要读取和写入 PCI 配置空间的寄存器来获取设备的信息。
```c
UINT32 Register;
UINT8 Buffer[4];
// 读取 Vendor ID 和 Device ID
PciRootBridgeIo->Pci.Read(PciRootBridgeIo, EfiPciWidthUint32, Address, 1, &Register);
UINT16 VendorId = (UINT16)(Register & 0xFFFF);
UINT16 DeviceId = (UINT16)(Register >> 16);
// 读取 BAR0 寄存器的值
PciRootBridgeIo->Pci.Read(PciRootBridgeIo, EfiPciWidthUint32, Address + PCI_BASE_ADDRESSREG_OFFSET(0), 1, &Register);
if (Register & PCI_BASE_ADDRESS_MEM_TYPE_MASK == PCI_BASE_ADDRESS_MEM_TYPE_32) {
PciRootBridgeIo->Mem.Read(PciRootBridgeIo, EfiPciWidthUint32, (UINT64)(Register & PCI_BASE_ADDRESS_MEM_MASK), 1, &Buffer);
} else {
PciRootBridgeIo->Io.Read(PciRootBridgeIo, EfiPciWidthUint32, (UINT64)(Register & PCI_BASE_ADDRESS_IO_MASK), 1, &Buffer);
}
```
需要注意的是,如果设备存在多个 BAR 寄存器,则需要根据相应的编程模型来读取和解释这些寄存器的值。此外,还需要考虑设备的中断、DMA 等资源的分配和管理。
阅读全文