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

       本文参考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还有很多不是很了解的地方,所以这篇博客如果有不对的地方欢迎大佬们指出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/354181.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

linux系统nohob安装,Linux启动详解1

一、固件运行 本部分主要参考 戴正华 著《UEFI原理与编程》 CPU在加电后会进入16位实模式状态运行&#xff0c;同时CPU的逻辑电路设计为加电瞬间将CS的值设置为 0xF000、IP的值置为0xFFF0&#xff0c;这样CS&#xff1a;IP就指向0xFFFF0这个地址位置。然后开始执行固件 固件的执…

《UEFI原理与编程》读书笔记

《UEFI原理与编程》读书笔记 读书笔记仅摘取对个人有用的部分&#xff0c;详细内容请阅读原著 目前更新至第七章&#xff0c;因个人仅需要引导程序&#xff0c;故其余部分未介绍&#xff0c;详细内容请阅读原著 书及其资料均已放置在本人资源中&#xff0c;如需下载请移步资源模…

UEFI简介

前言 大多数人接触UEFI都是在PC的应用场景上&#xff0c;有在PC上安装过多操作系统的经历的同学&#xff0c;通常会进入UEFI界面设置操作系统引导顺序、CPU虚拟化等设置。UEFI诞生之初也确实是作为BIOS的替代者&#xff0c;主要应用在PC电脑上。随着手机/平板等移动设备的发展&…

10月书讯(上) | 小长假我读这些新书

华章科技提前祝大家国庆快乐 7天小长假&#xff0c;正是读书好时节 又到上新季&#xff0c;读书与休假更配哦 10月书讯&#xff08;上&#xff09;请查收 快来看看哪本书最属你心意 参与文末赠书活动&#xff0c;好书就要抢先读 — 新书速览 — 1、《计算机系统解密&#xff1a…

UEFI启动流程浅析

BIOS启动流程 SEC&#xff08;Security Phase&#xff0c;安全阶段&#xff09;阶段 SEC阶段是平台初始话的第一个阶段&#xff0c;计算机系统加电后首先进入这个阶段。 CPU上电之后&#xff0c;首先会进行硬件初始化&#xff08;hard reset&#xff09; 其次会进行可选的自检…

UEFI规范实现EDKII项目学习笔记绪论[0]

UEFI规范实现EDKII项目学习笔记绪论[0] 2015-07-10 北京海淀区 张俊浩 这段时间在学习UEFI( Unified Extensible Firmware Interface,统一的可扩展固件接口)&#xff0c;熟悉EDKII&#xff08;EFI Developer KitII&#xff0c;EFI开发工具包&#xff09;项目&#xff0c;…

3.UEFI-edk2 增加中文显示

UEFI-edk2源码中默认只有英文和法文的字库&#xff0c;在UI界面上或者shell终端打印中文字符串&#xff0c;则无法显示。例如&#xff0c;上一篇博客中的TestoneApp.cpp中&#xff0c;增加一行带中文字符串的打印&#xff1a; Print(L"Hello, world!\r\n");Print(L&…

UEFI原理与编程(一)

第一章 UEFI概述(Unified Extensible Firmware Interface 统一的可扩展固件接口) 常见缩写及描述&#xff1a; 缩略词全名描述UEFIUnified Extensible Firmware Interface统一的可扩展固件接口BSBoot Services启动服务RTRuntime Service运行时服务BIOSBasic Input Output Sys…

UEFI学习——事件函数WaitForEvent和CreateEvent/CreateEventEx

本文参考戴正华《UEFI原理与编程》 1.等待事件的服务WaitForEvent 启动服务中的WaitForEvent服务的函数原型&#xff1a; /**等待Event数组内任一事件被触发retval EFI_SUCCESS 下表为*index的事件被触发retval EFI_UNSUPPORTED 当前的TPL不是TPL_AP…

开宗明义—UEFI介绍 (二)

UEFI介绍 声明 上一篇介绍了UEFI的发展历史&#xff0c;以及对UEFI在ARM嵌入式领域的生态状况做了简单的调研。本篇旨在对UEFI规范和PI规范的内容以及二者之间的关系做一个简单的梳理。 本篇参考内容主要来源于以下3方面&#xff1a; (1) 微信公众号“ Wolf UEFI社区 ”系列文章…

