综述

HOB的全称是Hand-Off Block,从名字上也可以看出来,它表示的是一种用于交接的数据。按照HOB的使用情况,可以将BIOS的启动阶段分为两个部分:

  • HOB生成阶段(HOB producer phase),用来创建和修改HOB;
  • HOB消费阶段(HOB consumer phase),用来使用HOB,注意此阶段HOB是只读的。

而这里说的“交接”就是从HOB生成阶段像HOB消费阶段交接数据,至于交接的是什么数据,后面会一一介绍。

本文参考《PI_Spec_1_7_A_final_May1.pdf》(后面统称为PI规范),该手册为了将x86的Platform Initialization扩展到更多的平台,已经不再直接使用PEI、DXE等阶段说明HOB的使用情况,不过对于x86架构的BIOS来说,HOB生成阶段其实就是SEC和PEI阶段,而HOB消费阶段就是DXE和BDS阶段。为了方便,本文还是直接使用PEI、DXE等术语。术语的对应关系如下表所示:

Term Used in the HOB SpecificationTerm Used in Other PI Specifications
HOB producer phasePEI phase
HOB consumer phaseDXE phase
executable content in the HOB producer phasePre-EFI Initialization Module (PEIM)
hand-off into the HOB consumer phaseDXE Initial Program Load (IPL) PEIM or
DXE IPL PEIM-to-PEIM Interface (PPI)
platform boot-policy phaseBoot Device Selection (BDS) phase

注意,虽然上表中只有PEI和DXE,但是从实际的情况来看,SEC和BDS也分别可以作为HOB生成阶段和HOB消费阶段。

HOB的构成

HOB在PEI阶段创建,并返回一个列表(称为HOB List,HOB列表),其中的HOB一个个堆叠放置,最终构成如下的形式:

在这里插入图片描述

根据HOB中包含的数据的不同可以对HOB进行分类,且HOB列表的第一个必须要是PHIT HOB。PHIT的全称是Phase Handoff Information Table,它是第一个被创建的HOB,对应的指针在PEI的核心数据中:

///
/// Union of all the possible HOB Types.
///
typedef union {
  EFI_HOB_GENERIC_HEADER                 *Header;
  EFI_HOB_HANDOFF_INFO_TABLE             *HandoffInformationTable;
  EFI_HOB_MEMORY_ALLOCATION              *MemoryAllocation;
  EFI_HOB_MEMORY_ALLOCATION_BSP_STORE    *MemoryAllocationBspStore;
  EFI_HOB_MEMORY_ALLOCATION_STACK        *MemoryAllocationStack;
  EFI_HOB_MEMORY_ALLOCATION_MODULE       *MemoryAllocationModule;
  EFI_HOB_RESOURCE_DESCRIPTOR            *ResourceDescriptor;
  EFI_HOB_GUID_TYPE                      *Guid;
  EFI_HOB_FIRMWARE_VOLUME                *FirmwareVolume;
  EFI_HOB_FIRMWARE_VOLUME2               *FirmwareVolume2;
  EFI_HOB_FIRMWARE_VOLUME3               *FirmwareVolume3;
  EFI_HOB_CPU                            *Cpu;
  EFI_HOB_MEMORY_POOL                    *Pool;
  EFI_HOB_UEFI_CAPSULE                   *Capsule;
  UINT8                                  *Raw;
} EFI_PEI_HOB_POINTERS;

///
/// Forward declaration for PEI_CORE_INSTANCE
///
typedef struct _PEI_CORE_INSTANCE PEI_CORE_INSTANCE;

///
/// Pei Core private data structure instance
///
struct _PEI_CORE_INSTANCE {
  UINTN                             Signature;

  ///
  /// Point to ServiceTableShadow
  ///
  EFI_PEI_SERVICES                  *Ps;
  PEI_PPI_DATABASE                  PpiData;

  /// 其它略。下面就是指向第一个HOB的指针,EFI_PEI_HOB_POINTERS是一个Union,包括各种指针:
  EFI_PEI_HOB_POINTERS              HobList;
}

