高通平台UEFI有關介紹


高通平台UEFI有關介紹

背景

我需要在高通平台上學習點亮LCD,目前通過同事在別的平台的配置代碼,我已經將kernel部分的屏幕點亮了;剩余的工作量就在BP側,也就是系統剛開機的那一段時間。在開發過程中,我發現我對BP側的開發有點不太熟悉,因此我需要搞清楚有關的概念。只有搞清楚了這些基本概念,我才能夠在后續的工作中不留下隱患。

有關文檔:

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從上電到關機,一共有七個階段:

  1. SEC(安全驗證)
    其功能包括:接受處理系統啟動與重啟信號、初始化臨時RAM區、作為可信系統的根、以及傳遞系統參數到下一階段。
    其執行流程是:
    上電 -> ResetVector -> SEC函數入口 -> PEI函數入口
  2. PEI
    主要功能是為DXE准備執行環境,將HOB列表傳遞給DXE。此階段到后期內存才被初始化,所以資源相當有限,尚未可進行復雜的工作。
  3. DXE
    此階段執行大部分系統初始化工作,內存已被初始化,可以進行大量復雜工作。當所有的Driver都執行完畢,說明系統初始化完成,接着通過EFI_BDS_ARCH_PROTOCAL找到BDS並調用BDS的入口函數,進入BDS階段。
  4. BDS
    此階段主要功能是執行啟動策略,等OS Loader啟動后,系統進入TSL階段。
  5. TSL
    TSL是OS Loader執行的第一階段,OS Loader在這個階段作為UEFI APPLICATION運行,當ExitBootServices服務被調用后,進入RT(RunTime)階段。
  6. RT
    系統進入此階段后,系統控制權從UEFI內核轉交到OS Loader上。隨着OS Loader的執行,OS最終取得對系統的 控制權。
  7. 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

  • 需要驅動DisplayUsbKeypadPmicVibrator

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個輸入參數:ThisRamPartitionsNumPartition

其他函數也是通過同樣的方法定義出來的,下面會用到。

再看看文末最后的那一個結構體:

/*===========================================================================
  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中可以直接調用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM