本文参考BIOS/UEFI基础——Protocol介绍

大四第一个签三方的工作,BIOS的开发,第一次接触这个领域,在实习之前很好奇,也很有兴趣,但是学习BIOS在一开始注定要碰多次碰壁,实习第三周第二天,终于写好了自己的第一个protocol并成功调用,这对我来说有很大的意义。从找到第一份工作到现在,已经有将近四个月没有写博客了,正好记录一下这个对我有重大意义的小成功。

安装UEFI开发环境和UEFI基础知识略过不写,实习之前配置UEFI开发环境一直不成功,很正常的打击了我的学习兴趣和信心,实习以后熟悉基础知识并编写第一个protocol又很正常的打击了我的学习兴趣和信心,没事,习惯被打击就好。

对protocol的介绍也不再多说,所有的概念戴正华大佬的《UEFI原理与编程》已经讲的很清楚(虽然我看的很懵),我认为熟悉工程的最有效的方法就是实际动手编写代码,我编写的protocol的功能是比较两个数的大小,将大的数打印出来,至于这两个数是从键盘输入还是给固定的值,这都不重要,重要的是先写好一个protocol并成功调用。

编写一个protocol并调用分三个部分,定义一个protocol,安装这个protocol,使用这个protocol。
       首先列出我的工程目录:
       G:\edk2-UDK2017\Nt32Pkg\UEFIStart
       UEFIStart是我创建的文件夹,在UEFIStart下有两个文件夹:
                            
       分别存放protocol的安装代码和使用代码,每个文件夹有一个.c文件和.inf文件。
       而定义protocol的文件在G:\edk2-UDK2017\Nt32Pkg\Include\Protocol下,是一个.h文件(Compare.h):

       同样,对于工程文件的类型比如.inf、.dec、.dsc等文件的作用也不多说,参考《UEFI原理与编程》。

1.定义一个protocol

代码:

#ifndef _UEFIMAIN_COMPARE_PROTOCOL_H_
#define _UEFIMAIN_COMPARE_PROTOCOL_H_#include<Uefi.h>#define EFI_CPMPARE_PROTOCOL_GUID \
{0xee7ba45e, 0x9642, 0x4a97, {0x83, 0xc3, 0x30, 0xeb, 0xed, 0x3f, 0x9d, 0xd6}}  //定义这个protocol的GUIDtypedef struct _EFI_COMPARE_PROTOCOL EFI_COMPARE_PROTOCOL;typedef EFI_STATUS (EFIAPI *COMPARE)(    //定义一个函数指针,包括EFI_COMPARE_PROTOCOL类型的指针和两个要比较大小的数IN EFI_COMPARE_PROTOCOL *This,IN UINT8 a,IN UINT8 b
);struct _EFI_COMPARE_PROTOCOL {    //定义这个protocol的结构体,因为只实现比较大小,所以成员只有一个函数指针类型的成员COMPARE compare;};extern EFI_GUID gEfiCompareProtocolGuid;  //唯一的protocol,后面也会提到#endif

在Compare.h文件中extern EFI_GUID gEfiCompareProtocolGuid;这一句的gEfiCompareProtocolGuid是在Nt32Pkg的.dec文件中的[Protocols]中声明的,内容和Compare.h文件中的值一样:

       GUID的值我是用VS2013自带的生成工具生成的,
       必须在该目录下打开,如果光把guidgen.exe移到桌面或其他地方会出错。每个.inf文件也要有guid,也可以用这个生成。

我之所以直接放在Nt32Pkg下面是因为我对工程文件还不熟悉,Nt32Pkg下面有现成的.dec、.dsc、.fdf文件,我只需要向这些文件中添加必要的内容即可,具体什么内容后面会指出(比如向.dec文件中的[Protocols]添加gEfiCompareProtocolGuid的声明)。

2.安装protocol

代码:

#include<Uefi.h>
#include<Library/UefiBootServicesTableLib.h>
#include<Library/MemoryAllocationLib.h>
#include<Library/DebugLib.h>#include<Protocol/Compare.h>EFI_STATUS EFIAPI Compare(IN EFI_COMPARE_PROTOCOL *This,IN UINT8 a,IN UINT8 b)   //protocol要实现的功能
{DEBUG((EFI_D_ERROR, "The Max Number is: %d\n",(a>b?a:b)));return EFI_SUCCESS;
}EFI_STATUS EFIAPIProtocolInstallerEntry(IN EFI_HANDLE             ImageHandle,IN EFI_SYSTEM_TABLE       *SystemTable
)
{EFI_STATUS                Status;EFI_COMPARE_PROTOCOL      *Protocol;Protocol = AllocatePool(sizeof(EFI_COMPARE_PROTOCOL));if(NULL == Protocol){DEBUG((EFI_D_ERROR, "[Compare][%s][%d]:Out of resource.",__FUNCTION__, __LINE__));return EFI_OUT_OF_RESOURCES;}Protocol->compare = Compare;Status = gBS->InstallProtocolInterface(&ImageHandle,&gEfiCompareProtocolGuid,EFI_NATIVE_INTERFACE,Protocol);if(EFI_ERROR(Status)){DEBUG((EFI_D_ERROR, "[Compare]Install EFI_COMPARE_PROTOCOL failed. - %d\n", Status));FreePool(Protocol);return Status;}return EFI_SUCCESS;
}

安装protocol调用两个函数(说函数也行,接口也行,反正就是一个有功能的东西),在这里我把它的函数实现列举出来:
       AllocatePool

/**Allocates a buffer of type EfiBootServicesData.Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns apointer to the allocated buffer.  If AllocationSize is 0, then a valid buffer of 0 size isreturned.  If there is not enough memory remaining to satisfy the request, then NULL is returned.@param  AllocationSize        The number of bytes to allocate.@return A pointer to the allocated buffer or NULL if allocation fails.**/
VOID *
EFIAPI
AllocatePool (IN UINTN  AllocationSize)
{return (VOID*) malloc (AllocationSize);
}

InstallProtocolInterface是一个函数指针类型: EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface;
       EFI_INSTALL_PROTOCOL_INTERFACE这个函数指针的声明如下:

//
// Protocol handler functions
//
typedef enum {EFI_NATIVE_INTERFACE
} EFI_INTERFACE_TYPE;typedef
EFI_BOOTSERVICE
EFI_STATUS
(EFIAPI *EFI_INSTALL_PROTOCOL_INTERFACE) (IN OUT EFI_HANDLE           * Handle,IN EFI_GUID                 * Protocol,IN EFI_INTERFACE_TYPE       InterfaceType,IN VOID                     *Interface);

还有两个函数DEGBUG和FreePool我也列举出来:
       DEGBUG

  //// DEBUG((DebugLevel, "format string", ...)) - if DebugLevel is active do //   the a debug print.//#define DEBUG(arg)        EfiDebugPrint arg

这个函数本来是输出错误信息的,但是我为了方便,就调用它显示我的结果,其中EfiDebugPrint 的定义是:

VOID
EfiDebugPrint (IN  UINTN                   ErrorLevel,IN  CHAR8                   *Format,...)

FreePool

/**Frees a buffer that was previously allocated with one of the pool allocation functions in theMemory Allocation Library.Frees the buffer specified by Buffer.  Buffer must have been allocated on a previous call to thepool allocation services of the Memory Allocation Library.  If it is not possible to free poolresources, then this function will perform no actions.If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,then ASSERT().@param  Buffer                Pointer to the buffer to free.**/
VOID
EFIAPI
FreePool (IN VOID   *Buffer)
{free ((void *) Buffer);
}

还有就是,调用的函数要声明它的头文件,要找到函数的头文件。

2.使用Protocol

#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DebugLib.h>#include <Protocol/Compare.h>EFI_STATUS EFIAPI ProtocolUserEntry(IN EFI_HANDLE             ImageHandle,IN EFI_SYSTEM_TABLE       *SystemTable
)
{EFI_STATUS                Status;EFI_COMPARE_PROTOCOL      *Protocol;Status = gBS->LocateProtocol(&gEfiCompareProtocolGuid, NULL, (VOID **)&Protocol);if(EFI_ERROR(Status)){DEBUG((EFI_D_ERROR, "[BENI]Locate EFI_COMPARE_PROTOCOL failed. - %r\n",Status));return Status;}Status = Protocol->compare(Protocol,5,9);if(EFI_ERROR(Status)){DEBUG((EFI_D_ERROR, "[BENI]Protocol->Compare failed. - %r\n", Status));return EFI_SUCCESS;}return EFI_SUCCESS;
}

