上次说到了除了IO枚举PCI设备,还有另一种方式枚举PCI设备,那就是通过pciio,这也是UEFI代码中的常规操作(当然还有MMIO,不过不写了)
UEFI BIOS 提供了两个主要的模块来支持PCI 总线,一个是PCI Host Bridge 控制器驱动,另一个是PCI 总线驱动。
PCI Host Bridge 控制器驱动是跟特定的平台硬件绑定的,根据系统实际IO 空间和memory map, 为PCI设备指定I/O 空间和Memory 空间的范围,并且产生PCI Host Bridge Resource Allocation 协议(protocol)供PCI 总线驱动使用。该驱动还对HostBridge控制器下所有RootBridge 设备产生句柄(Handle), 该句柄上安装了PciRootBridgeProtocol。PCI 总线驱动则利用PciRootBridgeIo Protocol 枚举系统中所有PCI 设备,发现并获得PCI 设备的Option Rom, 并且调用PCI Host Bridge Resource Allocation protocol 分配PCI设备资源,PCI RootBridge设备又产生了PCI Local Bus。PCI 设备驱动不会使用PCI Root Bridge I/O protocol访问PCI 设备,而是会使用PCI总线驱动为PCI 设备产生的PCI IO Protocol 来访问PCI IO/MEMORY 空间和配置空间。
看完上面的话,咱们就开始直接进入主题:
EFI_STATUS
EFIAPI
ShellAppMain (
IN UINTN Argc,
IN CHAR16 **Argv
)
{
EFI_STATUS Status = EFI_SUCCESS;
EFI_HANDLE *HandleBuffer;
UINTN PciController_Count, Seg, BufferSize=0;
UINTN NumHandles, i;
EFI_PCI_IO_PROTOCOL *PciIoProtocol;
UINT8 ListDevice = 0, SaveOpRom=0;
UINT8 IndexOfSavedDevice=0;
PCI_CONTROLLER_INFO PciController_Info[50];
UINT32 VenderDevId;
CHAR16 SaveFileName[100];
Print(L"===============================================\n");
PciController_Count = 0;
if(Argc >= 2)
{
if(StrCmp(Argv[1], L"-L")==0)
{
ListDevice = 1;
}else if(StrCmp(Argv[1], L"-S")==0)
{
if(Argc!=3)
{
Status = EFI_INVALID_PARAMETER;
Print(L"Please Specify Index of Device when save OpRom\n");
goto ProcExit;
}else
{
IndexOfSavedDevice = StrDecimalToUint64(Argv[2]);
SaveOpRom = 1;
}
}
}else
{
Print(L"Too few parameters\n");
Status = EFI_INVALID_PARAMETER;
goto ProcExit;
}
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPciIoProtocolGuid, NULL, &NumHandles, &HandleBuffer);
for(i=0; i< NumHandles; i++)
{
Status = gBS->HandleProtocol(HandleBuffer[i], &gEfiPciIoProtocolGuid, (void**)&PciIoProtocol);
if(!EFI_ERROR(Status)){
if(PciIoProtocol->RomSize>0){
VenderDevId = 0xFFFFFFFF;
PciIoProtocol->Pci.Read(PciIoProtocol, EfiPciIoWidthFillUint32, 0, 1, &VenderDevId);
Seg = 0;
PciIoProtocol->GetLocation(PciIoProtocol,
&Seg,
&PciController_Info[PciController_Count].Bus,
&PciController_Info[PciController_Count].Device,
&PciController_Info[PciController_Count].Func);
PciController_Info[PciController_Count].Handle = HandleBuffer[i];
PciController_Info[PciController_Count].PciIo = PciIoProtocol;
PciController_Info[PciController_Count].VidDid = VenderDevId;
PciController_Count +=1;
}
}
}
if(ListDevice)
{
Print(L"Controller With OpRom Number: %d \n",PciController_Count);
for(i=0;i<PciController_Count;i++)
{
Print(L"Controller ID: %d VidDid: %08x Bus: %x Dev: %x Func: %x Size: 0x%x\n",
i,
PciController_Info[i].VidDid ,
PciController_Info[i].Bus,
PciController_Info[i].Device,
PciController_Info[i].Func,
PciController_Info[i].PciIo->RomSize);
}
....
代码贴出了一部分,不过已经足够了,完全可以通过上述的代码自己写一个app,代码非常好理解