后面的HOB操作接口都是以这里为基础的,比如EFI_PEI_SERVICES中就有接口GetHobList(),其实现:

///
/// Pei Core Instance Data Macros
///
#define PEI_CORE_INSTANCE_FROM_PS_THIS(a) \
  CR(a, PEI_CORE_INSTANCE, Ps, PEI_CORE_HANDLE_SIGNATURE)

EFI_STATUS
EFIAPI
PeiGetHobList (
  IN CONST EFI_PEI_SERVICES  **PeiServices,
  IN OUT VOID                **HobList
  )
{
  PEI_CORE_INSTANCE  *PrivateData;

  //
  // Only check this parameter in debug mode
  //

  DEBUG_CODE_BEGIN ();
  if (HobList == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  DEBUG_CODE_END ();

  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);

  *HobList = PrivateData->HobList.Raw;

  return EFI_SUCCESS;
}

创建PHIT HOB的大致流程如下(不同的平台可能会有不同):

PeiCore
InitializeMemoryServices
PeiCoreBuildHobHandoffInfoTable

PeiCoreBuildHobHandoffInfoTable()函数中有PHIT HOB的初始化:

EFI_STATUS
PeiCoreBuildHobHandoffInfoTable (
  IN EFI_BOOT_MODE         BootMode,
  IN EFI_PHYSICAL_ADDRESS  MemoryBegin,
  IN UINT64                MemoryLength
  )
{
  EFI_HOB_HANDOFF_INFO_TABLE  *Hob;
  EFI_HOB_GENERIC_HEADER      *HobEnd;

  Hob                   = (VOID *)(UINTN)MemoryBegin;
  HobEnd                = (EFI_HOB_GENERIC_HEADER *)(Hob+1);
  Hob->Header.HobType   = EFI_HOB_TYPE_HANDOFF;
  Hob->Header.HobLength = (UINT16)sizeof (EFI_HOB_HANDOFF_INFO_TABLE);
  Hob->Header.Reserved  = 0;

  HobEnd->HobType   = EFI_HOB_TYPE_END_OF_HOB_LIST;
  HobEnd->HobLength = (UINT16)sizeof (EFI_HOB_GENERIC_HEADER);
  HobEnd->Reserved  = 0;

  Hob->Version  = EFI_HOB_HANDOFF_TABLE_VERSION;
  Hob->BootMode = BootMode;

  Hob->EfiMemoryTop        = MemoryBegin + MemoryLength;
  Hob->EfiMemoryBottom     = MemoryBegin;
  Hob->EfiFreeMemoryTop    = MemoryBegin + MemoryLength;
  Hob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS)(UINTN)(HobEnd + 1);
  Hob->EfiEndOfHobList     = (EFI_PHYSICAL_ADDRESS)(UINTN)HobEnd;

  return EFI_SUCCESS;
}

这里的数据可以跟前面的图对应。有了第一个HOB,之后的HOB就在此基础之上堆叠,最终完成所有需要的HOB。下面介绍目前PI规范中定义的HOB分类。

HOB分类

当前PI规范定义的HOB有如下的几种类型:

在这里插入图片描述

每一个HOB都包含一个通用的结构:

///
/// Describes the format and size of the data inside the HOB.
/// All HOBs must contain this generic HOB header.
///
typedef struct {
  ///
  /// Identifies the HOB data structure type.
  ///
  UINT16    HobType;
  ///
  /// The length in bytes of the HOB.
  ///
  UINT16    HobLength;
  ///
  /// This field must always be set to zero.
  ///
  UINT32    Reserved;
} EFI_HOB_GENERIC_HEADER;

这里就指定了HOB的类型HobType

