UEFI源码解析之HOB

HOB全程Hand off Block,粗暴的理解就是握手时候传递的block;Pei阶段和Dxe阶段的握手,Block中的信息主要是内存等一些平台资源;PEI阶段把自己能获取到的平台相关信息通过block的方式传递给Dxe阶段:兄弟,我只能帮到这里了,接下来要看你的了,你要的东西都在Block里面了;

Pei和Dxe阶段的HOB传递在代码中的体现为PeiMain中:HobList

TempPtr.DxeIpl->Entry (

                             TempPtr.DxeIpl,

                             &PrivateData.Ps,

                             PrivateData.HobList

                             );

DxeMain中:HobStart

DxeMain (IN  VOID *HobStart)

注意:Dxe阶段只会读取Hob,不会改写Hob;

HOB结构的实现分为三部分,PHIT头,描述Hob的其实位置和内存使用信息;各种Hob的列表,Dxe从该列表上获取资源,传参为Hob Type和guid;最后时Hob结束部分;

第一次进入PeiCore的时候,还是Car阶段,内存没有初始化,InitializeMemoryServices 中调用PeiCoreBuildHobHandoffInfoTable开启HOB创建;位置在Car中;

CAR:Cache As Ram,CPU内缓存当临时memory使用,此时实际的memory未完成初始化;

//PeiTemporaryMemoryBase 64K偏移处创建HOB 信息,仿真器中的实现

PeiCoreBuildHobHandoffInfoTable (

      BOOT_WITH_FULL_CONFIGURATION,

      (EFI_PHYSICAL_ADDRESS) (UINTN) SecCoreData->PeiTemporaryRamBase,

      (UINTN) SecCoreData->PeiTemporaryRamSize

      );

{

if (OldCoreData == NULL) {

    PrivateData->PeiMemoryInstalled = FALSE;  //内存为完成初始化

       PrivateData->HobList.Raw        = SecCoreData->PeiTemporaryRamBase;  //Hob位置

    PeiCoreBuildHobHandoffInfoTable (

      BOOT_WITH_FULL_CONFIGURATION,

      (EFI_PHYSICAL_ADDRESS) (UINTN) SecCoreData->PeiTemporaryRamBase,

      (UINTN) SecCoreData->PeiTemporaryRamSize

      );

}

}

进入PeiCoreBuildHobHandoffInfoTable 中的实现:此处几位构建PHIT(Phase Handoff InformationTable)头,描述了最基本的内存使用信息;

HOB基本结构描述:

HOB头结构

typedef struct {

  UINT16    HobType;   //Hob 类型

  UINT16    HobLength;  //Hob总长为多少byte,get Hob的时候需要该Length还定位Hob在内存中的位置

  UINT32    Reserved;

} EFI_HOB_GENERIC_HEADER;

Hob 类型:

#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类型对应不同的信息存储结构,如EFI_HOB_TYPE_HANDOFF对应PHIT,可通过上述PHIT的实现推测PHIT头结构的实现;

接下介绍几种典型常用的HOB:

EFI_HOB_TYPE_MEMORY_ALLOCATION/

EFI_HOB_TYPE_RESOURCE_DESCRIPTOR/

EFI_HOB_TYPE_GUID_EXTENSION/

EFI_HOB_TYPE_MEMORY_ALLOCATION:描述一次内存的分配,用于描述的内存范围包括:

EFI_HOB_MEMORY_ALLOCATION : 通用的内存使用描述  对应自定义guid

EFI_HOB_MEMORY_ALLOCATION_STACK:栈的使用描述 gEfiHobMemoryAllocStackGuid

EFI_HOB_MEMORY_ALLOCATION_MODULE: Image入口点Entry的描述 

typedef struct {

  EFI_GUID              Name;

  EFI_PHYSICAL_ADDRESS  MemoryBaseAddress;

  UINT64                MemoryLength;

  EFI_MEMORY_TYPE       MemoryType;   //内存分配时候会讲到,不同Type有不同的使用和生命周期

  UINT8                 Reserved[4];

} EFI_HOB_MEMORY_ALLOCATION_HEADER;

EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:对一个资源[一段内存区]的类型/属性/权限/内存位置等的描述,内存管理中使用;

    

资源类型定义

typedef struct {

  EFI_HOB_GENERIC_HEADER      Header;

  EFI_GUID                    Owner;

  EFI_RESOURCE_TYPE           ResourceType;

  EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute;

  EFI_PHYSICAL_ADDRESS        PhysicalStart;  //起始位置

  UINT64                      ResourceLength;   //区段长度

} EFI_HOB_RESOURCE_DESCRIPTOR;

EFI_HOB_TYPE_GUID_EXTENSION:未明确具体类型的自定义描述,与对应的guid绑定,根据guid获取HOB,如BuildGuidHob/GetFirstGuidHob/GetNextGuidHob

Hob在PEI阶段的实现

PEI_CORE_INSTANCE中EFI_PEI_HOB_POINTERS  HobList指向Hob位置,也是DxeCore Entry的入参;

 

新增HOB:

InternalPeiCreateHob (IN UINT16  Type, IN UINT16  Length)

{  

Status = PeiServicesCreateHob (Type, Length, &Hob);  //Length为Sizeof(HOB结构)

---->PeiServices = GetPeiServicesTablePointer ();

return (*PeiServices)->CreateHob (PeiServices, Type, Length, Hob);

}

---->

create的操作在PeiService中,直至保存在Pei Instance的Ps中,在PeiMain.c的gPs中:

PeiCreateHob (

  IN CONST EFI_PEI_SERVICES  **PeiServices,

  IN UINT16            Type,

  IN UINT16            Length,

  IN OUT VOID          **Hob

  )

{

  Status = PeiGetHobList (PeiServices, Hob);    //读取PEI_CORE_INSTANCE中HobList.Raw

  HandOffHob = *Hob;

  Length     = (UINT16)((Length + 0x7) & (~0x7));   //长度8byte对齐操作

//可用Hob的空间大小

  FreeMemory = HandOffHob->EfiFreeMemoryTop - HandOffHob->EfiFreeMemoryBottom;

// 取HOB end当作返回的HOB,填充Type和长度信息

  *Hob = (VOID*) (UINTN) HandOffHob->EfiEndOfHobList;

  ((EFI_HOB_GENERIC_HEADER*) *Hob)->HobType   = Type;

  ((EFI_HOB_GENERIC_HEADER*) *Hob)->HobLength = Length;

  ((EFI_HOB_GENERIC_HEADER*) *Hob)->Reserved  = 0;

//内存寻址增加Length(需返回的Hob大小)后新建HOB End,相当与在End前插入了一个有效hob,Hob end往后顺移;

  HobEnd = (EFI_HOB_GENERIC_HEADER*) ((UINTN) *Hob + Length);

  HandOffHob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;

  HobEnd->HobType   = EFI_HOB_TYPE_END_OF_HOB_LIST;

  HobEnd->HobLength = (UINT16) sizeof (EFI_HOB_GENERIC_HEADER);

  HobEnd->Reserved  = 0;

  HobEnd++;

// 可用空间位置修正

  HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;

}

新增样例:见各种BuildXXXXHob接口的实现,如:

 

HOB布局:此图为网上引用,本地重绘

 

 

查找/获取HOB

GetNextHob (IN UINT16                 Type,  IN CONST VOID             *HobStart)

{

  EFI_PEI_HOB_POINTERS  Hob;

  Hob.Raw = (UINT8 *) HobStart;    //HOB LIST其实位置

  while (!END_OF_HOB_LIST (Hob)) {

    if (Hob.Header->HobType == Type) {   //类型符合则找到

      return Hob.Raw;

    }

    Hob.Raw = GET_NEXT_HOB (Hob);   //否则查找下一个

  }

  return NULL;

}

