UEFI原理及编程
知识点总结:
第三章:
*pkg:包含模块和和.dsc文件和.dec文件
每个工程模块:原数据文件(.inf文件)和原文件(.efi文件组成)
标准应用程序模块包含的部分:头文件(Uefi.h)和入口函数(默认的入口函数为UefiMain,可以在UefiMain.inf文件中指定)
每个模块是如何被编译城.efi文件的:
(1)编译器将源文件编译成.obj文件
(2)链接器将.obj文件和其他使用的库文件生成.dll文件
(3)GenFw工具将.dll文件转换成.efi文件
(4)GenFd命令将.efi文件最终生成.fd文件
_ModuleEntryPoint函数的主要作用:
(1)初始化:初始化一些列的构造函数
(2)调用本模块的入口函数
(3)析构(执行解析构造函数)
AutoGen.c和AutoGen.h和如何生成的:
执行./build 命令后,解析模块的.inf文件然后生成AutoGen.c和AutoGen.h
标准应用程序模块执行的过程:
(1)将标准应用程序模块对应的.efi文件加载到内存,找到对应的StartImage文件
(2)然后进入函数_ModuleEntryPoint函数
(3)然后进入ProcessModuleEntryPointList
(4)然后进入对应的模块的入口函数
shell应用程序模块的入口 函数固定死:INTN ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
UEFI中驱动模块和应用程序模块的主要区别:驱动模块会常驻内存,应用程序模块不会。
.inf文件(工程文件)包含的内容:(用来编译一个模块)
[Defines]:定义模块的类型,模块名字,版本号,入口函数
[Sources]:定义本模块包含的源文件和目标文件
[Packages]:指明要引用的包,包中的头文件和库中的源文件
[LibraryClasses]:指明需要链接的库
[Protocols]:列出本模块调用的Protocol
[BuildOptions]:列出本模块编译源文件时用到的编译选项
Build命令需要的文件:.dsc文件 .dec文件 inf文件生成 .efi文件
GenFW命令需要的文件:.efi文件 .dec文件 .fdf文件 生成RomImage
.dsc文件包含的内容:(用来编译一个Package)
[Defines]:设置build相关的全局宏变量。这些变量要被.dsc文件的其他模块所引用
[LibraryClasses]:定义库的名字,以及库中的.inf文件,能够被其他模块所引用
[Components]:该区块内定义的模块会被build命令编译成对应的.efi文件
[BuildOptions]:列出本模块编译源文件时用到的编译选项,对所有模块的文件都有效
[PCD]:用于定义平台配置数据,目的在于不改动.inf文件和源文件的情况下完成对平台的配置。
.dec文件包含的内容:(主要定义公开的数据和接口供其他模块使用)
[Definces]:用于提供Package的名称,GUID和版本号等信息。
[Includes]:列出了Package所提供的头文件所在的目录。
[LibraryClasses]:用于明确库和头文件的对应关系。
[Guids]:Package/Include/Guid目录下面有很多文件,每个文件中定义了GUID号,这些号会被复制到对应的AutoGen.c中。
[Protocols]:Package/Include/Protocols目录下面有很多文件,每个文件中定义了Protocols号。
[Ppis]:用于定义源文件中用到的PPI(PPI是PEI阶段PEI模块之间的通信接口)
[PCD]:是.dsc文件中PCD块的补充。
[UserExtenssions]:
(1)FindOut()找出对应的硬件设备
(2)Install()/Start()安装驱动到指定的设备控制器
(3)Uninstall/Stop()从硬件设备上卸载驱动
UEFI驱动模型:
UEFI驱动模型的核心是通过EFI Driver Binding Protocol来管理驱动程序。
完整的驱动程序包含两部分:EFI Driver Binding Protocol和驱动程序本身
UEFI加载驱动的整个过程:
首先在Shell命令下使用load命令将驱动文件加载到内存,加载后UEFI后调用gBS->StartImage(...)执行DriverImage的入口函数,在入口函数里,Driver Binding Protocol被加载
到Handle(Driver Image Handle或者其他Controler Handle)上。然后遍历所有控制器为每个控制器调用CoreConnectSingleController函数,在CoreConnectSingleController中调用EDBP的Support函数测试是否支持这个驱动,如果支持责调用Start()函数进行安装。
编写UEFI驱动的步骤:
(1)编写硬件相关部分的驱动程序(驱动本身)
(2)驱动框架部分,实现Driver Binding Protocol 的三个接口函数Supported() Start() Stop()函数
Supported()函数要点:
(1)忽略参数RemainingDeivePath
(2)使用函数OpenProtocol()函数打开所需要的Protocol。标准的驱动要用EFI_OPEN_PROTOCOL_BY_DRIVER属性打开,如果要独占某个Protocol需要关闭所有使用该Protocol的驱动程序。然后用属性EFI_OPEN_PROTOCOL_BY_DRIVER|EFI_OPEN_PROTOCOL_EXCLUSIVE打开Protocol
(3)如果上面出错,调用CloseProtocol()关闭所有已经打开的Protocol并返回错误码。
(4)所需要的Protocol成功打开后,测试这个driver是否支持这个Controler,如果任意一项测试失败,调用CloseProtocol()函数挂比所有打开的Protocol,并返回EFI_UNSUPPORTED
(5)测试成功,调用CloseProtocol()关闭所有已打开的Protocol
(6)返回EFI_SUCCESS
Start()函数要点:
(1)忽略参数RemainingDeivePath
(2)使用函数OpenProtocol()函数打开所需要的Protocol。标准的驱动要用EFI_OPEN_PROTOCOL_BY_DRIVER属性打开,如果要独占某个Protocol需要关闭所有使用该Protocol的驱动程序。然后用属性EFI_OPEN_PROTOCOL_BY_DRIVER|EFI_OPEN_PROTOCOL_EXCLUSIVE打开Protocol
(3)如果上面出错,调用CloseProtocol()关闭所有已经打开的Protocol并返回错误码。
(4)初始化Controler所指定的设备,如果有错误,则关闭所有打开的Protocol,返回EFI_DEVICE_ERROR
(5)分配并初始化所用到的数据结构,数据结构包含Protocol相关的数据结构和其他 的私有的数据结构。如果分配资源的时候发生错误,就关闭所有已经打开的Protocol,释放已经得到的资源,EFI_OUT_OF_RESOURCE
(6)用InstallMultipleProtocolInterface()安装驱动协议到 ControlerHandle,如果有错误,关闭所有打开的Protocol,并返回错误码
(7)返回EFI_SUCCESS
Stop()函数要点:
(1)用UnInstallMultipleProtocolInterface()函数卸载所安装的Protocol
(2)关闭所有已经打开的Protocol。
(3)释放所有申请的资源
PCI设备驱动基础:
每个PCI设备都包含三种地址空间:配置空间,IO空间,内存空间。系统初始化时,系统会初始化每个PCI设备的配置空间寄存器。
PCI设备中的IO和MEM空间被划分为1-6个互不重叠的子空间,每个子空间用与于完成一组相对独立的子功能。Base Address 0-5表示子空间的基地址(物理地址)。 对设备的操作主要是对子空间的读写来实现。UEFI提供了EFI_PCI_IO_PROTOCOL简称(PciIo)来操作PCI设备。PciIo用于访问PCI总线或设备的内存空间,IO空间和配置空间,以及DMA接口。PCI总线的每一个控制器都会安装一个PciIo实例,安装后PCI总线驱动负责为这个PCI设备的ROM Image分配内存。并将设备的option ROM读到分配的内存中。
或者从系统平台特定的地址读取ROM。PCI设备的option ROM存放了用于配置或驱动该设备的代码。
现在以AC97驱动为例子,介绍下驱动模块的编写过程:
前面讲过驱动分为两个部分:第一,驱动框架部分将也就是驱动服务框架,第二。驱动本身也就是和硬件相关的驱动程序。
首先介绍下框架部分的设计:驱动服务EFI_AUDIO_PROTOCO
要提供的服务名为EFI_AUDIO_PROTOCOL,在这个服务中提供播放音频的服务,首先要提供硬件初始化服务,PCM音频播放服务,音量调节服务和创建一个Event来通知用户音频播放结束。
1:EFI_AUDIO_PROTOCOL头文件设计(在audio.h中)
(1)定义EFI_AUDIO_PROTOCOL相关的结构体,结构体里面包含上述提供服务的回调函数指针。
struct _EFI_AUDIO_PROTOCOL
{
uint64 Revirsion;
EFI_AC97_RESET Reset; //重置设备的回调函数
EFI_AC97_PLAY Play; //播放声音的回调函数
EFI_AC97_VOLUME Volume; //调节音量的回调函数
EFI_EVENT WaitForEndEvent; //播放结束后触发的事件
}
typedef _EFI_AUDIO_PROTOCOL EFI_AUDIO_PROTOCOL
(2)定义EFI_AUDIO_PROTOCOL_GUID宏
(3)定义EFI_AUDIO_PROTOCOL结构体中的回调函数原型
2:设计EFI_AUDIO_PROTOCOL的私有数据(accdriver.c中实现)
typedef struct
{
uintn Signature;
EFI_AUDIO_PROTOCOL Audio; //EFI_AUDIO_PROTOCOL
EFI_PCI_IO_PROTOCOL *PciIo; //AC控制器上的PciIo
BufferDescriptor Bdes[32]; //缓冲区描述符数组
}AUDIO_PRIVATE_DATA;
定义EFI_AUDIO_PROTOCOL模板,这个模板将用于初始化EFI_AUDIO_PROTOCOL
定义AUDIO_PRIVATE-DATA_FROM_THIS宏,中这个宏是下面要实现的三个服务函数的第一个入参,在函数里首先根据this 指针获得上下文额恩的Private,然后
根据上下文执行相应的操作。
(3)设计驱动服务的重置设备函数Reset函数
(4)设计驱动服务的播放函数Play
(5)设计驱动服务的音量调节函数
(6)设计WaitForEvent事件
AC97驱动的框架部分:
驱动框架部分主要完成三个功能:
(1)实现EFI_DRIVER_BINDING_PROTOCOL
(2)实现Component Name Protocol和Component Name2 Protocol
(3)在模块的初始化函数中安装EDBP ECNP ECN2P
1:实现EFI_DRIVER_BINDING_PROTOCOL
实现EDBP最关键的是实现EDBP的三个服务,Supported Start Stop。在AC97驱动的EDBP中,将实现
AC97DriverBindingSupported函数作为EDBP的Supported服务,AC97DriverBindingStart函数作为EDBP的
Start函数,AC97DriverBindingStop函数作为EDBP函数的Stop服务。
(1)Supported服务
函数AC97DriverBindindSupported实现了Suppprted服务,当检测的设备是AC97控制器时,返回EFI_SUCCESS,否则返回错误代码。
流程如下:
首先:判断Controller是否有EFI_IO_PROTOCOL,若没有返回错误。
其次:赌气PCI配置空间,根据配置空间的ClassCode判断设备是否是AC97驱动器
(2)Start服务
函数AC97DriverBindingStart实现了Start服务,功能是启动AC97控制器并安装EFI_AUDIO_PROTOCOL
启动包含三部分:
首先:打开EFI_PCI_IO_PROTOCOL
其次:为AC97控制器上下文分配内存
最后:在ControllerHandle上安装驱动Protocol,即安装EFI_AUDIO_PROTOCOL
(3)Stop服务
AC97DriverBindingStop函数实现了Stop服务,其过程包含三部分:
首先:关闭控制器上的PCI IO Protocol
其次:卸载ControllerHandle上的Audio IO Protocol
最后:释放申请的资源
2:实现ECNP ECN2P
作为一个完整的对用户友好的驱动程序,我们还要提供EFI Component Name Protocol(简称ECNP)和Component Name2 Protocol(简称ECN2P)
3:安装EDBP ECNP ECN2P
最后在模块的入口函数内安装EDBP ECNP ECN2P这三个Protocol。
4:编写AC97驱动的工程文件
编写.inf文件
(1)MODULE_TYPE设置为UEFI_DRIVER
(2)ENTRY_POINT设置为InitializeAcc
填充.inf文件的字段区域。
第四章:知识点总结
EFI_HANDLE:指向某种对象的指针,UEFI扫描总线后,会为每一个设备建立一个controller对象,用来控制该设备。所有该设备的驱动以Protocol的形式安装到这个controller上,这个controller就是一个EFI_HANDLE对象。
IHANDLE的结构体如下:
typedef struct
{
UINTN Singnature; //表明Handle的类型
LIST_ENTRY Ahandles; //所有IHandle组成的链表
LIST_ENTRY Protocol; //这个Handle下的Protocol链表
UINTN LocateRequust;
UINT64 Key;
}IHANDLE
如何使用Protocol:
要使用Protocol,首先要根据GUID找到Protocol的对象,可以通过以下上个函数来找出对应的Protocol
Openprotocol()/HandleProtocol()/LocateProtocol(),注意打开Protocol要注意关闭Protocol,否则会出现内存泄漏。
使用Protocol的步骤:
(1)通过gBS->OpenProtocol(或者HandleProtocol/LocateProtocol)找出Protocol对象
(2)使用这个Protocol提供的服务
(3)通过gBS->CloseProtocol关闭打开的Protocol
OpenProtocol服务:
OpenProtocol用于查询指定的Handle中是否支持指定的Protocol,如果支持就打开该Protocol,否则返回错误码。
HandleProtocol服务:
OpenProtocol服务功能强大,但是使用复杂,为此提供了简化般的OpenProtocol就是HandleProtocol。
LocateProtocol服务:
LocateProtocol服务可以从UEFI内核中找出指定的Handle的第一个Protocol实例。
LocateHandleBuffer服务:
LocateHandleBuffer服务用来找出支持某个Protocol的所有设备。
ProtocolPerHandle服务:
ProtocolPerHandle服务用于获得指定的设备所支持的所有的Protocol,这些Protocol的GUID通过ProtocolBuffer返回给调用者
UEFI负责分配内存给ProtocolBuffer,调用这负责释放该内存。
OpenProtocolInformation服务:
OpenProtocolInformation服务用于获得指定设备上指定Protocol的打开信息。
CloseProtocol服务:
CloseProtocol服务是用来关闭打开的Protocol。注意(通过HandleProtocol和LocateProtocol打开的Protocol因为没有指定AgentHandle,所以无法关闭。
必须通过调用OpenProtocolnformation()获得AgentHandle和ControllerHandle,然后关闭。)
第五章:知识点总结
系统表:
系统表在DXE阶段被初始哈,因此系统表只能用于DXE阶段之后的程序中。系统表是UEFI内核的一个全局结构体,其指针作为程序映像(Image)入口函数的参数传递到用户空间。程序映像包括UEFI应用程序/DXE驱动程序以及UEFI驱动程序的入口函数有统一的格式。
系统表指针从内核空间传递到用户空间的过程:
通常程序映像的入口函数是_ModuleEntryPoint(当一个Image被启动服务的StartImage服务启动时,执行的就是这个入口函数)。当应用程序或者驱动程序加载到内存形成的Image后(ImageHandle是这个Image的句柄),_ModuleEntryPoint函数地址被赋值给Image对象的EntryPoint,然后Image->EntryPoint(ImageHandle,SystemTable)会被执行,最终会从Image的入口函数_ModuleEntryPoint执行到模块的入口函数(模块的入口函数是通过.inf文件中ENTRY_POINT指定的那个函数)具体调用栈函数如下:
UefiMain()-->ProcessModuleEntryPointList()-->_ModuleEntryPoint()-->.inf文件中指定的模块入口函数
系统表的构成:(系统表提供了用户空间程序访问内核的接口)
表头:包括表的版本号/表的CRC校验码
固件信息:包括固件开发商名字字符串及固件版本号
标准输入控制台,标准输出控制台,标准错误控制台
启动服务表
运行时服务表
系统配置表
typedef struct
{
EFI_TABLE_HEADER Hdr; /标准UEFI表头
CHAR16 *FirmwareVendor; //固件提供商
UINT32 FirmwareRevision; //固件版本号
EFI_HANDLE ConsoleOutHandle; //输出控制台设备句柄
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Conout
EFI_HANDLE ConsoleInHandle; //输入控制台设备句柄
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Conin
EFI_HANDLE StandardErrorHandle; //标准错误控制太设备
EFI_SIMPLE_TEXT_个OUTPUT_PROTOCOL *StrErr;
EFI_RNTIME_SERVICES *RunTimeServices; //运行时服务表
EFI_BOOT_SERVICES *BootServices; //启动服务表
UNITN NumberOfTableEntry; //ConfigTable数组大小
EFI_CONFIGURATION_TABLE *ConfigurationTable; //系统配置表数组
}EFI_SYSTEM_TABLE
代码中常用到的全局变量:
gST = SystemTable;(注意gST定义在用户空间,而Stemtable在内核空间)
gBS = SystemTable->BootService;
启动服务:
在系统启动过程中,系统资源通过启动服务提供的服务来管理。系统进入DXE阶段时,启动服务表被初始化,最终通过System Tabel指针将启动服务(BS)表传递给UEFI应用城学程序或驱动程序。UEFI应用程序或者驱动程序可以通过gST->BootService或gBS访问启动服务表。启动服务是UEFI的核心数据结构,有了他我们才可是使用计算机系统内的资源他的服务可以分为以下几类资源:
(1)UEFI事件服务:事件是异步操作的基础,有了事件的支持,才可以在UEFI系统内执行并发操作。
(2)内存管理服务:主要是通过内存的分配和释放发服务,来管理系统的内存映射。
(3)Protocol管理服务:提供了安装Protocol与卸载Protocol的服务,以及注册Protocl通知函数(该函数在Protocol安装时调用)的服务。
(4)Protocol使用类服务:包括Protocol的打开与关闭,查找支持Protocol的控制器
(5)驱动管理服务:包括将用于将驱动安装到控制器的connect服务,以及将驱动从控制器上卸载的disconnect服务。
(6)Image管理服务:此类服务包括加载,卸载启动和退出UEFI应用程序或者驱动。
(7)ExitBootSerivce:用于结束启动服务,此服务成功返回系统进入RT期。
(8)其他服务
typedef struct
{
EFI_TABLE_HEADER Hdr;
//任务优先级服务
EFI_RAISE_TPL RaiseTpl;
EFI_RETORE_TPL RestoreTpl;
//内存服务
EFI_ALLOCATE_PAGES AllocatePages;
EFI_FREE_PAGES FreePages;
EFI_GET_GET_MEMORY_MAP GetMemoryMap;
EFI_ALLOCATE_POOL AllocatePool;
EFI_FREE_POOL FreePool;
//事件定时器服务
EFI_CREAT_EVENT CreatEvent;
EFI_SET_TIMER SetTimer;
EFI_WAIT_FOR_EVENT WaitForEvent;
EFI_SIGNAL_EVENT SignalEvent;
EFI_CLOSE_EVENT CloseEvent;
EFI_CHECK_EVENT CheckEvent;
//protocol相关的服务
EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface;
EFI_REINSTALL_PROTOCOL_INTERFACE ReinstallProtocolInterface;
EFI_UNINSTALL_PROTOCOL_INTERFACE UninstallProtocolInterface;
EFI_HANDLE_PROTOCOL HandleProtocol;
VOID *Reserved;
EFI_REGISTER_PROTOCOL_NOTIFY RegisterProtocolNotify;
EFI_LOCATE_HANDLE LocateHandle;
EFI_LOCATE_DEVICE_PATH LocateDevicePath;
EFI_INSTALL_CONFIGURATION_TABLE InstallConfigrationTable;
//Image相关的服务
EFI_IMAGE_LOAD ImageLoad;
EFI_IMAGE_START ImageStart;
EFI_EXIT Exit;
EFI_IMAGE_UNLOAD ImageUnload;
EFI_EXIT_BOOT_SERVICE ExitBootService;
//其他服务
EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount;
EFI_STALL Stall;
EFI_SET_WATCHDOG_TIMER SetWatchDogTimer;
//驱动相关的服务
EFI_CONNECT_CONTROLLER ConnectController;
EFI_DISCONNECT_CONTROLLER DisconnecController;
//Protocol相关的服务
EFI_OPEN_PROTOCOL OpenProtocol;
EFI_CLOSE_PROTOCOL CloseProtocol;
EFI_OPEN_PROTOCOL_INFORMATION OpenProtocolInformation;
EFI_PROTOCOL_PER_HANDLE ProtocolsPerHandle;
EFI_LOCATE_HANDLE_BUFFER LocateHandleBuffer;
EFI_LOCATE_PROTOCOL LocateProtocol;
EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACE InstallMultipleProtocolInterface;
EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACE UninstallMultipleProtocolnterface;
EFI_CALCULATE_CRC32 CalculateCrc32;
EFI_COPY_MEM CopyMem;
EFI_SET_MEM SetMem;
EFI_CREATE_EVENT_EX CreateEventEx;
}EFI_BOOT_SERVICES;
下面是启动服务中的8类服务简介:
UEFI事件服务:
UEFI事件服务包含事件(Event)定时器(Timer)和任务优先级(TPL)三类服务。
内存管理服务:
内存管理服务大致可分为三组:
(1)内存的申请和释放服务(AllocatePool/FreePool):必须成对出现,用于申请和释放内存。
int BuffSize = 1024
char16 *Buff = NULL
Status = gBS->AllocatePool(EfiBootServiceCode, BuffSize,(void**)&Buff)
Status = gBS->FreePool(Buff)
(2)申请和释放页(AllocatePages/FreePages):用于分配指定大小的内存,在内核和 驱动开发中经常要求分配到的内存不能跨页,或者分配完整的内存页。此时用AllocatePages比较方便。以及配对使用的FreePages函数。
(3)获取MEMMap(GetMemoryMap)(物理地址<------->虚拟地址)
Protocol管理服务:
UEFI提供了Protocol的安装和卸载服务,以及注册Protocol通知函数(该函数在Protocol安装时调用)。
InstallProtocolInterface() 安装Protocol到设备上
UninstallProtocolInterface() 卸载Protocol
ReinstallProtocolInterface() 从新安装Protocol到设备上
InstallMultipleProtocolInterface() 安装多个Protocol到设备上
UninstallMultipleProtocolInterface() 从设备上卸载多个Protocol
Protocol使用类服务:(Protocol的如何使用,主要包含以下几个函数)
OpenProtocol() 打开一个Protocol
HandleProtocol() 上个函数的简化版
启动服务的生存周期:(在DXEMain()----------->gBS->ExitBootService()之间)
运行服务:
从进入DXE阶段运行时服务被初始化,直到操作系统结束。运行时服务一直存在,并向上层(操作系统/操作系统加载器/UEFI应用程序和驱动程序)提供服务。
运行服务的构成:
(1)时间服务:读取/设定系统时间。读取设定系统从睡眠中唤醒的时间
(2)读写系统变量:读取/设置系统的变量。例如Bootorder 用于设置系统的启动顺序。
(3)虚拟内存服务:将物理地址转化为虚拟地址。
(4)其他服务:包括重启系统ResetSystem,获取系统的下一个单调单增值等。
typedef struct
{
EFI_TABLE_HEADER Hdr; //表头
//时间服务
EFI_GET_TIME GetTime;
EFI_SET_TIME SetTime;
EFI_GET_WAKEUP_TIME GetWakeupTime;
EFI_SET_WAKEUP_TIME SetWakeupTime;
//虚拟内存服务
EFI_SET_VIRTUAL_ADDRESS_MAP SetvirtualAddressMap;
EFI_CONVER_POINT ConverPoint;
//系统变量服务
EFI_GET_VARIABLE GetVariable;
EFI_EGT_NEXT_VARIABLE_NAME GetNextVariableName;
EFI_SET_VARIABLE SetVariable;
//其他服务
EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHighMonotonicCount;
EFI_RESET_SYSTEM ResetSystem;
EFI_UPDATE_CAPSULE UpdateCapsule;
EFI_QUERY_CAPSULE_CAPABILITIES QueryCapsuleCapbilities;
EFI_QUERY_VARIABLE_INFO QueryVariableInfo;
}EFI_RUNTIME_SERVICE;
LocateProtocol() 找出系统中指定Protocol的第一个实例
LocateHandleBuffer 找出支持指定Protocol的所有Handle。系统负责分配内存调用这负责释放没存
LocateHandle() 找出支持特定Protocol的所有Handle,调用这负责分配和释放内存
ProtocolPerHandle() 找出指定Handle上安装的所有Protocol
CloseProtocol() 关闭Protocol
LocateDevicePath() 在指定的设备路径下找出支持指定的Protocol的设备,并返回离指定设备路径最近的设备。
驱动管理服务:此类服务包括用于将驱动安装到控制器的connect服务,以及将驱动从控制器上卸载的disconnect服务。
Image 管理服务:主要包括加载,卸载 启动和退出UEFI应用程序或者 驱动程序
LoadImage() 加载.efi文件到内存并生成Image
StartImage() 启动Image,就是调用Image的入口函数
Exit() 退出Image
UnloadImage 卸载Image
ExitBootService:这个服务用于结束启动服务,成功返回后,系统进入RT期,操作系统加载器从启动服务接过对计算机系统的控制权。
UEFI中的事件
UEFI不在支持中断服务(准确的说UEFI不再为开发者提供中断支持,但是在UEFI内部还是使用了时钟中断)所有的异步操作都是通过事件来完成的,因此事件的重要性不言而喻。
产生事件的函数:CreatEvent/CreatEventEx
使用事件的函数:WaitForEvent/CheckEvent