//
// HobType of EFI_HOB_GENERIC_HEADER.
//
#define EFI_HOB_TYPE_HANDOFF              0x0001
#define EFI_HOB_TYPE_MEMORY_ALLOCATION    0x0002
#define EFI_HOB_TYPE_RESOURCE_DESCRIPTOR  0x0003
#define EFI_HOB_TYPE_GUID_EXTENSION       0x0004
#define EFI_HOB_TYPE_FV                   0x0005
#define EFI_HOB_TYPE_CPU                  0x0006
#define EFI_HOB_TYPE_MEMORY_POOL          0x0007
#define EFI_HOB_TYPE_FV2                  0x0009
#define EFI_HOB_TYPE_LOAD_PEIM_UNUSED     0x000A
#define EFI_HOB_TYPE_UEFI_CAPSULE         0x000B
#define EFI_HOB_TYPE_FV3                  0x000C
#define EFI_HOB_TYPE_UNUSED               0xFFFE
#define EFI_HOB_TYPE_END_OF_HOB_LIST      0xFFFF

然后是HOB的长度HobLength,通过它就可以知道下一个HOB的位置。

下面介绍一些常用的HOB。

PHIT HOB

前面已经介绍了PHIT HOB,它的结构体如下:

///
/// Contains general state information used by the HOB producer phase.
/// This HOB must be the first one in the HOB list.
///
typedef struct {
  ///
  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_HANDOFF.
  ///
  EFI_HOB_GENERIC_HEADER    Header;
  ///
  /// The version number pertaining to the PHIT HOB definition.
  /// This value is four bytes in length to provide an 8-byte aligned entry
  /// when it is combined with the 4-byte BootMode.
  ///
  UINT32                    Version;
  ///
  /// The system boot mode as determined during the HOB producer phase.
  ///
  EFI_BOOT_MODE             BootMode;
  ///
  /// The highest address location of memory that is allocated for use by the HOB producer
  /// phase. This address must be 4-KB aligned to meet page restrictions of UEFI.
  ///
  EFI_PHYSICAL_ADDRESS      EfiMemoryTop;
  ///
  /// The lowest address location of memory that is allocated for use by the HOB producer phase.
  ///
  EFI_PHYSICAL_ADDRESS      EfiMemoryBottom;
  ///
  /// The highest address location of free memory that is currently available
  /// for use by the HOB producer phase.
  ///
  EFI_PHYSICAL_ADDRESS      EfiFreeMemoryTop;
  ///
  /// The lowest address location of free memory that is available for use by the HOB producer phase.
  ///
  EFI_PHYSICAL_ADDRESS      EfiFreeMemoryBottom;
  ///
  /// The end of the HOB list.
  ///
  EFI_PHYSICAL_ADDRESS      EfiEndOfHobList;
} EFI_HOB_HANDOFF_INFO_TABLE;

里面主要有包含两个部分,一个用来描述启动模式,另一个用来描述HOB内存的分布,这个也已经在前文的图中说明。

Memory Allocation HOB

PHIT HOB之后是Memory Allocation HOB,它对应结构体:

///
/// Describes all memory ranges used during the HOB producer
/// phase that exist outside the HOB list. This HOB type
/// describes how memory is used, not the physical attributes of memory.
///
typedef struct {
  ///
  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION.
  ///
  EFI_HOB_GENERIC_HEADER              Header;
  ///
  /// An instance of the EFI_HOB_MEMORY_ALLOCATION_HEADER that describes the
  /// various attributes of the logical memory allocation.
  ///
  EFI_HOB_MEMORY_ALLOCATION_HEADER    AllocDescriptor;
  //
  // Additional data pertaining to the "Name" Guid memory
  // may go here.
  //
} EFI_HOB_MEMORY_ALLOCATION;

EFI_HOB_MEMORY_ALLOCATION_HEADER结构体的构成:

///
/// EFI_HOB_MEMORY_ALLOCATION_HEADER describes the
/// various attributes of the logical memory allocation. The type field will be used for
/// subsequent inclusion in the UEFI memory map.
///
typedef struct {
  ///
  /// A GUID that defines the memory allocation region's type and purpose, as well as
  /// other fields within the memory allocation HOB. This GUID is used to define the
  /// additional data within the HOB that may be present for the memory allocation HOB.
  /// Type EFI_GUID is defined in InstallProtocolInterface() in the UEFI 2.0
  /// specification.
  ///
  EFI_GUID                Name;

  ///
  /// The base address of memory allocated by this HOB. Type
  /// EFI_PHYSICAL_ADDRESS is defined in AllocatePages() in the UEFI 2.0
  /// specification.
  ///
  EFI_PHYSICAL_ADDRESS    MemoryBaseAddress;

  ///
  /// The length in bytes of memory allocated by this HOB.
  ///
  UINT64                  MemoryLength;

  ///
  /// Defines the type of memory allocated by this HOB. The memory type definition
  /// follows the EFI_MEMORY_TYPE definition. Type EFI_MEMORY_TYPE is defined
  /// in AllocatePages() in the UEFI 2.0 specification.
  ///
  EFI_MEMORY_TYPE         MemoryType;

  ///
  /// Padding for Itanium processor family
  ///
  UINT8                   Reserved[4];
} EFI_HOB_MEMORY_ALLOCATION_HEADER;

