天天看點

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}