问题:在做项目中,BIOS如何获得PCI外插卡设备信息?

1、使用rootbridge 定位

1、进入OS查看PCI设备

huawei@huawei:~$ lspci -tv+-[0004:00]-+-00.0  Ampere Computing, LLC Device e110|           +-01.0-[01]--|           +-05.0-[02]--|           +-06.0-[03]--|           +-07.0-[04]--|           \-08.0-[05]--+-[0003:00]-+-00.0  Ampere Computing, LLC Device e110|           +-01.0-[01]----00.0  Renesas Technology Corp. uPD720201 USB 3.0 Host Controller|           +-03.0-[02]--|           +-05.0-[03]--|           \-07.0-[04]--+-[0002:00]-+-00.0  Ampere Computing, LLC Device e110|           +-01.0-[01]--|           +-03.0-[02]--|           +-05.0-[03]--|           \-07.0-[04]--+-[0001:00]-+-00.0  Ampere Computing, LLC Device e100|           \-01.0-[01]----00.0  Huawei Technologies Co., Ltd. Device 3714\-[0000:00]-+-00.0  Ampere Computing, LLC Device e100+-01.0-[01]--\-03.0-[02]--

  0b:00:00.0 第一个是segment,后面依次是bus device function
  下面01.0是device和function
  [01]、[02]、[03]是rootport下面的bus号。
  基本思路:循环扫描segment,bus ,device ,function,判断四个元素合成地址上是否有设备,XX:00:00:00 为PCI桥设备,其它就是PCI设备。

2、PCI Root Bridge I/O Support

  PCI Root Bridge I/O Protocol 给通过PCI Host Bus Controller 产生的PCI Root Brideg 提供一个I/O抽象, 一个PCI主机总线控制器是一个硬件组件,它允许访问一组PCI设备,它们共享一个公共的PCII/O和PCI内存资源池。PCI设备驱动程序将不会直接使用此协议。相反,他们将使用由PCI总线驱动程序产生的I/O抽象,只有需要直接访问整个PCI总线的驱动程序才应该使用此协议。EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL中提供的接口用于对内存、I/O和PCI配置空间执行基本操作。
  一个PCI segment是最多256 个共享PCI配置空间的PCI 总线的集合。根据芯片组的不同,单个EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL可以抽象出PCI Segment的一部分,或整个PCI Segment.一个PCI host bridge可以产生一个或多个PCI root bridges。当一个PCI主桥产生多个PCI root bridge时,可能有多个PCI segments.一个PCI root Bridge控制器包括一个EFI_DEVICE_PATH_Protocol实例和EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.

  下图显示了具有一个具有PCI root bridge 的PCI host bus的示例。此PCI root bridge 产生一个PCI本地总线,它可以包含在主板或PCI插槽上的PCI设备

3、代码实现

