2016-09-21 04:30:12 +02:00
/** @file
SetImage instance to update system firmware .
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 .
FmpSetImage ( ) will receive untrusted input and do basic validation .
2018-03-31 19:17:29 +02:00
Copyright ( c ) 2016 - 2018 , Intel Corporation . All rights reserved . < BR >
2016-09-21 04:30:12 +02:00
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 "SystemFirmwareDxe.h"
//
// SystemFmp driver private data
//
SYSTEM_FMP_PRIVATE_DATA * mSystemFmpPrivate = NULL ;
EFI_GUID mCurrentImageTypeId ;
BOOLEAN mNvRamUpdated = FALSE ;
/**
Parse Config data file to get the updated data array .
@ param [ in ] DataBuffer Config raw file buffer .
@ param [ in ] BufferSize Size of raw buffer .
@ param [ in , out ] ConfigHeader Pointer to the config header .
@ param [ in , out ] UpdateArray Pointer to the config of update data .
@ retval EFI_NOT_FOUND No config data is found .
@ retval EFI_OUT_OF_RESOURCES No enough memory is allocated .
@ retval EFI_SUCCESS Parse the config file successfully .
* */
EFI_STATUS
ParseUpdateDataFile (
IN UINT8 * DataBuffer ,
IN UINTN BufferSize ,
IN OUT CONFIG_HEADER * ConfigHeader ,
IN OUT UPDATE_CONFIG_DATA * * UpdateArray
) ;
/**
Update System Firmware image component .
@ param [ in ] SystemFirmwareImage Points to the System Firmware image .
@ param [ in ] SystemFirmwareImageSize The length of the System Firmware image in bytes .
@ param [ in ] ConfigData Points to the component configuration structure .
@ param [ out ] LastAttemptVersion The last attempt version , which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR .
@ param [ out ] LastAttemptStatus The last attempt status , which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR .
@ retval EFI_SUCCESS The System Firmware image is updated .
@ retval EFI_WRITE_PROTECTED The flash device is read only .
* */
EFI_STATUS
PerformUpdate (
IN VOID * SystemFirmwareImage ,
IN UINTN SystemFirmwareImageSize ,
IN UPDATE_CONFIG_DATA * ConfigData ,
OUT UINT32 * LastAttemptVersion ,
OUT UINT32 * LastAttemptStatus
)
{
EFI_STATUS Status ;
DEBUG ( ( DEBUG_INFO , " PlatformUpdate: " ) ) ;
DEBUG ( ( DEBUG_INFO , " BaseAddress - 0x%lx, " , ConfigData - > BaseAddress ) ) ;
DEBUG ( ( DEBUG_INFO , " ImageOffset - 0x%x, " , ConfigData - > ImageOffset ) ) ;
DEBUG ( ( DEBUG_INFO , " Legnth - 0x%x \n " , ConfigData - > Length ) ) ;
Status = PerformFlashWrite (
ConfigData - > FirmwareType ,
ConfigData - > BaseAddress ,
ConfigData - > AddressType ,
( VOID * ) ( ( UINTN ) SystemFirmwareImage + ( UINTN ) ConfigData - > ImageOffset ) ,
ConfigData - > Length
) ;
if ( ! EFI_ERROR ( Status ) ) {
* LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS ;
if ( ConfigData - > FirmwareType = = PlatformFirmwareTypeNvRam ) {
mNvRamUpdated = TRUE ;
}
} else {
* LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL ;
}
return Status ;
}
/**
Update System Firmware image .
@ param [ in ] SystemFirmwareImage Points to the System Firmware image .
@ param [ in ] SystemFirmwareImageSize The length of the System Firmware image in bytes .
@ param [ in ] ConfigImage Points to the config file image .
@ param [ in ] ConfigImageSize The length of the config file image in bytes .
@ param [ out ] LastAttemptVersion The last attempt version , which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR .
@ param [ out ] LastAttemptStatus The last attempt status , which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR .
@ retval EFI_SUCCESS The System Firmware image is updated .
@ retval EFI_WRITE_PROTECTED The flash device is read only .
* */
EFI_STATUS
UpdateImage (
IN VOID * SystemFirmwareImage ,
IN UINTN SystemFirmwareImageSize ,
IN VOID * ConfigImage ,
IN UINTN ConfigImageSize ,
OUT UINT32 * LastAttemptVersion ,
OUT UINT32 * LastAttemptStatus
)
{
EFI_STATUS Status ;
UPDATE_CONFIG_DATA * ConfigData ;
UPDATE_CONFIG_DATA * UpdateConfigData ;
CONFIG_HEADER ConfigHeader ;
UINTN Index ;
if ( ConfigImage = = NULL ) {
DEBUG ( ( DEBUG_INFO , " PlatformUpdate (NoConfig): " ) ) ;
DEBUG ( ( DEBUG_INFO , " BaseAddress - 0x%x, " , 0 ) ) ;
DEBUG ( ( DEBUG_INFO , " Length - 0x%x \n " , SystemFirmwareImageSize ) ) ;
// ASSUME the whole System Firmware include NVRAM region.
Status = PerformFlashWrite (
PlatformFirmwareTypeNvRam ,
0 ,
FlashAddressTypeRelativeAddress ,
SystemFirmwareImage ,
SystemFirmwareImageSize
) ;
if ( ! EFI_ERROR ( Status ) ) {
* LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS ;
mNvRamUpdated = TRUE ;
} else {
* LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL ;
}
return Status ;
}
DEBUG ( ( DEBUG_INFO , " PlatformUpdate (With Config): \n " ) ) ;
ConfigData = NULL ;
ZeroMem ( & ConfigHeader , sizeof ( ConfigHeader ) ) ;
Status = ParseUpdateDataFile (
ConfigImage ,
ConfigImageSize ,
& ConfigHeader ,
& ConfigData
) ;
DEBUG ( ( DEBUG_INFO , " ParseUpdateDataFile - %r \n " , Status ) ) ;
if ( EFI_ERROR ( Status ) ) {
* LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL ;
return EFI_INVALID_PARAMETER ;
}
DEBUG ( ( DEBUG_INFO , " ConfigHeader.NumOfUpdates - 0x%x \n " , ConfigHeader . NumOfUpdates ) ) ;
DEBUG ( ( DEBUG_INFO , " PcdEdkiiSystemFirmwareFileGuid - %g \n " , PcdGetPtr ( PcdEdkiiSystemFirmwareFileGuid ) ) ) ;
Index = 0 ;
UpdateConfigData = ConfigData ;
while ( Index < ConfigHeader . NumOfUpdates ) {
if ( CompareGuid ( & UpdateConfigData - > FileGuid , PcdGetPtr ( PcdEdkiiSystemFirmwareFileGuid ) ) ) {
DEBUG ( ( DEBUG_INFO , " FileGuid - %g (processing) \n " , & UpdateConfigData - > FileGuid ) ) ;
Status = PerformUpdate (
SystemFirmwareImage ,
SystemFirmwareImageSize ,
UpdateConfigData ,
LastAttemptVersion ,
LastAttemptStatus
) ;
//
// Shall updates be serialized so that if an update is not successfully completed,
// the remaining updates won't be performed.
//
if ( EFI_ERROR ( Status ) ) {
break ;
}
} else {
DEBUG ( ( DEBUG_INFO , " FileGuid - %g (ignored) \n " , & UpdateConfigData - > FileGuid ) ) ;
}
Index + + ;
UpdateConfigData + + ;
}
return Status ;
}
/**
Authenticate and update System Firmware image .
Caution : This function may receive untrusted input .
@ param [ in ] Image The EDKII system FMP capsule image .
@ param [ in ] ImageSize The size of the EDKII system FMP capsule image in bytes .
@ param [ out ] LastAttemptVersion The last attempt version , which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR .
@ param [ out ] LastAttemptStatus The last attempt status , which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR .
@ retval EFI_SUCCESS EDKII system FMP capsule passes authentication and the System Firmware image is updated .
@ retval EFI_SECURITY_VIOLATION EDKII system FMP capsule fails authentication and the System Firmware image is not updated .
@ retval EFI_WRITE_PROTECTED The flash device is read only .
* */
EFI_STATUS
SystemFirmwareAuthenticatedUpdate (
IN VOID * Image ,
IN UINTN ImageSize ,
OUT UINT32 * LastAttemptVersion ,
OUT UINT32 * LastAttemptStatus
)
{
EFI_STATUS Status ;
VOID * SystemFirmwareImage ;
UINTN SystemFirmwareImageSize ;
VOID * ConfigImage ;
UINTN ConfigImageSize ;
VOID * AuthenticatedImage ;
UINTN AuthenticatedImageSize ;
2016-11-16 09:01:57 +01:00
AuthenticatedImage = NULL ;
AuthenticatedImageSize = 0 ;
2016-09-21 04:30:12 +02:00
DEBUG ( ( DEBUG_INFO , " SystemFirmwareAuthenticatedUpdate... \n " ) ) ;
Status = CapsuleAuthenticateSystemFirmware ( Image , ImageSize , FALSE , LastAttemptVersion , LastAttemptStatus , & AuthenticatedImage , & AuthenticatedImageSize ) ;
if ( EFI_ERROR ( Status ) ) {
DEBUG ( ( DEBUG_INFO , " SystemFirmwareAuthenticateImage - %r \n " , Status ) ) ;
return Status ;
}
DEBUG ( ( DEBUG_INFO , " ExtractSystemFirmwareImage ... \n " ) ) ;
ExtractSystemFirmwareImage ( AuthenticatedImage , AuthenticatedImageSize , & SystemFirmwareImage , & SystemFirmwareImageSize ) ;
DEBUG ( ( DEBUG_INFO , " ExtractConfigImage ... \n " ) ) ;
ExtractConfigImage ( AuthenticatedImage , AuthenticatedImageSize , & ConfigImage , & ConfigImageSize ) ;
DEBUG ( ( DEBUG_INFO , " UpdateImage ... \n " ) ) ;
Status = UpdateImage ( SystemFirmwareImage , SystemFirmwareImageSize , ConfigImage , ConfigImageSize , LastAttemptVersion , LastAttemptStatus ) ;
if ( EFI_ERROR ( Status ) ) {
DEBUG ( ( DEBUG_INFO , " UpdateImage - %r \n " , Status ) ) ;
return Status ;
}
DEBUG ( ( DEBUG_INFO , " SystemFirmwareAuthenticatedUpdate Done \n " ) ) ;
return EFI_SUCCESS ;
}
/**
This code finds variable in storage blocks ( Volatile or Non - Volatile ) .
@ param [ in ] VariableName Name of Variable to be found .
@ param [ in ] VendorGuid Variable vendor GUID .
@ param [ out ] Attributes Attribute value of the variable found .
@ param [ in , out ] DataSize Size of Data found . If size is less than the
data , this value contains the required size .
@ param [ out ] Data Data pointer .
@ return EFI_INVALID_PARAMETER Invalid parameter .
@ return EFI_SUCCESS Find the specified variable .
@ return EFI_NOT_FOUND Not found .
@ return EFI_BUFFER_TO_SMALL DataSize is too small for the result .
* */
EFI_STATUS
EFIAPI
GetVariableHook (
IN CHAR16 * VariableName ,
IN EFI_GUID * VendorGuid ,
OUT UINT32 * Attributes OPTIONAL ,
IN OUT UINTN * DataSize ,
OUT VOID * Data
)
{
DEBUG ( ( DEBUG_INFO , " GetVariableHook - %S, %g \n " , VariableName , VendorGuid ) ) ;
return EFI_NOT_AVAILABLE_YET ;
}
/**
This code Finds the Next available variable .
@ param [ in , out ] VariableNameSize Size of the variable name .
@ param [ in , out ] VariableName Pointer to variable name .
@ param [ in , out ] VendorGuid Variable Vendor Guid .
@ return EFI_INVALID_PARAMETER Invalid parameter .
@ return EFI_SUCCESS Find the specified variable .
@ return EFI_NOT_FOUND Not found .
@ return EFI_BUFFER_TO_SMALL DataSize is too small for the result .
* */
EFI_STATUS
EFIAPI
GetNextVariableNameHook (
IN OUT UINTN * VariableNameSize ,
IN OUT CHAR16 * VariableName ,
IN OUT EFI_GUID * VendorGuid
)
{
DEBUG ( ( DEBUG_INFO , " GetNextVariableNameHook - %S, %g \n " , VariableName , VendorGuid ) ) ;
return EFI_NOT_AVAILABLE_YET ;
}
/**
This code sets variable in storage blocks ( Volatile or Non - Volatile ) .
@ param [ in ] VariableName Name of Variable to be found .
@ param [ in ] VendorGuid Variable vendor GUID .
@ param [ in ] Attributes Attribute value of the variable found
@ param [ in ] DataSize Size of Data found . If size is less than the
data , this value contains the required size .
@ param [ in ] Data Data pointer .
@ return EFI_INVALID_PARAMETER Invalid parameter .
@ return EFI_SUCCESS Set successfully .
@ return EFI_OUT_OF_RESOURCES Resource not enough to set variable .
@ return EFI_NOT_FOUND Not found .
@ return EFI_WRITE_PROTECTED Variable is read - only .
* */
EFI_STATUS
EFIAPI
SetVariableHook (
IN CHAR16 * VariableName ,
IN EFI_GUID * VendorGuid ,
IN UINT32 Attributes ,
IN UINTN DataSize ,
IN VOID * Data
)
{
DEBUG ( ( DEBUG_INFO , " SetVariableHook - %S, %g, 0x%x (0x%x) \n " , VariableName , VendorGuid , Attributes , DataSize ) ) ;
return EFI_NOT_AVAILABLE_YET ;
}
/**
This code returns information about the EFI variables .
@ param [ in ] Attributes Attributes bitmask to specify the type of variables
on which to return information .
@ param [ out ] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
for the EFI variables associated with the attributes specified .
@ param [ out ] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
for EFI variables associated with the attributes specified .
@ param [ out ] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
associated with the attributes specified .
@ return EFI_SUCCESS Query successfully .
* */
EFI_STATUS
EFIAPI
QueryVariableInfoHook (
IN UINT32 Attributes ,
OUT UINT64 * MaximumVariableStorageSize ,
OUT UINT64 * RemainingVariableStorageSize ,
OUT UINT64 * MaximumVariableSize
)
{
DEBUG ( ( DEBUG_INFO , " QueryVariableInfoHook - 0x%x \n " , Attributes ) ) ;
return EFI_NOT_AVAILABLE_YET ;
}
/**
Updates the firmware image of the device .
This function updates the hardware with the new firmware image .
This function returns EFI_UNSUPPORTED if the firmware image is not updatable .
If the firmware image is updatable , the function should perform the following minimal validations
before proceeding to do the firmware image update .
- Validate the image authentication if image has attribute
IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED . The function returns
EFI_SECURITY_VIOLATION if the validation fails .
- Validate the image is a supported image for this device . The function returns EFI_ABORTED if
the image is unsupported . The function can optionally provide more detailed information on
why the image is not a supported image .
- Validate the data from VendorCode if not null . Image validation must be performed before
VendorCode data validation . VendorCode data is ignored or considered invalid if image
validation failed . The function returns EFI_ABORTED if the data is invalid .
VendorCode enables vendor to implement vendor - specific firmware image update policy . Null if
the caller did not specify the policy or use the default policy . As an example , vendor can implement
a policy to allow an option to force a firmware image update when the abort reason is due to the new
firmware image version is older than the current firmware image version or bad image checksum .
Sensitive operations such as those wiping the entire firmware image and render the device to be
non - functional should be encoded in the image itself rather than passed with the VendorCode .
AbortReason enables vendor to have the option to provide a more detailed description of the abort
reason to the caller .
@ param [ in ] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance .
@ param [ in ] ImageIndex A unique number identifying the firmware image ( s ) within the device .
The number is between 1 and DescriptorCount .
@ param [ in ] Image Points to the new image .
@ param [ in ] ImageSize Size of the new image in bytes .
@ param [ in ] VendorCode This enables vendor to implement vendor - specific firmware image update policy .
Null indicates the caller did not specify the policy or use the default policy .
@ param [ in ] Progress A function used by the driver to report the progress of the firmware update .
@ param [ out ] AbortReason A pointer to a pointer to a null - terminated string providing more
details for the aborted operation . The buffer is allocated by this function
with AllocatePool ( ) , and it is the caller ' s responsibility to free it with a
call to FreePool ( ) .
@ retval EFI_SUCCESS The device was successfully updated with the new image .
@ retval EFI_ABORTED The operation is aborted .
@ retval EFI_INVALID_PARAMETER The Image was NULL .
@ retval EFI_UNSUPPORTED The operation is not supported .
@ retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure .
* */
EFI_STATUS
EFIAPI
FmpSetImage (
IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL * This ,
IN UINT8 ImageIndex ,
IN CONST VOID * Image ,
IN UINTN ImageSize ,
IN CONST VOID * VendorCode ,
IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress ,
OUT CHAR16 * * AbortReason
)
{
EFI_STATUS Status ;
EFI_STATUS VarStatus ;
SYSTEM_FMP_PRIVATE_DATA * SystemFmpPrivate ;
if ( Image = = NULL | | ImageSize = = 0 | | AbortReason = = NULL ) {
return EFI_INVALID_PARAMETER ;
}
SystemFmpPrivate = SYSTEM_FMP_PRIVATE_DATA_FROM_FMP ( This ) ;
* AbortReason = NULL ;
if ( ImageIndex = = 0 | | ImageIndex > SystemFmpPrivate - > DescriptorCount ) {
return EFI_INVALID_PARAMETER ;
}
Status = SystemFirmwareAuthenticatedUpdate ( ( VOID * ) Image , ImageSize , & SystemFmpPrivate - > LastAttempt . LastAttemptVersion , & SystemFmpPrivate - > LastAttempt . LastAttemptStatus ) ;
DEBUG ( ( DEBUG_INFO , " SetImage - LastAttemp Version - 0x%x, State - 0x%x \n " , SystemFmpPrivate - > LastAttempt . LastAttemptVersion , SystemFmpPrivate - > LastAttempt . LastAttemptStatus ) ) ;
//
// If NVRAM is updated, we should no longer touch variable services, because
// the current variable driver may not manage the new NVRAM region.
//
if ( mNvRamUpdated ) {
DEBUG ( ( DEBUG_INFO , " NvRamUpdated, Update Variable Serivces \n " ) ) ;
gRT - > GetVariable = GetVariableHook ;
gRT - > GetNextVariableName = GetNextVariableNameHook ;
gRT - > SetVariable = SetVariableHook ;
gRT - > QueryVariableInfo = QueryVariableInfoHook ;
gRT - > Hdr . CRC32 = 0 ;
gBS - > CalculateCrc32 (
( UINT8 * ) & gRT - > Hdr ,
gRT - > Hdr . HeaderSize ,
& gRT - > Hdr . CRC32
) ;
}
VarStatus = gRT - > SetVariable (
SYSTEM_FMP_LAST_ATTEMPT_VARIABLE_NAME ,
& gSystemFmpLastAttemptVariableGuid ,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS ,
sizeof ( SystemFmpPrivate - > LastAttempt ) ,
& SystemFmpPrivate - > LastAttempt
) ;
DEBUG ( ( DEBUG_INFO , " SetLastAttemp - %r \n " , VarStatus ) ) ;
return Status ;
}
2018-03-31 19:17:29 +02:00
/**
Get the set of EFI_FIRMWARE_IMAGE_DESCRIPTOR structures from an FMP Protocol .
@ param [ in ] Handle Handle with an FMP Protocol or a System FMP
Protocol .
@ param [ in ] ProtocolGuid Pointer to the FMP Protocol GUID or System FMP
Protocol GUID .
@ param [ out ] FmpImageInfoCount Pointer to the number of
EFI_FIRMWARE_IMAGE_DESCRIPTOR structures .
@ param [ out ] DescriptorSize Pointer to the size , in bytes , of each
EFI_FIRMWARE_IMAGE_DESCRIPTOR structure .
@ return NULL No EFI_FIRMWARE_IMAGE_DESCRIPTOR structures found .
@ return ! NULL Pointer to a buffer of EFI_FIRMWARE_IMAGE_DESCRIPTOR structures
allocated using AllocatePool ( ) . Caller must free buffer with
FreePool ( ) .
* */
EFI_FIRMWARE_IMAGE_DESCRIPTOR *
GetFmpImageDescriptors (
IN EFI_HANDLE Handle ,
IN EFI_GUID * ProtocolGuid ,
OUT UINT8 * FmpImageInfoCount ,
OUT UINTN * DescriptorSize
)
{
EFI_STATUS Status ;
EFI_FIRMWARE_MANAGEMENT_PROTOCOL * Fmp ;
UINTN ImageInfoSize ;
EFI_FIRMWARE_IMAGE_DESCRIPTOR * FmpImageInfoBuf ;
UINT32 FmpImageInfoDescriptorVer ;
UINT32 PackageVersion ;
CHAR16 * PackageVersionName ;
* FmpImageInfoCount = 0 ;
* DescriptorSize = 0 ;
Status = gBS - > HandleProtocol (
Handle ,
ProtocolGuid ,
( VOID * * ) & Fmp
) ;
if ( EFI_ERROR ( Status ) ) {
return NULL ;
}
//
// Determine the size required for the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
//
ImageInfoSize = 0 ;
Status = Fmp - > GetImageInfo (
Fmp , // FMP Pointer
& ImageInfoSize , // Buffer Size (in this case 0)
NULL , // NULL so we can get size
& FmpImageInfoDescriptorVer , // DescriptorVersion
FmpImageInfoCount , // DescriptorCount
DescriptorSize , // DescriptorSize
& PackageVersion , // PackageVersion
& PackageVersionName // PackageVersionName
) ;
if ( Status ! = EFI_BUFFER_TOO_SMALL ) {
DEBUG ( ( DEBUG_ERROR , " SystemFirmwareUpdateDxe: Unexpected Failure. Status = %r \n " , Status ) ) ;
return NULL ;
}
//
// Allocate buffer for the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
//
FmpImageInfoBuf = NULL ;
FmpImageInfoBuf = AllocateZeroPool ( ImageInfoSize ) ;
if ( FmpImageInfoBuf = = NULL ) {
DEBUG ( ( DEBUG_ERROR , " SystemFirmwareUpdateDxe: Failed to allocate memory for descriptors. \n " ) ) ;
return NULL ;
}
//
// Retrieve the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
//
PackageVersionName = NULL ;
Status = Fmp - > GetImageInfo (
Fmp ,
& ImageInfoSize , // ImageInfoSize
FmpImageInfoBuf , // ImageInfo
& FmpImageInfoDescriptorVer , // DescriptorVersion
FmpImageInfoCount , // DescriptorCount
DescriptorSize , // DescriptorSize
& PackageVersion , // PackageVersion
& PackageVersionName // PackageVersionName
) ;
//
// Free unused PackageVersionName return buffer
//
if ( PackageVersionName ! = NULL ) {
FreePool ( PackageVersionName ) ;
PackageVersionName = NULL ;
}
if ( EFI_ERROR ( Status ) ) {
DEBUG ( ( DEBUG_ERROR , " SystemFirmwareUpdateDxe: Failure in GetImageInfo. Status = %r \n " , Status ) ) ;
if ( FmpImageInfoBuf ! = NULL ) {
FreePool ( FmpImageInfoBuf ) ;
}
return NULL ;
}
return FmpImageInfoBuf ;
}
/**
Search for handles with an FMP protocol whose EFI_FIRMWARE_IMAGE_DESCRIPTOR
ImageTypeId matches the ImageTypeId produced by this module .
@ param [ in ] ProtocolGuid Pointer to the GUID of the protocol to search .
@ param [ out ] HandleCount Pointer to the number of returned handles .
@ return NULL No matching handles found .
@ return ! NULL Pointer to a buffer of handles allocated using AllocatePool ( ) .
Caller must free buffer with FreePool ( ) .
* */
EFI_HANDLE *
FindMatchingFmpHandles (
IN EFI_GUID * ProtocolGuid ,
OUT UINTN * HandleCount
)
{
EFI_STATUS Status ;
2018-04-13 11:55:14 +02:00
UINTN TempHandleCount ;
2018-03-31 19:17:29 +02:00
EFI_HANDLE * HandleBuffer ;
UINTN Index ;
UINTN Index2 ;
UINTN Index3 ;
EFI_FIRMWARE_IMAGE_DESCRIPTOR * OriginalFmpImageInfoBuf ;
EFI_FIRMWARE_IMAGE_DESCRIPTOR * FmpImageInfoBuf ;
UINT8 FmpImageInfoCount ;
UINTN DescriptorSize ;
BOOLEAN MatchFound ;
* HandleCount = 0 ;
2018-04-13 11:55:14 +02:00
TempHandleCount = 0 ;
2018-03-31 19:17:29 +02:00
HandleBuffer = NULL ;
Status = gBS - > LocateHandleBuffer (
ByProtocol ,
ProtocolGuid ,
NULL ,
2018-04-13 11:55:14 +02:00
& TempHandleCount ,
2018-03-31 19:17:29 +02:00
& HandleBuffer
) ;
if ( EFI_ERROR ( Status ) ) {
return NULL ;
}
2018-04-13 11:55:14 +02:00
for ( Index = 0 ; Index < TempHandleCount ; Index + + ) {
2018-03-31 19:17:29 +02:00
OriginalFmpImageInfoBuf = GetFmpImageDescriptors (
HandleBuffer [ Index ] ,
ProtocolGuid ,
& FmpImageInfoCount ,
& DescriptorSize
) ;
//
// Loop through the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
//
FmpImageInfoBuf = OriginalFmpImageInfoBuf ;
MatchFound = FALSE ;
for ( Index2 = 0 ; Index2 < FmpImageInfoCount ; Index2 + + ) {
for ( Index3 = 0 ; Index3 < mSystemFmpPrivate - > DescriptorCount ; Index3 + + ) {
MatchFound = CompareGuid (
& FmpImageInfoBuf - > ImageTypeId ,
& mSystemFmpPrivate - > ImageDescriptor [ Index3 ] . ImageTypeId
) ;
if ( MatchFound ) {
break ;
}
}
if ( MatchFound ) {
break ;
}
//
// Increment the buffer pointer ahead by the size of the descriptor
//
FmpImageInfoBuf = ( EFI_FIRMWARE_IMAGE_DESCRIPTOR * ) ( ( ( UINT8 * ) FmpImageInfoBuf ) + DescriptorSize ) ;
}
2018-04-13 11:55:14 +02:00
if ( MatchFound ) {
HandleBuffer [ * HandleCount ] = HandleBuffer [ Index ] ;
( * HandleCount ) + + ;
2018-03-31 19:17:29 +02:00
}
FreePool ( OriginalFmpImageInfoBuf ) ;
}
2018-04-13 11:55:14 +02:00
if ( ( * HandleCount ) = = 0 ) {
//
// No any matching handle.
//
FreePool ( HandleBuffer ) ;
return NULL ;
}
2018-03-31 19:17:29 +02:00
return HandleBuffer ;
}
/**
Uninstall System FMP Protocol instances that may have been installed by
SystemFirmwareUpdateDxe drivers dispatches by other capsules .
@ retval EFI_SUCCESS All System FMP Protocols found were uninstalled .
@ return Other One or more System FMP Protocols could not be uninstalled .
* */
EFI_STATUS
UninstallMatchingSystemFmpProtocols (
VOID
)
{
EFI_STATUS Status ;
EFI_HANDLE * HandleBuffer ;
UINTN HandleCount ;
UINTN Index ;
EFI_FIRMWARE_MANAGEMENT_PROTOCOL * SystemFmp ;
//
// Uninstall SystemFmpProtocol instances that may have been produced by
// the SystemFirmwareUpdate drivers in FVs dispatched by other capsules.
//
HandleBuffer = FindMatchingFmpHandles (
& gSystemFmpProtocolGuid ,
& HandleCount
) ;
DEBUG ( ( DEBUG_INFO , " SystemFirmwareUpdateDxe: Found %d matching System FMP instances \n " , HandleCount ) ) ;
for ( Index = 0 ; Index < HandleCount ; Index + + ) {
Status = gBS - > HandleProtocol (
HandleBuffer [ Index ] ,
& gSystemFmpProtocolGuid ,
( VOID * * ) & SystemFmp
) ;
if ( EFI_ERROR ( Status ) ) {
continue ;
}
DEBUG ( ( DEBUG_INFO , " SystemFirmwareUpdateDxe: Uninstall SystemFmp produced by another capsule \n " ) ) ;
Status = gBS - > UninstallProtocolInterface (
HandleBuffer [ Index ] ,
& gSystemFmpProtocolGuid ,
SystemFmp
) ;
if ( EFI_ERROR ( Status ) ) {
DEBUG ( ( DEBUG_ERROR , " SystemFirmwareUpdateDxe: Failed to uninstall SystemFmp %r. Exiting. \n " , Status ) ) ;
FreePool ( HandleBuffer ) ;
return Status ;
}
}
if ( HandleBuffer ! = NULL ) {
FreePool ( HandleBuffer ) ;
}
return EFI_SUCCESS ;
}
2016-09-21 04:30:12 +02:00
/**
System FMP module entrypoint
2018-03-31 19:17:29 +02:00
@ param [ in ] ImageHandle The firmware allocated handle for the EFI image .
@ param [ in ] SystemTable A pointer to the EFI System Table .
2016-09-21 04:30:12 +02:00
2018-03-31 19:17:29 +02:00
@ retval EFI_SUCCESS System FMP module is initialized .
@ retval EFI_OUT_OF_RESOURCES There are not enough resources avaulable to
initialize this module .
@ retval Other System FMP Protocols could not be uninstalled .
@ retval Other System FMP Protocol could not be installed .
@ retval Other FMP Protocol could not be installed .
2016-09-21 04:30:12 +02:00
* */
EFI_STATUS
EFIAPI
SystemFirmwareUpdateMainDxe (
2018-03-31 19:17:29 +02:00
IN EFI_HANDLE ImageHandle ,
IN EFI_SYSTEM_TABLE * SystemTable
2016-09-21 04:30:12 +02:00
)
{
2018-03-31 19:17:29 +02:00
EFI_STATUS Status ;
EFI_HANDLE * HandleBuffer ;
UINTN HandleCount ;
2016-09-21 04:30:12 +02:00
//
// Initialize SystemFmpPrivateData
//
2018-03-31 19:17:29 +02:00
mSystemFmpPrivate = AllocateZeroPool ( sizeof ( SYSTEM_FMP_PRIVATE_DATA ) ) ;
2016-09-21 04:30:12 +02:00
if ( mSystemFmpPrivate = = NULL ) {
return EFI_OUT_OF_RESOURCES ;
}
2018-03-31 19:17:29 +02:00
Status = InitializePrivateData ( mSystemFmpPrivate ) ;
if ( EFI_ERROR ( Status ) ) {
FreePool ( mSystemFmpPrivate ) ;
2016-09-21 04:30:12 +02:00
mSystemFmpPrivate = NULL ;
return Status ;
}
//
2018-03-31 19:17:29 +02:00
// Uninstall SystemFmpProtocol instances that may have been produced by
// the SystemFirmwareUpdate drivers in FVs dispatched by other capsules.
2016-09-21 04:30:12 +02:00
//
2018-03-31 19:17:29 +02:00
Status = UninstallMatchingSystemFmpProtocols ( ) ;
2016-09-21 04:30:12 +02:00
if ( EFI_ERROR ( Status ) ) {
2018-03-31 19:17:29 +02:00
FreePool ( mSystemFmpPrivate ) ;
2016-09-21 04:30:12 +02:00
mSystemFmpPrivate = NULL ;
return Status ;
}
2018-03-31 19:17:29 +02:00
//
// Look for a handle with matching Firmware Management Protocol
//
HandleCount = 0 ;
HandleBuffer = FindMatchingFmpHandles (
& gEfiFirmwareManagementProtocolGuid ,
& HandleCount
) ;
DEBUG ( ( DEBUG_INFO , " SystemFirmwareUpdateDxe: Found %d matching FMP instances \n " , HandleCount ) ) ;
switch ( HandleCount ) {
case 0 :
//
// Install FMP protocol onto a new handle.
//
DEBUG ( ( DEBUG_INFO , " SystemFirmwareUpdateDxe: Install FMP onto a new handle \n " ) ) ;
Status = gBS - > InstallMultipleProtocolInterfaces (
& mSystemFmpPrivate - > Handle ,
& gEfiFirmwareManagementProtocolGuid ,
& mSystemFmpPrivate - > Fmp ,
NULL
) ;
break ;
case 1 :
//
// Install System FMP protocol onto handle with matching FMP Protocol
//
DEBUG ( ( DEBUG_INFO , " SystemFirmwareUpdateDxe: Install System FMP onto matching FMP handle \n " ) ) ;
2018-04-13 11:55:14 +02:00
mSystemFmpPrivate - > Handle = HandleBuffer [ 0 ] ;
2018-03-31 19:17:29 +02:00
Status = gBS - > InstallMultipleProtocolInterfaces (
& HandleBuffer [ 0 ] ,
& gSystemFmpProtocolGuid ,
& mSystemFmpPrivate - > Fmp ,
NULL
) ;
break ;
default :
//
// More than one matching handle is not expected. Unload driver.
//
DEBUG ( ( DEBUG_ERROR , " SystemFirmwareUpdateDxe: More than one matching FMP handle. Unload driver. \n " ) ) ;
Status = EFI_DEVICE_ERROR ;
break ;
}
if ( HandleBuffer ! = NULL ) {
FreePool ( HandleBuffer ) ;
}
if ( EFI_ERROR ( Status ) ) {
FreePool ( mSystemFmpPrivate ) ;
mSystemFmpPrivate = NULL ;
}
2016-09-21 04:30:12 +02:00
return Status ;
}