+/** @file\r
+ SetImage instance to update system firmware.\r
+\r
+ Caution: This module requires additional review when modified.\r
+ This module will have external input - capsule image.\r
+ This external input must be validated carefully to avoid security issue like\r
+ buffer overflow, integer overflow.\r
+\r
+ FmpSetImage() will receive untrusted input and do basic validation.\r
+\r
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SystemFirmwareDxe.h"\r
+\r
+//\r
+// SystemFmp driver private data\r
+//\r
+SYSTEM_FMP_PRIVATE_DATA *mSystemFmpPrivate = NULL;\r
+\r
+EFI_GUID mCurrentImageTypeId;\r
+\r
+BOOLEAN mNvRamUpdated = FALSE;\r
+\r
+/**\r
+ Parse Config data file to get the updated data array.\r
+\r
+ @param[in] DataBuffer Config raw file buffer.\r
+ @param[in] BufferSize Size of raw buffer.\r
+ @param[in, out] ConfigHeader Pointer to the config header.\r
+ @param[in, out] UpdateArray Pointer to the config of update data.\r
+\r
+ @retval EFI_NOT_FOUND No config data is found.\r
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.\r
+ @retval EFI_SUCCESS Parse the config file successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ParseUpdateDataFile (\r
+ IN UINT8 *DataBuffer,\r
+ IN UINTN BufferSize,\r
+ IN OUT CONFIG_HEADER *ConfigHeader,\r
+ IN OUT UPDATE_CONFIG_DATA **UpdateArray\r
+ );\r
+\r
+/**\r
+ Update System Firmware image component.\r
+\r
+ @param[in] SystemFirmwareImage Points to the System Firmware image.\r
+ @param[in] SystemFirmwareImageSize The length of the System Firmware image in bytes.\r
+ @param[in] ConfigData Points to the component configuration structure.\r
+ @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+ @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+\r
+ @retval EFI_SUCCESS The System Firmware image is updated.\r
+ @retval EFI_WRITE_PROTECTED The flash device is read only.\r
+**/\r
+EFI_STATUS\r
+PerformUpdate (\r
+ IN VOID *SystemFirmwareImage,\r
+ IN UINTN SystemFirmwareImageSize,\r
+ IN UPDATE_CONFIG_DATA *ConfigData,\r
+ OUT UINT32 *LastAttemptVersion,\r
+ OUT UINT32 *LastAttemptStatus\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ DEBUG((DEBUG_INFO, "PlatformUpdate:"));\r
+ DEBUG((DEBUG_INFO, " BaseAddress - 0x%lx,", ConfigData->BaseAddress));\r
+ DEBUG((DEBUG_INFO, " ImageOffset - 0x%x,", ConfigData->ImageOffset));\r
+ DEBUG((DEBUG_INFO, " Legnth - 0x%x\n", ConfigData->Length));\r
+ Status = PerformFlashWrite (\r
+ ConfigData->FirmwareType,\r
+ ConfigData->BaseAddress,\r
+ ConfigData->AddressType,\r
+ (VOID *)((UINTN)SystemFirmwareImage + (UINTN)ConfigData->ImageOffset),\r
+ ConfigData->Length\r
+ );\r
+ if (!EFI_ERROR(Status)) {\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
+ if (ConfigData->FirmwareType == PlatformFirmwareTypeNvRam) {\r
+ mNvRamUpdated = TRUE;\r
+ }\r
+ } else {\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Update System Firmware image.\r
+\r
+ @param[in] SystemFirmwareImage Points to the System Firmware image.\r
+ @param[in] SystemFirmwareImageSize The length of the System Firmware image in bytes.\r
+ @param[in] ConfigImage Points to the config file image.\r
+ @param[in] ConfigImageSize The length of the config file image in bytes.\r
+ @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+ @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+\r
+ @retval EFI_SUCCESS The System Firmware image is updated.\r
+ @retval EFI_WRITE_PROTECTED The flash device is read only.\r
+**/\r
+EFI_STATUS\r
+UpdateImage (\r
+ IN VOID *SystemFirmwareImage,\r
+ IN UINTN SystemFirmwareImageSize,\r
+ IN VOID *ConfigImage,\r
+ IN UINTN ConfigImageSize,\r
+ OUT UINT32 *LastAttemptVersion,\r
+ OUT UINT32 *LastAttemptStatus\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UPDATE_CONFIG_DATA *ConfigData;\r
+ UPDATE_CONFIG_DATA *UpdateConfigData;\r
+ CONFIG_HEADER ConfigHeader;\r
+ UINTN Index;\r
+\r
+ if (ConfigImage == NULL) {\r
+ DEBUG((DEBUG_INFO, "PlatformUpdate (NoConfig):"));\r
+ DEBUG((DEBUG_INFO, " BaseAddress - 0x%x,", 0));\r
+ DEBUG((DEBUG_INFO, " Length - 0x%x\n", SystemFirmwareImageSize));\r
+ // ASSUME the whole System Firmware include NVRAM region.\r
+ Status = PerformFlashWrite (\r
+ PlatformFirmwareTypeNvRam,\r
+ 0,\r
+ FlashAddressTypeRelativeAddress,\r
+ SystemFirmwareImage,\r
+ SystemFirmwareImageSize\r
+ );\r
+ if (!EFI_ERROR(Status)) {\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
+ mNvRamUpdated = TRUE;\r
+ } else {\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+ }\r
+ return Status;\r
+ }\r
+\r
+ DEBUG((DEBUG_INFO, "PlatformUpdate (With Config):\n"));\r
+ ConfigData = NULL;\r
+ ZeroMem (&ConfigHeader, sizeof(ConfigHeader));\r
+ Status = ParseUpdateDataFile (\r
+ ConfigImage,\r
+ ConfigImageSize,\r
+ &ConfigHeader,\r
+ &ConfigData\r
+ );\r
+ DEBUG((DEBUG_INFO, "ParseUpdateDataFile - %r\n", Status));\r
+ if (EFI_ERROR(Status)) {\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ DEBUG((DEBUG_INFO, "ConfigHeader.NumOfUpdates - 0x%x\n", ConfigHeader.NumOfUpdates));\r
+ DEBUG((DEBUG_INFO, "PcdEdkiiSystemFirmwareFileGuid - %g\n", PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid)));\r
+\r
+ Index = 0;\r
+ UpdateConfigData = ConfigData;\r
+ while (Index < ConfigHeader.NumOfUpdates) {\r
+ if (CompareGuid(&UpdateConfigData->FileGuid, PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid))) {\r
+ DEBUG((DEBUG_INFO, "FileGuid - %g (processing)\n", &UpdateConfigData->FileGuid));\r
+ Status = PerformUpdate (\r
+ SystemFirmwareImage,\r
+ SystemFirmwareImageSize,\r
+ UpdateConfigData,\r
+ LastAttemptVersion,\r
+ LastAttemptStatus\r
+ );\r
+ //\r
+ // Shall updates be serialized so that if an update is not successfully completed,\r
+ // the remaining updates won't be performed.\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ } else {\r
+ DEBUG((DEBUG_INFO, "FileGuid - %g (ignored)\n", &UpdateConfigData->FileGuid));\r
+ }\r
+\r
+ Index++;\r
+ UpdateConfigData++;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Authenticate and update System Firmware image.\r
+\r
+ Caution: This function may receive untrusted input.\r
+\r
+ @param[in] Image The EDKII system FMP capsule image.\r
+ @param[in] ImageSize The size of the EDKII system FMP capsule image in bytes.\r
+ @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+ @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+\r
+ @retval EFI_SUCCESS EDKII system FMP capsule passes authentication and the System Firmware image is updated.\r
+ @retval EFI_SECURITY_VIOLATION EDKII system FMP capsule fails authentication and the System Firmware image is not updated.\r
+ @retval EFI_WRITE_PROTECTED The flash device is read only.\r
+**/\r
+EFI_STATUS\r
+SystemFirmwareAuthenticatedUpdate (\r
+ IN VOID *Image,\r
+ IN UINTN ImageSize,\r
+ OUT UINT32 *LastAttemptVersion,\r
+ OUT UINT32 *LastAttemptStatus\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *SystemFirmwareImage;\r
+ UINTN SystemFirmwareImageSize;\r
+ VOID *ConfigImage;\r
+ UINTN ConfigImageSize;\r
+ VOID *AuthenticatedImage;\r
+ UINTN AuthenticatedImageSize;\r
+\r
+ DEBUG((DEBUG_INFO, "SystemFirmwareAuthenticatedUpdate...\n"));\r
+\r
+ Status = CapsuleAuthenticateSystemFirmware(Image, ImageSize, FALSE, LastAttemptVersion, LastAttemptStatus, &AuthenticatedImage, &AuthenticatedImageSize);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG((DEBUG_INFO, "SystemFirmwareAuthenticateImage - %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ DEBUG((DEBUG_INFO, "ExtractSystemFirmwareImage ...\n"));\r
+ ExtractSystemFirmwareImage(AuthenticatedImage, AuthenticatedImageSize, &SystemFirmwareImage, &SystemFirmwareImageSize);\r
+ DEBUG((DEBUG_INFO, "ExtractConfigImage ...\n"));\r
+ ExtractConfigImage(AuthenticatedImage, AuthenticatedImageSize, &ConfigImage, &ConfigImageSize);\r
+\r
+ DEBUG((DEBUG_INFO, "UpdateImage ...\n"));\r
+ Status = UpdateImage(SystemFirmwareImage, SystemFirmwareImageSize, ConfigImage, ConfigImageSize, LastAttemptVersion, LastAttemptStatus);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG((DEBUG_INFO, "UpdateImage - %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ DEBUG((DEBUG_INFO, "SystemFirmwareAuthenticatedUpdate Done\n"));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ This code finds variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+ @param[in] VariableName Name of Variable to be found.\r
+ @param[in] VendorGuid Variable vendor GUID.\r
+ @param[out] Attributes Attribute value of the variable found.\r
+ @param[in, out] DataSize Size of Data found. If size is less than the\r
+ data, this value contains the required size.\r
+ @param[out] Data Data pointer.\r
+\r
+ @return EFI_INVALID_PARAMETER Invalid parameter.\r
+ @return EFI_SUCCESS Find the specified variable.\r
+ @return EFI_NOT_FOUND Not found.\r
+ @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetVariableHook (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ OUT UINT32 *Attributes OPTIONAL,\r
+ IN OUT UINTN *DataSize,\r
+ OUT VOID *Data\r
+ )\r
+{\r
+ DEBUG((DEBUG_INFO, "GetVariableHook - %S, %g\n", VariableName, VendorGuid));\r
+ return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+\r
+ This code Finds the Next available variable.\r
+\r
+ @param[in, out] VariableNameSize Size of the variable name.\r
+ @param[in, out] VariableName Pointer to variable name.\r
+ @param[in, out] VendorGuid Variable Vendor Guid.\r
+\r
+ @return EFI_INVALID_PARAMETER Invalid parameter.\r
+ @return EFI_SUCCESS Find the specified variable.\r
+ @return EFI_NOT_FOUND Not found.\r
+ @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNextVariableNameHook (\r
+ IN OUT UINTN *VariableNameSize,\r
+ IN OUT CHAR16 *VariableName,\r
+ IN OUT EFI_GUID *VendorGuid\r
+ )\r
+{\r
+ DEBUG((DEBUG_INFO, "GetNextVariableNameHook - %S, %g\n", VariableName, VendorGuid));\r
+ return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+\r
+ This code sets variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+ @param[in] VariableName Name of Variable to be found.\r
+ @param[in] VendorGuid Variable vendor GUID.\r
+ @param[in] Attributes Attribute value of the variable found\r
+ @param[in] DataSize Size of Data found. If size is less than the\r
+ data, this value contains the required size.\r
+ @param[in] Data Data pointer.\r
+\r
+ @return EFI_INVALID_PARAMETER Invalid parameter.\r
+ @return EFI_SUCCESS Set successfully.\r
+ @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.\r
+ @return EFI_NOT_FOUND Not found.\r
+ @return EFI_WRITE_PROTECTED Variable is read-only.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetVariableHook (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN UINT32 Attributes,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
+ )\r
+{\r
+ DEBUG((DEBUG_INFO, "SetVariableHook - %S, %g, 0x%x (0x%x)\n", VariableName, VendorGuid, Attributes, DataSize));\r
+ return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+\r
+ This code returns information about the EFI variables.\r
+\r
+ @param[in] Attributes Attributes bitmask to specify the type of variables\r
+ on which to return information.\r
+ @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
+ for the EFI variables associated with the attributes specified.\r
+ @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
+ for EFI variables associated with the attributes specified.\r
+ @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
+ associated with the attributes specified.\r
+\r
+ @return EFI_SUCCESS Query successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+QueryVariableInfoHook (\r
+ IN UINT32 Attributes,\r
+ OUT UINT64 *MaximumVariableStorageSize,\r
+ OUT UINT64 *RemainingVariableStorageSize,\r
+ OUT UINT64 *MaximumVariableSize\r
+ )\r
+{\r
+ DEBUG((DEBUG_INFO, "QueryVariableInfoHook - 0x%x\n", Attributes));\r
+ return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+ Updates the firmware image of the device.\r
+\r
+ This function updates the hardware with the new firmware image.\r
+ This function returns EFI_UNSUPPORTED if the firmware image is not updatable.\r
+ If the firmware image is updatable, the function should perform the following minimal validations\r
+ before proceeding to do the firmware image update.\r
+ - Validate the image authentication if image has attribute\r
+ IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED. The function returns\r
+ EFI_SECURITY_VIOLATION if the validation fails.\r
+ - Validate the image is a supported image for this device. The function returns EFI_ABORTED if\r
+ the image is unsupported. The function can optionally provide more detailed information on\r
+ why the image is not a supported image.\r
+ - Validate the data from VendorCode if not null. Image validation must be performed before\r
+ VendorCode data validation. VendorCode data is ignored or considered invalid if image\r
+ validation failed. The function returns EFI_ABORTED if the data is invalid.\r
+\r
+ VendorCode enables vendor to implement vendor-specific firmware image update policy. Null if\r
+ the caller did not specify the policy or use the default policy. As an example, vendor can implement\r
+ a policy to allow an option to force a firmware image update when the abort reason is due to the new\r
+ firmware image version is older than the current firmware image version or bad image checksum.\r
+ Sensitive operations such as those wiping the entire firmware image and render the device to be\r
+ non-functional should be encoded in the image itself rather than passed with the VendorCode.\r
+ AbortReason enables vendor to have the option to provide a more detailed description of the abort\r
+ reason to the caller.\r
+\r
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.\r
+ @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.\r
+ The number is between 1 and DescriptorCount.\r
+ @param[in] Image Points to the new image.\r
+ @param[in] ImageSize Size of the new image in bytes.\r
+ @param[in] VendorCode This enables vendor to implement vendor-specific firmware image update policy.\r
+ Null indicates the caller did not specify the policy or use the default policy.\r
+ @param[in] Progress A function used by the driver to report the progress of the firmware update.\r
+ @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more\r
+ details for the aborted operation. The buffer is allocated by this function\r
+ with AllocatePool(), and it is the caller's responsibility to free it with a\r
+ call to FreePool().\r
+\r
+ @retval EFI_SUCCESS The device was successfully updated with the new image.\r
+ @retval EFI_ABORTED The operation is aborted.\r
+ @retval EFI_INVALID_PARAMETER The Image was NULL.\r
+ @retval EFI_UNSUPPORTED The operation is not supported.\r
+ @retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FmpSetImage (\r
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,\r
+ IN UINT8 ImageIndex,\r
+ IN CONST VOID *Image,\r
+ IN UINTN ImageSize,\r
+ IN CONST VOID *VendorCode,\r
+ IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,\r
+ OUT CHAR16 **AbortReason\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STATUS VarStatus;\r
+ SYSTEM_FMP_PRIVATE_DATA *SystemFmpPrivate;\r
+\r
+ if (Image == NULL || ImageSize == 0 || AbortReason == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ SystemFmpPrivate = SYSTEM_FMP_PRIVATE_DATA_FROM_FMP(This);\r
+ *AbortReason = NULL;\r
+\r
+ if (ImageIndex == 0 || ImageIndex > SystemFmpPrivate->DescriptorCount) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = SystemFirmwareAuthenticatedUpdate((VOID *)Image, ImageSize, &SystemFmpPrivate->LastAttempt.LastAttemptVersion, &SystemFmpPrivate->LastAttempt.LastAttemptStatus);\r
+ DEBUG((DEBUG_INFO, "SetImage - LastAttemp Version - 0x%x, State - 0x%x\n", SystemFmpPrivate->LastAttempt.LastAttemptVersion, SystemFmpPrivate->LastAttempt.LastAttemptStatus));\r
+\r
+ //\r
+ // If NVRAM is updated, we should no longer touch variable services, because\r
+ // the current variable driver may not manage the new NVRAM region.\r
+ //\r
+ if (mNvRamUpdated) {\r
+ DEBUG ((DEBUG_INFO, "NvRamUpdated, Update Variable Serivces\n"));\r
+ gRT->GetVariable = GetVariableHook;\r
+ gRT->GetNextVariableName = GetNextVariableNameHook;\r
+ gRT->SetVariable = SetVariableHook;\r
+ gRT->QueryVariableInfo = QueryVariableInfoHook;\r
+\r
+ gRT->Hdr.CRC32 = 0;\r
+ gBS->CalculateCrc32 (\r
+ (UINT8 *) &gRT->Hdr,\r
+ gRT->Hdr.HeaderSize,\r
+ &gRT->Hdr.CRC32\r
+ );\r
+ }\r
+\r
+ VarStatus = gRT->SetVariable(\r
+ SYSTEM_FMP_LAST_ATTEMPT_VARIABLE_NAME,\r
+ &gSystemFmpLastAttemptVariableGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ sizeof(SystemFmpPrivate->LastAttempt),\r
+ &SystemFmpPrivate->LastAttempt\r
+ );\r
+ DEBUG((DEBUG_INFO, "SetLastAttemp - %r\n", VarStatus));\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ System FMP module entrypoint\r
+\r
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param SystemTable A pointer to the EFI System Table.\r
+\r
+ @return EFI_SUCCESS System FMP module is initialized.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SystemFirmwareUpdateMainDxe (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Initialize SystemFmpPrivateData\r
+ //\r
+ mSystemFmpPrivate = AllocateZeroPool (sizeof(SYSTEM_FMP_PRIVATE_DATA));\r
+ if (mSystemFmpPrivate == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = InitializePrivateData(mSystemFmpPrivate);\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool(mSystemFmpPrivate);\r
+ mSystemFmpPrivate = NULL;\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Install FMP protocol.\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mSystemFmpPrivate->Handle,\r
+ &gEfiFirmwareManagementProtocolGuid,\r
+ &mSystemFmpPrivate->Fmp,\r
+ &gSystemFmpProtocolGuid,\r
+ &mSystemFmpPrivate->Fmp,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool(mSystemFmpPrivate);\r
+ mSystemFmpPrivate = NULL;\r
+ return Status;\r
+ }\r
+\r
+ return Status;\r
+}\r