UEFI学习——使用gRT->GetVariable读取Setup选项值

先列出代码&#xff0c;程序的解释在后面。 代码&#xff1a; #include <Uefi.h> #include <Library/UefiBootServicesTableLib.h> #include <Library/UefiRuntimeServicesTableLib.h> #include <Library/DebugLib.h> #include <Universal\DriverS…

2.1 对称量量化和非对称量化

前言 int8的数据范围可以表示为-128到127之间的整数 uint8的数据范围可以表示为0到255之间的整数 注释&#xff1a;int8就是用8个比特位来保存整数&#xff0c;第一位用来表示符号。uint8表示无符号整数&#xff0c;没有符号位&#xff0c;8个比特位全部用来表示整数。 1.问题…

Zinx框架学习 - 连接管理

Zinx - V0.9 连接管理 每个服务器的能够处理的最大IO数量是有限的&#xff0c;根据当前服务器能开辟的IO数量决定&#xff0c;最终决定权是内存大小现在我们要为Zinx框架增加链接个数的限定&#xff0c;如果超过⼀定量的客户端个数&#xff0c;Zinx为了保证后端的及时响应&…

澳网:公茂鑫/张择创历史 中国男网夺大满贯首胜

资料图&#xff1a;张择在比赛中。 中新网1月16日电 16日&#xff0c;2019年澳大利亚网球公开赛男双第一轮展开争夺&#xff0c;中国组合张择/公茂鑫苦战3盘战胜马特沃斯基/克里赞&#xff0c;收获中国男网在大满贯正赛的首场胜利&#xff0c;创造历史。 首盘比赛&#xff0c…

吴易昺,创造历史

中国网坛历史性一刻图片 当地时间2月12日 在ATP250达拉斯男单决赛中 中国球员吴易昺&#xff08;bǐng&#xff09;延续出色状态 顶住对手44记ACE的猛烈冲击&#xff0c;化解四个赛点后&#xff0c;以6-7(4)、7-6(3)、7-6(12)击败伊斯内尔&#xff0c;夺得个人以及中国大陆男网…

百合网“免费”革命 一场饮鸩止渴的大戏

在线婚恋市场一直以来都是有风乍起&#xff0c;吹乱一池春水的同时&#xff0c;也往往会带来自身的迷茫。 刚宣布融了15亿资的百合网计划下一步登陆A股&#xff0c; 于是推出了免费沟通的杀手锏&#xff0c;更是号称要彻底颠覆婚恋行业——果然是腰包鼓了&#xff0c;说话都财大…

澳网见证三巨头书写伟大时代 中国军团多点开花

中新网客户端北京1月28日电(记者 岳川) 随着排名世界第一的德约科维奇在男单决赛中直落三盘击败老对手纳达尔&#xff0c;2019年度澳大利亚网球公开赛大幕落下。这是一届注定会在未来被时常提起的赛事&#xff0c;罗德-拉沃尔球场见证了女单新霸主的诞生&#xff0c;见证了德约…

全球最大同性交友平台骚操作

文章目录 搜索快捷键高亮显示插件 github作为全球最大代码库&#xff0c;日常学习or工作都离不开她&#xff0c;这里介绍一些平时使用方面的技巧。 搜索 比如我们需要搜索spring boot相关的项目&#xff0c;如果直接搜索spring boot&#xff0c;结果如下&#xff1a; 可以看到…

RSA加密算法解析

目录 RSA加密 数学原理 证明: 欧拉函数 欧拉定理 模反元素 模运算 指数运算 同余 欧几里德算法GCD 填充(padding) 对称加密的应用工作流程 非对称加密的应用工作流程 1&#xff09;加密过程 2&#xff09;解密过程 代码实现 密码学知识扩展 加密体制 如何破解…

探究Vue源码:mustache模板引擎(1) 什么是模板引擎

之前在讲虚拟dom和diff算法时说过后续会讲模板引擎 啊 那这边 说到做到哈 对这个问题 有个比较官方的回答 模板引擎是将数据变为视图的最优雅的解决方案 比如 将左侧数据变为右侧视图 大家应该最先想到的就是 v-for 其实 v-for 就是一种模板引擎语法 从图中看出 模板引擎处理…