这里也有一个MemoryType表示类型,这里指的是UEFI下的内存使用类型,比如存放Boot Service的代码和数据的内存类型,Runtime的代码和数据的内存类型,等等。它们有如下的可选值:

///
/// Enumeration of memory types introduced in UEFI.
///
typedef enum {
  ///
  /// Not used.
  ///
  EfiReservedMemoryType,
  ///
  /// The code portions of a loaded application.
  /// (Note that UEFI OS loaders are UEFI applications.)
  ///
  EfiLoaderCode,
  ///
  /// The data portions of a loaded application and the default data allocation
  /// type used by an application to allocate pool memory.
  ///
  EfiLoaderData,
  ///
  /// The code portions of a loaded Boot Services Driver.
  ///
  EfiBootServicesCode,
  ///
  /// The data portions of a loaded Boot Serves Driver, and the default data
  /// allocation type used by a Boot Services Driver to allocate pool memory.
  ///
  EfiBootServicesData,
  ///
  /// The code portions of a loaded Runtime Services Driver.
  ///
  EfiRuntimeServicesCode,
  ///
  /// The data portions of a loaded Runtime Services Driver and the default
  /// data allocation type used by a Runtime Services Driver to allocate pool memory.
  ///
  EfiRuntimeServicesData,
  ///
  /// Free (unallocated) memory.
  ///
  EfiConventionalMemory,
  ///
  /// Memory in which errors have been detected.
  ///
  EfiUnusableMemory,
  ///
  /// Memory that holds the ACPI tables.
  ///
  EfiACPIReclaimMemory,
  ///
  /// Address space reserved for use by the firmware.
  ///
  EfiACPIMemoryNVS,
  ///
  /// Used by system firmware to request that a memory-mapped IO region
  /// be mapped by the OS to a virtual address so it can be accessed by EFI runtime services.
  ///
  EfiMemoryMappedIO,
  ///
  /// System memory-mapped IO region that is used to translate memory
  /// cycles to IO cycles by the processor.
  ///
  EfiMemoryMappedIOPortSpace,
  ///
  /// Address space reserved by the firmware for code that is part of the processor.
  ///
  EfiPalCode,
  ///
  /// A memory region that operates as EfiConventionalMemory,
  /// however it happens to also support byte-addressable non-volatility.
  ///
  EfiPersistentMemory,
  ///
  /// A memory region that describes system memory that has not been accepted
  /// by a corresponding call to the underlying isolation architecture.
  ///
  EfiUnacceptedMemoryType,
  EfiMaxMemoryType
} EFI_MEMORY_TYPE;

此外,还有几个特别的EFI_HOB_MEMORY_ALLOCATION

  • EFI_HOB_MEMORY_ALLOCATION_STACK
///
/// Describes the memory stack that is produced by the HOB producer
/// phase and upon which all post-memory-installed executable
/// content in the HOB producer phase is executing.
///
typedef struct {
  ///
  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION.
  ///
  EFI_HOB_GENERIC_HEADER              Header;
  ///
  /// An instance of the EFI_HOB_MEMORY_ALLOCATION_HEADER that describes the
  /// various attributes of the logical memory allocation.
  ///
  EFI_HOB_MEMORY_ALLOCATION_HEADER    AllocDescriptor;
} EFI_HOB_MEMORY_ALLOCATION_STACK;

从名称可以看出来它描述的是BSP执行所需的堆对应内存,通过BuildStackHob()创建,对应的流程:

