高通平台UEFI有关介绍

摘要:
高通平台UEFI有关介绍背景我需要在高通平台上学习点亮LCD,目前通过同事在别的平台的配置代码,我已经将kernel部分的屏幕点亮了;剩余的工作量就在BP侧,也就是系统刚开机的那一段时间。有关文档:https://www.cnblogs.com/we-hjb/p/9800627.htmlhttps://blog.csdn.net/u014089131/article/details/73617716https://blog.csdn.net/weixin_41803132/article/details/107692862高通UEFI、XBL及ABL的详细介绍:《80_P2484_37_LINUX_ANDROID_UEFI_OVERVIEW.pdf》。UEFI克服了上述的所有缺点,采用C语言实现,分层,模块化设计,实现了CPU以及驱动的无关性。RT系统进入此阶段后,系统控制权从UEFI内核转交到OSLoader上。而高通UEFI由XBL和ABL两部分组成。
高通平台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中涉及的名词缩写 :

缩写意义
UEFIUnified extensible firmware interface
SECSecurity
PEIPre EFI initialization
DXEDriver execution Environment
BDSBoot Dev Select
TSLTransient System Loa
RTRuntime
ALAfter life
GUIDGlobally Unique Identifier
CSMCompatibility Support Modul
TCGTrusted Computing Group
PEPortable executable
COFFCommon object file format
FVFirmware 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部分的代码。

高通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. 

  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. 

  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. 

  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. 

  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中可以直接调用。

免责声明:文章转载自《高通平台UEFI有关介绍》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Qt开发技术:QtCharts(一)QtCharts基本介绍以及图表框架详解Zabbix服务网页报错汇总下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

网络socket编程实现并发服务器——多线程编程

一、多线程简介1、什么是线程?       线程在操作系统原理中是这样描述的:线程是进程的一条执行路径。线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可以看作是Unix进程的表亲,所有的线程都是在同一进程空间运行,这也意味着多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调...

VS2015调用matlab Plot函数

最近经常采用Matlab仿真,然后C语言实现,最后需要将计算结果使用Qt的qwt或者matlab中的plot函数绘图。 因此想借用matlab的plot函数接口,使用VS2015来编写信号处理代码,最后通过绘图来验证。 参考博客: https://blog.csdn.net/shouzang/article/details/80795945 https:/...

1-嵌入式面试题库

嵌入式工程师:主要从事嵌入式软件开发工作,涉及应用层以及底层软件开发和设计的工作。以应用为中心,计算机技术为基础,软硬件可裁剪,适用于应用系统对功能、可靠性、成本、体积、功耗有严格要求的专用计算机系统。嵌入式产品一般由嵌入式微处理器、外围硬件设备、嵌入式操作系统以及用户程序等四个部分构成,用于对其他设备控制、监护、管理。 面试题目(自我介绍/项目/代码量/...

Linux Socket学习(十二)

套接口选项在前面的几章中,我们讨论了使用套接口的基础内容。现在我们要来探讨一些可用的其他的特征。在我们掌握了这一章的概念之后,我们就为后面的套接口的高级主题做好了准备。在这一章,我们将会专注于下列主题:如何使用getsockopt(2)函数获得套接口选项值如何使用setsockopt(2)函数设置套接口选项值如何使用这些常用的套接口选项得到套接口选项有时,...

Linux-c 线程锁

1 typedef struct_my_mutex { 2 pthread_mutex_t mutex; //互斥锁 3 pthread_mutexattr_t mta; //互斥锁属性 4 } my_mutex; 转自:http://blog.sina.com.cn/s/blog_8795b0970101il6g.html 在Posix Threa...

Promise 对象

Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从...