关于PCI_ROOT_BRIDGE_IO_PROTOCOL:

作用:该协议用于与PCI总线上的根桥(Root Bridge)进行通信,根桥是PCI总线的起始点,它负责转发数据和控制信号。
功能:EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL提供了访问PCI总线上的根桥所需的各种功能和方法,包括内存读写、I/O读写、配置空间读写等。
使用场景:主要用于与PCI总线上的根桥进行通信和配置,例如初始化PCI设备、读取和修改PCI设备的配置寄存器等。

#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Protocol/PciRootBridgeIo.h>

EFI_STATUS EnumeratePciDevices()
{
    EFI_STATUS Status;
    EFI_HANDLE *HandleBuffer;
    UINTN HandleCount;

    // 获取PCI根桥IO协议的句柄
    Status = gBS->LocateHandleBuffer(
        ByProtocol,
        &gEfiPciRootBridgeIoProtocolGuid,
        NULL,
        &HandleCount,
        &HandleBuffer);

    if (EFI_ERROR(Status))
    {
        // 错误处理
        return Status;
    }

    UINTN Index;
    EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;

    // 遍历所有PCI根桥IO协议
    for (Index = 0; Index < HandleCount; Index++)
    {
        // 获取PCI根桥IO协议实例
        Status = gBS->HandleProtocol(
            HandleBuffer[Index],
            &gEfiPciRootBridgeIoProtocolGuid,
            (VOID **)&PciRootBridgeIo);

        if (EFI_ERROR(Status))
        {
            // 错误处理
            continue;
        }

        // 获取PCI根桥上的所有PCI设备
        UINT64 Segment;
        Status = PciRootBridgeIo->Configuration->GetSegment(PciRootBridgeIo->Configuration, &Segment);

        if (EFI_ERROR(Status))
        {
            // 错误处理
            continue;
        }

        UINT64 Bus;
        for (Bus = 0; Bus <= 0xFF; Bus++)
        {
            UINT64 Device;
            for (Device = 0; Device <= 0x1F; Device++)
            {
                UINT64 Function;
                for (Function = 0; Function <= 0x7; Function++)
                {
                    // 构建PCI设备地址
                    EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress;
                    PciAddress.Bus = (UINT32)Bus;
                    PciAddress.Device = (UINT32)Device;
                    PciAddress.Function = (UINT32)Function;

                    // 读取设备的Vendor ID和Device ID
                    UINT16 VendorId, DeviceId;
                    Status = PciRootBridgeIo->Pci.Read(
                        PciRootBridgeIo,
                        EfiPciWidthUint16,
                        PciAddress,
                        offsetof(PCI_DEVICE_HEADER, VendorId),
                        1,
                        &VendorId);

                    if (EFI_ERROR(Status))
                    {
                        // 错误处理
                        continue;
                    }

                    Status = PciRootBridgeIo->Pci.Read(
                        PciRootBridgeIo,
                        EfiPciWidthUint16,
                        PciAddress,
                        offsetof(PCI_DEVICE_HEADER, DeviceId),
                        1,
                        &DeviceId);

                    if (EFI_ERROR(Status))
                    {
                        // 错误处理
                        continue;
                    }

                    // 打印设备的Vendor ID和Device ID
                    Print(L"PCI Device: Bus %02X, Device %02X, Function %X\n", Bus, Device, Function);
                    Print(L"Vendor ID: %04X\n", VendorId);
                    Print(L"Device ID: %04X\n\n", DeviceId);
                }
            }
        }
    }
 // 释放句柄缓冲区
    gBS->FreePool(HandleBuffer);

    return EFI_SUCCESS;
}

关于EFI_PCI_IO_PROTOCOL:

EFI_PCI_IO_PROTOCOL是用于与具体设备通信的协议,用于访问PCI总线上的具体设备。
在使用时,首先使用EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL来初始化和配置PCI总线上的根桥,然后使用EFI_PCI_IO_PROTOCOL来与具体设备进行通信和控制。
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL提供了用于访问配置空间的方法,可以用于获取和修改设备的配置信息。
EFI_PCI_IO_PROTOCOL提供了更多的操作方法,可以进行内存读写、I/O读写、数据传输等操作。

这里主要两个示例合二为一,读取配置空间以及BAR中的内容(网卡的mac地址):

#include <Uefi.h>
#include <Protocol/PciIo.h>

