Enable BIOS region update in single shot

Sometimes it is helpful if SBL can support firmware update from
SBL FW to UEFI FW, or update from incompatible SBL flash layout.
This will need SBL to write full BIOS region without using
redundant partition. To support this, a special capsule image
flag is added to indicate this special update. Please note, this
update might be very risky. This is only for development purpose.

Signed-off-by: Maurice Ma <maurice.ma@intel.com>
This commit is contained in:
Maurice Ma 2021-10-09 10:37:25 -07:00
parent 24f5aa59b5
commit 1f3de3399e
5 changed files with 176 additions and 30 deletions

View File

@ -71,6 +71,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#define CREATOR_REV_INTEL 0x20090903
#define ACPI_FWST_OEM_REV 0x00001000
#define CAPSULE_FLAG_FORCE_BIOS_UPDATE BIT31
typedef enum {
TopSwapSet,
TopSwapClear
@ -156,7 +158,7 @@ typedef struct {
UINT32 Version;
EFI_GUID UpdateImageTypeId;
UINT8 UpdateImageIndex;
UINT8 reserved_bytes[3];
UINT8 ReservedBytes[3];
UINT32 UpdateImageSize;
UINT32 UpdateVendorCodeSize;
UINT64 UpdateHardwareInstance;

View File

@ -1,6 +1,6 @@
## @ GenCapsuleFirmware.py
#
# Copyright (c) 2017-2020, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2017-2021, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
@ -114,6 +114,7 @@ class FmpCapsuleImageHeaderClass(object):
def DumpInfo(self, padding=''):
if not self._Valid:
raise ValueError
print(
padding +
'EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.Version = {Version:08X}'.format(
@ -198,6 +199,15 @@ class FmpCapsuleHeaderClass(object):
raise ValueError
return self._EmbeddedDriverList[Index]
def GetEmbeddedDriverCount(self):
return len(self._EmbeddedDriverList)
def GetPayload(self, Index):
return self._PayloadList[Index]
def GetPayloadCount(self):
return len(self._PayloadList)
def AddPayload(self,
UpdateImageTypeId,
Payload=b'',
@ -383,7 +393,10 @@ class FmpPayloadHeaderClass(object):
FIRMWARE_UPDATE_IMAGE_FILE_GUID = uuid.UUID('{1A3EAE58-B580-4fef-ACA3-A16D9E00DF5F}')
#0x1a3eae58, 0xb580, 0x4fef, 0xac, 0xa3, 0xa1, 0x6d, 0x9e, 0x0, 0xdf, 0x5f);
class Firmware_Update_Header(Structure):
class FirmwareUpdateHeader(Structure):
CAPSULE_FLAG_FORCE_BIOS_UPDATE = 0x80000000
_fields_ = [
('FileGuid', ARRAY(c_uint8, 16)),
('HeaderSize', c_uint32),
@ -399,14 +412,14 @@ class Firmware_Update_Header(Structure):
]
def SignImage(RawData, OutFile, HashType, SignScheme, PrivKey):
def SignImage(RawData, OutFile, HashType, SignScheme, PrivKey, ForceBiosUpdate):
#
# Generate the new image layout
# 1. write firmware update header
#
unsigned_image = bytearray(sizeof(Firmware_Update_Header))
header = Firmware_Update_Header.from_buffer(unsigned_image, 0)
unsigned_image = bytearray(sizeof(FirmwareUpdateHeader))
header = FirmwareUpdateHeader.from_buffer(unsigned_image, 0)
file_size = len(RawData)
@ -420,9 +433,11 @@ def SignImage(RawData, OutFile, HashType, SignScheme, PrivKey):
HashType = adjust_hash_type(PrivKey)
header.FileGuid = (c_ubyte *16).from_buffer_copy(FIRMWARE_UPDATE_IMAGE_FILE_GUID.bytes_le)
header.HeaderSize = sizeof(Firmware_Update_Header)
header.HeaderSize = sizeof(FirmwareUpdateHeader)
header.FirmwreVersion = 1
header.CapsuleFlags = 0
if ForceBiosUpdate:
header.CapsuleFlags |= FirmwareUpdateHeader.CAPSULE_FLAG_FORCE_BIOS_UPDATE
header.ImageOffset = header.HeaderSize
header.ImageSize = file_size
header.SignatureOffset = header.ImageOffset + header.ImageSize
@ -488,6 +503,7 @@ def main():
parser.add_argument('-s', '--sign_scheme', dest='SignScheme', type=str, choices=['RSA_PKCS1', 'RSA_PSS'], default='RSA_PSS', help='Signing Scheme types')
parser.add_argument('-o', '--output', dest='NewImage', type=str, required=True, help='Output file for signed image')
parser.add_argument("-v", "--verbose", dest='Verbose', action="store_true", help= "Turn on verbose output with informational messages printed, including capsule headers and warning messages.")
parser.add_argument("-f", "--force_bios_update", dest='ForceBiosUpdate', action="store_true", help= "Force update whole BIOS region in a single shot.")
#
# Parse command line arguments
@ -531,6 +547,15 @@ def main():
Guid = ValidateRegistryFormatGuid(PldUuid)
FmpCapsuleHeader.AddPayload(Guid, Result, '', HardwareInstance)
if args.ForceBiosUpdate:
if FmpCapsuleHeader.GetPayloadCount() != 1 or FmpCapsuleHeader.GetEmbeddedDriverCount() != 0:
raise Exception ("When '-f' flag is enabled, only one component is supported in capsule !")
Payload = FmpCapsuleHeader.GetPayload(0)
if str(Payload[0]) != PredefinedUuidDict['BIOS'].lower():
raise Exception ("When '-f' flag is enabled, only BIOS component is supported in capsule !")
if len(Payload[1]) & 0xFFF:
raise Exception ("BIOS component size is not 4KB aligned !")
Result = FmpCapsuleHeader.Encode()
#
@ -542,10 +567,20 @@ def main():
#
# Create final capsule
#
SignImage(Result, args.NewImage, args.HashType, args.SignScheme, args.PrivKey)
SignImage(Result, args.NewImage, args.HashType, args.SignScheme, args.PrivKey, args.ForceBiosUpdate)
print('Success')
#
# Warn the user for "-f" option
#
if args.ForceBiosUpdate:
print ("\nWAINING: ")
print ( " It might be risky to force BIOS region update since any firmware update failure might\n"
" not be recoverable and cause system in a non-bootable state. If it occurs, external \n"
" flash programmer has to be used to reprogram the full IFWI image. This feature is only\n"
" for development purpose, please use it with extreme caution !!!\n")
if __name__ == '__main__':
sys.exit(main())

View File

@ -22,7 +22,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/PayloadMemoryAllocationLib.h>
#include <Guid/MemoryMapInfoGuid.h>
#include <Guid/LoaderPlatformInfoGuid.h>
#include <Library/ResetSystemLib.h>
#include <Library/SecureBootLib.h>
#include <Library/BootloaderCommonLib.h>
#include <Library/FirmwareUpdateLib.h>
@ -357,9 +356,7 @@ EnforceFwUpdatePolicy (
}
if (ResetRequired) {
DEBUG((DEBUG_ERROR, "Reset required to proceed with the firmware update.\n"));
ResetSystem (EfiResetCold);
CpuDeadLoop ();
Reboot (EfiResetCold);
}
return EFI_SUCCESS;
@ -406,9 +403,7 @@ AfterUpdateEnforceFwUpdatePolicy (
}
if (FwPolicy.Fields.Reboot == 1) {
DEBUG((DEBUG_ERROR, "Reset required to proceed with the firmware update.\n"));
ResetSystem (EfiResetWarm);
CpuDeadLoop ();
Reboot (EfiResetWarm);
}
//
@ -922,10 +917,13 @@ ApplyFwImage (
OUT BOOLEAN *ResetRequired
)
{
EFI_STATUS Status;
UINT32 Signature;
VOID *CsmeUpdateInData;
BOOT_PARTITION Partition;
EFI_STATUS Status;
UINT32 Signature;
BOOT_PARTITION Partition;
VOID *CsmeUpdateInData;
FIRMWARE_UPDATE_HEADER *CapHdr;
CapHdr = (FIRMWARE_UPDATE_HEADER *)CapImage;
Status = EFI_SUCCESS;
*ResetRequired = FALSE;
@ -938,7 +936,12 @@ ApplyFwImage (
switch (Signature) {
case FW_UPDATE_COMP_BIOS_REGION:
Status = UpdateSystemFirmware(ImageHdr);
if ((CapHdr->CapsuleFlags & CAPSULE_FLAG_FORCE_BIOS_UPDATE) != 0) {
Status = UpdateFullBiosRegion (ImageHdr);
*ResetRequired = TRUE;
} else {
Status = UpdateSystemFirmware (ImageHdr);
}
break;
case FW_UPDATE_COMP_CSME_REGION:
Status = EFI_UNSUPPORTED;
@ -949,8 +952,7 @@ ApplyFwImage (
Partition = (BOOT_PARTITION)GetCurrentBootPartition ();
if (Partition == BackupPartition) {
SetBootPartition (PrimaryPartition);
ResetSystem (EfiResetCold);
CpuDeadLoop ();
Reboot (EfiResetCold);
}
CsmeUpdateInData = InitCsmeUpdInputData();
if (CsmeUpdateInData != NULL) {
@ -992,6 +994,7 @@ InitFirmwareUpdate (
BOOLEAN ResetRequired;
FW_UPDATE_COMP_STATUS FwUpdCompStatus[MAX_FW_COMPONENTS];
EFI_FW_MGMT_CAP_IMAGE_HEADER *ImgHdr;
FIRMWARE_UPDATE_HEADER *CapHdr;
ImgHdr = NULL;
FwUpdStatusOffset = PcdGet32(PcdFwUpdStatusBase);
@ -1035,6 +1038,29 @@ InitFirmwareUpdate (
return Status;
}
//
// Handle full BIOS region update separately.
// It needs to consider cases that the user updates firmware from SBL FW to UEFI FW.
// SBL FWU state machine and status stored in flash should not be updated in a successful
// update since the new FW might have used this region for other purpose.
//
CapHdr = (FIRMWARE_UPDATE_HEADER *)CapsuleImage;
if ((CapHdr->CapsuleFlags & CAPSULE_FLAG_FORCE_BIOS_UPDATE) != 0) {
// Only expect a single BIOS component update.
Status = FindImage (FwUpdCompStatus[0].HardwareInstance, CapsuleImage, CapsuleSize, &ImgHdr);
if (!EFI_ERROR (Status)) {
Status = ApplyFwImage(CapsuleImage, CapsuleSize, ImgHdr, &ResetRequired);
}
DEBUG ((DEBUG_INFO, "Full BIOS region update status: %r\n", Status));
if (EFI_ERROR (Status)) {
// Clear state machine anyway to prevent FWU loop.
SetStateMachineFlag (FW_UPDATE_SM_DONE);
}
// Always reboot since full BIOS was updated
Reboot (EfiResetCold);
return Status;
}
//
// Loop through the components to perform update
//
@ -1091,8 +1117,7 @@ InitFirmwareUpdate (
// Reset system if required
//
if (ResetRequired == TRUE) {
ResetSystem (EfiResetCold);
CpuDeadLoop ();
Reboot (EfiResetCold);
}
}
}
@ -1254,7 +1279,5 @@ PayloadMain (
DEBUG((DEBUG_ERROR, "EndFirmwareUpdate, Status = 0x%x\n", Status));
}
DEBUG((DEBUG_ERROR, "Reset required to proceed with the firmware update.\n"));
ResetSystem (EfiResetCold);
CpuDeadLoop ();
Reboot (EfiResetCold);
}

View File

@ -1,7 +1,7 @@
/** @file
Internal functions to update firmware in boot media.
Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@ -460,6 +460,48 @@ UpdateBootPartition (
return Status;
}
/**
Perform full BIOS region update.
@param[in] ImageHdr Pointer to fw mgmt capsule Image header
@retval EFI_SUCCESS Update successful.
@retval other error occurred during firmware update
**/
EFI_STATUS
UpdateFullBiosRegion (
IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr
)
{
EFI_STATUS Status;
UINT32 BiosRgnBase;
UINT32 BiosRgnSize;
FIRMWARE_UPDATE_REGION UpdateRegion;
DEBUG((DEBUG_INFO, "Update full BIOS region\n"));
Status = BootMediaGetRegion (FlashRegionBios, &BiosRgnBase, &BiosRgnSize);
if (!EFI_ERROR (Status)) {
if (ImageHdr->UpdateImageSize > BiosRgnSize) {
DEBUG((DEBUG_ERROR, "BIOS image in capsule is bigger than BIOS region on flash\n"));
Status = EFI_UNSUPPORTED;
}
}
if (ALIGN_DOWN(ImageHdr->UpdateImageSize, SIZE_4KB) != ImageHdr->UpdateImageSize) {
DEBUG((DEBUG_ERROR, "BIOS image size in capsule is not 4KB aligned\n"));
Status = EFI_UNSUPPORTED;
}
if (EFI_ERROR (Status)) {
return Status;
}
ZeroMem (&UpdateRegion, sizeof(UpdateRegion));
UpdateRegion.ToUpdateAddress = BiosRgnSize - ImageHdr->UpdateImageSize;
UpdateRegion.UpdateSize = ImageHdr->UpdateImageSize;
UpdateRegion.SourceAddress = (UINT8 *)((UINTN)ImageHdr + sizeof(EFI_FW_MGMT_CAP_IMAGE_HEADER));
Status = UpdateBootRegion (&UpdateRegion, 0, UpdateRegion.UpdateSize);
return Status;
}
/**
Perform system Firmware update.
@ -967,3 +1009,19 @@ UpdateSblComponent (
return Status;
}
/**
Reboot platform.
@param[in] ResetType Cold, Warm or Shutdown
**/
VOID
Reboot (
IN EFI_RESET_TYPE ResetType
)
{
DEBUG ((DEBUG_INFO, "Reset required to proceed with the firmware update.\n\n"));
ResetSystem (ResetType);
CpuDeadLoop ();
}

View File

@ -1,7 +1,7 @@
/** @file
The header file for internal firmware update definitions.
Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@ -9,6 +9,9 @@
#ifndef __INTERNAL_FIRMWARE_UPDATE_LIB_H__
#define __INTERNAL_FIRMWARE_UPDATE_LIB_H__
#include <Uefi/UefiBaseType.h>
#include <Library/ResetSystemLib.h>
/**
Update a region block.
@ -136,6 +139,19 @@ AfterUpdateEnforceFwUpdatePolicy (
IN FIRMWARE_UPDATE_POLICY FwPolicy
);
/**
Perform full BIOS region update.
@param[in] ImageHdr Pointer to fw mgmt capsule Image header
@retval EFI_SUCCESS Update successful.
@retval other error occurred during firmware update
**/
EFI_STATUS
UpdateFullBiosRegion (
IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr
);
/**
Perform system Firmware update.
@ -202,4 +218,16 @@ CheckSblConfigDataSvn (
IN FIRMWARE_UPDATE_POLICY FwPolicy,
OUT UINT8 *SvnStatus
);
/**
Reboot platform.
@param[in] ResetType Cold, Warm or Shutdown
**/
VOID
Reboot (
IN EFI_RESET_TYPE ResetType
);
#endif