BIOS实战之PCI设备枚举二

上次说到了除了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,代码非常好理解
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值