EFI_STATUS GetMacAddressFromPci()
{
    EFI_STATUS Status;
    EFI_HANDLE *HandleBuffer;
    UINTN HandleCount;

    // 获取所有PCI设备的句柄
    Status = gBS->LocateHandleBuffer(
        ByProtocol,
        &gEfiPciIoProtocolGuid,
        NULL,
        &HandleCount,
        &HandleBuffer);

    if (EFI_ERROR(Status))
    {
        // 错误处理
        return Status;
    }

    UINTN Index;
    EFI_PCI_IO_PROTOCOL *PciIo;

    // 遍历所有PCI设备
    for (Index = 0; Index < HandleCount; Index++)
    {
        // 获取PCI IO Protocol
        Status = gBS->HandleProtocol(
            HandleBuffer[Index],
            &gEfiPciIoProtocolGuid,
            (VOID **)&PciIo);

        if (EFI_ERROR(Status))
        {
            // 错误处理
            continue;
        }

        // 判断是否为网卡设备(可根据设备的Vendor ID和Device ID进行判断)
        UINT16 VendorId, DeviceId;
        Status = PciIo->Pci.Read(
            PciIo,
            EfiPciIoWidthUint16,
            0x00, // Vendor ID寄存器地址
            1,    // 寄存器数量
            &VendorId);

        if (EFI_ERROR(Status))
        {
            // 错误处理
            continue;
        }

        Status = PciIo->Pci.Read(
            PciIo,
            EfiPciIoWidthUint16,
            0x02, // Device ID寄存器地址
            1,    // 寄存器数量
            &DeviceId);

        if (EFI_ERROR(Status))
        {
            // 错误处理
            continue;
        }

        if (VendorId == 0x10EC && DeviceId == 0x8168)
        {
            // 根据具体的Vendor ID和Device ID判断是否为目标网卡设备

            // 读取MAC地址
            UINT8 MacAddress[6];
            Status = PciIo->Pci.Read(
                PciIo,
                EfiPciIoWidthUint8,
                0x00, // MAC地址起始寄存器地址
                6,    // 寄存器数量
                MacAddress);

            if (EFI_ERROR(Status))
            {
                // 错误处理
                continue;
            }

            // 打印MAC地址
            Print(L"MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
                  MacAddress[0], MacAddress[1], MacAddress[2],
                  MacAddress[3], MacAddress[4], MacAddress[5]);
        }
    }

    // 释放句柄缓冲区
    gBS->FreePool(HandleBuffer);

    return EFI_SUCCESS;
}

获取BDF:

#include <Uefi.h>
#include <Protocol/PciIo.h>

EFI_STATUS GetPciBdf()
{
    EFI_STATUS Status;
    EFI_HANDLE *HandleBuffer;
    UINTN HandleCount;

    // 获取所有PCI设备的句柄
    Status = gBS->LocateHandleBuffer(
        ByProtocol,
        &gEfiPciIoProtocolGuid,
        NULL,
        &HandleCount,
        &HandleBuffer);

    if (EFI_ERROR(Status))
    {
        // 错误处理
        return Status;
    }

    UINTN Index;
    EFI_PCI_IO_PROTOCOL *PciIo;

    // 遍历所有PCI设备
    for (Index = 0; Index < HandleCount; Index++)
    {
        // 获取PCI IO Protocol
        Status = gBS->HandleProtocol(
            HandleBuffer[Index],
            &gEfiPciIoProtocolGuid,
            (VOID **)&PciIo);

        if (EFI_ERROR(Status))
        {
            // 错误处理
            continue;
        }

        // 获取BDF信息
        UINTN SegmentNumber;
        UINTN BusNumber;
        UINTN DeviceNumber;
        UINTN FunctionNumber;

        Status = PciIo->GetLocation(
            PciIo,
            &SegmentNumber,
            &BusNumber,
            &DeviceNumber,
            &FunctionNumber);

        if (EFI_ERROR(Status))
        {
            // 错误处理
            continue;
        }

        // 打印BDF信息
        Print(L"BDF: %04x:%02x:%02x.%x\n",
              SegmentNumber, BusNumber, DeviceNumber, FunctionNumber);
    }

    // 释放句柄缓冲区
    gBS->FreePool(HandleBuffer);

    return EFI_SUCCESS;
}

当然还有另外一种读网卡mac地址的方式:

#include <Uefi.h>
#include <Protocol/SimpleNetwork.h>

