我的BIOS之行5-hob的使用

发布时间 2023-08-15 14:26:31作者: King_Alex

HOB(hand off block)简介

有些时候,我们需要将一些information从PEI阶段传递到DXE阶段,那么这个时候我们就需要hob当做桥梁来给我们进行传递了。总的来说,PEI生产HOB,DXE消费HOB,在这里需要注意HOB只有在PEI阶段是可修改的,在DXE阶段是只读的,每一个Block都有自己的GUID与Struct

运作模式

当PEI阶段的module需要传递信息给DXE时,会Call PEI Service去建立一个HOB的block,并加载在HOB的list上。

HOB使用的实例

在这里我是将上一章所使用的setup的item选项联系起来,在PEI阶段获取item的值,并建立HOB,将item的值进行保存,然后由DXE阶段获取。

具体需要看源码的请移步我的github的homework项目

HOB在PEI阶段

新建pei文件并获取item的值

在sdl文件中加入

TOKEN
    Name  = "HomeWorkPeim_INF_SUPPORT"
    Value  = "1"
    Help  = "Main switch to enable HomeWorkDxe support in Project"
    TokenType = Boolean
    Token = "HomeWork_SUPPORT" "=" "1"
End

INFComponent
    Name  = "HomeWorkPeim"
    File  = "Pei/HomeWorkPeim.inf"
    Package  = "Homework"
    ModuleTypes  = "PEIM"
    Token = "HomeWorkPeim_INF_SUPPORT" "=" "1"
End

这样就已经将PEI的inf文件定义好了,此时要做的是在module的目录中建立Pei目录并在其中新建HomeWorkPeim.c/HomeWorkPeim.inf
并在inf文件中

[Defines]
  INF_VERSION           = 0x00010015
  BASE_NAME             = HomeWorkPeim
  FILE_GUID             = d133c000-7911-4e7f-abff-71f14f3337a8
  MODULE_TYPE           = PEIM
  VERSION_STRING        = 1.0
  ENTRY_POINT           = HomeWorkPeimEntryPoint

定义这个PEI文件的name 与入口参数,还有一些guid,依赖等,这个在后续专门出博客来讲解inf的一些定义,这里主要讲hob,我就不描述了。

注意:这里的入口函数一定要与C文件对应

同时你需要在module建立一个homework.h文件用于建立hob所需要的结构体与GUID

#define HOMEWORK_HOB_GUID \
{0x6ff0434a, 0x9598, 0x42cc, 0xb7, 0x38, 0xad, 0x17, 0x55, 0x48, 0x42, 0x9c}
typedef struct {
  EFI_HOB_GUID_TYPE    EfiHobGuidType; 
  UINT8    homeworkdata;  
} HOMEWORK_HOB;

如前面所说,hob就是通过guid来获取相关的信息,那么这个GUID就必须可以让PEI阶段的文件抓取的到,有可以让DXE文件抓取的到。

首先要做的是讲setup的值获取到,此时你需要用到的是gEfiPeiReadOnlyVariable2PpiGuid这个PPI。至于什么是PPI请移步我前面发布的一些博客


    EFI_GUID                          SetupGuid = SETUP_GUID;
    EFI_PEI_READ_ONLY_VARIABLE2_PPI   *ReadOnlyVariable;
    UINTN                              VariableSize;
    SETUP_DATA                         SetupData;
 Status = PeiServicesLocatePpi(&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, &ReadOnlyVariable);
  //  ASSERT_EFI_ERROR(Status);
    VariableSize = sizeof(SETUP_DATA);
    Status = ReadOnlyVariable->GetVariable(ReadOnlyVariable, L"Setup", &SetupGuid, NULL, &VariableSize, &SetupData);
 
    if (EFI_ERROR(Status)) {
        return Status;
    }

通过ReadOnlyVariable->GetVariable方法来获取setup的所有值。

创建一个hob

    HOMEWORK_HOB                      *homeworkhob = NULL;
    EFI_GUID                           homeworkHobGuid = HOMEWORK_HOB_GUID;

Status = (*PeiServices)->CreateHob (
                               PeiServices,
                               EFI_HOB_TYPE_GUID_EXTENSION,
                               sizeof(HOMEWORK_HOB),
                               &homeworkhob);
    if (EFI_ERROR(Status)) {
        return Status;
    }

仔细看这些code你会发现用到了h文件中定义的GUID与结构体,当然这边只是做了一个简单的数据类型,其实你可以做得更加多的东西。

讲取到的值放入hob中

  homeworkhob->EfiHobGuidType.Name=homeworkHobGuid;
    homeworkhob->homeworkdata=SetupData.HomeWorkoption;     

这里的HomeWorkoption就是我们上一文所加的新选项

HOB在Dxe阶段

新建inf文件

同样的道理需要新建inf文件,加入相关的依赖项

[Defines]
  INF_VERSION           = 0x00010015
  BASE_NAME             = HomeWorkDxe
  FILE_GUID             = 43a12ef5-0372-4119-9f0f-000a8c104c62
  MODULE_TYPE           = DXE_DRIVER
  VERSION_STRING        = 1.0
  ENTRY_POINT           = HomeWorkDxeEntryPoint

新建dxe的 c文件

 EFI_GUID                GuidHob = HOB_LIST_GUID;
    EFI_STATUS              Status;
    HOMEWORK_HOB *Homeworkhob=NULL;
    EFI_GUID    HomeworkHobGuid=HOMEWORK_HOB_GUID;
    VOID       *pHobList = NULL;
pHobList = GetEfiConfigurationTable(SystemTable, &GuidHob);
    if (!pHobList) return EFI_NOT_READY;
    
    Homeworkhob = (HOMEWORK_HOB*)pHobList;
    while (!EFI_ERROR(Status = FindNextHobByType(EFI_HOB_TYPE_GUID_EXTENSION, &Homeworkhob)))
    {
            if (guidcmp(&(*Homeworkhob).EfiHobGuidType.Name, &HomeworkHobGuid) == 0)
                break;
    }
       if (EFI_ERROR(Status)) 
      {
          return EFI_NOT_FOUND;
       }else{
             OEM_TRACE("data=%d\n",Homeworkhob->homeworkdata);
       }

在dxe阶段,你需要通过GetEfiConfigurationTable拿到hob list的hander,也相当与一个链表的头指针,然后通过FindNextHobByType去遍历这个链表,通过比较GUID进行锁定,并把值写出来。

在这里我提醒一下,所谓的OEM_TRACE是我们自主写的一个module用于串口debug的。如果有可能,我会在纯净的UEFI中再做这个module,让大家可以进行自行编译,而不是现在的只能看博客。