PeiCore
PeiDispatcher
PeiCheckAndSwitchStack
BuildStackHob

函数实现的主要代码:

  CopyGuid (&(Hob->AllocDescriptor.Name), &gEfiHobMemoryAllocStackGuid);
  Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress;
  Hob->AllocDescriptor.MemoryLength      = Length;
  Hob->AllocDescriptor.MemoryType        = EfiBootServicesData;

DXE阶段会进一步的使用该HOB。

  • EFI_HOB_MEMORY_ALLOCATION_BSP_STORE
///
/// Defines the location of the boot-strap
/// processor (BSP) BSPStore ("Backing Store Pointer Store").
/// This HOB is valid for the Itanium processor family only
/// register overflow store.
///
typedef struct {
  ///
  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION.
  ///
  EFI_HOB_GENERIC_HEADER              Header;
  ///
  /// An instance of the EFI_HOB_MEMORY_ALLOCATION_HEADER that describes the
  /// various attributes of the logical memory allocation.
  ///
  EFI_HOB_MEMORY_ALLOCATION_HEADER    AllocDescriptor;
} EFI_HOB_MEMORY_ALLOCATION_BSP_STORE;

该HOB主要在Itanium平台的CPU上使用,这里就不再说明。

  • EFI_HOB_MEMORY_ALLOCATION_MODULE
///
/// Defines the location and entry point of the HOB consumer phase.
///
typedef struct {
  ///
  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION.
  ///
  EFI_HOB_GENERIC_HEADER              Header;
  ///
  /// An instance of the EFI_HOB_MEMORY_ALLOCATION_HEADER that describes the
  /// various attributes of the logical memory allocation.
  ///
  EFI_HOB_MEMORY_ALLOCATION_HEADER    MemoryAllocationHeader;
  ///
  /// The GUID specifying the values of the firmware file system name
  /// that contains the HOB consumer phase component.
  ///
  EFI_GUID                            ModuleName;
  ///
  /// The address of the memory-mapped firmware volume
  /// that contains the HOB consumer phase firmware file.
  ///
  EFI_PHYSICAL_ADDRESS                EntryPoint;
} EFI_HOB_MEMORY_ALLOCATION_MODULE;

它描述的其实是DXE入口,创建的流程:

DxeLoadCore
BuildModuleHob

对应的代码:

  //
  // Load the DXE Core from a Firmware Volume.
  //
  Instance = 0;
  do {
    Status = PeiServicesLocatePpi (&gEfiPeiLoadFilePpiGuid, Instance++, NULL, (VOID **)&LoadFile);
    //
    // These must exist an instance of EFI_PEI_LOAD_FILE_PPI to support to load DxeCore file handle successfully.
    //
    ASSERT_EFI_ERROR (Status);

    Status = LoadFile->LoadFile (
                         LoadFile,
                         FileHandle,
                         &DxeCoreAddress,
                         &DxeCoreSize,
                         &DxeCoreEntryPoint,
                         &AuthenticationState
                         );
  } while (EFI_ERROR (Status));

  //
  // Get the DxeCore File Info from the FileHandle for the DxeCore GUID file name.
  //
  Status = PeiServicesFfsGetFileInfo (FileHandle, &DxeCoreFileInfo);
  ASSERT_EFI_ERROR (Status);

  //
  // Add HOB for the DXE Core
  //
  BuildModuleHob (
    &DxeCoreFileInfo.FileName,
    DxeCoreAddress,
    ALIGN_VALUE (DxeCoreSize, EFI_PAGE_SIZE),
    DxeCoreEntryPoint
    );

