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