UINTN
PciSoltEnumeratedDevice (OUT KL_SET_SYSTEM_INFO_FOR_PCIE_CARD  *KLpSetSystemInfo,OUT KL_SET_PCIE_CARD_BDF_INFO  *pPcieCardInfo
)
{EFI_STATUS              Status;EFI_HANDLE              *RbHandleBuffer;UINTN                   RbHandleCount=0;UINTN                   Index;PCI_CFG_ADDR            addr;UINT32                  buff = 0;EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL     *RbIoProtocol;UINT8                   PriBus;UINT8                   SecBus;UINT16                              Device;UINT16                           Function;UINT16                  SoltNum1 = 0;UINT16                  SoltNum2 = 0;UINT16                  PortNum = 0;UINT32                                PciVidDid ;UINT32                                SubPciVidDid ;UINT16  VendorId = 0xFFFF;UINT16  DeviceId = 0xFFFF;UINT8                           BaseClass;UINT8                           SubClass;UINT8                           CardType;// Locate all PciIo protocolStatus = gBS->LocateHandleBuffer (ByProtocol,&gEfiPciRootBridgeIoProtocolGuid,NULL,&RbHandleCount,&RbHandleBuffer );if(EFI_ERROR(Status)){DEBUG((DEBUG_ERROR,"ERROR Locating RbIo Protocols: Status:%r \n", Status));return FALSE;}DEBUG((DEBUG_ERROR, "RbHandleCount:%d\n",RbHandleCount));/* Loop through each root complex */for (Index = 0 ; Index < RbHandleCount; Index ++) { // Handle CountStatus = gBS->HandleProtocol (RbHandleBuffer[Index],&gEfiPciRootBridgeIoProtocolGuid,(VOID **)&RbIoProtocol );if(EFI_ERROR(Status)){continue;}/* Loop through each root port *///device/function根据OS下 lspci布线得到,for (Device = 1; Device <= 8; Device++) {for (Function = 0;Function <8; Function++){addr.Addr.Bus = 0;addr.Addr.Device = Device;addr.Addr.Function = Function;addr.Addr.Register = 0;addr.Addr.ExtendedRegister = 0;Status = RbIoProtocol->Pci.Read(RbIoProtocol, EfiPciWidthUint32, addr.ADDR, 1, (VOID*)&buff);if(EFI_ERROR(Status)){DEBUG((DEBUG_ERROR,"RbIo Protocols Pci Read Failed - Status: %r\n", Status));continue;}if (buff == 0xFFFFFFFF){//DEBUG((DEBUG_ERROR,"Device Not Exist!\n"));continue;}DEBUG((DEBUG_ERROR,"buff:0x%04x\n",buff));addr.Addr.Register = PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET;Status = RbIoProtocol->Pci.Read(RbIoProtocol, EfiPciWidthUint8, addr.ADDR, 1, (VOID*)&SecBus);addr.Addr.Bus = (UINT8)SecBus;addr.Addr.Device = 0;addr.Addr.Function = 0;addr.Addr.Register = 0;addr.Addr.ExtendedRegister = 0;DEBUG((EFI_D_ERROR, " PCIE SECONDARY_BUS:0x%04x\n",SecBus));Status = RbIoProtocol->Pci.Read(RbIoProtocol, EfiPciWidthUint32, addr.ADDR, 1, (VOID*)&PciVidDid);if(EFI_ERROR(Status)){DEBUG((DEBUG_ERROR,"RbIo Protocols Pci Read Failed - Status: %r,SoltNum1:%d\n", Status,SoltNum1));continue;}VendorId = (UINT16)(PciVidDid & 0xFFFF);DeviceId = (UINT16)(PciVidDid >> 16) & 0xFFFF;//过滤掉USB 设备if (((VendorId == 0x1912) && (DeviceId == 0x0014))||((VendorId == 0x1CC4) && (DeviceId == 0x0123))){continue;}if (PciVidDid != 0xFFFFFFFF){  addr.Addr.Register = 0x0B;Status = RbIoProtocol->Pci.Read(RbIoProtocol, EfiPciWidthUint32, addr.ADDR, 1, (VOID*)&BaseClass);if ( BaseClass == 0x02 ){  continue;}SoltNum2++;   addr.Addr.Register = PCI_SVID_OFFSET;Status = RbIoProtocol->Pci.Read(RbIoProtocol, EfiPciWidthUint32, addr.ADDR, 1, (VOID*)&SubPciVidDid);KLpSetSystemInfo->PcieCardInfo[SoltNum2].VIDSLOT = (UINT16)(PciVidDid & 0xFFFF);KLpSetSystemInfo->PcieCardInfo[SoltNum2].DIDSLOT = (UINT16)(PciVidDid >> 16) & 0xFFFF;KLpSetSystemInfo->PcieCardInfo[SoltNum2].SUBVID  = (UINT16)(SubPciVidDid & 0xFFFF);KLpSetSystemInfo->PcieCardInfo[SoltNum2].SUBDID  = (UINT16)(SubPciVidDid >> 16) & 0xFFFF;}}} // Handle Count}DEBUG((EFI_D_ERROR,"%a() DeviceExist,SoltNum=%d\n",__FUNCTION__, SoltNum1));return SoltNum1;
}

