mirror of https://github.com/acidanthera/audk.git
MdeModulePkg/DxeCapsuleLibFmp: Add DxeCapsuleLibFmp instance.
This instance handles Microsoft UX capsule, UEFI defined FMP capsule. This instance should not assume any capsule image format. Cc: Feng Tian <feng.tian@intel.com> Cc: Star Zeng <star.zeng@intel.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Liming Gao <liming.gao@intel.com> Cc: Chao Zhang <chao.b.zhang@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> Reviewed-by: Michael Kinney <michael.d.kinney@intel.com> Tested-by: Michael Kinney <michael.d.kinney@intel.com>
This commit is contained in:
parent
bf468a6ca0
commit
d2a160304e
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,80 @@
|
|||
## @file
|
||||
# Capsule library instance for DXE_DRIVER.
|
||||
#
|
||||
# Capsule library instance for DXE_DRIVER module types.
|
||||
#
|
||||
# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
|
||||
# This program and the accompanying materials
|
||||
# are licensed and made available under the terms and conditions of the BSD License
|
||||
# which accompanies this distribution. The full text of the license may be found at
|
||||
# http://opensource.org/licenses/bsd-license.php
|
||||
#
|
||||
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = DxeCapsuleLib
|
||||
MODULE_UNI_FILE = DxeCapsuleLib.uni
|
||||
FILE_GUID = 534E35DE-8EB3-47b3-A4E0-72A571E50733
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = CapsuleLib|DXE_DRIVER UEFI_APPLICATION
|
||||
CONSTRUCTOR = DxeCapsuleLibConstructor
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
|
||||
#
|
||||
|
||||
[Sources]
|
||||
DxeCapsuleLib.c
|
||||
DxeCapsuleProcessLib.c
|
||||
DxeCapsuleReportLib.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
BaseMemoryLib
|
||||
DebugLib
|
||||
MemoryAllocationLib
|
||||
DxeServicesTableLib
|
||||
UefiBootServicesTableLib
|
||||
DevicePathLib
|
||||
ReportStatusCodeLib
|
||||
PrintLib
|
||||
HobLib
|
||||
|
||||
[Pcd]
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag ## CONSUMES
|
||||
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeSubClassCapsule ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesBegin ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesEnd ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmware ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareSuccess ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareFailed ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSystem ## CONSUMES
|
||||
|
||||
[Protocols]
|
||||
gEsrtManagementProtocolGuid ## CONSUMES
|
||||
gEfiFirmwareManagementProtocolGuid ## SOMETIMES_CONSUMES
|
||||
gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
|
||||
|
||||
[Guids]
|
||||
gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
|
||||
gWindowsUxCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
|
||||
gEfiSystemResourceTableGuid ## SOMETIMES_CONSUMES ## GUID
|
||||
gEfiCapsuleReportGuid ## CONSUMES ## Variable
|
||||
gEfiCapsuleVendorGuid ## CONSUMES ## Variable
|
||||
gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
|
||||
|
||||
[Depex]
|
||||
gEfiVariableWriteArchProtocolGuid
|
|
@ -0,0 +1,22 @@
|
|||
// /** @file
|
||||
// Capsule library instance for DXE_DRIVER.
|
||||
//
|
||||
// Capsule library instance for DXE_DRIVER module types.
|
||||
//
|
||||
// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// This program and the accompanying materials
|
||||
// are licensed and made available under the terms and conditions of the BSD License
|
||||
// which accompanies this distribution. The full text of the license may be found at
|
||||
// http://opensource.org/licenses/bsd-license.php
|
||||
//
|
||||
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
//
|
||||
// **/
|
||||
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Capsule Support Library"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "Capsule library instance for DXE_DRIVER module types."
|
||||
|
|
@ -0,0 +1,475 @@
|
|||
/** @file
|
||||
DXE capsule process.
|
||||
|
||||
Caution: This module requires additional review when modified.
|
||||
This module will have external input - capsule image.
|
||||
This external input must be validated carefully to avoid security issue like
|
||||
buffer overflow, integer overflow.
|
||||
|
||||
ProcessCapsules(), ProcessTheseCapsules() will receive untrusted
|
||||
input and do basic validation.
|
||||
|
||||
Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include <PiDxe.h>
|
||||
#include <Protocol/EsrtManagement.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/PcdLib.h>
|
||||
#include <Library/HobLib.h>
|
||||
#include <Library/ReportStatusCodeLib.h>
|
||||
#include <Library/CapsuleLib.h>
|
||||
|
||||
#include <IndustryStandard/WindowsUxCapsule.h>
|
||||
|
||||
/**
|
||||
Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.
|
||||
|
||||
@param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
|
||||
|
||||
@retval TRUE It is a system FMP.
|
||||
@retval FALSE It is a device FMP.
|
||||
**/
|
||||
BOOLEAN
|
||||
IsFmpCapsule (
|
||||
IN EFI_CAPSULE_HEADER *CapsuleHeader
|
||||
);
|
||||
|
||||
/**
|
||||
Validate Fmp capsules layout.
|
||||
|
||||
Caution: This function may receive untrusted input.
|
||||
|
||||
This function assumes the caller validated the capsule by using
|
||||
IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
|
||||
The capsule buffer size is CapsuleHeader->CapsuleImageSize.
|
||||
|
||||
This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
|
||||
and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
|
||||
|
||||
This function need support nested FMP capsule.
|
||||
|
||||
@param[in] CapsuleHeader Points to a capsule header.
|
||||
@param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.
|
||||
|
||||
@retval EFI_SUCESS Input capsule is a correct FMP capsule.
|
||||
@retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.
|
||||
**/
|
||||
EFI_STATUS
|
||||
ValidateFmpCapsule (
|
||||
IN EFI_CAPSULE_HEADER *CapsuleHeader,
|
||||
OUT UINT16 *EmbeddedDriverCount OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
Validate if it is valid capsule header
|
||||
|
||||
This function assumes the caller provided correct CapsuleHeader pointer
|
||||
and CapsuleSize.
|
||||
|
||||
This function validates the fields in EFI_CAPSULE_HEADER.
|
||||
|
||||
@param[in] CapsuleHeader Points to a capsule header.
|
||||
@param[in] CapsuleSize Size of the whole capsule image.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
IsValidCapsuleHeader (
|
||||
IN EFI_CAPSULE_HEADER *CapsuleHeader,
|
||||
IN UINT64 CapsuleSize
|
||||
);
|
||||
|
||||
extern BOOLEAN mDxeCapsuleLibEndOfDxe;
|
||||
extern BOOLEAN mAreAllImagesProcessed;
|
||||
BOOLEAN mNeedReset;
|
||||
|
||||
/**
|
||||
|
||||
This routine is called to process capsules.
|
||||
|
||||
Caution: This function may receive untrusted input.
|
||||
|
||||
Each individual capsule result is recorded in capsule record variable.
|
||||
|
||||
@param[in] NeedBlockDriver TRUE: Need skip the FMP capsules with non zero EmbeddedDriverCount.
|
||||
FALSE: No need to skip any FMP capsules.
|
||||
|
||||
@retval EFI_SUCCESS There is no error when processing capsules.
|
||||
@retval EFI_OUT_OF_RESOURCES No enough resource to process capsules.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
ProcessTheseCapsules (
|
||||
IN BOOLEAN NeedBlockDriver
|
||||
)
|
||||
{
|
||||
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;
|
||||
EFI_GUID *CapsuleGuidCache;
|
||||
EFI_STATUS *CapsuleStatusArray;
|
||||
BOOLEAN DisplayCapsuleExist;
|
||||
ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;
|
||||
UINT16 EmbeddedDriverCount;
|
||||
|
||||
REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesBegin)));
|
||||
|
||||
CapsuleNumber = 0;
|
||||
CapsuleTotalNumber = 0;
|
||||
CacheIndex = 0;
|
||||
CacheNumber = 0;
|
||||
CapsulePtr = NULL;
|
||||
CapsulePtrCache = NULL;
|
||||
CapsuleGuidCache = NULL;
|
||||
DisplayCapsuleExist = FALSE;
|
||||
EsrtManagement = NULL;
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
//
|
||||
// Find all capsule images from hob
|
||||
//
|
||||
HobPointer.Raw = GetHobList ();
|
||||
while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {
|
||||
if (!IsValidCapsuleHeader((VOID *)(UINTN)HobPointer.Capsule->BaseAddress, HobPointer.Capsule->Length)) {
|
||||
HobPointer.Header->HobType = EFI_HOB_TYPE_UNUSED; // Mark this hob as invalid
|
||||
} else {
|
||||
CapsuleTotalNumber++;
|
||||
}
|
||||
HobPointer.Raw = GET_NEXT_HOB (HobPointer);
|
||||
}
|
||||
|
||||
if (CapsuleTotalNumber == 0) {
|
||||
//
|
||||
// We didn't find a hob, so had no errors.
|
||||
//
|
||||
DEBUG ((DEBUG_ERROR, "We can not find capsule data in capsule update boot mode.\n"));
|
||||
Status = EFI_SUCCESS;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
//
|
||||
// Init temp Capsule Data table.
|
||||
//
|
||||
CapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);
|
||||
ASSERT (CapsulePtr != NULL);
|
||||
if (CapsulePtr == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto Done;
|
||||
}
|
||||
CapsulePtrCache = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);
|
||||
ASSERT (CapsulePtrCache != NULL);
|
||||
if (CapsulePtrCache == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto Done;
|
||||
}
|
||||
CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * CapsuleTotalNumber);
|
||||
ASSERT (CapsuleGuidCache != NULL);
|
||||
if (CapsuleGuidCache == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto Done;
|
||||
}
|
||||
CapsuleStatusArray = (EFI_STATUS *) AllocateZeroPool (sizeof (EFI_STATUS) * CapsuleTotalNumber);
|
||||
ASSERT (CapsuleStatusArray != NULL);
|
||||
if (CapsuleStatusArray == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
//
|
||||
// Find all capsule images from hob
|
||||
//
|
||||
HobPointer.Raw = GetHobList ();
|
||||
while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {
|
||||
CapsulePtr [CapsuleNumber++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress;
|
||||
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
|
||||
// System to have information persist across a system reset. EFI System Table must
|
||||
// point to an array of capsules that contains the same CapsuleGuid value. And 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. Two steps below describes
|
||||
// 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
|
||||
// array for later sorting capsules by CapsuleGuid.
|
||||
//
|
||||
for (Index = 0; Index < CapsuleTotalNumber; Index++) {
|
||||
CapsuleStatusArray [Index] = EFI_UNSUPPORTED;
|
||||
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.
|
||||
// If already has the Guid, skip it. Whereas, record it in the CacheArray as
|
||||
// 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) {
|
||||
CapsuleNumber = 0;
|
||||
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;
|
||||
//
|
||||
// When a Capsule is listed in CapsulePtrCache, it will be reported in ConfigurationTable
|
||||
// So, report the CapsuleStatus as "processed successfully".
|
||||
//
|
||||
CapsuleStatusArray [Index] = EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CapsuleNumber != 0) {
|
||||
Size = sizeof(EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof(VOID*);
|
||||
CapsuleTable = AllocateRuntimePool (Size);
|
||||
ASSERT (CapsuleTable != NULL);
|
||||
if (CapsuleTable == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
CapsuleTable->CapsuleArrayNumber = CapsuleNumber;
|
||||
CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*));
|
||||
Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
}
|
||||
CacheIndex++;
|
||||
}
|
||||
|
||||
REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdatingFirmware)));
|
||||
|
||||
//
|
||||
// If Windows UX capsule exist, process it first
|
||||
//
|
||||
for (Index = 0; Index < CapsuleTotalNumber; Index++) {
|
||||
CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];
|
||||
if (CompareGuid(&CapsuleHeader->CapsuleGuid ,&gWindowsUxCapsuleGuid)) {
|
||||
DEBUG ((DEBUG_INFO, "ProcessCapsuleImage (Ux) - 0x%x\n", CapsuleHeader));
|
||||
DisplayCapsuleExist = TRUE;
|
||||
DEBUG ((DEBUG_INFO, "Display logo capsule is found.\n"));
|
||||
Status = ProcessCapsuleImage (CapsuleHeader);
|
||||
DEBUG((DEBUG_INFO, "ProcessCapsuleImage (Ux) - %r\n", Status));
|
||||
CapsuleStatusArray [Index] = Status;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!DisplayCapsuleExist) {
|
||||
//
|
||||
// Display Capsule not found. Display the default string.
|
||||
//
|
||||
Print (L"Updating the firmware ......\r\n");
|
||||
}
|
||||
|
||||
//
|
||||
// All capsules left are recognized by platform.
|
||||
//
|
||||
for (Index = 0; Index < CapsuleTotalNumber; Index++) {
|
||||
CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];
|
||||
if (!CompareGuid(&CapsuleHeader->CapsuleGuid ,&gWindowsUxCapsuleGuid)) {
|
||||
//
|
||||
// Call capsule library to process capsule image.
|
||||
//
|
||||
EmbeddedDriverCount = 0;
|
||||
if (IsFmpCapsule(CapsuleHeader)) {
|
||||
Status = ValidateFmpCapsule(CapsuleHeader, &EmbeddedDriverCount);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((DEBUG_ERROR, "ValidateFmpCapsule failed. Ignore!\n"));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!NeedBlockDriver) || (EmbeddedDriverCount == 0)) {
|
||||
DEBUG((DEBUG_INFO, "ProcessCapsuleImage - 0x%x\n", CapsuleHeader));
|
||||
Status = ProcessCapsuleImage (CapsuleHeader);
|
||||
CapsuleStatusArray [Index] = Status;
|
||||
DEBUG((DEBUG_INFO, "ProcessCapsuleImage - %r\n", Status));
|
||||
|
||||
if (EFI_ERROR(Status)) {
|
||||
REPORT_STATUS_CODE(EFI_ERROR_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareFailed)));
|
||||
DEBUG ((DEBUG_ERROR, "Capsule process failed. reset the system!\n"));
|
||||
Print (L"Firmware update failed...\r\n");
|
||||
} else {
|
||||
REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareSuccess)));
|
||||
}
|
||||
|
||||
if ((CapsuleHeader->Flags & PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0 ||
|
||||
IsFmpCapsule(CapsuleHeader)) {
|
||||
mNeedReset = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement);
|
||||
//
|
||||
// Always sync ESRT Cache from FMP Instance
|
||||
//
|
||||
if (!EFI_ERROR(Status)) {
|
||||
EsrtManagement->SyncEsrtFmp();
|
||||
}
|
||||
Status = EFI_SUCCESS;
|
||||
|
||||
Done:
|
||||
//
|
||||
// Free the allocated temp memory space.
|
||||
//
|
||||
if (CapsuleGuidCache != NULL) {
|
||||
FreePool(CapsuleGuidCache);
|
||||
}
|
||||
if (CapsulePtrCache != NULL) {
|
||||
FreePool(CapsulePtrCache);
|
||||
}
|
||||
if (CapsulePtr != NULL) {
|
||||
FreePool(CapsulePtr);
|
||||
}
|
||||
|
||||
REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesEnd)));
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Do reset system.
|
||||
**/
|
||||
VOID
|
||||
DoResetSystem (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeResettingSystem)));
|
||||
|
||||
Print(L"Capsule Request Cold Reboot.\n");
|
||||
DEBUG((DEBUG_INFO, "Capsule Request Cold Reboot."));
|
||||
|
||||
for (Index = 5; Index > 0; Index--) {
|
||||
Print(L"\rResetting system in %d seconds ...", Index);
|
||||
DEBUG((DEBUG_INFO, "\rResetting system in %d seconds ...", Index));
|
||||
gBS->Stall(1000000);
|
||||
}
|
||||
|
||||
gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
|
||||
|
||||
CpuDeadLoop();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
This routine is called to process capsules.
|
||||
|
||||
Caution: This function may receive untrusted input.
|
||||
|
||||
The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.
|
||||
If there is no EFI_HOB_UEFI_CAPSULE, this routine does nothing.
|
||||
|
||||
This routine should be called twice in BDS.
|
||||
1) The first call must be before EndOfDxe. The system capsules is processed.
|
||||
If device capsule FMP protocols are exposted at this time and device FMP
|
||||
capsule has zero EmbeddedDriverCount, the device capsules are processed.
|
||||
Each individual capsule result is recorded in capsule record variable.
|
||||
System may reset in this function, if reset is required by capsule and
|
||||
all capsules are processed.
|
||||
If not all capsules are processed, reset will be defered to second call.
|
||||
|
||||
2) The second call must be after EndOfDxe and after ConnectAll, so that all
|
||||
device capsule FMP protocols are exposed.
|
||||
The system capsules are skipped. If the device capsules are NOT processed
|
||||
in first call, they are processed here.
|
||||
Each individual capsule result is recorded in capsule record variable.
|
||||
System may reset in this function, if reset is required by capsule
|
||||
processed in first call and second call.
|
||||
|
||||
@retval EFI_SUCCESS There is no error when processing capsules.
|
||||
@retval EFI_OUT_OF_RESOURCES No enough resource to process capsules.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
ProcessCapsules (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
if (!mDxeCapsuleLibEndOfDxe) {
|
||||
//
|
||||
// Initialize mAreAllImagesProcessed to be TRUE.
|
||||
//
|
||||
// It will be updated to FALSE in ProcessTheseCapsules()->ProcessCapsuleImage(),
|
||||
// if there is any FMP image in any FMP capsule not processed.
|
||||
//
|
||||
mAreAllImagesProcessed = TRUE;
|
||||
|
||||
Status = ProcessTheseCapsules(TRUE);
|
||||
//
|
||||
// Reboot System if and only if all capsule processed.
|
||||
// If not, defer reset to 2nd process.
|
||||
//
|
||||
if (mNeedReset && mAreAllImagesProcessed) {
|
||||
DoResetSystem();
|
||||
}
|
||||
} else {
|
||||
Status = ProcessTheseCapsules(FALSE);
|
||||
//
|
||||
// Reboot System if required after all capsule processed
|
||||
//
|
||||
if (mNeedReset) {
|
||||
DoResetSystem();
|
||||
}
|
||||
}
|
||||
return Status;
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/** @file
|
||||
DXE capsule process.
|
||||
Dummy function for runtime module, because CapsuleDxeRuntime
|
||||
does not need call ProcessCapsules().
|
||||
|
||||
Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include <PiDxe.h>
|
||||
#include <Library/CapsuleLib.h>
|
||||
|
||||
/**
|
||||
|
||||
This routine is called to process capsules.
|
||||
|
||||
Caution: This function may receive untrusted input.
|
||||
|
||||
The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.
|
||||
If there is no EFI_HOB_UEFI_CAPSULE, this routine does nothing.
|
||||
|
||||
This routine should be called twice in BDS.
|
||||
1) The first call must be before EndOfDxe. The system capsules is processed.
|
||||
If device capsule FMP protocols are exposted at this time and device FMP
|
||||
capsule has zero EmbeddedDriverCount, the device capsules are processed.
|
||||
Each individual capsule result is recorded in capsule record variable.
|
||||
System may reset in this function, if reset is required by capsule and
|
||||
all capsules are processed.
|
||||
If not all capsules are processed, reset will be defered to second call.
|
||||
|
||||
2) The second call must be after EndOfDxe and after ConnectAll, so that all
|
||||
device capsule FMP protocols are exposed.
|
||||
The system capsules are skipped. If the device capsules are NOT processed
|
||||
in first call, they are processed here.
|
||||
Each individual capsule result is recorded in capsule record variable.
|
||||
System may reset in this function, if reset is required by capsule
|
||||
processed in first call and second call.
|
||||
|
||||
@retval EFI_SUCCESS There is no error when processing capsules.
|
||||
@retval EFI_OUT_OF_RESOURCES No enough resource to process capsules.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
ProcessCapsules (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
|
@ -0,0 +1,489 @@
|
|||
/** @file
|
||||
DXE capsule report related function.
|
||||
|
||||
Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include <PiDxe.h>
|
||||
#include <Protocol/FirmwareManagement.h>
|
||||
#include <Protocol/VariableLock.h>
|
||||
#include <Guid/CapsuleReport.h>
|
||||
#include <Guid/FmpCapsule.h>
|
||||
#include <Guid/CapsuleVendor.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/PcdLib.h>
|
||||
#include <Library/HobLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/ReportStatusCodeLib.h>
|
||||
#include <Library/CapsuleLib.h>
|
||||
|
||||
#include <IndustryStandard/WindowsUxCapsule.h>
|
||||
|
||||
typedef struct {
|
||||
EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultHeader;
|
||||
EFI_CAPSULE_RESULT_VARIABLE_FMP CapsuleResultFmp;
|
||||
} CAPSULE_RESULT_VARIABLE_CACHE;
|
||||
|
||||
#define CAPSULE_RESULT_VARIABLE_CACHE_COUNT 0x10
|
||||
|
||||
CAPSULE_RESULT_VARIABLE_CACHE *mCapsuleResultVariableCache;
|
||||
UINTN mCapsuleResultVariableCacheMaxCount;
|
||||
UINTN mCapsuleResultVariableCacheCount;
|
||||
|
||||
/**
|
||||
Get current capsule last variable index.
|
||||
|
||||
@return Current capsule last variable index.
|
||||
@retval -1 No current capsule last variable.
|
||||
**/
|
||||
INTN
|
||||
GetCurrentCapsuleLastIndex (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINTN Size;
|
||||
CHAR16 CapsuleLastStr[sizeof("Capsule####")];
|
||||
EFI_STATUS Status;
|
||||
UINT16 CurrentIndex;
|
||||
|
||||
Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator
|
||||
Status = gRT->GetVariable(
|
||||
L"CapsuleLast",
|
||||
&gEfiCapsuleReportGuid,
|
||||
NULL,
|
||||
&Size,
|
||||
CapsuleLastStr
|
||||
);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return -1;
|
||||
}
|
||||
CurrentIndex = (UINT16)StrHexToUintn(&CapsuleLastStr[sizeof("Capsule") - 1]);
|
||||
return CurrentIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
Check if this FMP capsule is processed.
|
||||
|
||||
@param[in] CapsuleHeader The capsule image header
|
||||
@param[in] PayloadIndex FMP payload index
|
||||
@param[in] ImageHeader FMP image header
|
||||
|
||||
@retval TRUE This FMP capsule is processed.
|
||||
@retval FALSE This FMP capsule is not processed.
|
||||
**/
|
||||
BOOLEAN
|
||||
IsFmpCapsuleProcessed (
|
||||
IN EFI_CAPSULE_HEADER *CapsuleHeader,
|
||||
IN UINTN PayloadIndex,
|
||||
IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResult;
|
||||
EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultFmp;
|
||||
|
||||
for (Index = 0; Index < mCapsuleResultVariableCacheCount; Index++) {
|
||||
//
|
||||
// Check
|
||||
//
|
||||
CapsuleResult = &mCapsuleResultVariableCache[Index].CapsuleResultHeader;
|
||||
if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)) {
|
||||
if (CompareGuid(&CapsuleResult->CapsuleGuid, &gEfiFmpCapsuleGuid)) {
|
||||
if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP)) {
|
||||
CapsuleResultFmp = (EFI_CAPSULE_RESULT_VARIABLE_FMP *)(CapsuleResult + 1);
|
||||
if (CompareGuid(&CapsuleResultFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId) &&
|
||||
(CapsuleResultFmp->UpdateImageIndex == ImageHeader->UpdateImageIndex) &&
|
||||
(CapsuleResultFmp->PayloadIndex == PayloadIndex) ) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
Write a new capsule status variable cache.
|
||||
|
||||
@param[in] CapsuleResult The capsule status variable
|
||||
@param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
|
||||
|
||||
@retval EFI_SUCCESS The capsule status variable is cached.
|
||||
@retval EFI_OUT_OF_RESOURCES No resource to cache the capsule status variable.
|
||||
**/
|
||||
EFI_STATUS
|
||||
WriteNewCapsuleResultVariableCache (
|
||||
IN VOID *CapsuleResult,
|
||||
IN UINTN CapsuleResultSize
|
||||
)
|
||||
{
|
||||
if (CapsuleResultSize > sizeof(CAPSULE_RESULT_VARIABLE_CACHE)) {
|
||||
CapsuleResultSize = sizeof(CAPSULE_RESULT_VARIABLE_CACHE);
|
||||
}
|
||||
|
||||
if (mCapsuleResultVariableCacheCount == mCapsuleResultVariableCacheMaxCount) {
|
||||
mCapsuleResultVariableCache = ReallocatePool(
|
||||
mCapsuleResultVariableCacheMaxCount * sizeof(CAPSULE_RESULT_VARIABLE_CACHE),
|
||||
(mCapsuleResultVariableCacheMaxCount + CAPSULE_RESULT_VARIABLE_CACHE_COUNT) * sizeof(CAPSULE_RESULT_VARIABLE_CACHE),
|
||||
mCapsuleResultVariableCache
|
||||
);
|
||||
if (mCapsuleResultVariableCache == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
mCapsuleResultVariableCacheMaxCount += CAPSULE_RESULT_VARIABLE_CACHE_COUNT;
|
||||
}
|
||||
|
||||
ASSERT(mCapsuleResultVariableCacheCount < mCapsuleResultVariableCacheMaxCount);
|
||||
ASSERT(mCapsuleResultVariableCache != NULL);
|
||||
CopyMem(
|
||||
&mCapsuleResultVariableCache[mCapsuleResultVariableCacheCount],
|
||||
CapsuleResult,
|
||||
CapsuleResultSize
|
||||
);
|
||||
mCapsuleResultVariableCacheCount++;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Get a new capsule status variable index.
|
||||
|
||||
@return A new capsule status variable index.
|
||||
@retval -1 No new capsule status variable index.
|
||||
**/
|
||||
INTN
|
||||
GetNewCapsuleResultIndex (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
INTN CurrentIndex;
|
||||
|
||||
CurrentIndex = GetCurrentCapsuleLastIndex();
|
||||
if (CurrentIndex >= PcdGet16(PcdCapsuleMax)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return CurrentIndex + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
Write a new capsule status variable.
|
||||
|
||||
@param[in] CapsuleResult The capsule status variable
|
||||
@param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
|
||||
|
||||
@retval EFI_SUCCESS The capsule status variable is recorded.
|
||||
@retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
|
||||
**/
|
||||
EFI_STATUS
|
||||
WriteNewCapsuleResultVariable (
|
||||
IN VOID *CapsuleResult,
|
||||
IN UINTN CapsuleResultSize
|
||||
)
|
||||
{
|
||||
INTN CapsuleResultIndex;
|
||||
CHAR16 CapsuleResultStr[sizeof("Capsule####")];
|
||||
UINTN Size;
|
||||
EFI_STATUS Status;
|
||||
|
||||
CapsuleResultIndex = GetNewCapsuleResultIndex();
|
||||
DEBUG((DEBUG_INFO, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex));
|
||||
if (CapsuleResultIndex == -1) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
UnicodeSPrint(
|
||||
CapsuleResultStr,
|
||||
sizeof(CapsuleResultStr),
|
||||
L"Capsule%04x",
|
||||
CapsuleResultIndex
|
||||
);
|
||||
|
||||
Status = gRT->SetVariable(
|
||||
CapsuleResultStr,
|
||||
&gEfiCapsuleReportGuid,
|
||||
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
CapsuleResultSize,
|
||||
CapsuleResult
|
||||
);
|
||||
if (!EFI_ERROR(Status)) {
|
||||
Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator
|
||||
DEBUG((DEBUG_INFO, "Set CapsuleLast - %s\n", CapsuleResultStr));
|
||||
Status = gRT->SetVariable(
|
||||
L"CapsuleLast",
|
||||
&gEfiCapsuleReportGuid,
|
||||
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
Size,
|
||||
CapsuleResultStr
|
||||
);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Record capsule status variable and to local cache.
|
||||
|
||||
@param[in] CapsuleHeader The capsule image header
|
||||
@param[in] CapsuleStatus The capsule process stauts
|
||||
|
||||
@retval EFI_SUCCESS The capsule status variable is recorded.
|
||||
@retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
|
||||
**/
|
||||
EFI_STATUS
|
||||
RecordCapsuleStatusVariable (
|
||||
IN EFI_CAPSULE_HEADER *CapsuleHeader,
|
||||
IN EFI_STATUS CapsuleStatus
|
||||
)
|
||||
{
|
||||
EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable;
|
||||
EFI_STATUS Status;
|
||||
|
||||
CapsuleResultVariable.VariableTotalSize = sizeof(CapsuleResultVariable);
|
||||
CopyGuid (&CapsuleResultVariable.CapsuleGuid, &CapsuleHeader->CapsuleGuid);
|
||||
ZeroMem(&CapsuleResultVariable.CapsuleProcessed, sizeof(CapsuleResultVariable.CapsuleProcessed));
|
||||
gRT->GetTime(&CapsuleResultVariable.CapsuleProcessed, NULL);
|
||||
CapsuleResultVariable.CapsuleStatus = CapsuleStatus;
|
||||
|
||||
//
|
||||
// Save Local Cache
|
||||
//
|
||||
Status = WriteNewCapsuleResultVariableCache(&CapsuleResultVariable, sizeof(CapsuleResultVariable));
|
||||
|
||||
if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
|
||||
Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable));
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Record FMP capsule status variable and to local cache.
|
||||
|
||||
@param[in] CapsuleHeader The capsule image header
|
||||
@param[in] CapsuleStatus The capsule process stauts
|
||||
@param[in] PayloadIndex FMP payload index
|
||||
@param[in] ImageHeader FMP image header
|
||||
|
||||
@retval EFI_SUCCESS The capsule status variable is recorded.
|
||||
@retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
|
||||
**/
|
||||
EFI_STATUS
|
||||
RecordFmpCapsuleStatusVariable (
|
||||
IN EFI_CAPSULE_HEADER *CapsuleHeader,
|
||||
IN EFI_STATUS CapsuleStatus,
|
||||
IN UINTN PayloadIndex,
|
||||
IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader
|
||||
)
|
||||
{
|
||||
UINT8 CapsuleResultVariable[sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP)];
|
||||
EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResultVariableHeader;
|
||||
EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultVariableFmp;
|
||||
EFI_STATUS Status;
|
||||
|
||||
CapsuleResultVariableHeader = (VOID *)&CapsuleResultVariable[0];
|
||||
CapsuleResultVariableHeader->VariableTotalSize = sizeof(CapsuleResultVariable);
|
||||
CopyGuid(&CapsuleResultVariableHeader->CapsuleGuid, &CapsuleHeader->CapsuleGuid);
|
||||
ZeroMem(&CapsuleResultVariableHeader->CapsuleProcessed, sizeof(CapsuleResultVariableHeader->CapsuleProcessed));
|
||||
gRT->GetTime(&CapsuleResultVariableHeader->CapsuleProcessed, NULL);
|
||||
CapsuleResultVariableHeader->CapsuleStatus = CapsuleStatus;
|
||||
|
||||
CapsuleResultVariableFmp = (VOID *)&CapsuleResultVariable[sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)];
|
||||
CapsuleResultVariableFmp->Version = 0x1;
|
||||
CapsuleResultVariableFmp->PayloadIndex = (UINT8)PayloadIndex;
|
||||
CapsuleResultVariableFmp->UpdateImageIndex = ImageHeader->UpdateImageIndex;
|
||||
CopyGuid (&CapsuleResultVariableFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId);
|
||||
|
||||
//
|
||||
// Save Local Cache
|
||||
//
|
||||
Status = WriteNewCapsuleResultVariableCache(&CapsuleResultVariable, sizeof(CapsuleResultVariable));
|
||||
|
||||
if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
|
||||
Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable));
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize CapsuleMax variables.
|
||||
**/
|
||||
VOID
|
||||
InitCapsuleMaxVariable (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN Size;
|
||||
CHAR16 CapsuleMaxStr[sizeof("Capsule####")];
|
||||
EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
|
||||
|
||||
UnicodeSPrint(
|
||||
CapsuleMaxStr,
|
||||
sizeof(CapsuleMaxStr),
|
||||
L"Capsule%04x",
|
||||
PcdGet16(PcdCapsuleMax)
|
||||
);
|
||||
|
||||
Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator
|
||||
Status = gRT->SetVariable(
|
||||
L"CapsuleMax",
|
||||
&gEfiCapsuleReportGuid,
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
Size,
|
||||
CapsuleMaxStr
|
||||
);
|
||||
if (!EFI_ERROR(Status)) {
|
||||
// Lock it per UEFI spec.
|
||||
Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);
|
||||
if (!EFI_ERROR(Status)) {
|
||||
Status = VariableLock->RequestToLock(VariableLock, L"CapsuleMax", &gEfiCapsuleReportGuid);
|
||||
ASSERT_EFI_ERROR(Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize CapsuleLast variables.
|
||||
**/
|
||||
VOID
|
||||
InitCapsuleLastVariable (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_BOOT_MODE BootMode;
|
||||
EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
|
||||
VOID *CapsuleResult;
|
||||
UINTN Size;
|
||||
CHAR16 CapsuleLastStr[sizeof("Capsule####")];
|
||||
|
||||
BootMode = GetBootModeHob();
|
||||
if (BootMode == BOOT_ON_FLASH_UPDATE) {
|
||||
Status = gRT->SetVariable(
|
||||
L"CapsuleLast",
|
||||
&gEfiCapsuleReportGuid,
|
||||
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
// Do not lock it because it will be updated later.
|
||||
} else {
|
||||
//
|
||||
// Check if OS/APP cleared L"Capsule####"
|
||||
//
|
||||
ZeroMem(CapsuleLastStr, sizeof(CapsuleLastStr));
|
||||
Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator
|
||||
Status = gRT->GetVariable(
|
||||
L"CapsuleLast",
|
||||
&gEfiCapsuleReportGuid,
|
||||
NULL,
|
||||
&Size,
|
||||
CapsuleLastStr
|
||||
);
|
||||
if (!EFI_ERROR(Status)) {
|
||||
//
|
||||
// L"CapsuleLast" is got, check if data is there.
|
||||
//
|
||||
Status = GetVariable2 (
|
||||
CapsuleLastStr,
|
||||
&gEfiCapsuleReportGuid,
|
||||
(VOID **) &CapsuleResult,
|
||||
NULL
|
||||
);
|
||||
if (EFI_ERROR(Status)) {
|
||||
//
|
||||
// If no data, delete L"CapsuleLast"
|
||||
//
|
||||
Status = gRT->SetVariable(
|
||||
L"CapsuleLast",
|
||||
&gEfiCapsuleReportGuid,
|
||||
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Lock it in normal boot path per UEFI spec.
|
||||
Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);
|
||||
if (!EFI_ERROR(Status)) {
|
||||
Status = VariableLock->RequestToLock(VariableLock, L"CapsuleLast", &gEfiCapsuleReportGuid);
|
||||
ASSERT_EFI_ERROR(Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize capsule update variables.
|
||||
**/
|
||||
VOID
|
||||
InitCapsuleUpdateVariable (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN Index;
|
||||
CHAR16 CapsuleVarName[30];
|
||||
CHAR16 *TempVarName;
|
||||
|
||||
//
|
||||
// Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
|
||||
// as early as possible which will avoid the next time boot after the capsule update
|
||||
// will still into the capsule loop
|
||||
//
|
||||
StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), EFI_CAPSULE_VARIABLE_NAME);
|
||||
TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
|
||||
Index = 0;
|
||||
while (TRUE) {
|
||||
if (Index > 0) {
|
||||
UnicodeValueToString (TempVarName, 0, Index, 0);
|
||||
}
|
||||
Status = gRT->SetVariable (
|
||||
CapsuleVarName,
|
||||
&gEfiCapsuleVendorGuid,
|
||||
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
||||
0,
|
||||
(VOID *)NULL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// There is no capsule variables, quit
|
||||
//
|
||||
break;
|
||||
}
|
||||
Index++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize capsule related variables.
|
||||
**/
|
||||
VOID
|
||||
InitCapsuleVariable (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
InitCapsuleUpdateVariable();
|
||||
InitCapsuleMaxVariable();
|
||||
InitCapsuleLastVariable();
|
||||
//
|
||||
// No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
|
||||
// to check status and delete them.
|
||||
//
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/** @file
|
||||
DXE capsule report related function.
|
||||
Dummy function for runtime module, because CapsuleDxeRuntime
|
||||
does not need record capsule status variable.
|
||||
|
||||
Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include <PiDxe.h>
|
||||
#include <Protocol/FirmwareManagement.h>
|
||||
#include <Guid/FmpCapsule.h>
|
||||
#include <Library/CapsuleLib.h>
|
||||
|
||||
/**
|
||||
Check if this FMP capsule is processed.
|
||||
|
||||
@param[in] CapsuleHeader The capsule image header
|
||||
@param[in] PayloadIndex FMP payload index
|
||||
@param[in] ImageHeader FMP image header
|
||||
|
||||
@retval TRUE This FMP capsule is processed.
|
||||
@retval FALSE This FMP capsule is not processed.
|
||||
**/
|
||||
BOOLEAN
|
||||
IsFmpCapsuleProcessed (
|
||||
IN EFI_CAPSULE_HEADER *CapsuleHeader,
|
||||
IN UINTN PayloadIndex,
|
||||
IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader
|
||||
)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
Record capsule status variable and to local cache.
|
||||
|
||||
@param[in] CapsuleHeader The capsule image header
|
||||
@param[in] CapsuleStatus The capsule process stauts
|
||||
|
||||
@retval EFI_SUCCESS The capsule status variable is recorded.
|
||||
@retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
|
||||
**/
|
||||
EFI_STATUS
|
||||
RecordCapsuleStatusVariable (
|
||||
IN EFI_CAPSULE_HEADER *CapsuleHeader,
|
||||
IN EFI_STATUS CapsuleStatus
|
||||
)
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
Record FMP capsule status variable and to local cache.
|
||||
|
||||
@param[in] CapsuleHeader The capsule image header
|
||||
@param[in] CapsuleStatus The capsule process stauts
|
||||
@param[in] PayloadIndex FMP payload index
|
||||
@param[in] ImageHeader FMP image header
|
||||
|
||||
@retval EFI_SUCCESS The capsule status variable is recorded.
|
||||
@retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
|
||||
**/
|
||||
EFI_STATUS
|
||||
RecordFmpCapsuleStatusVariable (
|
||||
IN EFI_CAPSULE_HEADER *CapsuleHeader,
|
||||
IN EFI_STATUS CapsuleStatus,
|
||||
IN UINTN PayloadIndex,
|
||||
IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader
|
||||
)
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize capsule related variables.
|
||||
**/
|
||||
VOID
|
||||
InitCapsuleVariable (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/** @file
|
||||
Capsule library runtime support.
|
||||
|
||||
Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include <PiDxe.h>
|
||||
|
||||
#include <Guid/FmpCapsule.h>
|
||||
#include <Guid/SystemResourceTable.h>
|
||||
#include <Guid/EventGroup.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DxeServicesTableLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
|
||||
extern EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable;
|
||||
extern BOOLEAN mIsVirtualAddrConverted;
|
||||
|
||||
/**
|
||||
Convert EsrtTable physical address to virtual address.
|
||||
|
||||
@param[in] Event Event whose notification function is being invoked.
|
||||
@param[in] Context The pointer to the notification function's context, which
|
||||
is implementation-dependent.
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
DxeCapsuleLibVirtualAddressChangeEvent (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
EFI_CONFIGURATION_TABLE *ConfigEntry;
|
||||
|
||||
//
|
||||
// Get Esrt table first
|
||||
//
|
||||
ConfigEntry = gST->ConfigurationTable;
|
||||
for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
|
||||
if (CompareGuid(&gEfiSystemResourceTableGuid, &ConfigEntry->VendorGuid)) {
|
||||
break;
|
||||
}
|
||||
ConfigEntry++;
|
||||
}
|
||||
|
||||
//
|
||||
// If no Esrt table installed in Configure Table
|
||||
//
|
||||
if (Index < gST->NumberOfTableEntries) {
|
||||
//
|
||||
// Search Esrt to check given capsule is qualified
|
||||
//
|
||||
mEsrtTable = (EFI_SYSTEM_RESOURCE_TABLE *) ConfigEntry->VendorTable;
|
||||
|
||||
//
|
||||
// Update protocol pointer to Esrt Table.
|
||||
//
|
||||
gRT->ConvertPointer (0x00, (VOID**) &(mEsrtTable));
|
||||
}
|
||||
|
||||
mIsVirtualAddrConverted = TRUE;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
The constructor function hook VirtualAddressChange event to use ESRT table as capsule routing table.
|
||||
|
||||
@param ImageHandle The firmware allocated handle for the EFI image.
|
||||
@param SystemTable A pointer to the EFI System Table.
|
||||
|
||||
@retval EFI_SUCCESS The constructor successfully .
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
DxeRuntimeCapsuleLibConstructor (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_EVENT Event;
|
||||
|
||||
//
|
||||
// Make sure we can handle virtual address changes.
|
||||
//
|
||||
Event = NULL;
|
||||
Status = gBS->CreateEventEx (
|
||||
EVT_NOTIFY_SIGNAL,
|
||||
TPL_NOTIFY,
|
||||
DxeCapsuleLibVirtualAddressChangeEvent,
|
||||
NULL,
|
||||
&gEfiEventVirtualAddressChangeGuid,
|
||||
&Event
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
## @file
|
||||
# Capsule library instance for DXE_RUNTIME_DRIVER.
|
||||
#
|
||||
# Capsule library instance for DXE_RUNTIME_DRIVER module types.
|
||||
#
|
||||
# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
|
||||
# This program and the accompanying materials
|
||||
# are licensed and made available under the terms and conditions of the BSD License
|
||||
# which accompanies this distribution. The full text of the license may be found at
|
||||
# http://opensource.org/licenses/bsd-license.php
|
||||
#
|
||||
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = DxeRuntimeCapsuleLib
|
||||
MODULE_UNI_FILE = DxeRuntimeCapsuleLib.uni
|
||||
FILE_GUID = 19BE1E4B-1A9A-44c1-8F12-32DD0470516A
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = CapsuleLib|DXE_RUNTIME_DRIVER
|
||||
CONSTRUCTOR = DxeCapsuleLibConstructor
|
||||
CONSTRUCTOR = DxeRuntimeCapsuleLibConstructor
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
|
||||
#
|
||||
|
||||
[Sources]
|
||||
DxeCapsuleLib.c
|
||||
DxeCapsuleProcessLibNull.c
|
||||
DxeCapsuleReportLibNull.c
|
||||
DxeCapsuleRuntime.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
BaseMemoryLib
|
||||
DebugLib
|
||||
MemoryAllocationLib
|
||||
DxeServicesTableLib
|
||||
UefiBootServicesTableLib
|
||||
DevicePathLib
|
||||
ReportStatusCodeLib
|
||||
PrintLib
|
||||
HobLib
|
||||
|
||||
[Pcd]
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag ## CONSUMES
|
||||
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeSubClassCapsule ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesBegin ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesEnd ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmware ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareSuccess ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareFailed ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSystem ## CONSUMES
|
||||
|
||||
[Protocols]
|
||||
gEsrtManagementProtocolGuid ## CONSUMES
|
||||
gEfiFirmwareManagementProtocolGuid ## SOMETIMES_CONSUMES
|
||||
gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
|
||||
|
||||
[Guids]
|
||||
gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
|
||||
gWindowsUxCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
|
||||
gEfiSystemResourceTableGuid ## SOMETIMES_CONSUMES ## GUID
|
||||
gEfiCapsuleReportGuid ## CONSUMES ## Variable
|
||||
gEfiCapsuleVendorGuid ## CONSUMES ## Variable
|
||||
gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
|
||||
gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
|
||||
|
||||
[Depex]
|
||||
gEfiVariableWriteArchProtocolGuid
|
|
@ -0,0 +1,22 @@
|
|||
// /** @file
|
||||
// Capsule library instance for DXE_RUNTIME_DRIVER.
|
||||
//
|
||||
// Capsule library instance for DXE_RUNTIME_DRIVER module types.
|
||||
//
|
||||
// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// This program and the accompanying materials
|
||||
// are licensed and made available under the terms and conditions of the BSD License
|
||||
// which accompanies this distribution. The full text of the license may be found at
|
||||
// http://opensource.org/licenses/bsd-license.php
|
||||
//
|
||||
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
//
|
||||
// **/
|
||||
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Capsule Support Library"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "Capsule library instance for DXE_RUNTIME_DRIVER module types."
|
||||
|
Loading…
Reference in New Issue