高通平台UEFI有關介紹
背景
我需要在高通平台上學習點亮LCD,目前通過同事在別的平台的配置代碼,我已經將kernel部分的屏幕點亮了;剩余的工作量就在BP側,也就是系統剛開機的那一段時間。在開發過程中,我發現我對BP側的開發有點不太熟悉,因此我需要搞清楚有關的概念。只有搞清楚了這些基本概念,我才能夠在后續的工作中不留下隱患。
有關文檔:
- https://www.cnblogs.com/we-hjb/p/9800627.html
- https://blog.csdn.net/u014089131/article/details/73617716
- https://blog.csdn.net/weixin_41803132/article/details/107692862
- 高通UEFI、XBL及ABL的詳細介紹: 《80_P2484_37_LINUX_ANDROID_UEFI_OVERVIEW.pdf》。
UEFI 介紹
UEFI(Unified extensible firmware interface)統一的可擴展固件接口,是一種詳細描述類型接口的標准。
可擴展固件接口(Extensible Firmware Interface,EFI)是 Intel 為 PC 固件的體系結構、接口和服務提出的建議標准。其主要目的是為了提供一組在 OS 加載之前(啟動前)在所有平台上一致的、正確指定的啟動服務,被看做是有近20多年歷史的 BIOS 的繼任者。
BIOS是匯編實現的,采用的是16bit 實模式尋址方式,最大支持的內存只有1M,代碼易讀性以及實現的功能都受到限制,而且移植起來不方便。BIOS支持的最大磁盤空間不超過2TB。
UEFI克服了上述的所有缺點,采用C語言實現,分層,模塊化設計,實現了CPU以及驅動的無關性。UEFI可以理解為一個完整的系統,包含了上電時序,驅動實現,os環境建立(這個os可以理解為UEFI運行獨有的os,非linux,windows),應用程序。其中應用程序支持網絡配置,類shell環境,fastboot,linux loader等。
UEFI啟動階段
UEFI從上電到關機,一共有七個階段:
- SEC(安全驗證)
其功能包括:接受處理系統啟動與重啟信號、初始化臨時RAM區、作為可信系統的根、以及傳遞系統參數到下一階段。
其執行流程是:
上電 -> ResetVector -> SEC函數入口 -> PEI函數入口 - PEI
主要功能是為DXE准備執行環境,將HOB列表傳遞給DXE。此階段到后期內存才被初始化,所以資源相當有限,尚未可進行復雜的工作。 - DXE
此階段執行大部分系統初始化工作,內存已被初始化,可以進行大量復雜工作。當所有的Driver都執行完畢,說明系統初始化完成,接着通過EFI_BDS_ARCH_PROTOCAL找到BDS並調用BDS的入口函數,進入BDS階段。 - BDS
此階段主要功能是執行啟動策略,等OS Loader啟動后,系統進入TSL階段。 - TSL
TSL是OS Loader執行的第一階段,OS Loader在這個階段作為UEFI APPLICATION運行,當ExitBootServices服務被調用后,進入RT(RunTime)階段。 - RT
系統進入此階段后,系統控制權從UEFI內核轉交到OS Loader上。隨着OS Loader的執行,OS最終取得對系統的 控制權。 - AL
在RT階段,如果系統遇到災難性錯誤,系統固件需要提供錯誤處理和災難恢復機制,而這種機制運行在AL階段。
其中UEFI中涉及的名詞縮寫 :
縮寫 | 意義 |
---|---|
UEFI | Unified extensible firmware interface |
SEC | Security |
PEI | Pre EFI initialization |
DXE | Driver execution Environment |
BDS | Boot Dev Select |
TSL | Transient System Loa |
RT | Runtime |
AL | After life |
GUID | Globally Unique Identifier |
CSM | Compatibility Support Modul |
TCG | Trusted Computing Group |
PE | Portable executable |
COFF | Common object file format |
FV | Firmware Volume |
UEFI有關文件格式
fdf:flash definitionfile,描述flash分區地址范圍
dec:package declarationfile,定義了不同模塊的GUID信息
dsc:description file,主要包含需要用到的所有inf文件
inf:單個模塊的編譯信息,類似makefile
efi :最終編譯生成的UEFI可執行文件
高通平台的UEFI設計
高通在MSM8998上引入了UEFI,用來代替LK(Little Kernel)。
而高通UEFI由XBL和ABL兩部分組成。
在新版本中,之前屬於LK的設備驅動都放在了XBL核心,Linux加載啟動及fastboot等功能組件則作為獨立的UEFI應用存在。
XBL
XBL負責芯片驅動及充電等核心應用功能。
XBL核心是none-HLOS boot_image
代碼的一部分,屬於高通私有代碼。
代碼路徑為:BP側的BOOT.XX/boot_images
tree -L 2
.
├── about.html
├── ADSP.VT.5.4.1
│ ├── adsp_proc
│ ├── BuildProducts.txt
│ └── HY11_1.txt
├── Agatti.LA.1.0.1
│ ├── common
│ └── contents.xml
├── BOOT.XF.4.1
│ ├── BOOT.XF.4.1-00200-KAMORTALAZ-1.brfx
│ ├── BOOT.XF.4.1-00200-KAMORTALAZ-1_notes.txt
│ ├── boot_images ▲
│ │ ├── ArmPkg
│ │ ├── ArmPlatformPkg
│ │ ├── BaseTools
│ │ ├── Build
│ │ ├── Conf
│ │ ├── EmbeddedPkg
│ │ ├── FatPkg
│ │ ├── IntelFrameworkModulePkg
│ │ ├── IntelFrameworkPkg
│ │ ├── MdeModulePkg
│ │ ├── MdePkg
│ │ ├── NetworkPkg
│ │ ├── OptionRomPkg
│ │ ├── QcomPkg
│ │ └── ShellPkg
│ ├── BuildProducts.txt
│ ├── copyrightmod.xml
│ ├── CRM_BOOT.XF.4.1-00200-KAMORTALAZ-1.cs
│ ├── si
│ └── VerifySrc.log
├── BTFM.CHE.2.1.5
│ └── btfm_proc
├── BTFM.CMC.1.2.0
│ └── btfm_proc
├── build_sdm6115.bat
├── CDSP.VT.2.4.1
│ ├── BuildProducts.txt
│ ├── cdsp_proc
│ └── HY11_1.txt
├── env.bat
├── Kamorta.LA.1.0.1
│ ├── common
│ └── contents.xml
├── LA.QSSI.11.0
│ └── LINUX
├── LA.UM.9.15
│ └── LINUX
├── MPSS.HA.1.0
│ └── modem_proc
├── RPM.BF.1.10
│ └── rpm_proc
├── TZ.APPS.1.1
│ └── qtee_tas
├── TZ.APPS.2.0
│ └── qtee_tas
├── TZ.XF.5.1
│ └── trustzone_images
├── VIDEO.VE.6.0
│ ├── manifest.xml
│ └── venus_proc
└── WLAN.HL.3.2.4
└── wlan_proc
UEFI代碼中大量使用了protocol概念,這個protocol其實指的是驅動,包含了驅動函數指針和數據。我們會在附錄中介紹這一部分。
總之,記住:XBL實現的protocol,在ABL中可以直接調用。
ABL
ABL包括芯片無關的應用如fastboot
。ABL則在開源Linux Android代碼樹里。
ABL的編譯非常簡單,依次執行命令:
source build/envsetup.sh
lunch 32
make aboot
不同的廠商對UEFI有不同的實現,一種比較常用的開源實現是EDK2;EDK2是一個遵循UEFI標准和PI標准的跨平台固件開發環境,EDK2支持多種操作系統, 也支持跨平台編譯。
確切來講,高通所使用的edk2編譯以后就是做為ABL部分的代碼,同XBL一同構成了UEFI。
高通UEFI有關源碼
對於高通平台啟動過程依次為:PBL
->XBL
->ABL
。
一般用戶定制化主要集中在ABL中,這部分代碼樹如下:
這部分里面主要是作為linux-loader 用來加載linux,以及fastboot。
用戶修改主要集中在這兩個部分,入口函數LinuxLoaderEntry。
${Andrioid源碼樹}/bootable/bootloader/edk2/QcomModulePkg
├── Application
│ └── LinuxLoader
│ ├── LinuxLoader.c
│ └── LinuxLoader.inf
├── Include
│ ├── Library
│ │ ├──BoardCustom.h
│ │ ├── Board.h
│ │ ├──BootImage.h
│ │ ├──BootLinux.h
│ │ ├──BootStats.h
│ │ ├──Decompress.h
│ │ ├──DeviceInfo.h
│ │ ├── DrawUI.h
│ │ ├──FastbootMenu.h
│ │ ├── Fonts.h
│ │ ├── KeyPad.h
│ │ ├──LinuxLoaderLib.h
│ │ ├── list.h
│ │ ├──LocateDeviceTree.h
│ │ ├──MenuKeysDetection.h
│ │ ├──PartitionTableUpdate.h
│ │ ├── Recovery.h
│ │ ├── Reg.h
│ │ ├──ShutdownServices.h
│ │ ├──StackCanary.h
│ │ ├──UnlockMenu.h
│ │ ├──UpdateCmdLine.h
│ │ ├──UpdateDeviceTree.h
│ │ └──VerifiedBootMenu.h
│ └── Protocol
│ ├── EFICardInfo.h
│ ├── EFIChargerEx.h
│ ├── EFIChipInfo.h
│ ├── EFIChipInfoTypes.h
│ ├── EFIEraseBlock.h
│ ├── EFILimits.h
│ ├── EFIMdtp.h
│ ├── EFIPlatformInfo.h
│ ├── EFIPlatformInfoTypes.h
│ ├── EFIPmicPon.h
│ ├── EFIPmicVersion.h
│ ├── EFIQseecom.h
│ ├── EFIRamPartition.h
│ ├── EFIResetReason.h
│ ├── EFIRng.h
│ ├── EFIScmModeSwitch.h
│ ├── EFIUsbDevice.h
│ ├── EFIUsbEx.h
│ ├── EFIVerifiedBoot.h
│ └── UsbEx.h
├── Library
│ ├── BootLib
│ │ ├── Board.c
│ │ ├──BootLib.inf
│ │ ├──BootLinux.c
│ │ ├──BootStats.c
│ │ ├──Decompress.c
│ │ ├──DeviceInfo.c
│ │ ├── DrawUI.c
│ │ ├──FastbootMenu.c
│ │ ├── KeyPad.c
│ │ ├──LinuxLoaderLib.c
│ │ ├──LocateDeviceTree.c
│ │ ├──MenuKeysDetection.c
│ │ ├──PartitionTableUpdate.c
│ │ ├── Recovery.c
│ │ ├──ShutdownServices.c
│ │ ├──UnlockMenu.c
│ │ ├──UpdateCmdLine.c
│ │ ├──UpdateDeviceTree.c
│ │ └──VerifiedBootMenu.c
│ ├── FastbootLib
│ │ ├──FastbootCmds.c
│ │ ├──FastbootCmds.h
│ │ ├──FastbootLib.inf
│ │ ├──FastbootMain.c
│ │ ├──FastbootMain.h
│ │ ├──MetaFormat.h
│ │ ├──SparseFormat.h
│ │ ├──UsbDescriptors.c
│ │ └──UsbDescriptors.h
│ ├── StackCanary
│ │ ├──StackCanary.c
│ │ └──StackCanary.inf
│ └── zlib
│ ├── adler32.c
│ ├── inffast.c
│ ├── inffast.h
│ ├── inffixed.h
│ ├── inflate.c
│ ├── inflate.h
│ ├── inftrees.c
│ ├── inftrees.h
│ ├── zconf.h
│ ├── zlib.h
│ ├── zlib.inf
│ ├── zutil.c
│ └── zutil.h
├──QcomModulePkg.dec
├──QcomModulePkg.dsc
├──QcomModulePkg.fdf
└── Tools
├── app_path_set.cmm
├── check_paths.cmm
├── debug_app.cmm
├── elf_tools.py
├── image_header.py
├── load_uefi_dump.cmm
├── log_save.cmm
├── symbol_Load.cmm
└── uefi_core_path_set.cmm
附錄:為什么android 默認bootloader選擇lk?
reference:https://blog.csdn.net/leo_wdls/article/details/45173643
結論:用於移動通信的android設備(如手機平板):軟件小巧,架構簡單,滿足android bootloader的基本需求。
lk源碼目錄位置:
bootable/bootloader/lk
Android bootloader需求:
-
加載引導
linux kernel
-
需要驅動
Display
、Usb
、Keypad
、Pmic
、Vibrator
Uboot 的特點:
-
加載引導linux kernel
-
發展早,軟件成熟穩定,功能完備;
-
支持的多個CPU 體系
-
支持復雜驅動,如Fs/Network等等;
Little Kernel特點:
-
加載引導linux kernel
-
輕量級、不支持復雜的驅動
附錄:關於UEFI的Protocol概念
為什么要有Protocol?
大家都知道,UEFI的英文翻譯過來應該叫“可擴展固件接口”。這個名詞中最重要的事實上是“可擴展”這三個字。換言之,相比傳統的系統固件而言,UEFI固件具備了完善的可擴展支持。這個概念對軟件行業不是一個新概念,但是對bios這樣一個陳舊腐朽的東西而言,的確是一個創新的思想。
所謂可擴展的含義就是可以在系統完成后(編譯為binary)之后,再次為系統增加新的功能,而不用重新rebuild整個系統。在這個大的需求的前提下,還有一些其他的重要的含義,比如必須支持不同的組件的獨立開發。
比如A廠商今天針對某硬件開發了一個驅動,他們發布了一個二進制包APackage;而B廠商則針對另一個硬件開發了一個驅動,他們發布了一個二進制包BPackage;現在APackage和BPackage都需要集成到bios內。且必須以二進制的形式集成。因為A和B廠商的知識產權需要得到尊重。或者像OS下那樣,可以通過某種方法在系統已經運行起來后加載到內存。
更好玩的是,A廠商並不希望自己需要重新從車輪開始發明。比如他們針對的硬件是一個PCI的適配器,他們希望希望系統里已經有了諸如ReadPci()或者WritePci()這樣調用來簡化他們編程上的工作。換言之,他們希望目標系統能夠支持不同的二進制組件之間的運行時通訊。
支持二進制組件的運行時通訊是一個十分復雜的技術。這里所謂的通訊,包括但不限於如下的含義:
1、互操作。A組件自由可以調用B組件實現的函數。反過來也一樣。
2、數據傳遞。雙方可以通過某種方法(shared memory, pipes and etc)互相交換數據。
3、可探測。某組件必須具備探測另一個組件是否存在的能力。
4、組件的開發必須是獨立的。開發A組件不需要B組件的源代碼,反之亦然。
這可以說是現代操作系統的一個核心概念。
熟悉Windows的朋友可能十分清楚Windows下的COM組件,所有的COM組件都可以互相通訊的。且應用程序可以自由的使用任何一個組件提供的服務。
只有具備了這樣的能力的系統才可以被叫做“可擴展”的。而UEFI為了達到可擴展的能力,必須提供一種機制來提供支持,於是UEFI領域的專家們發明了Protocol。
從約定到接口
Protocol從本質上說是一種調用者與被調用者之間的“約定”。而這種“約定”在軟件開發領域有另一個更形象化的名字叫接口(Interface)。
為了做到二進制間的互操作,那么參與操作的雙方(調用者與被調用者)都必須做出一定的讓步,這個讓步就是雙方必須遵循實現商量好的調用方法(接口)。而這種事先的約定的接口就是protocol的定義。而這種定義尤以.h文件的形式加以實現。
由於目前UEFI還是幾乎是用C語言開發,基本上不存在跨語言的問題,所以Protocol才可以表達成.h
文件。
而Windows下的COM的Interface,由於考慮到跨語言的問題,才專門有了一個新的通用語言叫接口定義語言(IDL,Interface Definiton Language),使用時候專門有一個IDL的compiler將IDL翻譯成各個其他語言專用的表達方法(對於C語言,就是生成對應的.h文件)。
具體實現
定義
我們現在來看一個.h文件,看看一個protocol到底是怎樣定義出來的。
用任意一個編輯器打開一個.h
的接口文件,無論是什么樣的接口,都必定是遵循UEFI規范所定義的標准而實現的。
以rampatition為例:boot_images/QcomPkg/Include/Protocol/EFIRamPartition.h
中聲明了rampatition protocol
:
/**
@file EFIRamPartition.h
@brief RamPartition EFI protocol interface.
*/
/*=============================================================================
Copyright (c) 2015,2018 Qualcomm Technologies, Incorporated.
All rights reserved.
Qualcomm Technologies, Confidential and Proprietary.
=============================================================================*/
/*=============================================================================
EDIT HISTORY
when who what, where, why
-------- --- -----------------------------------------------------------
06/05/18 daisond Added GetMinPasrSize module in rampartition protocol
09/30/15 vk Initial Revision
=============================================================================*/
#ifndef __EFIRAMPARTITION_H__
#define __EFIRAMPARTITION_H__
/** @cond */
typedef struct _EFI_RAMPARTITION_PROTOCOL EFI_RAMPARTITION_PROTOCOL;
/** @endcond */
/** @addtogroup efi_ramPartition_constants
@{ */
/**
Protocol version.
*/
#define EFI_RAMPARTITION_PROTOCOL_REVISION 0x0000000000010001
/** @} */ /* end_addtogroup efi_ramPartition_constants */
/* Protocol GUID definition */
/** @ingroup efi_ramPartition_protocol */
#define EFI_RAMPARTITION_PROTOCOL_GUID \
{ 0x5172FFB5, 0x4253, 0x7D51, { 0xC6, 0x41, 0xA7, 0x01, 0xF9, 0x73, 0x10, 0x3C } }
/** @cond */
/**
External reference to the RAMPARTITION Protocol GUID defined
in the .dec file.
*/
extern EFI_GUID gEfiRamPartitionProtocolGuid;
/** @endcond */
typedef struct _RamPartition
{
UINT64 Base;
UINT64 AvailableLength;
}RamPartitionEntry;
/** @} */ /* end_addtogroup efi_ramPartition_data_types */
/*==============================================================================
API IMPLEMENTATION
==============================================================================*/
/* ============================================================================
** Function : EFI_RamPartition_GetRamPartitionVersion
** ============================================================================
*/
/** @ingroup efi_ramPartition_getRamVersion
@par Summary
Gets the RAM Partition table version.
@param[in] This Pointer to the EFI_RAMPARTITION_PROTOCOL instance.
@param[out] MajorVersion Pointer to UINT32 which returns RAM partition table version
@param[out] MinorVersion Pointer to UINT32 which returns RAM partition table version
@return
EFI_SUCCESS -- Function completed successfully. \n
EFI_PROTOCOL_ERROR -- Error occurred during the operation.
*/
typedef
EFI_STATUS
(EFIAPI *EFI_RAMPARTITION_GETRAMPARTITIONVERSION)(
IN EFI_RAMPARTITION_PROTOCOL *This,
OUT UINT32 *MajorVersion,
OUT UINT32 *MinorVersion
);
/* ============================================================================
** Function : EFI_RamPartition_GetHighestBankBit
** ============================================================================
*/
/** @ingroup efi_ramPartition_getHighestBankBit
@par Summary
Gets the RAM Partition table version.
@param[in] This Pointer to the EFI_RAMPARTITION_PROTOCOL instance.
@param[out] HighestBankBit Pointer to Highest Bank Bit
@return
EFI_SUCCESS -- Function completed successfully. \n
EFI_PROTOCOL_ERROR -- Error occurred during the operation.
*/
typedef
EFI_STATUS
(EFIAPI *EFI_RAMPARTITION_GETHIGHESTBANKBIT)(
IN EFI_RAMPARTITION_PROTOCOL *This,
OUT UINT32 *HighestBankBit
);
/* ============================================================================
** Function : EFI_RamPartition_GetMinPasrSize
** ============================================================================
*/
/** @ingroup EFI_RamPartition_GetMinPasrSize
@par Summary
Gets the MinPasrSize
@param[in] This Pointer to the EFI_RAMPARTITION_PROTOCOL instance.
@param[out] MinPasrSize Pointer to MinPasrSize
@return
EFI_SUCCESS -- Function completed successfully. \n
EFI_PROTOCOL_ERROR -- Error occurred during the operation.
*/
typedef
EFI_STATUS
(EFIAPI *EFI_RAMPARTITION_GETMINPASRSIZE)(
IN EFI_RAMPARTITION_PROTOCOL *This,
OUT UINT32 *MinPasrSize
);
/* ============================================================================
** Function : EFI_RamPartition_GetRamPartitions
** ============================================================================
*/
/** @ingroup efi_ramPartition_getRamPartitions
@par Summary
Gets the Ram version as read from the hardware register.
@param[in] This Pointer to the EFI_RAMPARTITION_PROTOCOL instance.
@param[out] pnVersion Pointer to a UINT32 passed by the caller that
will be populated by the driver.
@return
EFI_SUCCESS -- Function completed successfully. \n
EFI_BUFFER_TOO_SMALL -- Returns number of partitions available
EFI_PROTOCOL_ERROR -- Error occurred during the operation.
*/
typedef
EFI_STATUS
(EFIAPI *EFI_RAMPARTITION_GETRAMPARTITIONS)(
IN EFI_RAMPARTITION_PROTOCOL* This,
OUT RamPartitionEntry *RamPartitions,
IN OUT UINT32 *NumPartition
);
/*===========================================================================
PROTOCOL INTERFACE
===========================================================================*/
/** @ingroup efi_ramPartition_protocol
@par Summary
Ram Information Protocol interface.
@par Parameters
*/
struct _EFI_RAMPARTITION_PROTOCOL {
UINT64 Revision;
EFI_RAMPARTITION_GETRAMPARTITIONVERSION GetRamPartitionVersion;
EFI_RAMPARTITION_GETHIGHESTBANKBIT GetHighestBankBit;
EFI_RAMPARTITION_GETRAMPARTITIONS GetRamPartitions;
EFI_RAMPARTITION_GETMINPASRSIZE GetMinPasrSize;
};
#endif /* __EFIRAMPARTITION_H__ */
我們注意到這些相同的形式:
typedef
EFI_STATUS
(EFIAPI *EFI_RAMPARTITION_GETRAMPARTITIONS)(
IN EFI_RAMPARTITION_PROTOCOL* This,
OUT RamPartitionEntry *RamPartitions,
IN OUT UINT32 *NumPartition
);
這是一個指向函數的指針類型的定義,它定義了一個新的指針類型叫EFI_RAMPARTITION_GETRAMPARTITIONS
,如此是希望今后的系統能直接使用EFI_RAMPARTITION_GETRAMPARTITIONS
類型,這樣做主要希望能夠提高代碼的可讀性。
這個指針類型指向了一個函數,這個函數有3個輸入參數:This
、RamPartitions
、NumPartition
其他函數也是通過同樣的方法定義出來的,下面會用到。
再看看文末最后的那一個結構體:
/*===========================================================================
PROTOCOL INTERFACE
===========================================================================*/
/** @ingroup efi_ramPartition_protocol
@par Summary
Ram Information Protocol interface.
@par Parameters
*/
struct _EFI_RAMPARTITION_PROTOCOL {
UINT64 Revision;
EFI_RAMPARTITION_GETRAMPARTITIONVERSION GetRamPartitionVersion;
EFI_RAMPARTITION_GETHIGHESTBANKBIT GetHighestBankBit;
EFI_RAMPARTITION_GETRAMPARTITIONS GetRamPartitions;
EFI_RAMPARTITION_GETMINPASRSIZE GetMinPasrSize;
};
這里又定義了一個大的結構類型_EFI_RAMPARTITION_PROTOCOL
,注意到這個結構幾乎是由之前提及的指針函數所構成的。
這樣定義是顯而易見的,既然是約定的定義,那么自然需要約定的函數的定義。
這個結構體是對應的Protocol
的最主要的組成部分。
GUID
除此之外,一個Protocol還有一些其他的組成部分。
/* Protocol GUID definition */
/** @ingroup efi_ramPartition_protocol */
#define EFI_RAMPARTITION_PROTOCOL_GUID \
{ 0x5172FFB5, 0x4253, 0x7D51, { 0xC6, 0x41, 0xA7, 0x01, 0xF9, 0x73, 0x10, 0x3C } }
/** @cond */
/**
External reference to the RAMPARTITION Protocol GUID defined
in the .dec file.
*/
extern EFI_GUID gEfiRamPartitionProtocolGuid;
/** @endcond */
首先是GUID,正如Windows下的COM Interfaces一樣,每一個Protocol也有一個定義好的,唯一的標識符。這個標識符就用GUID來表達。這樣一來每個Protocol都有了自己的名字,那么使用者可以方便的通過指明不同的GUID來得到不同的Protocol。
其次是一個指向GUID的全局指針變量,比如這里提到的這個_EFI_RAMPARTITION_PROTOCOL
,就有一個全局的指針叫gEfiRamPartitionProtocolGuid
的指針,它是EFI_GUID *
結構的。
這樣做事實上完全是為了方便,他的變量名的命名規則是統一的,即g + Efi + Protocol 名稱 + ProtocolGuid。這樣一來,程序員就不需記住相應GUID具體的值,而只在需要GUID作為參數的時候,使用這個全局變量即可,這有點類似Windows下的UUID宏。
實現
在boot_images/QcomPkg/Drivers/EnvDxe/EnvDxe.c
中實現了上文提到的協議:
STATIC EFI_RAMPARTITION_PROTOCOL RamPartitionProtocol =
{
EFI_RAMPARTITION_PROTOCOL_REVISION,
EFI_GetRamPartitionVersion,
EFI_GetHighestBankBit,
EFI_GetRamPartitions,
EFI_GetMinPasrSize
};
EFI_STATUS
SetupRamPartitionProtocol ()
{
EFI_STATUS Status;
STATIC EFI_HANDLE ImageHandle;
Status = InitRamPartitionTableLib();
if (Status != EFI_SUCCESS)
return EFI_UNSUPPORTED;
Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
&gEfiRamPartitionProtocolGuid,
&RamPartitionProtocol,
NULL, NULL);
return Status;
}
具體的內容我們就不再往下看,但是可以推測,在這里綁定了對應的函數;之后只要得到gEfiRamPartitionProtocolGuid
的地址,就可以訪問到有關的接口。
這也就是所謂的:在XBL中實現了protocol,也就是驅動,在ABL中可以直接調用。