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}