用LocateProtocol定位到protocol,然后调用,这里我给compare传的参数是5和9。
       其中LocateProtocol是EFI_LOCATE_PROTOCOL LocateProtocol;
       EFI_LOCATE_PROTOCOL是个函数指针:

typedef
EFI_BOOTSERVICE11
EFI_STATUS
(EFIAPI *EFI_LOCATE_PROTOCOL) (EFI_GUID  * Protocol,VOID      *Registration, OPTIONALVOID      **Interface);

这些做完了以后还要配置Nt32Pkg的.dec、.dsc、.fdf文件,.dec文件已经说过了,在.dsc文件中,要在[Components]下添加:
        Nt32Pkg/UEFIStart/ProtocolInstaller/ProtocolInstaller.inf
        Nt32Pkg/UEFIStart/ProtocolUser/ProtocolUser.inf
        在.fdf文件中,要在DXE Phase modules下添加:
        INF Nt32Pkg/UEFIStart/ProtocolInstaller/ProtocolInstaller.inf
       INF Nt32Pkg/UEFIStart/ProtocolUser/ProtocolUser.inf

3.运行结果


       因为我写的是UEFI_DRIVER所以要用load命令加载。

       比较5和9的大小,并将结果打印出来。

在写protocol的过程中遇到了很多问题,其中编写.inf文件遇到的问题最多,原因还是因为我对.inf文件不是很了解,以后会继续学习,加油。
       附上两个文件的.inf:
       ①ProtocolInstaller.inf

[Defines]INF_VERSION                 = 0x00010005BASE_NAME                   = ProtocolInstallerFILE_GUID                     = 8D952513-D3B5-43C7-87DF-CD3B382D65F7MODULE_TYPE                = UEFI_DRIVER        VERSION_STRING            = 1.0ENTRY_POINT                 = ProtocolInstallerEntry[Sources.common]ProtocolInstaller.c[Packages]Nt32Pkg/Nt32Pkg.decMdePkg/MdePkg.dec[LibraryClasses]UefiDriverEntryPointUefiBootServicesTableLibMemoryAllocationLibDebugLib[Protocols]gEfiCompareProtocolGuid[Depex]TRUE

②ProtocolUser.inf

[Defines]INF_VERSION                 = 0x00010005BASE_NAME                   = ProtocolUserFILE_GUID                     = 16BEFBED-60DC-4EA2-8E81-A3430A6CD6D5MODULE_TYPE                = UEFI_DRIVERVERSION_STRING            = 1.0ENTRY_POINT                 = ProtocolUserEntry[Sources.common]ProtocolUser.c[Packages]Nt32Pkg/Nt32Pkg.decMdePkg/MdePkg.dec[LibraryClasses]UefiDriverEntryPointUefiBootServicesTableLibDebugLib[Protocols]gEfiCompareProtocolGuid[Depex]TRUE

第一次写一个protocol还有很多不是很了解的地方,所以这篇博客如果有不对的地方欢迎大佬们指出。

