解析 DevicePath 的例子

krishnaLee(sssky307)为我们提供了一个解析DevicePath 的例子:

#include <Uefi.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>  //global gST gBS gImageHandle

#include <Protocol/LoadedImage.h> //EFI_LOADED_IMAGE_PROTOCOL
#include <Protocol/DevicePath.h> //EFI_DEVICE_PATH_PROTOCOL
#include <Protocol/DevicePathToText.h> //EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
#include <Library/DevicePathLib.h> //link

//reference:http://www.cppblog.com/djxzh/archive/2012/03/06/167106.aspx
//reference:https://www.lab-z.com/getcurd/


//My custom struct defined by UEFI 2.6 Spec
typedef struct
{
        UINT8 Type;
        UINT8 SubType;
        UINT16 Length;
        UINT32 PartitionNumber;
        UINT64 PartitionStart;
        UINT64 PartitionSize;
        GUID PartitionSig;
        UINT8 PartitionFormat;
        UINT8 SignatureType;
} HardDriveMediaDevicePath;

EFI_STATUS
EFIAPI
UefiMain (
        IN EFI_HANDLE        ImageHandle,
        IN EFI_SYSTEM_TABLE  *SystemTable
)
{
        EFI_STATUS                Status;
        EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
        EFI_DEVICE_PATH_PROTOCOL  *ImageDevicePath=NULL;
        UINT8                     *path;

        EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *Device2TextProtocol;
        CHAR16  *TextDevicePath;
        Print(L"Print Nodes:\n");


        //open the Loaded image protocol,which is binded on the imageHandle,to get the device handle.
        Status = gBS->OpenProtocol (
                         gImageHandle,
                         &gEfiLoadedImageProtocolGuid,
                         (VOID**)&LoadedImage,
                         gImageHandle,
                         NULL,
                         EFI_OPEN_PROTOCOL_GET_PROTOCOL
                 );

//get the device path protocol for the device handle.
        if (!EFI_ERROR (Status))
        {
                Status = gBS->OpenProtocol (
                                 LoadedImage->DeviceHandle,
                                 &gEfiDevicePathProtocolGuid,
                                 (VOID**)&ImageDevicePath,    //get the path protocol
                                 gImageHandle,
                                 NULL,
                                 EFI_OPEN_PROTOCOL_GET_PROTOCOL
                         );
        }

//parse the device path
        path=(UINT8 *)ImageDevicePath;

        while(1)
        {
                if(((EFI_DEVICE_PATH_PROTOCOL  *)path)->Type==0x7F||((EFI_DEVICE_PATH_PROTOCOL  *)path)->SubType==0xFF)
                {
                        //if it is end node:
                        Print(L"type:%d,subType:%d,length:%d\n",\
                              ((EFI_DEVICE_PATH_PROTOCOL  *)path)->Type,\
                              ((EFI_DEVICE_PATH_PROTOCOL  *)path)->SubType,\
                              ((EFI_DEVICE_PATH_PROTOCOL  *)path)->Length[0]+((EFI_DEVICE_PATH_PROTOCOL  *)path)->Length[1]*0xff);
                        break;
                }
                else
                {
                        UINT16 len=((EFI_DEVICE_PATH_PROTOCOL  *)path)->Length[0]+((EFI_DEVICE_PATH_PROTOCOL  *)path)->Length[1]*0xff;
                        Print(L"type:%d,subType:%d,length:%d\n",\
                              ((EFI_DEVICE_PATH_PROTOCOL  *)path)->Type,\
                              ((EFI_DEVICE_PATH_PROTOCOL  *)path)->SubType,\
                              ((EFI_DEVICE_PATH_PROTOCOL  *)path)->Length[0]+((EFI_DEVICE_PATH_PROTOCOL  *)path)->Length[1]*0xff);

                        //print my concern node
                        if(((EFI_DEVICE_PATH_PROTOCOL  *)path)->Type==0x4&&((EFI_DEVICE_PATH_PROTOCOL  *)path)->SubType==0x1)
                        {
                                HardDriveMediaDevicePath *path2=(HardDriveMediaDevicePath *)path;
                                Print(L"    PartitionNumber:%d \n    PartitionStart:0x%lx \n    PartitionSize:0x%lx \n    PartitionSig:%g \n    PartitionFormat:%d \n    SignatureType:%d \n",\
                                      path2->PartitionNumber,path2->PartitionStart,path2->PartitionSize,path2->PartitionSig,path2->PartitionFormat,path2->SignatureType);
                        }

                        //go to next node;
                        path+=len;
                }
        }//while end

//get a converter.
        Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid,
                                     NULL,
                                     (VOID**)&Device2TextProtocol
                                    );

//convert device path to text.
        if (!EFI_ERROR (Status))
        {
                TextDevicePath= Device2TextProtocol->ConvertDevicePathToText(ImageDevicePath, 1, 1);
                Print(L"%s\n",TextDevicePath);
                gBS->FreePool(TextDevicePath);
        }

//clear
        gBS->CloseProtocol(
                LoadedImage->DeviceHandle,
                &gEfiDevicePathProtocolGuid,
                gImageHandle,
                NULL);

        gBS->CloseProtocol(
                gImageHandle,
                &gEfiLoadedImageProtocolGuid,
                gImageHandle,
                NULL);

        return EFI_SUCCESS;
}

 

运行结果如下:

ptdf

X64 的 EFI: mytestpathX64
完整的代码下载: mytestpath

《解析 DevicePath 的例子》有6个想法

  1. 还有一个小问题是,我之前练习一直用的QEMU,现在看VirtualBOX也挺好用。博主有用过么?用过的话能请教下将编译好的.efi放到什么位置并进行设置才能让虚拟机在shell里读到呢。在VirtualBOX里不太会。

    1. VirtualBox 的话,我还没有找到好办法直接把外面的东西 copy 到里面去。理论上你可以创建一个虚拟硬盘,然后把外面东西copy到这个硬盘上就可以在 fs0: 下面运行。 可行的接口有:串口, USB ,网卡.......但是目前我还没有找到方便易行的方案。如果你有空不妨研究一下。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注