2009-01-23 08:24:55 +01:00
|
|
|
/** @file
|
|
|
|
BDS routines to handle capsules.
|
|
|
|
|
2018-06-27 15:06:35 +02:00
|
|
|
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
|
2019-04-04 01:03:59 +02:00
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
2009-01-23 08:24:55 +01:00
|
|
|
|
|
|
|
**/
|
|
|
|
#include "Bds.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
This routine is called to see if there are any capsules we need to process.
|
|
|
|
If the boot mode is not UPDATE, then we do nothing. Otherwise find the
|
|
|
|
capsule HOBS and produce firmware volumes for them via the DXE service.
|
|
|
|
Then call the dispatcher to dispatch drivers from them. Finally, check
|
|
|
|
the status of the updates.
|
|
|
|
|
|
|
|
This function should be called by BDS in case we need to do some
|
|
|
|
sort of processing even if there is no capsule to process. We
|
|
|
|
need to do this if an earlier update went away and we need to
|
|
|
|
clear the capsule variable so on the next reset PEI does not see it and
|
|
|
|
think there is a capsule available.
|
|
|
|
|
|
|
|
@param BootMode the current boot mode
|
|
|
|
|
|
|
|
@retval EFI_INVALID_PARAMETER boot mode is not correct for an update
|
|
|
|
@retval EFI_SUCCESS There is no error when processing capsule
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
2009-12-17 00:28:46 +01:00
|
|
|
EFIAPI
|
2009-07-21 09:57:29 +02:00
|
|
|
BdsProcessCapsules (
|
2009-01-23 08:24:55 +01:00
|
|
|
EFI_BOOT_MODE BootMode
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_PEI_HOB_POINTERS HobPointer;
|
|
|
|
EFI_CAPSULE_HEADER *CapsuleHeader;
|
|
|
|
UINT32 Size;
|
|
|
|
UINT32 CapsuleNumber;
|
|
|
|
UINT32 CapsuleTotalNumber;
|
|
|
|
EFI_CAPSULE_TABLE *CapsuleTable;
|
|
|
|
UINT32 Index;
|
|
|
|
UINT32 CacheIndex;
|
|
|
|
UINT32 CacheNumber;
|
|
|
|
VOID **CapsulePtr;
|
|
|
|
VOID **CapsulePtrCache;
|
2018-06-27 15:06:35 +02:00
|
|
|
EFI_GUID *CapsuleGuidCache;
|
2013-10-15 03:31:49 +02:00
|
|
|
BOOLEAN NeedReset;
|
2009-01-23 08:24:55 +01:00
|
|
|
|
2013-10-15 03:31:49 +02:00
|
|
|
CapsuleNumber = 0;
|
2009-01-23 08:24:55 +01:00
|
|
|
CapsuleTotalNumber = 0;
|
2013-10-15 03:31:49 +02:00
|
|
|
CacheIndex = 0;
|
|
|
|
CacheNumber = 0;
|
|
|
|
CapsulePtr = NULL;
|
|
|
|
CapsulePtrCache = NULL;
|
|
|
|
CapsuleGuidCache = NULL;
|
|
|
|
NeedReset = FALSE;
|
2009-01-23 08:24:55 +01:00
|
|
|
|
|
|
|
//
|
|
|
|
// We don't do anything else if the boot mode is not flash-update
|
|
|
|
//
|
|
|
|
if (BootMode != BOOT_ON_FLASH_UPDATE) {
|
2011-09-02 16:45:30 +02:00
|
|
|
DEBUG ((EFI_D_ERROR, "Boot mode is not correct for capsule update.\n"));
|
2009-01-23 08:24:55 +01:00
|
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
}
|
2018-06-27 15:06:35 +02:00
|
|
|
|
2009-01-23 08:24:55 +01:00
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
//
|
|
|
|
// Find all capsule images from hob
|
|
|
|
//
|
|
|
|
HobPointer.Raw = GetHobList ();
|
2009-10-28 08:54:17 +01:00
|
|
|
while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {
|
2009-01-23 08:24:55 +01:00
|
|
|
CapsuleTotalNumber ++;
|
|
|
|
HobPointer.Raw = GET_NEXT_HOB (HobPointer);
|
|
|
|
}
|
2018-06-27 15:06:35 +02:00
|
|
|
|
2009-01-23 08:24:55 +01:00
|
|
|
if (CapsuleTotalNumber == 0) {
|
|
|
|
//
|
|
|
|
// We didn't find a hob, so had no errors.
|
|
|
|
//
|
2011-09-02 16:45:30 +02:00
|
|
|
DEBUG ((EFI_D_ERROR, "We can not find capsule data in capsule update boot mode.\n"));
|
|
|
|
DEBUG ((EFI_D_ERROR, "Please check the followings are correct if unexpected capsule update error happens.\n"));
|
|
|
|
DEBUG ((EFI_D_ERROR, "1. CapsuleX64 is built as X64 module when PEI is IA32 and DXE is X64\n"));
|
|
|
|
DEBUG ((EFI_D_ERROR, "2. Capsule data should persist in memory across a system reset.\n"));
|
2009-01-23 08:24:55 +01:00
|
|
|
PlatformBdsLockNonUpdatableFlash ();
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
2018-06-27 15:06:35 +02:00
|
|
|
|
2009-01-23 08:24:55 +01:00
|
|
|
//
|
|
|
|
// Init temp Capsule Data table.
|
|
|
|
//
|
|
|
|
CapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);
|
|
|
|
ASSERT (CapsulePtr != NULL);
|
|
|
|
CapsulePtrCache = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);
|
|
|
|
ASSERT (CapsulePtrCache != NULL);
|
|
|
|
CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * CapsuleTotalNumber);
|
|
|
|
ASSERT (CapsuleGuidCache != NULL);
|
2018-06-27 15:06:35 +02:00
|
|
|
|
2009-01-23 08:24:55 +01:00
|
|
|
//
|
|
|
|
// Find all capsule images from hob
|
|
|
|
//
|
|
|
|
HobPointer.Raw = GetHobList ();
|
2009-10-28 08:54:17 +01:00
|
|
|
while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {
|
|
|
|
CapsulePtr [CapsuleNumber++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress;
|
2009-01-23 08:24:55 +01:00
|
|
|
HobPointer.Raw = GET_NEXT_HOB (HobPointer);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
//Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install
|
|
|
|
//capsuleTable to configure table with EFI_CAPSULE_GUID
|
|
|
|
//
|
|
|
|
|
|
|
|
//
|
|
|
|
// Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating
|
2018-06-27 15:06:35 +02:00
|
|
|
// System to have information persist across a system reset. EFI System Table must
|
2009-01-23 08:24:55 +01:00
|
|
|
// point to an array of capsules that contains the same CapsuleGuid value. And agents
|
2018-06-27 15:06:35 +02:00
|
|
|
// searching for this type capsule will look in EFI System Table and search for the
|
2009-01-23 08:24:55 +01:00
|
|
|
// capsule's Guid and associated pointer to retrieve the data. Two steps below describes
|
2018-06-27 15:06:35 +02:00
|
|
|
// how to sorting the capsules by the unique guid and install the array to EFI System Table.
|
|
|
|
// Firstly, Loop for all coalesced capsules, record unique CapsuleGuids and cache them in an
|
2009-01-23 08:24:55 +01:00
|
|
|
// array for later sorting capsules by CapsuleGuid.
|
|
|
|
//
|
|
|
|
for (Index = 0; Index < CapsuleTotalNumber; Index++) {
|
|
|
|
CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];
|
|
|
|
if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {
|
|
|
|
//
|
|
|
|
// For each capsule, we compare it with known CapsuleGuid in the CacheArray.
|
2018-06-27 15:06:35 +02:00
|
|
|
// If already has the Guid, skip it. Whereas, record it in the CacheArray as
|
2009-01-23 08:24:55 +01:00
|
|
|
// an additional one.
|
|
|
|
//
|
|
|
|
CacheIndex = 0;
|
|
|
|
while (CacheIndex < CacheNumber) {
|
|
|
|
if (CompareGuid(&CapsuleGuidCache[CacheIndex],&CapsuleHeader->CapsuleGuid)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
CacheIndex++;
|
|
|
|
}
|
|
|
|
if (CacheIndex == CacheNumber) {
|
|
|
|
CopyMem(&CapsuleGuidCache[CacheNumber++],&CapsuleHeader->CapsuleGuid,sizeof(EFI_GUID));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Secondly, for each unique CapsuleGuid in CacheArray, gather all coalesced capsules
|
|
|
|
// whose guid is the same as it, and malloc memory for an array which preceding
|
|
|
|
// with UINT32. The array fills with entry point of capsules that have the same
|
|
|
|
// CapsuleGuid, and UINT32 represents the size of the array of capsules. Then install
|
|
|
|
// this array into EFI System Table, so that agents searching for this type capsule
|
|
|
|
// will look in EFI System Table and search for the capsule's Guid and associated
|
|
|
|
// pointer to retrieve the data.
|
|
|
|
//
|
|
|
|
CacheIndex = 0;
|
|
|
|
while (CacheIndex < CacheNumber) {
|
2018-06-27 15:06:35 +02:00
|
|
|
CapsuleNumber = 0;
|
2009-01-23 08:24:55 +01:00
|
|
|
for (Index = 0; Index < CapsuleTotalNumber; Index++) {
|
|
|
|
CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];
|
|
|
|
if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {
|
|
|
|
if (CompareGuid (&CapsuleGuidCache[CacheIndex], &CapsuleHeader->CapsuleGuid)) {
|
|
|
|
//
|
|
|
|
// Cache Caspuleheader to the array, this array is uniqued with certain CapsuleGuid.
|
|
|
|
//
|
|
|
|
CapsulePtrCache[CapsuleNumber++] = (VOID*)CapsuleHeader;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (CapsuleNumber != 0) {
|
2018-06-27 15:06:35 +02:00
|
|
|
Size = sizeof(EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof(VOID*);
|
2009-01-23 08:24:55 +01:00
|
|
|
CapsuleTable = AllocateRuntimePool (Size);
|
|
|
|
ASSERT (CapsuleTable != NULL);
|
|
|
|
CapsuleTable->CapsuleArrayNumber = CapsuleNumber;
|
|
|
|
CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*));
|
|
|
|
Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
}
|
|
|
|
CacheIndex++;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Besides ones with CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag, all capsules left are
|
2018-06-27 15:06:35 +02:00
|
|
|
// recognized by platform with CapsuleGuid. For general platform driver, UpdateFlash
|
2009-01-23 08:24:55 +01:00
|
|
|
// type is commonly supported, so here only deal with encapsuled FVs capsule. Additional
|
|
|
|
// type capsule transaction could be extended. It depends on platform policy.
|
|
|
|
//
|
|
|
|
for (Index = 0; Index < CapsuleTotalNumber; Index++) {
|
|
|
|
CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];
|
|
|
|
if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {
|
2013-10-15 03:31:49 +02:00
|
|
|
//
|
|
|
|
// Always reset system after all capsule processed if FMP capsule exist
|
|
|
|
//
|
|
|
|
if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)){
|
|
|
|
NeedReset = TRUE;
|
|
|
|
}
|
|
|
|
|
2009-01-23 08:24:55 +01:00
|
|
|
//
|
|
|
|
// Call capsule library to process capsule image.
|
|
|
|
//
|
|
|
|
ProcessCapsuleImage (CapsuleHeader);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-15 03:31:49 +02:00
|
|
|
if (NeedReset) {
|
|
|
|
Print(L"Capsule Request Cold Reboot.\n");
|
|
|
|
|
|
|
|
for (Index = 5; Index > 0; Index--) {
|
|
|
|
Print(L"\rResetting system in %d seconds ...", Index);
|
|
|
|
gBS->Stall (1000000);
|
|
|
|
}
|
|
|
|
|
|
|
|
gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
|
|
|
|
|
|
|
|
CpuDeadLoop ();
|
|
|
|
}
|
|
|
|
|
2009-01-23 08:24:55 +01:00
|
|
|
PlatformBdsLockNonUpdatableFlash ();
|
2018-06-27 15:06:35 +02:00
|
|
|
|
2009-01-23 08:24:55 +01:00
|
|
|
//
|
|
|
|
// Free the allocated temp memory space.
|
|
|
|
//
|
|
|
|
FreePool (CapsuleGuidCache);
|
|
|
|
FreePool (CapsulePtrCache);
|
|
|
|
FreePool (CapsulePtr);
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
2009-10-28 08:54:17 +01:00
|
|
|
|