UEFI ESRT表

Windows DevMgr中可以以更新驱动的方式更新ME/Bios/TPM模块。为了实现这个功能,离不开UEFI的ESRT表。

ESRT的定义在MSDN上有详细描述,读者对ESRT表有基本概念后可以再看下ESRT表的实现。

根据MSDN的定义,ESRT分两部分:

EFI_SYSTEM_RESOURCE_TABLE:ESRT的描述符部分,用于描述EFI_SYSTEM_RESOURCE_ENTRY:

EFI_SYSTEM_RESOURCE_ENTRY[N]:ESRT数组,整个结构的主体部分。Bios/ME/TPM Image通过Windows Device Manager执行Capsule Update需要在数组中注册ESRT项。注册后会在DevMgr中出现设备节点,这样就能通过Firmware Package(inf/cat/bin)更新Image。

系统配置表ConfigurationTable中的一项指向ESRT表

EFI_STATUS EFIAPI
CoreInstallConfigurationTable (EFI_GUID *Guid,VOID     *Table)
{
    CopyGuid ((VOID *)&EfiConfigurationTable[Index].VendorGuid, Guid);
EfiConfigurationTable[Index].VendorTable  = Table;
}

ESRT表的Guid定义于MdePkg\MdePkg.dec:

gEfiSystemResourceTableGuid    = { 0xb122a263, 0x3661, 0x4f68, {0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80 }}

这个值和MSDN上定义的一致:

#define EFI_SYSTEM_RESOURCE_TABLE_GUID   \

{ 0xb122a263, 0x3661, 0x4f68,  0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80  }

MdeModulePkg\Universal\EsrtDxe\EsrtDxe.c是DXE service,实现并注册ESRT_MANAGEMENT_PROTOCOL,供ME/TPM模块注册更新ESRT表项。

struct _ESRT_MANAGEMENT_PROTOCOL {
  GET_ESRT_ENTRY        GetEsrtEntry;
  UPDATE_ESRT_ENTRY     UpdateEsrtEntry;
  REGISTER_ESRT_ENTRY   RegisterEsrtEntry;
  UNREGISTER_ESRT_ENTRY UnRegisterEsrtEntry;
  SYNC_ESRT_FMP         SyncEsrtFmp;
  LOCK_ESRT_REPOSITORY  LockEsrtRepository;
};
extern EFI_GUID gEsrtManagementProtocolGuid;

在EsrtDxeEntryPoint入口安装Protocol:

ESRT_MANAGEMENT_PROTOCOL  mEsrtManagementProtocolTemplate = {
                            EsrtDxeGetEsrtEntry,
                            EsrtDxeUpdateEsrtEntry,
                            EsrtDxeRegisterEsrtEntry,
                            EsrtDxeUnRegisterEsrtEntry,
                            EsrtDxeSyncFmp,
                            EsrtDxeLockEsrtRepository
                            };

EFI_STATUS
EFIAPI
EsrtDxeEntryPoint (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable)
{
  Status = gBS->InstallMultipleProtocolInterfaces (
 					…
                  &gEsrtManagementProtocolGuid,
                  &mEsrtManagementProtocolTemplate,
                  …);
}

然后等待ReadyToBoot信号

  Status = gBS->CreateEventEx (
					…
                  EsrtReadyToBootEventNotify,
					…
                  &gEfiEventReadyToBootGuid,
                  …);

当ReadyToBoot信号触发时,会调用EsrtReadyToBootEventNotify,该函数向EFI_CONFIGURATION_TABLE安装ESRT表项

EsrtReadyToBootEventNotify
  EsrtTable = AllocatePool(sizeof(EFI_SYSTEM_RESOURCE_TABLE) + NonFmpRepositorySize + FmpRepositorySize);

  EsrtTable->FwResourceVersion  = EFI_SYSTEM_RESOURCE_TABLE_FIRMWARE_RESOURCE_VERSION;
  EsrtTable->FwResourceCount    = (UINT32)((NonFmpRepositorySize + FmpRepositorySize) / sizeof(EFI_SYSTEM_RESOURCE_ENTRY));
  EsrtTable->FwResourceCountMax = PcdGet32(PcdMaxNonFmpEsrtCacheNum) + PcdGet32(PcdMaxFmpEsrtCacheNum);

  if (NonFmpRepositorySize != 0 && NonFmpEsrtRepository != NULL) {
    CopyMem(EsrtTable + 1, NonFmpEsrtRepository, NonFmpRepositorySize);
  }

  Status = gBS->InstallConfigurationTable (&gEfiSystemResourceTableGuid, EsrtTable);

{附注:gBS->InstallConfigurationTable是EFI提供的Boot Service,指向CoreInstallConfigurationTable}

上面代码段中反复出现一个词:Repository----仓库,这个仓库(临时)存储就是ESRT表项。在gEfiEventReadyToBootGuid收到通知前,DXE模块通过ESRT_MANAGEMENT_PROTOCOL->RegisterEsrtEntry向这个临时仓库添加表项。RegisterEsrtEntry的实现比较容易,可以认为是数据结构课程中数组插入操作。

最后看下EsrtReadyToBootEventNotify函数的作用:

EsrtReadyToBootEventNotify计算EFI_SYSTEM_RESOURCE_TABLE和EFI_SYSTEM_RESOURCE_ENTRY数组的大小并分配空间,然后根据EFI_SYSTEM_RESOURCE_ENTRY数组的数组项数更新EFI_SYSTEM_RESOURCE_ENTRY描述符----EFI_SYSTEM_RESOURCE_TABLE;最后调用gBS->InstallConfigurationTable向系统配置表安装ESRT表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值