UEFI开发,记录第一场胜利——调用一个自己编写的protocol相关推荐

  1. 瑞芯微芯片AI部分开发记录 第一节 《PC端环境搭建2》

    此部分为瑞芯微芯片NPU部分的开发记录.包括服务器(PC)端模型训练.模型转换以及瑞芯微接口调用rknn模型,实现目标检测任务. 本小节使用yolov3算法训练自己的数据集,并且部署到瑞芯微rk356 ...

  2. 瑞芯微芯片AI部分开发记录 第一节 《PC端环境搭建1》

    此部分为瑞芯微芯片NPU部分的开发记录.包括服务器(PC)端模型训练.模型转换以及瑞芯微接口调用rknn模型,实现目标检测任务. 本小节使用yolov3算法训练自己的数据集,并且部署到瑞芯微rk356 ...

  3. openresty通过ffi调用一个c编写的base64动态库

    base64编码的原理 base64不是加密,就是一种编码,将字符串的二进制按6个bit一组,每组的6个bit的形式转换一下. 每组6个bit对应的字符是 有特定的映射表决定. 映射表: 字符 序号 ...

  4. CY7C68013 USB接口相机开发记录 - 第一天:资料下载

    一直觉得从头开发一套东西出来会极大的提升自己的自信心,能够最大化的开发自己的潜能.所以在犹豫很久之后决定学习下CY7C68013 USB接口相机的开发. 通过在网上查找多份资料后,觉得工欲善其事必先利 ...

  5. api 接口开发理论 在php中调用接口以及编写接口

    如: http://localhost/openUser.php?act=get_user_list&type=json 在这里openUser.php相当于一个接口,其中get_user_l ...

  6. koa2 mysql_koa2+vue+mysql 全栈开发记录

    koa2+vue2+mysql 全栈开发记录 基于想要自己制作一个个人项目为由,于是有了这么一个开发记录(梳理开发过程也是一个知识巩固的过程) koa2+vue2+mysql 个人的一个通用DEMO( ...

  7. 【.NET Core 跨平台 GUI 开发】第一篇:编写你的第一个 Gtk# 应用

    本文是[.NET Core 跨平台 GUI 开发]系列博文的第一篇.该系列博文是一个关于 Gtk# 跨平台应用开发的初级随笔集合.该随笔集合介绍了 GTK 和 Gtk# 的基本信息以及开发方法,并展示 ...

  8. core开发linux桌面应用,【.NET Core 跨平台 GUI 开发】第一篇:编写你的第一个 Gtk# 应用...

    本文是[.NET Core 跨平台 GUI 开发]系列博文的第一篇.该系列博文是一个关于 Gtk# 跨平台应用开发的初级随笔集合.该随笔集合介绍了 GTK 和 Gtk# 的基本信息以及开发方法,并展示 ...

  9. 关于android开发中使用VideoView切换视频源时同时改变大小会出现下一个视频第一帧为上一个视频最后显示帧问题解决

    最近开发中使用到VideoView切换视频源时同时改变大小会出现下一个视频第一帧为上一个视频最后显示帧,网上找了很多资料想清除视频界面内容,但VideoView没有提供相关接口,尝试使用Surface ...

  10. Python全栈开发记录_第一篇(循环练习及杂碎的知识点)

    Python全栈开发记录只为记录全栈开发学习过程中一些难和重要的知识点,还有问题及课后题目,以供自己和他人共同查看.(该篇代码行数大约:300行) 知识点1:优先级:not>and 短路原则:a ...

最新文章

  1. MATLAB实现图像镜像变换的源代码
  2. 户外私密Party| 在大峡谷中聊点平时不能聊的产品干货(报名结束)
  3. Bound Services
  4. android studio 解决gradle加载依赖慢的问题
  5. Retrofit的简单使用
  6. android 通过代码seekbar控制led闪烁_02【pinpong库控制硬件】之Arduino unoLed闪烁1
  7. 洛谷 P4503 [CTSC2014]企鹅QQ 解题报告
  8. java 107问_JAVA面试题26-107(答案)
  9. 数据库MySQL/mariadb知识点——操作篇(4)数据操作语句
  10. 初、中、高级Java工程师有哪些区别?
  11. python2.7 UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5
  12. pdf 目录导入 macos
  13. 俄罗斯方块python代码
  14. IDEA的short command line 的作用
  15. 数据清洗有哪些方法?
  16. hpsocket错误码对照表
  17. Flir Blackfly S USB3 工业相机:白平衡设置方法
  18. Spring Boot基础教程 - 程序猿DD
  19. matlab如何导入大量数据
  20. ARM开发——常见仿真器

热门文章

  1. notepad实现垂直标签
  2. Vbs脚本编程简明教程之十二
  3. PLC 控制三相异步电动机正反转实验
  4. python第三方库:chardet字符编码检测和乱码处理
  5. 解决java.io.EOFException 异常
  6. Visual studio 2019 报错没有“dirent.h”文件
  7. C语言之数组的正向逆向输出
  8. 慧荣SM2258XT固态硬盘量产开卡经验sm2259xt雷同
  9. 硬件设计基础--电路仿真EDA软件
  10. 计算机网络-第一章测试题及答案