- 2.3系统表SystemTable
- 2.4启动服务Boot Services
- 2.5运行时服务Runtime Services
- 2.6模块加载过程
- 2.7 EFI Byte Code (EBC)
- 2.8 EFI系统分区
- 2.9 分区表
- 3,UEFI的Protocol
- 4,UEFI Driver Model 驱动模型
- 5, EDK2
- source ./edksetup.sh
# build -p EmulatorPkg/EmulatorPkg.dsc -a X64
Build命令执行的是脚本edk2/BaseTools/Source/Python/build/build.py
选项参数:
-a指定架构,可以是IA32(32位x86 CPU)、X64(64位x86_64 CPU)、IPF(Itanium Processor Family)、ARM和EBC(EFI byte code)。
-p指定平台描述文件(.dsc文件)做编译
-m指定元数据文件(.inf文件)做编译 - GenFw -e UEFI_APPLICATION -o UefiMain.efi ./build/UefiMain.dll
GenFw命令执行的是edk2/BaseTools/Source/C/bin/GenFw
选项参数:
-e指定生成的efi映像类型,可以是BASE,SMM_CORE,
PEI_CORE, PEIM, DXE_CORE, DXE_DRIVER, UEFI_APPLICATION,
SEC, DXE_SAL_DRIVER, UEFI_DRIVER, DXE_RUNTIME_DRIVER,
DXE_SMM_DRIVER, SECURITY_CORE, COMBINED_PEIM_DRIVER,
MM_STANDALONE, MM_CORE_STANDALONE,
PIC_PEIM, RELOCATABLE_PEIM, BS_DRIVER, RT_DRIVER,
APPLICATION, SAL_RT_DRIVER
-o指定输出文件名 - 6,参考资料
- 代码分析
- SlimBootloader
- 附录
参考文章下载地址:
链接: https://pan.baidu.com/s/1LjrydEzCACG3ohpx7mMKKg 提取码: 4i3j
UEFI的服务组成
UEFI包括 启动服务(Boot Services, BS)和运行时服务(Runtime Service, RT)以及隐藏在BS之后丰富的Protocol。UEFI驱动和服务以Protocol的形式通过BS提供给操作系统。
gBS->ExitBootService()结束BS阶段并回收BS的资源,开始进入RT阶段。从操作系统加载器(OS Loader)被加载,到OS Loader执行ExitBootServices()的这段时间,是从UEFI环境向操作系统过渡的过程。OS Loader可以通过BS和RT使用UEFI提供的服务,将计算机系统资源逐渐转移到自己手中,此过程是TSL(Transient System Load,操作系统加载前期)阶段。
当OS Loader完全掌握了计算机系统资源时,BS完成了使命。OS Loader调用ExitBootServices()结束BS并回收BS占用的资源,之后计算机进入Run Time阶段。在Run Time阶段只有RT继续为OS提供服务,BS已经从计算机中销毁。
2.3系统表SystemTable
系统表SystemTable,在进入DXE阶段后被初始化。系统表是UEFI核心的一个全局结构体,其指针作为程序映像(Image)入口函数的参数传递到用户空间。程序映像包括UEFI应用程序、DXE driver和UEFI driver),程序映像入口函数有统一的格式,函数原型:
typedef EFI_STATUS (EFI_API *EFI_IMAGE_ENTRY_POINT)(
IN EFI_HANDLE ImageHandle; //程序映像(Image)的句柄(Handle)
IN EFI_SYSTEM_TABLE *SystemTable; //系统表指针
);
.efi文件(UEFI应用程序或UEFI驱动程序)加载到内存后生成的对象称为Image(映像)。ImageHandle是Image对象的句柄,作为模块入口函数参数,它表示模自身加载到内存后生成的Image对象。
全局变量gST指向系统表,需引用头文件#include
2.4启动服务Boot Services
启动服务BootServices表在进入DXE阶段后被初始化。可通过gST->BootServices或gBS访问启动服务表。
启动服务BootServices中的服务分为8类:UEFI事件服务、内存管理服务、Protocol管理服务、Protocol使用类服务、驱动管理服务、Image管理服务、ExitBootServices及其他服务。
全局变量gBS指向启动服务表,需引用头文件#include
typedef struct {
EFI_TABLE_HEADER Hdr;
EFI_RAISE_TPL RaiseTPL; // Task Priority Services
EFI_RESTORE_TPL RestoreTPL;
EFI_ALLOCATE_PAGES AllocatePages; // Memory Services
EFI_FREE_PAGES FreePages;
EFI_GET_MEMORY_MAP GetMemoryMap;
EFI_ALLOCATE_POOL AllocatePool;
EFI_FREE_POOL FreePool;
EFI_CREATE_EVENT CreateEvent; // Event & Timer Services
EFI_SET_TIMER SetTimer;
EFI_WAIT_FOR_EVENT WaitForEvent;
EFI_SIGNAL_EVENT SignalEvent;
EFI_CLOSE_EVENT CloseEvent;
EFI_CHECK_EVENT CheckEvent;
EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface; // Protocol Handler Services
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 InstallConfigurationTable;
EFI_IMAGE_LOAD LoadImage; // Image Services
EFI_IMAGE_START StartImage;
EFI_EXIT Exit;
EFI_IMAGE_UNLOAD UnloadImage;
EFI_EXIT_BOOT_SERVICES ExitBootServices;
EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount; // Miscellaneous Services
EFI_STALL Stall;
EFI_SET_WATCHDOG_TIMER SetWatchdogTimer;
EFI_CONNECT_CONTROLLER ConnectController; // DriverSupport Services
EFI_DISCONNECT_CONTROLLER DisconnectController;
EFI_OPEN_PROTOCOL OpenProtocol; // Open and Close Protocol Services
EFI_CLOSE_PROTOCOL CloseProtocol;
EFI_OPEN_PROTOCOL_INFORMATION OpenProtocolInformation;
EFI_PROTOCOLS_PER_HANDLE ProtocolsPerHandle; // Library Services
EFI_LOCATE_HANDLE_BUFFER LocateHandleBuffer;
EFI_LOCATE_PROTOCOL LocateProtocol;
EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES InstallMultipleProtocolInterfaces;
EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES UninstallMultipleProtocolInterfaces;
EFI_CALCULATE_CRC32 CalculateCrc32; // 32-bit CRC Services
EFI_COPY_MEM CopyMem; // Miscellaneous Services
EFI_SET_MEM SetMem;
EFI_CREATE_EVENT_EX CreateEventEx;
} EFI_BOOT_SERVICES;
2.5运行时服务Runtime Services
从进入DXE阶段运行时服务被初始化,直到操作系统结束,运行时服务都一直存在并向上层(操作系统、操作系统加载器(os loader)、UEFI应用程序或UEFI驱动)提供服务。
运行时服务提供一下功能:
- 时间服务。读取/设置硬件时间、读取/设置唤醒定时器。
- 读写系统变量。读取/设置系统变量,例如BootOrder用于指定启动项顺序。
- 虚拟内存服务。将物理地址转换为虚拟地址。gBS->ExitBootServices()后才能使用。
- 其他服务。重启系统的ResetSystem等
全局变量gRT指向启动时服务表,需引用头文件#include
typedef struct {
EFI_TABLE_HEADER Hdr;
EFI_GET_TIME GetTime; // Time Services
EFI_SET_TIME SetTime;
EFI_GET_WAKEUP_TIME GetWakeupTime;
EFI_SET_WAKEUP_TIME SetWakeupTime;
EFI_SET_VIRTUAL_ADDRESS_MAP SetVirtualAddressMap; // Virtual Memory Services
EFI_CONVERT_POINTER ConvertPointer;
EFI_GET_VARIABLE GetVariable; // Variable Services
EFI_GET_NEXT_VARIABLE_NAME GetNextVariableName;
EFI_SET_VARIABLE SetVariable;
EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHighMonotonicCount; // Miscellaneous Services
EFI_RESET_SYSTEM ResetSystem;
EFI_UPDATE_CAPSULE UpdateCapsule; // UEFI 2.0 Capsule Services
EFI_QUERY_CAPSULE_CAPABILITIES QueryCapsuleCapabilities;
EFI_QUERY_VARIABLE_INFO QueryVariableInfo; // Miscellaneous UEFI 2.0 Service
} EFI_RUNTIME_SERVICES;
2.6模块加载过程
UEFI模块包括应用程序模块、驱动程序模块、库模块、Shell应用程序模块。模块(可执行文件,即.efi文件)像插件一样可以动态地加载到UEFI内核中。
gBS->LoadImage()将.efi文件加载到内存生成Image对象,然后gBS->StartImage(Image)启用这个Image对象。
StartImage(调用CoreStartImage)将找出程序映像(Image)的入口函数并执行,Image->EntryPoint()。
全局变量gImageHandle指向正在执行的驱动或应用程序,需引用头文件#include
2.7 EFI Byte Code (EBC)
Build命令编译时,可通过-a参数选择目标CPU架构,可以是IA32, X64, IPF, ARM, AARCH64, EBC。选择EBC编程生成的Image映像,可以多平台下执行,EFI Byte Code是一组专用于EFI驱动程序的虚拟机器语言,必须在DXE阶段被解释运行。
UEFI固件里实现EBC解析器(EBC virtual machine interpreter),在加载EBC映像时会调用该程序。EBC使用64位C代码,EBC解析器负责处理32位/64位问题。
2.8 EFI系统分区
EFI系统分区(EFI SystemPartition, ESP)是一个FAT或FAT32格式的磁盘分区,通常为100MB。其中存储已安装系统的EFI加载器(OS Loader)以及启动时固件使用的应用程序。UEFI固件可从ESP加载EFI启动程式或者EFI应用程序。在安装操作系统(OS)后会生成EFI系统分区。
在不同操作系统下的可见性:
Windows:一般是不可见的。在磁盘管理程序中可以显示,但不能直接分配驱动器号。
Linux发行版:视同普通分区,可使用mount程序直接挂载其对应的块设备。一般挂载于/boot/efi目录下。
2.9 分区表
分区表是在磁盘(存储介质)上的,用于描述该磁盘的分区情况,有GPT和MBR两种格式。传统BIOS使用MBR分区表,UEFI使用GPT分区表
MBR(主引导记录分区表)只能记录4个主分区信息,通过扩展分区及逻辑分区的概念后,最大可管理空间为2TB。
GPT,全称为Globally Unique Identifier Partition Table,也叫做GUID分区表,即全局唯一标识分区列表,它是UEFI规范的一部分。
3,UEFI的Protocol
在EFI中,Protocol是一种方法和属性的封装,类似于高级语言中的类(Class)。
Protocol是一种特殊的结构体,每个Protocol对应一个唯一的GUID,利用系统BS的OpenProtocol,并根据GUID来打开对应的Protocol,进而使用这个Protocol提供的服务。DXE驱动之间通过Protocol通信。
UEFI驱动和服务以Protocol的形式通过BS提供给操作系统。
UEFI规范定义了大量的Protocol
使用BS中Protocol的API函数
3.1,EFI Driver Binding Protocol (EDBP)
用于驱动的安装和卸载。
Start()函数用于将驱动安装到设备上并启动硬件设备。调用gBS->InstallProtocolInterface()或InstallMultiProtocolInterface()在ControllerHandle上安装驱动Protocol。
Stop()函数用于停止硬件设备并卸载驱动。调用gBS->UninstallProtocolInterface()或UninstallMultiProtocolInterfaces()从ControllerHandle卸载驱动Protocol。
#define EFI_DRIVER_BINDING_PROTOCOL_GUID \
{ \
0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0xc, 0x9, 0x26, 0x1e, 0x9f, 0x71 } \
}
typedef struct _EFI_DRIVER_BINDING_PROTOCOL EFI_DRIVER_BINDING_PROTOCOL;
struct _EFI_DRIVER_BINDING_PROTOCOL {
EFI_DRIVER_BINDING_SUPPORTED Supported;
EFI_DRIVER_BINDING_START Start;
EFI_DRIVER_BINDING_STOP Stop;
UINT32 Version;
EFI_HANDLE ImageHandle;
EFI_HANDLE DriverBindingHandle;
};
extern EFI_GUID gEfiDriverBindingProtocolGuid;
3.2 EFI Component Name Protocol (ECNP或ECN2P)
每个驱动有一个可打印的名字,便于向用户显示驱动的信息。ECNP即提供此服务。
struct _EFI_COMPONENT_NAME_PROTOCOL {
EFI_COMPONENT_NAME_GET_DRIVER_NAME GetDriverName;
EFI_COMPONENT_NAME_GET_CONTROLLER_NAME GetControllerName;
CHAR8 *SupportedLanguages;
};
3.3 EFI PCI IO Protocol
struct _EFI_PCI_IO_PROTOCOL {
EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollMem;
EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollIo;
EFI_PCI_IO_PROTOCOL_ACCESS Mem;
EFI_PCI_IO_PROTOCOL_ACCESS Io;
EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS Pci;
EFI_PCI_IO_PROTOCOL_COPY_MEM CopyMem;
EFI_PCI_IO_PROTOCOL_MAP Map;
EFI_PCI_IO_PROTOCOL_UNMAP Unmap;
EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer;
EFI_PCI_IO_PROTOCOL_FREE_BUFFER FreeBuffer;
EFI_PCI_IO_PROTOCOL_FLUSH Flush;
EFI_PCI_IO_PROTOCOL_GET_LOCATION GetLocation;
EFI_PCI_IO_PROTOCOL_ATTRIBUTES Attributes;
EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES GetBarAttributes;
EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES SetBarAttributes;
///
/// The size, in bytes, of the ROM image.
///
UINT64 RomSize;
///
/// A pointer to the in memory copy of the ROM image. The PCI Bus Driver is responsible
/// for allocating memory for the ROM image, and copying the contents of the ROM to memory.
/// The contents of this buffer are either from the PCI option ROM that can be accessed
/// through the ROM BAR of the PCI controller, or it is from a platform-specific location.
/// The Attributes() function can be used to determine from which of these two sources
/// the RomImage buffer was initialized.
///
VOID *RomImage;
};
3.4 EFI Graphic Output Protocol (GOP)
GOP provides a basic abstraction to set video modes and copy pixels to and from the graphics controller’s frame buffer.
Graphics Controller必须支持以下操作:
- Block transfer to fill a region of the frame buffer
- Block transfer from system memory to region of frame buffer
- Block transfer from region of frame buffer to system memory
- Block transfer between two regions of the frame buffer
- Query attached display devices for EDID information
- Set the supported graphics modes that is intersection of modes that the graphics controller supports and the display device supports
The Graphics Output Protocol supports this capability by providing the EFI OS loader access to a hardware frame buffer and enough information to allow the OS to draw directly to the graphics output device.
The basic graphics operation in the EFI_GRAPHICS_OUTPUT_PROTOCOL is the Block Transfer or Blt. The Blt operation allows data to be read or written to the video adapter’s video memory. The Blt operation abstracts the video adapters hardware implementation by introducing the concept of a software Blt buffer.
struct _EFI_GRAPHIC_OUTPUT_PROTOCOL {
EFI_GRAPHIC_OUTPUT_PROTOCOL_QUERY_MODE QueryMode;
EFI_GRAPHIC_OUTPUT_PROTOCOL_SET_MODE SetMode;
EFI_GRAPHIC_OUTPUT_PROTOCOL_BLT Blt;
EFI_GRAPHIC_OUTPUT_PROTOCOL_MODE *Mode;
}
typedef struct _EFI_GRAPHICS_OUTPUT_PROTOCOL EFI_GRAPHICS_OUTPUT_PROTOCOL;
#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \
{ \
0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a } \
}
extern EFI_GUID gEfiGraphicsOutputProtocolGuid;
typedef struct {
UINT32 Data1;
UINT16 Data2;
UINT16 Data3;
UINT8 Data4[8];
} EFI_GUID;
EFI_GUID gEfiGraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
3.5自定义Protocol
UEFI Spec定义了大量的标准Protocol,除此之外,如果开发自有的特色功能,或者开发EFI相关功能的增强版,则需要规范要提供的Service,将之封装到相关的Protocol中。在实际应用中,往往会发现其中存在着服务的提供者/生产者(Producer)和服务的消费者(Consumer),将提供者支持的服务加以规范,封装成一个相对标准的接口,即Protocol,提供给消费者使用,就是在定义Protocol时要遵守的方法。
4,UEFI Driver Model 驱动模型
UEFI驱动模型是通过EFI_DRIVER_BINDING_PROTOCOL管理驱动程序。
遵循UEFI驱动模型的驱动包括几个部分:
- EFI Driver Binding Protocol (EDBP)
- 驱动内容。驱动硬件设备,提供服务。
- EFI Component Name Protocol (ECNP) 或EFI Component Name2 Protocol (ECN2P)
遵循UEFI驱动模型的是UEFI driver(对应.inf里MODULE_TYPE= UEF_DRIVER),不遵循UEFI驱动模型的是DXE driver(对应.inf里MODULE_TYPE= DXE_DRIVER)。
GOP driver遵循UEFI驱动模型。
4.1 AC97驱动及设备自定义Protocol
为驱动服务本身功能自定义一个Protocol。
AC97芯片的一个例子:
//
// Driver binding protocol implementation for AC97 driver.
//
EFI_DRIVER_BINDING_PROTOCOL gAudioDriverBinding = {
AC97DriverBindingSupported,
AC97DriverBindingStart,
AC97DriverBindingStop,
0xa,
NULL,
NULL
};
struct _EFI_AUDIO_PROTOCOL{
UINT64 Revision;
EFI_AC97_RESET Reset;
EFI_AC97_PLAY Play;
EFI_AC97_VOLUME Volume;
EFI_EVENT WaitForEndEvent;
};
typedef struct _EFI_AUDIO_PROTOCOL EFI_AUDIO_PROTOCOL;
typedef struct {
UINTN Signature;
EFI_AUDIO_PROTOCOL Audio;
EFI_PCI_IO_PROTOCOL *PciIo;
BufferDescriptor Bdes[32];
} AUDIO_PRIVATE_DATA;
AUDIO_PRIVATE_DATA gDiskIoPrivateDataTemplate = {
AUDIO_PRIVATE_DATA_SIGNATURE,
{
EFI_AUDIO_PROTOCOL_REVISION,
AC97Reset,
AC97Play,
AC97Volume,
0
},
NULL,
{0}
};
AC97初始化过程:
- UEFI DXE阶段加载驱动模块映像ac97.efi,audio.inf 定义的ENTRY_POINT=InitializeACC
Image->EntryPoint(ImageHandle, SystemTable)
2)执行模块入口函数InitializeACC() -> EfiLibInstallDriverBindingComponentName2()
为AC97安装EDBP和ECNP/ECN2P的实例
3)AC97 EDBP里的Start函数AC97DriverBindingStart()
打开EFI_PCI_IO_PROTOCOL,为AC97控制器上下文分配内存,在ControllerHandle上安装AC97驱动子定义的EFI_AUDIO_PROTOCOL。
4.2 EmuGopDxe驱动
EDK2里代码目录:edk2/EmulatorPkg/EmuGopDxe
.inf文件指定模块入口函数为InitializeEmuGop()
InitializeEmuGop() -> EfiLibInstallDriverBindingComponentName2()
调用gBS->InstallMultipleProtocolInterfaces()执行安装EDBP和ECNP/ECN2P
Driver Binding Protocol实现
Start成员函数 EmuGopDriverBindingStart
gBS->OpenProtocol(&gEmuIoThunkProtocolGuid) 打开总线的Protocol
gBS->AllocatePool() 申请内存空间,用于私有数据Private
EmuGopConstructor() 给EFI_GRAPHIC_OUTPUT_PROTOCOL结构体赋值
gBS->InstallMultipleProtocolInterfaces()
gEfiGraphicsOutputProtocolGuid
gEfiSimpleTextInProtocolGuid
gEfiSimplePointerProtocolGuid
gEfiSimpleTextInputExProtocolGuid
Stop成员函数EmuGopDriverBindingStop()
gBS->OpenProtocol(&gEfiGraphicsOutputProtocolGuid)
gBS->UninstallMultipleProtocolInterfaces()
gEfiGraphicsOutputProtocolGuid
gEfiSimpleTextInProtocolGuid
gEfiSimplePointerProtocolGuid
gEfiSimpleTextInputExProtocolGuid
EmuGopDestructor()
gBS->CloseProtocol(&gEmuIoThunkProtocolGuid)
gBS->FreePool() 释放私有数据的内存空间Private
5, EDK2
UEFI是个规范标准,具体由各厂商实现:
商业实现方案(需要获取NDA授权):
AMI, Insyde, Phoenix, 南京百敖软件 Byosoft
开源实现方案:
Tiano EDK2
EDK2源码git仓库:
https://github.com/tianocore/edk2.git
5.1 EDK2目录介绍
EDK2根目录内容如下:
- MdePkg
Module Development Environment Package,包含了用于开发module所需要的最小环境。所有moduel必须依赖于MdePkg
- MdeModulePkg
提供符合UEFI/PI工业标准的模块,也提供该标准相关的开发环境。
- BaseTools
提供编译相关的工具,包括工具:AutoGen, Build, GenSec, GenFV, GenFW, GenRds等
- EmulatorPkg
Emulator虚拟环境,用来取代Nt32Pkg和UnixPkg,可以跨平台编译运行的一个虚拟器
- ArmPkg
提供ARM架构相关的Protocol,属于ARM平台上的通用代码
- NetworkPkg
提供网络支持的包,比如:IPv6网络协议栈/IPsec驱动/PXE驱动/iSCSI驱动/网络配置相关的shell app。
- StdLib, StdLibPrivateInternalFiles
StdLib提供了标准库的UDK实现,StdLibPrivateInternalFiles包是用来给StdLib使用的,不能用作其他引用。
- OptionRomPkg
这个包的目的是为了提供Option ROM image支持的,如果要编译PCI兼容的Option ROM image,需要依赖此包。
5.2 EDK2工程文件
EDK2的2个概念,模块(Module)和包(Package)。
EDK2根目录下,有很多以*Pkg命名的文件夹,文件夹下有模块和平台描述文件(.dsc文件)和包声明文件(.dec文件),称为包(Package)。如果一个包用于生成固件Image或Option Rom Image,这个包还要包含.fdf(Flash Description F iles)文件,.fdf文件用于生成固件Image、Option Rom Image或可启动Image。
模块是UEFI系统的一个特色。模块(可执行文件,即.ef i文件)像插件一样可以动态地加载到UEFI内核中。对应到源文件,EDK2中的每个工程模块由元数据文件(.inf文件)和源文件(有些情况下也可以包含.ef i文件)组成。
5.2.1编译命令
- build命令用于编译包,它需要一个.dsc文件、一个.dec文件以及一个或多个.inf
文件。
- GenFW命令用于制作固件或Option Rom Image,它需要一个.dec文件和一个.fdf
文件。
build命令把应用程序是被编译成.ef i文件的,整个过程分为以下三步。
- Uef iMain.c首先被编译成目标文件Uef iMain.obj。
2)连接器将目标文件Uef iMain.obj和其他库连接成Uef iMain.dll。
3)GenFw工具将Uef iMain.dll转换成Uef iMain.ef i
source ./edksetup.sh
# build -p EmulatorPkg/EmulatorPkg.dsc -a X64
Build命令执行的是脚本edk2/BaseTools/Source/Python/build/build.py
选项参数:
-a指定架构,可以是IA32(32位x86 CPU)、X64(64位x86_64 CPU)、IPF(Itanium Processor Family)、ARM和EBC(EFI byte code)。
-p指定平台描述文件(.dsc文件)做编译
-m指定元数据文件(.inf文件)做编译
GenFw -e UEFI_APPLICATION -o UefiMain.efi ./build/UefiMain.dll
GenFw命令执行的是edk2/BaseTools/Source/C/bin/GenFw
选项参数:
-e指定生成的efi映像类型,可以是BASE,SMM_CORE,
PEI_CORE, PEIM, DXE_CORE, DXE_DRIVER, UEFI_APPLICATION,
SEC, DXE_SAL_DRIVER, UEFI_DRIVER, DXE_RUNTIME_DRIVER,
DXE_SMM_DRIVER, SECURITY_CORE, COMBINED_PEIM_DRIVER,
MM_STANDALONE, MM_CORE_STANDALONE,
PIC_PEIM, RELOCATABLE_PEIM, BS_DRIVER, RT_DRIVER,
APPLICATION, SAL_RT_DRIVER
-o指定输出文件名
5.2.2 .inf文件
.inf(Module Information File)文件是模块的工程文件,作用相当于Makefile文件。源文件包括C/C++文件、.asm汇编文件,也可以包括.uni文件(字符串资源文件)和.vfr(窗体资源文件)等资源文件。
.inf文件包括多个块,包括[Def ines]、[Sources]、[Packages]和[LibraryClasses]
其中[defines]块的属性ENTRYPOINT定义了模块的入口函数。
[defines]块的属性MODULE_TYPE定义模块的模块类型,可以是SEC、PEI_CORE、PEIM、DXE
CORE、DXE_SAL_DRIVER、DXE_SMM_DRIVER、UEF_DRIVER、DXE_DRIVER、
DXE_RUNTIME_DRIVER、UEFI_APPLICATION、BASE中的一个。
函数格式
typedef EFI_STATUS (EFI_API *EFI_IMAGE_ENTRY_POINT)(
IN EFI_HANDLE ImageHandle; //程序映像(Image)的句柄(Handle)
IN EFI_SYSTEM_TABLE *SystemTable; //系统表指针
);
UEFI所有程序返回值都是EFI_STATUS,无符号长整型。最高位为1时其值为错误码,最高位为0时表示非错误码。EFI_SUCCESS为值为0的预定义常量。
typedef
EFI_STATUS
(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT)(
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
IN UINTN SourceX,
IN UINTN SourceY,
IN UINTN DestinationX,
IN UINTN DestinationY,
IN UINTN Width,
IN UINTN Height,
IN UINTN Delta OPTIONAL
);
5.2.3 .dec和.dsc文件
每个包(Package)包含一个.dec(Package Declaration File)文件、一个.dsc文件。.inf用于编译一个模块,而.dsc文件用于编译一个Package,它包含了[Def ines]、[LibraryClasses]、[Components]几个必需部分以及[PCD]、[BuildOptions]等几个可选部分。
- [Defines]用于设置build相关的全局宏变量,这些变量可以被.dsc文件的其他模块引用。
- [LibraryClasses]块中定义了库的名字以及库.inf文件的路径。这些库可以被[Components]块内的模块引用。
- [Components]块内定义的模块都会被build工具编译并生成.efi文件。
.dec文件定义了公开的数据和接口,供其他模块使用。它包含了必需区块[Def ines]以及可选区块[Includes]、[LibraryClasses]、[Guids]、[Protocols]、[Ppis]和[PCD]几个部分。
- [Defines]区块用于提供package的名称、GUID、版本号等信息。
6,参考资料
《UEFI原理与编程》戴正华(著)机械工业出版社
UEFI_Spec_2_8
https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf
UEFI Platform Initialization Spec
https://uefi.org/sites/default/files/resources/PI_Spec_1_7_final_Jan_2019.pdf
EDK II UEFI Driver Writer’s Guide
https://edk2-docs.gitbooks.io/edk-ii-uefi-driver-writer-s-guide/content/1_introduction/11_overview/
UEFI组成
由启动服务BS(BootService)服务和运行时服务RT(RunTime Service)组成,以及BS后边丰富的Protocol
UEFI系统启动过程
UEFI从加电到关机可分为七个过程:
我们后期关注重点是DXE
SEC(安全验证)-> PEI(EFI前期初始化) -> DXE(驱动执行环境)
-> BDS(启动设备选择) -> TSL(操作系统加载前期)
-> RT(Run Time)
-> AL(系统灾难恢复期)
代码分析
gBS和gST初始化
参考资料
# file: UefiBootServicesTableLib.c
UefiBootServicesTableLibConstructor
gST = SystemTable;
gBS = SystemTable->BootServices;
那么SystemTable从哪获取?-Dxe初始化
uefi\edk2\MdeModulePkg\Core\Dxe\DxeMain\DxeMain.c
mEfiSystemTableTemplate ==>gST
&mBootServices ==>gBS
mBootServices 定义了gBS所有的操作接口