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表