BuildModuleHob()的核心代码:

  CopyGuid (&(Hob->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid);
  Hob->MemoryAllocationHeader.MemoryBaseAddress = MemoryAllocationModule;
  Hob->MemoryAllocationHeader.MemoryLength      = ModuleLength;
  Hob->MemoryAllocationHeader.MemoryType        = EfiBootServicesCode;

可以看到代码其实就是从FV中获取DXE核心入口,并根据它的值创建HOB,根据它可以创建DXE核心的Image Hand了,对应的操作位于函数CoreInitializeImageServices()

  // 获取EFI_HOB_MEMORY_ALLOCATION_MODULE这个HOB
  DxeCoreHob.Raw = HobStart;
  while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
    if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
      //
      // Find Dxe Core HOB
      //
      break;
    }

    DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
  }

  // 获取到DxeCoreEntryPoint
  DxeCoreImageBaseAddress = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
  DxeCoreImageLength      = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength;
  DxeCoreEntryPoint       = (VOID *)(UINTN)DxeCoreHob.MemoryAllocationModule->EntryPoint;
  gDxeCoreFileName        = &DxeCoreHob.MemoryAllocationModule->ModuleName;

  // 安装Image Handle
  Image = &mCorePrivateImage;

  Image->EntryPoint       = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint;
  Image->ImageBasePage    = DxeCoreImageBaseAddress;
  Image->NumberOfPages    = (UINTN)(EFI_SIZE_TO_PAGES ((UINTN)(DxeCoreImageLength)));
  Image->Tpl              = gEfiCurrentTpl;
  Image->Info.SystemTable = gDxeCoreST;
  Image->Info.ImageBase   = (VOID *)(UINTN)DxeCoreImageBaseAddress;
  Image->Info.ImageSize   = DxeCoreImageLength;

  //
  // Install the protocol interfaces for this image
  //
  Status = CoreInstallProtocolInterface (
             &Image->Handle,
             &gEfiLoadedImageProtocolGuid,
             EFI_NATIVE_INTERFACE,
             &Image->Info
             );
  ASSERT_EFI_ERROR (Status);

Resource Descriptor HOB

该HOB定义物理内存的属性,其结构:

///
/// Describes the resource properties of all fixed,
/// nonrelocatable resource ranges found on the processor
/// host bus during the HOB producer phase.
///
typedef struct {
  ///
  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR.
  ///
  EFI_HOB_GENERIC_HEADER         Header;
  ///
  /// A GUID representing the owner of the resource. This GUID is used by HOB
  /// consumer phase components to correlate device ownership of a resource.
  ///
  EFI_GUID                       Owner;
  ///
  /// The resource type enumeration as defined by EFI_RESOURCE_TYPE.
  ///
  EFI_RESOURCE_TYPE              ResourceType;
  ///
  /// Resource attributes as defined by EFI_RESOURCE_ATTRIBUTE_TYPE.
  ///
  EFI_RESOURCE_ATTRIBUTE_TYPE    ResourceAttribute;
  ///
  /// The physical start address of the resource region.
  ///
  EFI_PHYSICAL_ADDRESS           PhysicalStart;
  ///
  /// The number of bytes of the resource region.
  ///
  UINT64                         ResourceLength;
} EFI_HOB_RESOURCE_DESCRIPTOR;

这样的HOB一般有很多个,它们通过BuildResourceDescriptorHob()函数创建:

/**
  Builds a HOB that describes a chunk of system memory.

  This function builds a HOB that describes a chunk of system memory.
  If there is no additional space for HOB creation, then ASSERT().

  @param  ResourceType        The type of resource described by this HOB.
  @param  ResourceAttribute   The resource attributes of the memory described by this HOB.
  @param  PhysicalStart       The 64 bit physical address of memory described by this HOB.
  @param  NumberOfBytes       The length of the memory described by this HOB in bytes.

**/
VOID
EFIAPI
BuildResourceDescriptorHob (
  IN EFI_RESOURCE_TYPE            ResourceType,
  IN EFI_RESOURCE_ATTRIBUTE_TYPE  ResourceAttribute,
  IN EFI_PHYSICAL_ADDRESS         PhysicalStart,
  IN UINT64                       NumberOfBytes
  )
{
  EFI_HOB_RESOURCE_DESCRIPTOR  *Hob;

  Hob = CreateHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, sizeof (EFI_HOB_RESOURCE_DESCRIPTOR));
  ASSERT (Hob != NULL);

  Hob->ResourceType      = ResourceType;
  Hob->ResourceAttribute = ResourceAttribute;
  Hob->PhysicalStart     = PhysicalStart;
  Hob->ResourceLength    = NumberOfBytes;
}

