123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901 |
- /** @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.
- Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #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.
- @param[in] Progress A function used by the driver to report the progress of the firmware update.
- @param[in] StartPercentage The start completion percentage value that may be used to report progress during the flash write operation.
- @param[in] EndPercentage The end completion percentage value that may be used to report progress during the flash write operation.
- @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,
- IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,
- IN UINTN StartPercentage,
- IN UINTN EndPercentage
- )
- {
- 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));
- if (Progress != NULL) {
- Progress (StartPercentage);
- }
- Status = PerformFlashWriteWithProgress (
- ConfigData->FirmwareType,
- ConfigData->BaseAddress,
- ConfigData->AddressType,
- (VOID *)((UINTN)SystemFirmwareImage + (UINTN)ConfigData->ImageOffset),
- ConfigData->Length,
- Progress,
- StartPercentage,
- EndPercentage
- );
- if (Progress != NULL) {
- Progress (EndPercentage);
- }
- 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.
- @param[in] Progress A function used by the driver to report the progress of the firmware update.
- @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,
- IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress
- )
- {
- EFI_STATUS Status;
- UPDATE_CONFIG_DATA *ConfigData;
- UPDATE_CONFIG_DATA *UpdateConfigData;
- CONFIG_HEADER ConfigHeader;
- UINTN Index;
- UINTN TotalSize;
- UINTN BytesWritten;
- UINTN StartPercentage;
- UINTN EndPercentage;
- 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.
- StartPercentage = 0;
- EndPercentage = 100;
- if (Progress != NULL) {
- Progress (StartPercentage);
- }
- Status = PerformFlashWriteWithProgress (
- PlatformFirmwareTypeNvRam,
- 0,
- FlashAddressTypeRelativeAddress,
- SystemFirmwareImage,
- SystemFirmwareImageSize,
- Progress,
- StartPercentage,
- EndPercentage
- );
- if (Progress != NULL) {
- Progress (EndPercentage);
- }
- 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)));
- TotalSize = 0;
- for (Index = 0; Index < ConfigHeader.NumOfUpdates; Index++) {
- if (CompareGuid (&ConfigData[Index].FileGuid, PcdGetPtr (PcdEdkiiSystemFirmwareFileGuid))) {
- TotalSize = TotalSize + ConfigData[Index].Length;
- }
- }
- BytesWritten = 0;
- Index = 0;
- UpdateConfigData = ConfigData;
- while (Index < ConfigHeader.NumOfUpdates) {
- if (CompareGuid (&UpdateConfigData->FileGuid, PcdGetPtr (PcdEdkiiSystemFirmwareFileGuid))) {
- DEBUG ((DEBUG_INFO, "FileGuid - %g (processing)\n", &UpdateConfigData->FileGuid));
- StartPercentage = (BytesWritten * 100) / TotalSize;
- EndPercentage = ((BytesWritten + UpdateConfigData->Length) * 100) / TotalSize;
- Status = PerformUpdate (
- SystemFirmwareImage,
- SystemFirmwareImageSize,
- UpdateConfigData,
- LastAttemptVersion,
- LastAttemptStatus,
- Progress,
- StartPercentage,
- EndPercentage
- );
- //
- // 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));
- }
- BytesWritten += UpdateConfigData->Length;
- 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.
- @param[in] Progress A function used by the driver to report the progress of the firmware update.
- @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,
- IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress
- )
- {
- EFI_STATUS Status;
- VOID *SystemFirmwareImage;
- UINTN SystemFirmwareImageSize;
- VOID *ConfigImage;
- UINTN ConfigImageSize;
- VOID *AuthenticatedImage;
- UINTN AuthenticatedImageSize;
- AuthenticatedImage = NULL;
- AuthenticatedImageSize = 0;
- 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, Progress);
- 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_VIOLATION 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, Progress);
- DEBUG ((DEBUG_INFO, "SetImage - LastAttempt 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 Services\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, "SetLastAttempt - %r\n", VarStatus));
- return Status;
- }
- /**
- 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;
- UINTN TempHandleCount;
- 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;
- TempHandleCount = 0;
- HandleBuffer = NULL;
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- ProtocolGuid,
- NULL,
- &TempHandleCount,
- &HandleBuffer
- );
- if (EFI_ERROR (Status)) {
- return NULL;
- }
- for (Index = 0; Index < TempHandleCount; Index++) {
- OriginalFmpImageInfoBuf = GetFmpImageDescriptors (
- HandleBuffer[Index],
- ProtocolGuid,
- &FmpImageInfoCount,
- &DescriptorSize
- );
- //
- // Loop through the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
- //
- MatchFound = FALSE;
- if (OriginalFmpImageInfoBuf != NULL) {
- FmpImageInfoBuf = OriginalFmpImageInfoBuf;
- 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);
- }
- if (MatchFound) {
- HandleBuffer[*HandleCount] = HandleBuffer[Index];
- (*HandleCount)++;
- }
- FreePool (OriginalFmpImageInfoBuf);
- }
- }
- if ((*HandleCount) == 0) {
- //
- // No any matching handle.
- //
- FreePool (HandleBuffer);
- return NULL;
- }
- 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;
- }
- /**
- System FMP module entrypoint
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
- @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.
- **/
- EFI_STATUS
- EFIAPI
- SystemFirmwareUpdateMainDxe (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- EFI_STATUS Status;
- EFI_HANDLE *HandleBuffer;
- UINTN HandleCount;
- //
- // Initialize SystemFmpPrivateData
- //
- mSystemFmpPrivate = AllocateZeroPool (sizeof (SYSTEM_FMP_PRIVATE_DATA));
- if (mSystemFmpPrivate == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- Status = InitializePrivateData (mSystemFmpPrivate);
- if (EFI_ERROR (Status)) {
- FreePool (mSystemFmpPrivate);
- mSystemFmpPrivate = NULL;
- return Status;
- }
- //
- // Uninstall SystemFmpProtocol instances that may have been produced by
- // the SystemFirmwareUpdate drivers in FVs dispatched by other capsules.
- //
- Status = UninstallMatchingSystemFmpProtocols ();
- if (EFI_ERROR (Status)) {
- FreePool (mSystemFmpPrivate);
- mSystemFmpPrivate = NULL;
- return Status;
- }
- //
- // 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"));
- mSystemFmpPrivate->Handle = HandleBuffer[0];
- 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;
- }
- return Status;
- }
|