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表

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章