---->通过HobLength定位下一个HOB

#define GET_HOB_LENGTH(HobStart) \

  ((*(EFI_HOB_GENERIC_HEADER **)&(HobStart))->HobLength)

#define GET_NEXT_HOB(HobStart) \

  (VOID *)(*(UINT8 **)&(HobStart) + GET_HOB_LENGTH (HobStart))

与guid绑定的HOB全在EFI_HOB_TYPE_GUID_EXTENSION类型中;

GetNextGuidHob (

  IN CONST EFI_GUID         *Guid,

  IN CONST VOID             *HobStart

  )

{

  EFI_PEI_HOB_POINTERS  GuidHob;

  GuidHob.Raw = (UINT8 *) HobStart;

  while ((GuidHob.Raw = GetNextHob (EFI_HOB_TYPE_GUID_EXTENSION, GuidHob.Raw)) != NULL) {

    if (CompareGuid (Guid, &GuidHob.Guid->Name)) {  //判断GUID是否满足

      break;

    }

    GuidHob.Raw = GET_NEXT_HOB (GuidHob);  //GUID不满足,寻找下一个

  }

  return GuidHob.Raw;

}

使用样例:GetFirstHob/GetFirstGuidHob/GetNextHob/GetNextGuidHob

 

HOB在内存中的实际布局:

以仿真器的实现为例,Sec阶段传递过来的初始Car信息为:

// |-----------| <---- TemporaryRamBase + TemporaryRamSize  128K

  // |   Heap    |

  // |           |

  // |-----------| <---- StackBase / PeiTemporaryMemoryBase 64K

sizeof (EFI_SEC_PEI_HAND_OFF)

  // |-----------| <---- TopOfStack 0x000001b1a5ceffb0   <----SecCoreData

  // |           |

  // |  Stack    |

  // |-----------| <---- TemporaryRamBase 

// SEC阶段传递给PEI阶段的PEI运行环境,PeiCode的入参之一,主要为Car内存信息,见上图解析;

typedef struct _EFI_SEC_PEI_HAND_OFF {

  UINT16  DataSize;

  VOID    *BootFirmwareVolumeBase;  //FD文件在内存中的首地址

  UINTN   BootFirmwareVolumeSize;   //FD 镜像文件大小

  VOID    *TemporaryRamBase;   //temperary memory/car的首地址

  UINTN   TemporaryRamSize;    //Car大小,缓存为内存可用空间

  VOID    *PeiTemporaryRamBase;   //可用的Car位置和大小

  UINTN   PeiTemporaryRamSize;

  VOID    *StackBase;    // Car阶段栈大小和地址

  UINTN   StackSize;

} EFI_SEC_PEI_HAND_OFF;

内存初始化完成后整体内存空间会进行搬迁;

内存初始化(在某个特性的PEIM中)完成后,调用PeiInstallPeiMemory建立物理内存的描述;

PeiInstallPeiMemory (

  IN CONST EFI_PEI_SERVICES  **PeiServices,

  IN EFI_PHYSICAL_ADDRESS    MemoryBegin,

  IN UINT64                  MemoryLength

  )

{

  PrivateData->PhysicalMemoryBegin   = MemoryBegin;

  PrivateData->PhysicalMemoryLength  = MemoryLength;

  PrivateData->FreePhysicalMemoryTop = MemoryBegin + MemoryLength;

  PrivateData->SwitchStackSignal      = TRUE;

}

之后的内存迁移,即Car到物理内存的迁移在PeiCheckAndSwitchStack完成,形成Stack/Heap空间;SwitchStack完成car到实际内存运行空间的切换;

PeiCheckAndSwitchStack嗲用用BuildStackHob将实际内存Stack保存在Hob中:

BuildStackHob (TopOfNewStack - NewStackSize, NewStackSize)----》

 

内存初始化完成后第二次进入PeiCode调整内存分配的位置;

 

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值