UEFI 基础教程 (十九) — PCIe 简单使用

文章展示了如何在UEFI应用中定位PCI根桥并枚举PCI设备。通过`LocatePciRootBridgeIo`和`PciDevicePresent`函数,程序查找`gPciRootBridgeIoProtocol`,读取设备信息,并使用`PciIoProtocol`访问设备。代码实现了从EFI入口点开始的PCI设备搜索过程。
摘要由CSDN通过智能技术生成

一 编写源代码

//OvmfPkg/HelloWorldPci/HelloWorldPci.c
#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/ShellCEntryLib.h>
#include <Library/DebugLib.h>

#include <Protocol/PciIo.h>
#include <Protocol/PciRootBridgeIo.h>
#include <IndustryStandard/Pci.h>


EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *gPciRootBridgeIo;

EFI_STATUS LocatePciRootBridgeIo(void);

EFI_STATUS PciDevicePresent(
  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * PciRootBridgeIo,
  OUT PCI_TYPE00 * Pci,
  IN UINT8 Bus,
  IN UINT8 Device,
  IN UINT8 Func
  );

EFI_STATUS ListPciInformation(void);


EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS Status;


  Status = LocatePciRootBridgeIo();
  if(EFI_ERROR(Status))
  {
    DEBUG((DEBUG_ERROR, "[CSDN]Call LocatePciRootBridgeIo failed,Can't find protocol!\n"));
  }
  else
  {
    DEBUG((DEBUG_ERROR, "[CSDN]Call LocatePciRootBridgeIo successed,Find protocol!\n"));
  }


  ListPciInformation();
  
  return EFI_SUCCESS;
}

EFI_STATUS LocatePciRootBridgeIo()
{
  EFI_STATUS Status;
  EFI_HANDLE *PciHandleBuffer = NULL;
  UINTN      HandleIndex = 0;
  UINTN      HandleCount = 0;

  Status = gBS->LocateHandleBuffer(
    ByProtocol,
    &gEfiPciRootBridgeIoProtocolGuid,
    NULL,
    &HandleCount,
    &PciHandleBuffer 
    );
  if(EFI_ERROR(Status))  return Status;

  for(HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++)
  {
    Status = gBS->HandleProtocol(
      PciHandleBuffer[HandleIndex],
      &gEfiPciRootBridgeIoProtocolGuid,
      (VOID **)&gPciRootBridgeIo
      );
    if(EFI_ERROR(Status))  continue;
    else                   return EFI_SUCCESS;
  }

  return Status;
  
}

EFI_STATUS ListPciInformation()
{
  EFI_STATUS Status = EFI_SUCCESS;
  PCI_TYPE00 Pci;
  UINT16 Dev,Func,Bus,PciDevicecount = 0;

  DEBUG((DEBUG_ERROR, "[CSDN] PciDeviceNo\tBus\tDev\tFunc | Vendor.Device.ClassCode\n"));
  for(Bus=0; Bus<256; Bus++) {
    for(Dev=0; Dev<= PCI_MAX_DEVICE; Dev++)
      for(Func=0; Func<=PCI_MAX_FUNC; Func++)
      {
        Status = PciDevicePresent(gPciRootBridgeIo,&Pci,(UINT8)Bus,(UINT8)Dev,(UINT8)Func);
          if(Status == EFI_SUCCESS)
          {
            PciDevicecount++;
            DEBUG((DEBUG_ERROR, "[CSDN] %d\t\t%x\t%x\t%x\t",PciDevicecount,(UINT8)Bus,(UINT8)Dev,(UINT8)Func));
            DEBUG((DEBUG_ERROR, "%x\t%x\t%x\n",Pci.Hdr.VendorId,Pci.Hdr.DeviceId,Pci.Hdr.ClassCode[0]));
          }
      }
  }
  return EFI_SUCCESS;
}

EFI_STATUS
PciDevicePresent (
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL     *PciRootBridgeIo,
  OUT PCI_TYPE00                          *Pci,
  IN  UINT8                               Bus,
  IN  UINT8                               Device,
  IN  UINT8                               Func
  )
{
  UINT64      Address;
  EFI_STATUS  Status;

  //
  // Create PCI address map in terms of Bus, Device and Func
  //
  Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);

  //
  // Read the Vendor ID register
  //
  Status = PciRootBridgeIo->Pci.Read (
                                  PciRootBridgeIo,
                                  EfiPciWidthUint32,
                                  Address,
                                  1,
                                  Pci
                                  );

  if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId != 0xffff) {
    //
    // Read the entire config header for the device
    //
    Status = PciRootBridgeIo->Pci.Read (
                                    PciRootBridgeIo,
                                    EfiPciWidthUint32,
                                    Address,
                                    sizeof (PCI_TYPE00) / sizeof (UINT32),
                                    Pci
                                    );

    return EFI_SUCCESS;
  }

  return EFI_NOT_FOUND;
}
//OvmfPkg/HelloWorldPci/HelloWorldPci.inf
[Defines]
  INF_VERSION                    = 0x00010005
  BASE_NAME                      = HelloWorldPci
  FILE_GUID                      = 6987935E-ED34-44db-AE97-1FA5E4ED2116
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 1.0
  ENTRY_POINT                    = UefiMain

#
#  This flag specifies whether HII resource section is generated into PE image.
#
  UEFI_HII_RESOURCE_SECTION      = TRUE

#
# The following information is for reference only and not required by the build tools.
#
#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
#

[Sources]
  HelloWorldPci.c


[Packages]
  MdePkg/MdePkg.dec
  MdeModulePkg/MdeModulePkg.dec
  ShellPkg/ShellPkg.dec 

[LibraryClasses]
  UefiApplicationEntryPoint
  UefiShellCEntryLib
  BaseLib
  BaseMemoryLib
  DebugLib
  UefiBootServicesTableLib
  MemoryAllocationLib
  UefiLib
  UefiLib
  PcdLib

二、 编译生成EFI文件 & 运行

在这里插入图片描述

三、 小结

UEFI 中枚举PCIe device过程主要创建两个Protocol,分别是 gPciRootBridgeIoProtocolPciIoProtocol 。其中,gPciRootBridgeIoProtocol对应一个RootBridge(RootCompex), 实现了该RootBridge下所有PCIe读写实现。 PciIoProtocol对应每一个枚举到的设备。 如果想在UEFI 下访问PCIe设备,可以借助这两个Protocol

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UEFI引导修复教程如下: 1. 确认ESP分区:首先,确保你的硬盘上有一个ESP(EFI System Partition)分区。这个分区通常是一个FAT格式的分区,用于存储引导文件。你可以使用磁盘管理工具来查看分区情况。 2. 使用Windows安装介质:如果你有Windows安装光盘或USB安装介质,可以使用它来修复UEFI引导。插入安装介质并重启计算机。 3. 进入UEFI设置:在计算机启动时,按下相应的按键(通常是F2、F10、F12或Delete键)进入UEFI设置界面。在设置界面中,找到启动选项。 4. 选择引导设备:在启动选项中,选择你的安装介质作为首选引导设备。保存设置并退出UEFI设置界面。 5. 进入修复环境:计算机将从安装介质启动,并进入Windows修复环境。在修复环境中,选择“修复你的计算机”。 6. 选择故障排除:在修复选项中,选择“故障排除”。 7. 选择高级选项:在故障排除选项中,选择“高级选项”。 8. 选择命令提示符:在高级选项中,选择“命令提示符”。 9. 修复引导:在命令提示符中,输入以下命令来修复UEFI引导: ``` bootrec /fixboot bootrec /fixmbr bootrec /rebuildbcd ``` 10. 重启计算机:完成修复后,输入“exit”命令退出命令提示符,并重启计算机。 这些步骤将帮助你修复UEFI引导问题。请注意,具体的步骤可能因计算机品牌和型号而有所不同。如果你不确定如何操作,请参考计算机的用户手册或联系计算机制造商的技术支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值