UEFI有关的文件格式介绍:
fdf:flash definitionfile,描述flash分区地址范围
dec:package declarationfile,定义了不同模块的GUID信息
dsc:description file,主要包含需要用到的所有inf文件
inf:单个模块的编译信息,类似makefile
efi :最终编译生成的UEFI可执行文件
一、xbl创建 protocol 驱动
先看下创建一个 protocol 驱动改了哪些文件
boot_images/QcomPkg/Drivers/TestDxe 目录下创建2个文件:
TestDxe.inf //定义驱动入口点和编译内容(类似于makefile)
TestDxe.c //定义驱动内容
1、定义驱动入口
1.1 定义 QcomPkg/Drivers/TestDxe/TestDxe.inf 文件内容(类似于makefile)
加载驱动时会运行 ENTRY_POINT 入口函数
[Defines]
INF_VERSION = 0x00010005 //平台UEFI Protocol版本号
BASE_NAME = TestDxe //UEFI Protocol 名
FILE_GUID = 1e5605ad-daf5-41a8-8141-4fdb7ccbd032 //文件GUID, 可以上https://www.guidgen.com网站生成
MODULE_TYPE = UEFI_DRIVER
// 模块类型,分为DXE_DRIVER(UEFI驱动)、BASE(EDK库或PEI)、UEFI_APPLICATION(UEFI应用程序)三种
VERSION_STRING = 1.0 //驱动自定义的版本号
ENTRY_POINT = TestEntryPoint //驱动入口函数,加载该驱动时会首先运行该函数
[Sources] //驱动的C文件
TestDxe.c
[Packages] //本驱动包含的库的头文件
ArmPkg/ArmPkg.dec
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
QcomPkg/QcomPkg.dec
[LibraryClasses] //本驱动中会使用到的库
BaseLib
DevicePathLib
MemoryAllocationLib
PrintLib
UefiDriverEntryPoint
UefiLib
QcomLib
[Guids]
gEfiUfsLU0Guid
[Protocols] //本驱动中会使用到的驱动guid
gEfiTestProtocolGuid
1.2 设置 TestDxe.inf 运行
创建好 TestDxe.inf 文件后,如果需要能够运行,则需要将 inf 添加进平台配置文件中:
- 配置 boot_images/QcomPkg/SDMPkg/855/AU/Apriori.fdf.inc 文件
INF QcomPkg/Drivers/DDRInfoDxe/DDRInfoDxe.inf
INF QcomPkg/Drivers/ResetRuntimeDxe/ResetRuntimeDxe.inf
INF QcomPkg/Drivers/TestDxe/TestDxe.inf #新增
- 配置 boot_images/QcomPkg/SDMPkg/855/AU/Core.dsc 文件
#
# ShmBridgeDxe Driver
#
QcomPkg/Drivers/ShmBridgeDxe/ShmBridgeDxeLA.inf
QcomPkg/Drivers/TestDxe/TestDxe.inf #新增
- 配置 boot_images/QcomPkg/SDMPkg/855/AU/Core.fdf 文件
INF QcomPkg/Drivers/UsbConfigDxe/UsbConfigDxe.inf
INF QcomPkg/Drivers/TestDxe/TestDxe.inf #新增
2、创建驱动的 GUID
- 在线生成GUID,https://www.guidgen.com,界面如下:
- 设置 boot_images/QcomPkg/QcomPkg.dec
[Defines]
DEC_SPECIFICATION = 0x00010005
PACKAGE_NAME = QcomPkg
PACKAGE_GUID = 8F99F539-2EE4-4A97-BD6E-FA412A26A06A
PACKAGE_VERSION = 0.1
[Protocols]
# Test Protocol #新增
gEfiTestProtocolGuid = { 0x13e277b3, 0xe631, 0x41ca,{ 0xb4, 0xb5, 0x75, 0x9d, 0x7f, 0x2f, 0xed, 0xd9 } }
注意:此处的guid 和前面的FILE_GUID不是同一个,guid类似一个身份证,FILE_GUID指代的是TestDxe.inf 文件,而gEfiTestProtocolGuid 指代的是整个Test驱动。
3、定义驱动及头文件
3.1 修改 boot_images/QcomPkg/Drivers/TestDxe/TestDxe.c 文件
- TestEntryPoint 入口函数
- gEfiTestProtocol 驱动定义
将 gEfiTestProtocolGuid 与 gEfiTestProtocol 结构体绑定起来,通过 gEfiTestProtocolGuid 就能获取 gEfiTestProtocol 中的驱动函数和数据。
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UncachedMemoryAllocationLib.h>
#include <Library/ArmLib.h>
#include <Library/SerialPortShLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/StorSecApp.h>
#include <Library/UefiCfgLib.h>
#include <Protocol/BlockIo.h>
#include <Protocol/BlockIo2.h>
#include <Protocol/DevicePath.h>
#include <Protocol/EFICardInfo.h>
#include <Protocol/EFIClock.h>
#include <Protocol/EFIHWIO.h>
#include <Library/GPTListener.h>
#include <Library/RpmbListener.h>
#include <Library/RpmbLib.h>
#include <Protocol/EFIRpmb.h>
#include <Protocol/EFIEraseBlock.h>
#include <Protocol/EFIStorageWriteProtect.h>
#include <Protocol/EFIHALIOMMUProtocol.h>
#include <Library/KernelLib.h>
#include <Protocol/EFITest.h>
#include <errno.h>
#include <stdio.h>
/* 传递函数 */
static char s_TestData[128] = {0};
/* 传递函数 */
EFI_STATUS Test_Printf(void)
{
DEBUG((EFI_D_ERROR, "%a : test protocols \r\n", __func__));
return 0;
}
/* 驱动函数结构体 */
EFI_TEST_PROTOCOL gEfiTestProtocol =
{
EFI_TEST_REVISION,
Test_Printf,
s_TestData,
};
// 注册驱动:将 `gEfiTestProtocolGuid` 与 `gEfiTestProtocol` 结构体绑定起来
EFI_STATUS EFIAPI TestEntryPoint(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS status = EFI_SUCCESS;
memcpy(s_TestData, "test data\n", sizeof("test data\n"));
/* Install protocol */
status = gBS->InstallMultipleProtocolInterfaces(&ImageHandle,
&gEfiTestProtocolGuid, (void *)&gEfiTestProtocol,
NULL);
if (EFI_ERROR(status)) {
DEBUG((EFI_D_ERROR, "%a : Failed to Install protocols \r\n", __func__));
}
return status;
}
3.2 创建头文件 boot_images/QcomPkg/Include/Protocol/EFITest.h
如果定义的驱动需要被其他应用程序调用的话,需要配置头文件,外部应用程序只需要包含当前头文件即可。
在头文件中定义了 驱动的GUID 及 驱动中包含的所有方法,如下:
#ifndef __EFI_TEST_H_
#define __EFI_TEST_H_
#include <stdarg.h>
/*Protocol version. */
#define EFI_TEST_REVISION 0x0000000000010000
/* Protocol GUID definition */
#define EFI_TEST_PROTOCOL_GUID \
{ 0x13e277b3, 0xe631, 0x41ca,{ 0xb4, 0xb5, 0x75, 0x9d, 0x7f, 0x2f, 0xed, 0xd9 } };
extern EFI_GUID gEfiTestProtocolGuid;
/*Raw Message protocal*/
typedef struct _EFI_TEST_PROTOCOL EFI_TEST_PROTOCOL;
typedef EFI_STATUS (EFIAPI *EFI_TEST_PRINT)();
struct _EFI_TEST_PROTOCOL {
UINT64 Revision;
EFI_TEST_PRINT TestPrintf;
char* pData;
};
#endif
二、abl如何调用xbl驱动
前面,我们在xbl中创建了 boot_images/QcomPkg/Drivers/TestDxe/ 驱动,下面,我们来看下它是怎么被应用程序调用的。
使用 Protocol 驱动,需要做如下动作:
- 在 c文件中包含驱动协议相关的头文件。如: #include <Protocol/EFITest.h>
- 定义驱动协议的结构体指针。如:EFI_TEST_PROTOCOL *TestProtocol;
- 加载 gEfiTestProtocolGuid 对应的驱动,将驱动结构体指针保存在TestProtocol 中
Status = gBS->LocateProtocol (&gEfiTestProtocolGuid , NULL, (VOID **)&TestProtocol );
- 通这 TestProtocol 结构体指针调用驱动的相关函数。
Status = TestProtocol->TestPrintf();
下面详细介绍步骤。
1、如何在abl中调用xbl中的驱动
1)新建 abl/QcomModulePkg/Include/Protocol/EFITest.h(可与xbl中 EFITest.h 相同)
#ifndef __EFI_TEST_H_
#define __EFI_TEST_H_
#include <stdarg.h>
/*Protocol version. */
#define EFI_TEST_REVISION 0x0000000000010000
/* Protocol GUID definition */
#define EFI_TEST_PROTOCOL_GUID \
{ 0x13e277b3, 0xe631, 0x41ca,{ 0xb4, 0xb5, 0x75, 0x9d, 0x7f, 0x2f, 0xed, 0xd9 } };
extern EFI_GUID gEfiTestProtocolGuid;
/*Raw Message protocal*/
typedef struct _EFI_TEST_PROTOCOL EFI_TEST_PROTOCOL;
typedef EFI_STATUS (EFIAPI *EFI_TEST_PRINT)();
struct _EFI_TEST_PROTOCOL {
UINT64 Revision;
EFI_TEST_PRINT TestPrintf;
char* pData;
};
#endif
2)QcomModulePkg/QcomModulePkg.dec 中 [Protocols] 添加 gEfiTestProtocolGuid(GUID值和xbl中的一定要相同)
[Protocols]
# Test Protocol
gEfiTestProtocolGuid = { 0x13e277b3, 0xe631, 0x41ca,{ 0xb4, 0xb5, 0x75, 0x9d, 0x7f, 0x2f, 0xed, 0xd9 } }
此时,abl可以使用 xbl中的 gEfiTestProtocolGuid 了
3)新建 QcomModulePkg/Library/TestLib/TestLib.c 和 TestLib.inf,用来将 gEfiTestProtocolGuid 封装一层,abl调用封装后的函数即可调用xbl驱动了。
#include <Uefi.h>
#include <Library/DebugLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/CacheMaintenanceLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/BaseMemoryLib.h>
#include <Protocol/EFIScm.h>
#include <Protocol/EFIScmModeSwitch.h>
#include <Protocol/EFITest.h> //包含头文件
#include <stdarg.h>
int test_print(void)
{
EFI_STATUS Status;
EFI_TEST_PROTOCOL *TestProtocol;
Status = gBS->LocateProtocol (&gEfiTestProtocolGuid,
NULL,
(VOID **)&TestProtocol);
if (EFI_ERROR(Status)) {
DEBUG ((DEBUG_ERROR, "test Protocol Failed %d\n", Status));
return Status;
}
Status = TestProtocol->TestPrintf();
if (Status)
DEBUG ((DEBUG_ERROR, "test Local Failed %d\n", Status));
return Status;
}
int test_get_data(void)
{
EFI_STATUS Status;
EFI_TEST_PROTOCOL *TestProtocol;
Status = gBS->LocateProtocol (&gEfiTestProtocolGuid,
NULL,
(VOID **)&TestProtocol);
if (EFI_ERROR(Status)) {
DEBUG ((DEBUG_ERROR, "test Protocol Failed %d\n", Status));
return Status;
}
DEBUG ((DEBUG_ERROR, "get xbl data: %a\n", TestProtocol->pData));
return Status;
}
TestLib.inf 的 [Protocols] 配置 驱动协议的GUID,这里是 gEfiTestProtocolGuid
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = TestLib
FILE_GUID = b0c5efb2-d180-404a-8524-8f222fb27f5c
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = TestLib
[BuildOptions]
RVCT:*_*_*_CC_FLAGS = -DCONFIG_SPL_BUILD
GCC:*_*_*_CC_FLAGS = -DCONFIG_SPL_BUILD
[BuildOptions.AARCH64]
GCC:*_*_*_CC_FLAGS = -DCONFIG_SPL_BUILD
[Sources.common]
TestLib.c //源文件
[Packages]
QcomModulePkg/QcomModulePkg.dec
ArmPkg/ArmPkg.dec
MdePkg/MdePkg.dec
StdLib/StdLib.dec
EmbeddedPkg/EmbeddedPkg.dec
ArmPlatformPkg/ArmPlatformPkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
[Protocols]
gEfiTestProtocolGuid //协议
[Depex]
TRUE
新建 QcomModulePkg/Include/Library/Test.h 头文件
#ifndef _TEST_H__
#define _TEST_H__
int test_print(void);
int test_get_data(void);
#endif /* _TEST_H__*/
4)QcomModulePkg/QcomModulePkg.dsc 中定义 LinuxLoader.inf 包含需要用到的所有inf文件,新增 TestLib.inf,之后LinuxLoader.c就能调用TestLib.c中的内容
[Components.common]
QcomModulePkg/Application/LinuxLoader/LinuxLoader.inf {
<LibraryClasses>
... ...
TestLib|QcomModulePkg/Library/TestLib/TestLib.inf #新增
}
此时,LinuxLoader.c可以调用 test_print() 和 test_get_data()。
[LibraryClasses]
... ...
TestLib
#include <Library/Test.h>
... ...
/* 调用测试 */
test_print();
test_get_data();
三、测试结果
串口打印结果可以看到,执行了 xbl 中 protocol 驱动内容