UEFI开发学习15 – Device Path

前言

最近在写小功能,其中需要把信息以文件的形式保存在U盘上。U盘是一个存储设备,可以用 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL 把找出来,但是如果有其它的存储设备,如硬盘(fat32分区),也会被列出来。那怎么来区分这两种设备呢?进入efi shell的时候,可以通过观察设备路径(Device Path)就很容易分辨出哪个是USB,哪个是SATA了,所以程序上也可据此判断。

Device Path Protocol

此Protocol可以在任何Device Handle上都可以使用,用以获得与物理设备或逻辑设备有关的通用路径/位置信息, 定义如下:

//*******************************************************
// EFI_DEVICE_PATH_PROTOCOL
//*******************************************************
typedef struct _EFI_DEVICE_PATH_PROTOCOL {
  UINT8 Type;
  UINT8 SubType;
  UINT8 Length[2];
} EFI_DEVICE_PATH_PROTOCOL;

其中,Type为主类型,SubType为子类型,Length为结构体的长度。要注意一下的是,这个定义不是一个完整的设备路径,这只相当于设备路径中的一个Header,通用的设备路径(Generic Device Path)定义如下:

最后一部分的数据是跟随设备类型变化的,所以才有一个Length,它的长度是Length=n+4。

一个完整的Device Path是由多个部分组成的,每个部分被称为Node,每个Node由一个通用设备路径和设备数据组成。UEFI中支持6种主类型,如上图。每种主类型下可能还有几种子类型,如Type1 Hardware Device Path下就有PCI、PCCARD、Memory Mapped、Vendor、Controller、BMC这6种Sub-Type。

下面通过实例来认识设备路径。

实例1:打印设备路径

思路:

1.找到一个Device Path

2.使用EFI_DEVICE_PATH_TO_TEXT_PROTOCOL 将得到的设备路径转换为字符串

程序实现如下:

#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/DevicePath.h>
#include <Protocol/DevicePathToText.h>

int main(int argc, char **argv) 
{
    EFI_STATUS                         Status;
    EFI_DEVICE_PATH_PROTOCOL         * DevPath;
    EFI_DEVICE_PATH_TO_TEXT_PROTOCOL * DevPath2Text;
    CHAR16                           * DevPathText;

    Status = gBS->LocateProtocol(&gEfiDevicePathProtocolGuid, NULL, (VOID *) &DevPath);
    if (EFI_ERROR(Status)) {
        Print(L"Error %r\n\r", Status);
        return Status;
    }

    Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID *) &DevPath2Text);
    if (EFI_ERROR(Status)) {
        Print(L"Error %r\n\r", Status);
        return Status;
    }

    DevPathText = DevPath2Text->ConvertDevicePathToText(DevPath, TRUE, FALSE);

    Print(L"Device path: %s\n\r", DevPathText);

    return 0;
}

实例2:找到所有USB存储设备

思路:

1.找到所有的文件系统设备

2.在找到的设备中逐个判断其设备路径,直到找到USB Node的设备

程序如下:

#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellLib.h>
#include <Library/DevicePathLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/DevicePath.h>
#include <Protocol/DevicePathToText.h>

int main(int argc, char **argv) 
{
    EFI_STATUS                         Status;
    EFI_DEVICE_PATH_PROTOCOL         * DevPath;
    EFI_DEVICE_PATH_TO_TEXT_PROTOCOL * DevPath2Text;
    EFI_HANDLE                       * HandleBuffer;
    UINTN                              HandleCount;
    UINTN                              Index;

    Status = gBS->LocateHandleBuffer(
                        ByProtocol,
                        &gEfiSimpleFileSystemProtocolGuid,
                        NULL,
                        &HandleCount,
                        &HandleBuffer
                        );
    if (EFI_ERROR(Status)) {
        Print(L"Error %r\n\r", Status);
        return Status;
    }

    for (Index = 0; Index < HandleCount; Index ++) {
        Status = gBS->HandleProtocol(HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *)&DevPath);
        if (EFI_ERROR(Status)) continue;

        while (1) {
            if (DevPath->Type == MESSAGING_DEVICE_PATH &&
                DevPath->SubType == MSG_USB_DP ) {
                Print (L"Usb storage found:%s\n\r", DevPath2Text->ConvertDevicePathToText(DevPath, TRUE, FALSE));
                break;
            }

            if (IsDevicePathEnd (DevPath)) {
                break;
            }

            DevPath = NextDevicePathNode(DevPath);
        }
    }

    return 0;
}

代码

以后代码都会传到Gitee,避免链接失效。

https://gitee.com/ay123net/uefistudy

版权声明:
作者:bin
链接:https://ay123.net/mystudy/uefi/1107/
来源:爱影博客
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
海报
UEFI开发学习15 – Device Path
前言 最近在写小功能,其中需要把信息以文件的形式保存在U盘上。U盘是一个存储设备,可以用 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL 把找出来,但是如果有其它的存储……
<<上一篇
下一篇>>