EFI_STATUS GetMacAddress()
{
    EFI_STATUS Status;
    EFI_HANDLE *HandleBuffer;
    UINTN HandleCount;

    // 获取所有网络设备的句柄
    Status = gBS->LocateHandleBuffer(
        ByProtocol,
        &gEfiSimpleNetworkProtocolGuid,
        NULL,
        &HandleCount,
        &HandleBuffer);

    if (EFI_ERROR(Status))
    {
        // 错误处理
        return Status;
    }

    UINTN Index;
    EFI_SIMPLE_NETWORK_PROTOCOL *Snp;

    // 遍历所有网络设备
    for (Index = 0; Index < HandleCount; Index++)
    {
        // 获取Simple Network Protocol
        Status = gBS->HandleProtocol(
            HandleBuffer[Index],
            &gEfiSimpleNetworkProtocolGuid,
            (VOID **)&Snp);

        if (EFI_ERROR(Status))
        {
            // 错误处理
            continue;
        }

        EFI_MAC_ADDRESS MacAddress;

        // 获取MAC地址
        Status = Snp->GetMacAddress(Snp, &MacAddress);

        if (EFI_ERROR(Status))
        {
            // 错误处理
            continue;
        }

        // 打印MAC地址
        Print(L"MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
              MacAddress.Addr[0], MacAddress.Addr[1], MacAddress.Addr[2],
              MacAddress.Addr[3], MacAddress.Addr[4], MacAddress.Addr[5]);
    }

    // 释放句柄缓冲区
    gBS->FreePool(HandleBuffer);

    return EFI_SUCCESS;
}

然后就是文件系统,比如读取USB设备中的文件:

#include <Uefi.h>
#include <Protocol/SimpleFileSystem.h>
#include <Protocol/LoadedImage.h>

EFI_STATUS ReadFileFromUSB()
{
    EFI_STATUS Status;
    EFI_HANDLE *HandleBuffer;
    UINTN HandleCount;

    // 获取所有文件系统协议的句柄
    Status = gBS->LocateHandleBuffer(
        ByProtocol,
        &gEfiSimpleFileSystemProtocolGuid,
        NULL,
        &HandleCount,
        &HandleBuffer);

    if (EFI_ERROR(Status))
    {
        // 错误处理
        return Status;
    }

    UINTN Index;
    EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
    EFI_FILE_PROTOCOL *RootDir;

    // 遍历所有文件系统
    for (Index = 0; Index < HandleCount; Index++)
    {
        // 获取文件系统协议
        Status = gBS->HandleProtocol(
            HandleBuffer[Index],
            &gEfiSimpleFileSystemProtocolGuid,
            (VOID **)&FileSystem);

        if (EFI_ERROR(Status))
        {
            // 错误处理
            continue;
        }

        // 打开根目录
        Status = FileSystem->OpenVolume(FileSystem, &RootDir);
        if (EFI_ERROR(Status))
        {
            // 错误处理
            continue;
        }

        // 打开目标文件
        EFI_FILE_PROTOCOL *FileHandle;
        Status = RootDir->Open(
            RootDir,
            &FileHandle,
            L"filename.txt", // 文件名
            EFI_FILE_MODE_READ, // 打开模式
            0); // 属性

        if (EFI_ERROR(Status))
        {
            // 错误处理
            RootDir->Close(RootDir);
            continue;
        }

        // 读取文件内容
        UINTN BufferSize = 1024; // 缓冲区大小
        UINT8 Buffer[BufferSize];
        Status = FileHandle->Read(
            FileHandle,
            &BufferSize,
            Buffer);

        if (EFI_ERROR(Status))
        {
            // 错误处理
            FileHandle->Close(FileHandle);
            RootDir->Close(RootDir);
            continue;
        }

        // 在此处对读取的文件内容进行处理或打印

        // 关闭文件和根目录
        FileHandle->Close(FileHandle);
        RootDir->Close(RootDir);
    }

    // 释放句柄缓冲区
    gBS->FreePool(HandleBuffer);

    return EFI_SUCCESS;
}

再一个就是USB设备扫描:

#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/UsbIo.h>
#include <Protocol/Usb2HostController.h>