该HOB包含的类型:

//
// Value of ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR.
//
#define EFI_RESOURCE_SYSTEM_MEMORY          0x00000000
#define EFI_RESOURCE_MEMORY_MAPPED_IO       0x00000001
#define EFI_RESOURCE_IO                     0x00000002
#define EFI_RESOURCE_FIRMWARE_DEVICE        0x00000003
#define EFI_RESOURCE_MEMORY_MAPPED_IO_PORT  0x00000004
#define EFI_RESOURCE_MEMORY_RESERVED        0x00000005
#define EFI_RESOURCE_IO_RESERVED            0x00000006
//
// BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED is defined for unaccepted memory.
// But this defitinion has not been officially in the PI spec. Base
// on the code-first we define BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED at
// MdeModulePkg/Include/Pi/PrePiHob.h and update EFI_RESOURCE_MAX_MEMORY_TYPE
// to 8. After BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED is officially published
// in PI spec, we will re-visit here.
//
// #define BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED      0x00000007
#define EFI_RESOURCE_MAX_MEMORY_TYPE  0x00000008

包含的属性:

//
// These types can be ORed together as needed.
//
// The following attributes are used to describe settings
//
#define EFI_RESOURCE_ATTRIBUTE_PRESENT         0x00000001
#define EFI_RESOURCE_ATTRIBUTE_INITIALIZED     0x00000002
#define EFI_RESOURCE_ATTRIBUTE_TESTED          0x00000004
#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED  0x00000080
//
// This is typically used as memory cacheability attribute today.
// NOTE: Since PI spec 1.4, please use EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED
// as Physical write protected attribute, and EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED
// means Memory cacheability attribute: The memory supports being programmed with
// a writeprotected cacheable attribute.
//
#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED      0x00000100
#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED  0x00000200
#define EFI_RESOURCE_ATTRIBUTE_PERSISTENT           0x00800000
//
// The rest of the attributes are used to describe capabilities
//
#define EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC           0x00000008
#define EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC         0x00000010
#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1           0x00000020
#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2           0x00000040
#define EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE              0x00000400
#define EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE        0x00000800
#define EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE  0x00001000
#define EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE     0x00002000
#define EFI_RESOURCE_ATTRIBUTE_16_BIT_IO                0x00004000
#define EFI_RESOURCE_ATTRIBUTE_32_BIT_IO                0x00008000
#define EFI_RESOURCE_ATTRIBUTE_64_BIT_IO                0x00010000
#define EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED        0x00020000
#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE         0x00100000
//
// This is typically used as memory cacheability attribute today.
// NOTE: Since PI spec 1.4, please use EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE
// as Memory capability attribute: The memory supports being protected from processor
// writes, and EFI_RESOURCE_ATTRIBUTE_WRITE_PROTEC TABLE means Memory cacheability attribute:
// The memory supports being programmed with a writeprotected cacheable attribute.
//
#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE      0x00200000
#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE  0x00400000
#define EFI_RESOURCE_ATTRIBUTE_PERSISTABLE            0x01000000

#define EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED    0x00040000
#define EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE  0x00080000

//
// Physical memory relative reliability attribute. This
// memory provides higher reliability relative to other
// memory in the system. If all memory has the same
// reliability, then this bit is not used.
//
#define EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE  0x02000000

在内存初始化完成之后,会调用该接口来定义内存的属性,比如:

  //
  // Report first 640KB of memory
  //
  BuildResourceDescriptorHob (
    EFI_RESOURCE_SYSTEM_MEMORY,
    MEM_TESTED_ATTR,
    (EFI_PHYSICAL_ADDRESS) (0),
    (UINT64) (0xA0000)
  );

  //
  // Report first 0A0000h - 0FFFFFh as RESERVED memory
  //
  BuildResourceDescriptorHob (
    EFI_RESOURCE_MEMORY_RESERVED,
    MEM_TESTED_ATTR,
    (EFI_PHYSICAL_ADDRESS) (0xA0000),
    (UINT64) (0x60000)
  );

  //
  // Report first 0x100000 - FSP reserved memory as system memory
  //
  BuildResourceDescriptorHob (
    EFI_RESOURCE_SYSTEM_MEMORY,
    MEM_TESTED_ATTR,
    (EFI_PHYSICAL_ADDRESS) (0x100000),
    (UINT64) (PeiMemBase - 0x100000)
  );