参考OS下的lspci结果,可以对应上

2、gEfiPciIoProtocolGuid 定位

  BUS ,Device,Function ,可以识别网卡设备,但是网卡下面的 几个port口识别不出, port口插网卡的功能是相同的,每个port口都绑定了gEfiPciIoProtocol,可使用gEfiPciIoProtocol识别。网卡类型使用BaseClass == 2判断,raid卡使用 ((BaseClass == 0x01)&& ((SubClass == 0x07)||(SubClass == 0x04)))判断。

UINTN
ReportEthernetPortDeviceInfoToBMC(OUT SET_SYSTEM_BDF_INFO_FOR_NET_PORT_ROOT_BDF *pSetNetPortRootInfo
)
{EFI_STATUS                         Status = EFI_SUCCESS;UINTN                              HandleArrayCount;EFI_HANDLE                         *HandleArray;UINTN                              Index;UINTN                              Index2;EFI_PCI_IO_PROTOCOL                *PciIo;UINT8                              PortNum = 0;UINT8                              Segment;UINT8                              BusNum;UINT8                              DevNum;UINT8                              FunNum;UINT8                              CardType;EFI_HANDLE                         HandleSlot;EFI_PCI_IO_PROTOCOL                *PciIoSlot;UINT8                           BaseClass;UINT8                           SubClass;Status = gBS->LocateHandleBuffer(ByProtocol,&gEfiPciIoProtocolGuid,NULL,&HandleArrayCount,&HandleArray);if (EFI_ERROR(Status)) {return PortNum;}DEBUG((EFI_D_ERROR, "HandleArrayCount=%d\n",HandleArrayCount ));for (Index2=0; Index2<HandleArrayCount; Index2++){Status = gBS->HandleProtocol(HandleArray[Index2],&gEfiPciIoProtocolGuid,(VOID **)&PciIo);Status = PciIo->Pci.Read(PciIo,EfiPciIoWidthUint8,0x0B, //PCI_CLASSCODE_OFFSET1,&BaseClass);Status = PciIo->Pci.Read(PciIo,EfiPciIoWidthUint8,0x0A, //PCI_CLASSCODE_OFFSET1,&SubClass);// network cardif (BaseClass == 0x02){  CardType = 0;}//raid cardif((BaseClass == 0x01)&& ((SubClass == 0x07)||(SubClass == 0x04))){  CardType = 2;  }//report net port data here//net cardif ((CardType == 0) || (CardType == 2)) {PciIo->GetLocation(PciIo,&Segment,&BusNum,&DevNum,&FunNum);DEBUG((EFI_D_ERROR, "Index2=%d net card: seg=0x%x bus=0x%x dev=0x%x fun=0x%x\n", Index2, Segment, BusNum, DevNum, FunNum));pSetNetPortRootInfo->BDF_Info[PortNum].CardType = CardType; pSetNetPortRootInfo->BDF_Info[PortNum].BusNum = BusNum;pSetNetPortRootInfo->BDF_Info[PortNum].DeviceNum = DevNum;pSetNetPortRootInfo->BDF_Info[PortNum].FunctionNum = FunNum;pSetNetPortRootInfo->BDF_Info[PortNum].Segment = Segment;pSetNetPortRootInfo->BDF_Info[PortNum].SlotNum = PortNum;PortNum++;}} return PortNum;
}···

UEFI查找PCI设备相关推荐

  1. Linux下PCI设备驱动程序开发[转]

    PCI是一种广泛采用的总线标准,它提供了许多优于其它总线标准(如EISA)的新特性,目前已经成为计算机系统中应用最为广泛,并且最为通用的总线标准.Linux的内核能较好地支持PCI总线,本文以Inte ...

  2. Linux下PCI设备驱动程序开发 --- PCI驱动程序实现(三)

    <script type="text/javascript"> </script><script type="text/javascript ...

  3. UEFI中的PCI设备扫描及分配Mem/Io空间过程

    最近在调试解决PCI设备相关的问题,然后对UEFI下面的这部分实现有了初步的了解,为了防止后面慢慢的又忘记了,所以还是决定将最近的收获都记录起来,各位读者如果发现哪里记录或者总结的不对,欢迎留言指正. ...

  4. Linux PCI 设备驱动基本框架(一)

    Linux将所有外部设备看成是一类特殊文件,称之为"设备文件",如果说系统调用是Linux内核和应用程序之间的接口,那么设备驱动程序则可以看成是 Linux内核与外部设备之间的接口 ...

  5. Linux内核机器ID,linux-如何强制内核重新读取/重新初始化PCI设备ID?

    我的机器(正在运行Linux内核3.2.38的计算机)在引导时具有错误的PCI设备的子系统ID(子设备和子供应商ID).如果我然后在系统仍处于启动状态(即热插拔)时物理地拔出PCI设备并重新插入,则它 ...

  6. KVM虚拟机PCI设备直通

    1. pci passthrough 1.1 概念 guest排他使用host上的某个PCI设备,就像将该设备物理连接到guest上一样 1.2 使用场景 提升性能(如直通网卡和显卡) 减少延迟(避免 ...

  7. Windows驱动——利用WinDriver开发PCI设备驱动程序

    摘要 WinDriver是Jungo公司出版的一个设备驱动程序开发组件,它可以大大加速PCI设备驱动程序的开发.作者在实际的项目中采用了WinDriver来开发设备驱动程序,取得了相当好的运行效果.从 ...

  8. Linux内核之PCI设备

    PCI设备 外围设备互连(PCI)是一种将系统中外部设备以结构化与可控制方式连接到起来的总线标准,包括系统部件连接的电气特性及行为.本章将详细讨论Linux核心对系统中的PCI总线与设备的初始化过程. ...

  9. linux设备驱动之pci设备的I/O和内存

    ------------------------------------------ 本文系本站原创,欢迎转载! 转载请注明出处:http://ericxiao.cublog.cn/ -------- ...

最新文章

  1. Python安装模块出错(No module named setuptools)解决方法
  2. 神策数据 VP 张涛:个性化推荐从入门到精通(附推荐产品经理修炼秘籍)
  3. android程序大牛,冲向大牛之安卓:学习界面怎么在程序中画出来
  4. HDU 1874 畅通工程续 2008浙大研究生复试热身赛(2)
  5. Android SQLite数据库demo。架构组件Room
  6. JSP中的:request.getScheme()+://+request.getServerName()+:+request.getServer
  7. python2.7中文字符串_python2.7 怎样将中文字符串转为字节流?
  8. python随笔系列--多进程多线程并发度初探
  9. 疫情之后,人工智能该如何走?
  10. cisco 三层交换机作DHCP服务器的配置
  11. C#.NET如何将cs文件编译成dll文件 exe文件 如何调用dll文件
  12. left join 一对多只取一条_Python爬虫教程:验证码的爬取和识别详解
  13. LVS_Cluster
  14. EIGRP协议的配置
  15. 全国青少年软件编程等级考试标准(正式级)
  16. 车站计算机系统sc英文,城市轨道交通信号系统常见英文缩写大全(二)
  17. vs2012安装出错解决方案
  18. 60秒学脑科学常识——《科学美国人》专栏文集
  19. WTL 自绘控件库 (CQSTreeView)
  20. 安装时总是显示“$(DllSelfRegisterEx)不能被注册” 的解决方法

热门文章

  1. VB编程:While...Wend语句实例漂亮的星星-17
  2. SSM的小说上传下载网站含前后台-JAVA【数据库设计、源码、开题报告】
  3. [C语言]给出一个大于或等于3的正整数,判断他是不是一个素数。
  4. flex-grow 与flex-shink
  5. Hololens shader pack 全息材质库免费下载
  6. 如何启用计算机上的摄像头,笔记本的摄像头怎么打开,详细教您笔记本电脑摄像头如何打开...
  7. CCNA与CCNP的路该如何走?
  8. 操作系统第九章笔记---存储管理
  9. day10 房屋出租系统
  10. ubuntu_PL2303