EFI_STATUS ScanUsbDevices()
{
    EFI_STATUS status;
    EFI_HANDLE *controllerHandles;
    UINTN controllerHandleCount;
    UINTN index;

    // 获取所有USB控制器的句柄
    status = gBS->LocateHandleBuffer(
        ByProtocol,
        &gEfiUsb2HcProtocolGuid,
        NULL,
        &controllerHandleCount,
        &controllerHandles
    );
    if (EFI_ERROR(status)) {
        Print(L"Failed to locate USB controllers. Error: %r\n", status);
        return status;
    }

    // 遍历所有USB控制器并扫描设备
    for (index = 0; index < controllerHandleCount; index++) {
        EFI_USB2_HC_PROTOCOL *usbHc;
        status = gBS->OpenProtocol(
            controllerHandles[index],
            &gEfiUsb2HcProtocolGuid,
            (VOID **)&usbHc,
            gImageHandle,
            NULL,
            EFI_OPEN_PROTOCOL_GET_PROTOCOL
        );
        if (EFI_ERROR(status)) {
            Print(L"Failed to open USB2_HC_PROTOCOL. Error: %r\n", status);
            continue;
        }

        // 扫描USB设备
        EFI_USB_DEVICE_DESCRIPTOR deviceDescriptor;
        EFI_USB_INTERFACE_DESCRIPTOR interfaceDescriptor;
        EFI_HANDLE deviceHandle = NULL;

        for (UINT8 port = 1; port <= usbHc->GetRootHubPortNumber(usbHc); port++) {
            status = usbHc->GetRootHubPortStatus(usbHc, port, &portStatus);
            if (EFI_ERROR(status)) {
                // 处理错误
                continue;
            }

            if (portStatus.PortStatus.PortConnected) {
                // 获取USB设备描述符
                status = usbHc->GetRootHubPortStatus(usbHc, port, &deviceDescriptor);
                if (EFI_ERROR(status)) {
                    // 处理错误
                    continue;
                }

                // 创建USB设备的句柄
                status = usbHc->CreateDevice(usbHc, &deviceHandle);
                if (EFI_ERROR(status)) {
                    // 处理错误
                    continue;
                }

                // 设置USB设备的配置
                status = usbHc->SetConfig(usbHc, deviceHandle, deviceConfig);
                if (EFI_ERROR(status)) {
                    // 处理错误
                    continue;
                }

                // 获取USB设备的接口描述符
                status = usbHc->GetInterfaceDescriptor(usbHc, deviceHandle, &interfaceDescriptor);
                if (EFI_ERROR(status)) {
                    // 处理错误
                    continue;
                }

                // 处理扫描到的USB设备

                // 关闭USB设备的句柄
                usbHc->DestroyDevice(usbHc, deviceHandle);
                deviceHandle = NULL;
            }
        }

上述代码可以说是一个模版,需要用到的时候直接参照就行,当然还有比如PCI设备的Capability部分怎么去获取等等

获取DEVICE PATH:

#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DevicePathLib.h>

EFI_STATUS PrintDevicePath(EFI_HANDLE deviceHandle)
{
    EFI_STATUS status;
    EFI_DEVICE_PATH_PROTOCOL *devicePath;

    // 获取设备的Device Path
    status = gBS->HandleProtocol(
        deviceHandle,
        &gEfiDevicePathProtocolGuid,
        (VOID **)&devicePath
    );
    if (EFI_ERROR(status)) {
        Print(L"Failed to get Device Path Protocol. Error: %r\n", status);
        return status;
    }

    // 打印设备的Device Path
    CHAR16 *devicePathString = ConvertDevicePathToText(devicePath, FALSE, FALSE);
    if (devicePathString != NULL) {
        Print(L"Device Path: %s\n", devicePathString);
        FreePool(devicePathString);
    }

    return EFI_SUCCESS;
}

EFI_STATUS EFIAPI UefiMain(
    IN EFI_HANDLE ImageHandle,
    IN EFI_SYSTEM_TABLE *SystemTable
)
{
    EFI_STATUS status;
    EFI_HANDLE *deviceHandles;
    UINTN deviceHandleCount;
    UINTN index;

    // 获取所有设备的句柄
    status = gBS->LocateHandleBuffer(
        AllHandles,
        NULL,
        NULL,
        &deviceHandleCount,
        &deviceHandles
    );
    if (EFI_ERROR(status)) {
        Print(L"Failed to locate devices. Error: %r\n", status);
        return status;
    }

    // 遍历所有设备并打印Device Path
    for (index = 0; index < deviceHandleCount; index++) {
        status = PrintDevicePath(deviceHandles[index]);
        if (EFI_ERROR(status)) {
            // 处理错误
        }
    }

    // 释放内存
    FreePool(deviceHandles);

    return EFI_SUCCESS;
}
05-18 00:59