在DXE阶段会收集这些HOB并初始化GDC(Global Coherency Domain)映射表。

GUID Extension HOB

该HOB术语自定义类型,如果我们需要自己创建从PEI阶段到DXE阶段传递数据的HOB,就可以使用这种类型,这也是BIOS开发时最可能用到的HOB,其结构体:

///
/// Allows writers of executable content in the HOB producer phase to
/// maintain and manage HOBs with specific GUID.
///
typedef struct {
  ///
  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_GUID_EXTENSION.
  ///
  EFI_HOB_GENERIC_HEADER    Header;
  ///
  /// A GUID that defines the contents of this HOB.
  ///
  EFI_GUID                  Name;
  //
  // Guid specific data goes here
  //
} EFI_HOB_GUID_TYPE;

它是一个不定长的结构体,Name之后还可以有自定义的数据。这个的Name是一个唯一的GUID,后续DXE阶段通过该GUID来找到自定义的数据。

下面是一个示例,首选是HOB的创建,它位于PEI阶段,对应代码模块BeniPkg\Pei\HobProvider\HobProvider.inf:

EFI_STATUS
EFIAPI
HobProviderEntry (
  IN  EFI_PEI_FILE_HANDLE           FileHandle,
  IN  CONST EFI_PEI_SERVICES        **PeiServices
  )
{
  BENI_HOB_DATA *Hob = NULL;
  UINT8         Index = 0;

  DEBUG ((EFI_D_ERROR, "Creating HOB ...\n"));

  Hob = BuildGuidHob (&gBeniHobGuid, sizeof (BENI_HOB_DATA));
  if (NULL == Hob) {
    DEBUG ((EFI_D_ERROR, "[%a][%d] BuildGuidHob failed.\n", __FUNCTION__, __LINE__));
    return EFI_OUT_OF_RESOURCES;
  }

  for (Index = 0; Index < BENI_HOB_DATA_LEN; Index++) {
    Hob->Data[Index] = Index;
  }

  DEBUG ((EFI_D_ERROR, "Done\n"));

  return EFI_SUCCESS;
}

然后在DXE阶段就可以使用,对应模块BeniPkg\Dxe\HobConsumer\HobConsumer.inf:

EFI_STATUS
EFIAPI
HobConsumerEntry (
  IN  EFI_HANDLE                    ImageHandle,
  IN  EFI_SYSTEM_TABLE              *SystemTable
  )
{
  EFI_PEI_HOB_POINTERS  Hob;
  UINTN                 Index = 0;
  UINT8                 *Data = NULL;

  Hob.Raw = GetFirstGuidHob (&gBeniHobGuid);
  if (NULL == Hob.Raw) {
    DEBUG ((EFI_D_ERROR, "[%a][%d] Failed. - %r\n", __FUNCTION__, __LINE__, EFI_NOT_FOUND));
    return EFI_NOT_FOUND;
  }

  Data = (UINT8 *)(GET_GUID_HOB_DATA (Hob.Raw));
  DEBUG ((EFI_D_ERROR, "BENI Hob data:\n"));
  for (Index = 0; Index < BENI_HOB_DATA_LEN; Index++) {
    DEBUG ((EFI_D_ERROR, "0x%02x ", *(Data + Index)));
  }
  DEBUG ((EFI_D_ERROR, "\n"));

  return EFI_SUCCESS;
}

End of HOB List

HOB列表的最后是一个End of HOB,它有特定了类型EFI_HOB_TYPE_END_OF_HOB_LIST,在PHIT HOB中就有一个成员EfiEndOfHobList指向它。

其它

还有跟FV、CPU、SMRAM相关的HOB,这里就不再介绍了,有兴趣的可以直接看PI手册。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