summaryrefslogtreecommitdiffstats
path: root/SignedCapsulePkg
diff options
context:
space:
mode:
Diffstat (limited to 'SignedCapsulePkg')
-rw-r--r--SignedCapsulePkg/Universal/RecoveryModuleLoadPei/ParseConfigProfile.c163
-rw-r--r--SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.c806
-rw-r--r--SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.h44
-rw-r--r--SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.inf71
-rw-r--r--SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.uni21
-rw-r--r--SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPeiExtra.uni20
6 files changed, 1125 insertions, 0 deletions
diff --git a/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/ParseConfigProfile.c b/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/ParseConfigProfile.c
new file mode 100644
index 0000000000..fef1daf081
--- /dev/null
+++ b/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/ParseConfigProfile.c
@@ -0,0 +1,163 @@
+/** @file
+ Parse the INI configuration file and pass the information to the recovery driver
+ so that the driver can perform recovery accordingly.
+
+ 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 "RecoveryModuleLoadPei.h"
+#include <Library/IniParsingLib.h>
+#include <Library/PrintLib.h>
+
+#define MAX_LINE_LENGTH 512
+
+/**
+ 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] RecoveryArray Pointer to the config of recovery 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
+ParseRecoveryDataFile (
+ IN UINT8 *DataBuffer,
+ IN UINTN BufferSize,
+ IN OUT CONFIG_HEADER *ConfigHeader,
+ IN OUT RECOVERY_CONFIG_DATA **RecoveryArray
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *SectionName;
+ CHAR8 Entry[MAX_LINE_LENGTH];
+ UINTN Num;
+ UINTN Index;
+ EFI_GUID FileGuid;
+ VOID *Context;
+
+ //
+ // First process the data buffer and get all sections and entries
+ //
+ Context = OpenIniFile(DataBuffer, BufferSize);
+ if (Context == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Now get NumOfUpdate
+ //
+ Status = GetDecimalUintnFromDataFile(
+ Context,
+ "Head",
+ "NumOfRecovery",
+ &Num
+ );
+ if (EFI_ERROR(Status) || (Num == 0)) {
+ DEBUG((DEBUG_ERROR, "NumOfRecovery not found\n"));
+ CloseIniFile(Context);
+ return EFI_NOT_FOUND;
+ }
+
+ ConfigHeader->NumOfRecovery = Num;
+ *RecoveryArray = AllocateZeroPool ((sizeof (RECOVERY_CONFIG_DATA) * Num));
+ if (*RecoveryArray == NULL) {
+ CloseIniFile(Context);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Index = 0 ; Index < ConfigHeader->NumOfRecovery; Index++) {
+ //
+ // Get the section name of each update
+ //
+ AsciiStrCpyS (Entry, MAX_LINE_LENGTH, "Recovery");
+ AsciiValueToString(Entry + AsciiStrLen(Entry), 0, Index, 0);
+ Status = GetStringFromDataFile(
+ Context,
+ "Head",
+ Entry,
+ &SectionName
+ );
+ if (EFI_ERROR(Status) || (SectionName == NULL)) {
+ DEBUG((DEBUG_ERROR, "[%d] %a not found\n", Index, Entry));
+ CloseIniFile(Context);
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // The section name of this update has been found.
+ // Now looks for all the config data of this update
+ //
+
+ //
+ // FileBuid
+ //
+ Status = GetGuidFromDataFile(
+ Context,
+ SectionName,
+ "FileGuid",
+ &FileGuid
+ );
+ if (EFI_ERROR(Status)) {
+ CloseIniFile(Context);
+ DEBUG((DEBUG_ERROR, "[%d] FileGuid not found\n", Index));
+ return EFI_NOT_FOUND;
+ }
+
+ CopyGuid(&((*RecoveryArray)[Index].FileGuid), &FileGuid);
+
+ //
+ // Length
+ //
+ Status = GetHexUintnFromDataFile(
+ Context,
+ SectionName,
+ "Length",
+ &Num
+ );
+ if (EFI_ERROR(Status)) {
+ CloseIniFile(Context);
+ DEBUG((DEBUG_ERROR, "[%d] Length not found\n", Index));
+ return EFI_NOT_FOUND;
+ }
+ (*RecoveryArray)[Index].Length = Num;
+
+ //
+ // ImageOffset
+ //
+ Status = GetHexUintnFromDataFile(
+ Context,
+ SectionName,
+ "ImageOffset",
+ &Num
+ );
+ if (EFI_ERROR(Status)) {
+ CloseIniFile(Context);
+ DEBUG((DEBUG_ERROR, "[%d] ImageOffset not found\n", Index));
+ return EFI_NOT_FOUND;
+ }
+ (*RecoveryArray)[Index].ImageOffset = Num;
+ }
+
+ //
+ // Now all configuration data got. Free those temporary buffers
+ //
+ CloseIniFile(Context);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.c b/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.c
new file mode 100644
index 0000000000..58a15e4953
--- /dev/null
+++ b/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.c
@@ -0,0 +1,806 @@
+/** @file
+ Recovery module.
+
+ 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.
+
+ ProcessRecoveryCapsule(), ProcessFmpCapsuleImage(), ProcessRecoveryImage(),
+ ValidateFmpCapsule() 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.
+
+**/
+
+//
+// The package level header files this module uses
+//
+#include <Uefi.h>
+#include <PiPei.h>
+//
+// The protocols, PPI and GUID defintions for this module
+//
+#include <Ppi/MasterBootMode.h>
+#include <Ppi/BootInRecoveryMode.h>
+#include <Ppi/RecoveryModule.h>
+#include <Ppi/DeviceRecoveryModule.h>
+#include <Ppi/FirmwareVolumeInfo.h>
+#include <Guid/FirmwareFileSystem2.h>
+#include <Guid/FmpCapsule.h>
+#include <Guid/EdkiiSystemFmpCapsule.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+
+#include "RecoveryModuleLoadPei.h"
+
+/**
+ Loads a DXE capsule from some media into memory and updates the HOB table
+ with the DXE firmware volume information.
+
+ @param[in] PeiServices General-purpose services that are available to every PEIM.
+ @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
+
+ @retval EFI_SUCCESS The capsule was loaded correctly.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+LoadRecoveryCapsule (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_MODULE_PPI *This
+ );
+
+EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi = {
+ LoadRecoveryCapsule
+};
+
+EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiRecoveryModulePpiGuid,
+ &mRecoveryPpi
+};
+
+/**
+ 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] RecoveryArray Pointer to the config of recovery 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
+ParseRecoveryDataFile (
+ IN UINT8 *DataBuffer,
+ IN UINTN BufferSize,
+ IN OUT CONFIG_HEADER *ConfigHeader,
+ IN OUT RECOVERY_CONFIG_DATA **RecoveryArray
+ );
+
+/**
+ Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.
+
+ @param[in] FmpImageHeader A pointer to EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
+
+ @return TRUE It is a system FMP.
+ @return FALSE It is a device FMP.
+**/
+BOOLEAN
+IsSystemFmpImage (
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *FmpImageHeader
+ )
+{
+ GUID *Guid;
+ UINTN Count;
+ UINTN Index;
+
+ Guid = PcdGetPtr(PcdSystemFmpCapsuleImageTypeIdGuid);
+ Count = PcdGetSize(PcdSystemFmpCapsuleImageTypeIdGuid) / sizeof(GUID);
+
+ for (Index = 0; Index < Count; Index++, Guid++) {
+ if (CompareGuid(&FmpImageHeader->UpdateImageTypeId, Guid)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Return if this CapsuleGuid is a FMP capsule GUID or not.
+
+ @param[in] CapsuleGuid A pointer to EFI_GUID
+
+ @return TRUE It is a FMP capsule GUID.
+ @return FALSE It is not a FMP capsule GUID.
+**/
+BOOLEAN
+IsFmpCapsuleGuid (
+ IN EFI_GUID *CapsuleGuid
+ )
+{
+ if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ This function assumes the input Capusule image already passes basic check in
+ ValidateFmpCapsule().
+
+ Criteria of system FMP capsule is:
+ 1) FmpCapsuleHeader->EmbeddedDriverCount is 0.
+ 2) FmpCapsuleHeader->PayloadItemCount is not 0.
+ 3) All ImageHeader->UpdateImageTypeId matches PcdSystemFmpCapsuleImageTypeIdGuid.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+
+ @retval TRUE Input capsule is a correct system FMP capsule.
+ @retval FALSE Input capsule is not a correct system FMP capsule.
+**/
+BOOLEAN
+IsSystemFmpCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+ UINT64 *ItemOffsetList;
+ UINT32 ItemNum;
+ UINTN Index;
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
+
+ if (FmpCapsuleHeader->EmbeddedDriverCount != 0) {
+ return FALSE;
+ }
+
+ if (FmpCapsuleHeader->PayloadItemCount == 0) {
+ return FALSE;
+ }
+
+ ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
+
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+
+ for (Index = 0; Index < ItemNum; Index++) {
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
+ if (!IsSystemFmpImage(ImageHeader)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ 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
+ )
+{
+ if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
+ return FALSE;
+ }
+ if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ 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.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+ @param[out] IsSystemFmp If it is a system FMP.
+ @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 BOOLEAN *IsSystemFmp, OPTIONAL
+ OUT UINT16 *EmbeddedDriverCount OPTIONAL
+ )
+{
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ UINT8 *EndOfCapsule;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+ UINT8 *EndOfPayload;
+ UINT64 *ItemOffsetList;
+ UINT32 ItemNum;
+ UINTN Index;
+ UINTN FmpCapsuleSize;
+ UINTN FmpCapsuleHeaderSize;
+ UINT64 FmpImageSize;
+ UINTN FmpImageHeaderSize;
+
+ if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
+ DEBUG((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
+ EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;
+ FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;
+
+ if (FmpCapsuleSize < sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {
+ DEBUG((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
+ if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
+ DEBUG((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));
+ return EFI_INVALID_PARAMETER;
+ }
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+
+ // No overflow
+ ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
+
+ if ((FmpCapsuleSize - sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof(UINT64) < ItemNum) {
+ DEBUG((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));
+ return EFI_INVALID_PARAMETER;
+ }
+ FmpCapsuleHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof(UINT64)*ItemNum;
+
+ // Check ItemOffsetList
+ for (Index = 0; Index < ItemNum; Index++) {
+ if (ItemOffsetList[Index] >= FmpCapsuleSize) {
+ DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));
+ return EFI_INVALID_PARAMETER;
+ }
+ if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {
+ DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // All the address in ItemOffsetList must be stored in ascending order
+ //
+ if (Index > 0) {
+ if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {
+ DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index, ItemOffsetList[Index - 1]));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
+ for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
+ if (Index == ItemNum - 1) {
+ EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);
+ } else {
+ EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];
+ }
+ FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];
+
+ if (FmpImageSize < OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance)) {
+ DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize));
+ return EFI_INVALID_PARAMETER;
+ }
+ FmpImageHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);
+ if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||
+ (ImageHeader->Version < 1)) {
+ DEBUG((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));
+ return EFI_INVALID_PARAMETER;
+ }
+ if (ImageHeader->Version < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+ FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
+ }
+
+ // No overflow
+ if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {
+ DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (ItemNum == 0) {
+ //
+ // No driver & payload element in FMP
+ //
+ EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
+ if (EndOfPayload != EndOfCapsule) {
+ DEBUG((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check in system FMP capsule
+ //
+ if (IsSystemFmp != NULL) {
+ *IsSystemFmp = IsSystemFmpCapsuleImage(CapsuleHeader);
+ }
+
+ if (EmbeddedDriverCount != NULL) {
+ *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Recovery module entrypoint
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @return EFI_SUCCESS Recovery module is initialized.
+**/
+EFI_STATUS
+EFIAPI
+InitializeRecoveryModule (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ UINTN BootMode;
+
+ BootMode = GetBootModeHob();
+ ASSERT(BootMode == BOOT_IN_RECOVERY_MODE);
+
+ Status = (**PeiServices).InstallPpi (PeiServices, &mRecoveryPpiList);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Create hob and install FvInfo PPI for recovery capsule.
+
+ @param[in] FvImage Points to the DXE FV image.
+ @param[in] FvImageSize The length of the DXE FV image in bytes.
+
+ @retval EFI_SUCESS Create hob and install FvInfo PPI successfully.
+ @retval EFI_VOLUME_CORRUPTED The input data is not an FV.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to process the input data.
+**/
+EFI_STATUS
+EFIAPI
+CreateHobForRecoveryCapsule (
+ IN VOID *FvImage,
+ IN UINTN FvImageSize
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ UINT32 FvAlignment;
+ UINT64 FvLength;
+ VOID *NewFvBuffer;
+
+ //
+ // FvImage should be at its required alignment.
+ //
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage;
+ //
+ // Validate FV Header, if not as expected, return
+ //
+ if (ReadUnaligned32 (&FvHeader->Signature) != EFI_FVH_SIGNATURE) {
+ DEBUG((DEBUG_ERROR, "CreateHobForRecoveryCapsule (Fv Signature Error)\n"));
+ return EFI_VOLUME_CORRUPTED;
+ }
+ //
+ // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
+ // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
+ // its initial linked location and maintain its alignment.
+ //
+ if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
+ //
+ // Get FvHeader alignment
+ //
+ FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);
+ //
+ // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
+ //
+ if (FvAlignment < 8) {
+ FvAlignment = 8;
+ }
+ //
+ // Allocate the aligned buffer for the FvImage.
+ //
+ if ((UINTN) FvHeader % FvAlignment != 0) {
+ DEBUG((DEBUG_INFO, "CreateHobForRecoveryCapsule (FvHeader 0x%lx is not aligned)\n", (UINT64)(UINTN)FvHeader));
+ FvLength = ReadUnaligned64 (&FvHeader->FvLength);
+ NewFvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN) FvLength), FvAlignment);
+ if (NewFvBuffer == NULL) {
+ DEBUG((DEBUG_ERROR, "CreateHobForRecoveryCapsule (Not enough resource to allocate 0x%lx bytes)\n", FvLength));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (NewFvBuffer, FvHeader, (UINTN) FvLength);
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) NewFvBuffer;
+ }
+ }
+
+ BuildFvHob((UINT64)(UINTN)FvHeader, FvHeader->FvLength);
+ DEBUG((DEBUG_INFO, "BuildFvHob (FV in recovery) - 0x%lx - 0x%lx\n", (UINT64)(UINTN)FvHeader, FvHeader->FvLength));
+
+ PeiServicesInstallFvInfoPpi(
+ NULL,
+ (VOID *)FvHeader,
+ (UINT32)FvHeader->FvLength,
+ NULL,
+ NULL
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create recovery context based upon System Firmware image and config file.
+
+ @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.
+
+ @retval EFI_SUCESS Process Recovery Image successfully.
+**/
+EFI_STATUS
+RecoverImage (
+ IN VOID *SystemFirmwareImage,
+ IN UINTN SystemFirmwareImageSize,
+ IN VOID *ConfigImage,
+ IN UINTN ConfigImageSize
+ )
+{
+ EFI_STATUS Status;
+ RECOVERY_CONFIG_DATA *ConfigData;
+ RECOVERY_CONFIG_DATA *RecoveryConfigData;
+ CONFIG_HEADER ConfigHeader;
+ UINTN Index;
+
+ if (ConfigImage == NULL) {
+ DEBUG((DEBUG_INFO, "RecoverImage (NoConfig)\n"));
+ Status = CreateHobForRecoveryCapsule(
+ SystemFirmwareImage,
+ SystemFirmwareImageSize
+ );
+ return Status;
+ }
+
+ ConfigData = NULL;
+ ZeroMem (&ConfigHeader, sizeof(ConfigHeader));
+ Status = ParseRecoveryDataFile (
+ ConfigImage,
+ ConfigImageSize,
+ &ConfigHeader,
+ &ConfigData
+ );
+ DEBUG((DEBUG_INFO, "ParseRecoveryDataFile - %r\n", Status));
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ DEBUG((DEBUG_INFO, "ConfigHeader.NumOfRecovery - 0x%x\n", ConfigHeader.NumOfRecovery));
+ DEBUG((DEBUG_INFO, "PcdEdkiiSystemFirmwareFileGuid - %g\n", PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid)));
+
+ Index = 0;
+ RecoveryConfigData = ConfigData;
+ while (Index < ConfigHeader.NumOfRecovery) {
+ if (CompareGuid(&RecoveryConfigData->FileGuid, PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid))) {
+ DEBUG((DEBUG_INFO, "FileGuid - %g (processing)\n", &RecoveryConfigData->FileGuid));
+ Status = CreateHobForRecoveryCapsule (
+ (UINT8 *)SystemFirmwareImage + RecoveryConfigData->ImageOffset,
+ RecoveryConfigData->Length
+ );
+ //
+ // Shall updates be serialized so that if a recovery FV is not successfully completed,
+ // the remaining updates won't be performed.
+ //
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ } else {
+ DEBUG((DEBUG_INFO, "FileGuid - %g (ignored)\n", &RecoveryConfigData->FileGuid));
+ }
+
+ Index++;
+ RecoveryConfigData++;
+ }
+
+ return Status;
+}
+
+/**
+ Process recovery image.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] Image Points to the recovery image.
+ @param[in] Length The length of the recovery image in bytes.
+
+ @retval EFI_SUCESS Process Recovery Image successfully.
+ @retval EFI_SECURITY_VIOLATION Recovery image is not processed due to security violation.
+**/
+EFI_STATUS
+ProcessRecoveryImage (
+ IN VOID *Image,
+ IN UINTN Length
+ )
+{
+ UINT32 LastAttemptVersion;
+ UINT32 LastAttemptStatus;
+ EFI_STATUS Status;
+ VOID *SystemFirmwareImage;
+ UINTN SystemFirmwareImageSize;
+ VOID *ConfigImage;
+ UINTN ConfigImageSize;
+ VOID *AuthenticatedImage;
+ UINTN AuthenticatedImageSize;
+
+ Status = CapsuleAuthenticateSystemFirmware(Image, Length, TRUE, &LastAttemptVersion, &LastAttemptStatus, &AuthenticatedImage, &AuthenticatedImageSize);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_INFO, "CapsuleAuthenticateSystemFirmware - %r\n", Status));
+ return Status;
+ }
+
+ ExtractSystemFirmwareImage(AuthenticatedImage, AuthenticatedImageSize, &SystemFirmwareImage, &SystemFirmwareImageSize);
+ ExtractConfigImage(AuthenticatedImage, AuthenticatedImageSize, &ConfigImage, &ConfigImageSize);
+
+ Status = RecoverImage(SystemFirmwareImage, SystemFirmwareImageSize, ConfigImage, ConfigImageSize);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_INFO, "RecoverImage - %r\n", Status));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Process Firmware management protocol data capsule.
+
+ Caution: This function may receive untrusted input.
+
+ This function assumes the caller validated the capsule by using
+ ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+ @param[in] IsSystemFmp If this capsule is a system FMP capsule.
+
+ @retval EFI_SUCESS Process Capsule Image successfully.
+ @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
+ @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory.
+**/
+EFI_STATUS
+ProcessFmpCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN BOOLEAN IsSystemFmp
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+ UINT8 *Image;
+ UINT64 *ItemOffsetList;
+ UINTN ItemIndex;
+
+ if (!IsSystemFmp) {
+ return EFI_UNSUPPORTED;
+ }
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+
+ for (ItemIndex = 0; ItemIndex < FmpCapsuleHeader->PayloadItemCount; ItemIndex++) {
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemIndex]);
+ if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+ Image = (UINT8 *)(ImageHeader + 1);
+ } else {
+ //
+ // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, only match ImageTypeId.
+ // Header should exclude UpdateHardwareInstance field
+ //
+ Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
+ }
+
+ Status = ProcessRecoveryImage (Image, ImageHeader->UpdateImageSize);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Process recovery capsule image.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] CapsuleBuffer The capsule image buffer.
+ @param[in] CapsuleSize The size of the capsule image in bytes.
+
+ @retval EFI_SUCCESS The recovery capsule is processed.
+ @retval EFI_SECURITY_VIOLATION The recovery capsule is not process because of security violation.
+ @retval EFI_NOT_FOUND The recovery capsule is not process because of unrecognization.
+**/
+EFI_STATUS
+EFIAPI
+ProcessRecoveryCapsule (
+ IN VOID *CapsuleBuffer,
+ IN UINTN CapsuleSize
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN IsSystemFmp;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+
+ CapsuleHeader = CapsuleBuffer;
+ if (!IsValidCapsuleHeader (CapsuleHeader, CapsuleSize)) {
+ DEBUG((DEBUG_ERROR, "CapsuleImageSize incorrect\n"));
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // Check FMP capsule layout
+ //
+ if (IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {
+ DEBUG((DEBUG_INFO, "CreateHobForRecoveryCapsule\n"));
+
+ DEBUG((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));
+ DEBUG((DEBUG_INFO, "ValidateFmpCapsule ...\n"));
+ Status = ValidateFmpCapsule(CapsuleHeader, &IsSystemFmp, NULL);
+ DEBUG((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Press EFI FMP Capsule
+ //
+ DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
+ Status = ProcessFmpCapsuleImage(CapsuleHeader, IsSystemFmp);
+ DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
+
+ DEBUG((DEBUG_INFO, "CreateHobForRecoveryCapsule Done\n"));
+ return Status;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Loads a DXE capsule from some media into memory and updates the HOB table
+ with the DXE firmware volume information.
+
+ @param[in] PeiServices General-purpose services that are available to every PEIM.
+ @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
+
+ @retval EFI_SUCCESS The capsule was loaded correctly.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+LoadRecoveryCapsule (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_MODULE_PPI *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *DeviceRecoveryPpi;
+ UINTN NumberRecoveryCapsules;
+ UINTN Instance;
+ UINTN CapsuleInstance;
+ UINTN CapsuleSize;
+ EFI_GUID CapsuleType;
+ VOID *CapsuleBuffer;
+
+ DEBUG((DEBUG_INFO | DEBUG_LOAD, "Recovery Entry\n"));
+
+ for (Instance = 0; ; Instance++) {
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiDeviceRecoveryModulePpiGuid,
+ Instance,
+ NULL,
+ (VOID **)&DeviceRecoveryPpi
+ );
+ DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - LocateRecoveryPpi (%d) - %r\n", Instance, Status));
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ NumberRecoveryCapsules = 0;
+ Status = DeviceRecoveryPpi->GetNumberRecoveryCapsules (
+ (EFI_PEI_SERVICES **)PeiServices,
+ DeviceRecoveryPpi,
+ &NumberRecoveryCapsules
+ );
+ DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - GetNumberRecoveryCapsules (%d) - %r\n", NumberRecoveryCapsules, Status));
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ for (CapsuleInstance = 1; CapsuleInstance <= NumberRecoveryCapsules; CapsuleInstance++) {
+ CapsuleSize = 0;
+ Status = DeviceRecoveryPpi->GetRecoveryCapsuleInfo (
+ (EFI_PEI_SERVICES **)PeiServices,
+ DeviceRecoveryPpi,
+ FeaturePcdGet(PcdFrameworkCompatibilitySupport) ? CapsuleInstance - 1 : CapsuleInstance,
+ &CapsuleSize,
+ &CapsuleType
+ );
+ DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - GetRecoveryCapsuleInfo (%d - %x) - %r\n", CapsuleInstance, CapsuleSize, Status));
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ CapsuleBuffer = AllocatePages (EFI_SIZE_TO_PAGES(CapsuleSize));
+ if (CapsuleBuffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - AllocatePool fail\n"));
+ continue;
+ }
+ Status = DeviceRecoveryPpi->LoadRecoveryCapsule (
+ (EFI_PEI_SERVICES **)PeiServices,
+ DeviceRecoveryPpi,
+ FeaturePcdGet(PcdFrameworkCompatibilitySupport) ? CapsuleInstance - 1 : CapsuleInstance,
+ CapsuleBuffer
+ );
+ DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance, Status));
+ if (EFI_ERROR (Status)) {
+ FreePages (CapsuleBuffer, EFI_SIZE_TO_PAGES(CapsuleSize));
+ break;
+ }
+ //
+ // good, load capsule buffer
+ //
+ Status = ProcessRecoveryCapsule (CapsuleBuffer, CapsuleSize);
+ return Status;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
diff --git a/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.h b/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.h
new file mode 100644
index 0000000000..ce3a35f0f9
--- /dev/null
+++ b/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.h
@@ -0,0 +1,44 @@
+/** @file
+ Recovery module header file.
+
+ 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.
+
+**/
+
+#ifndef _RECOVERY_MODULE_LOAD_PEI_H_
+#define _RECOVERY_MODULE_LOAD_PEI_H_
+
+#include <PiPei.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/EdkiiSystemCapsuleLib.h>
+
+//
+// Update data
+//
+
+typedef struct {
+ UINTN NumOfRecovery;
+} CONFIG_HEADER;
+
+typedef struct {
+ UINTN Index;
+ EFI_GUID FileGuid;
+ UINTN Length;
+ UINTN ImageOffset;
+} RECOVERY_CONFIG_DATA;
+
+#endif
+
diff --git a/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.inf b/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.inf
new file mode 100644
index 0000000000..563be18821
--- /dev/null
+++ b/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.inf
@@ -0,0 +1,71 @@
+## @file
+# Recovery module.
+#
+# Load Recovery capsule and install FV.
+#
+# 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 = RecoveryModuleLoadPei
+ MODULE_UNI_FILE = RecoveryModuleLoadPei.uni
+ FILE_GUID = 4278A574-4769-4D60-B090-DD4916691590
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeRecoveryModule
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ RecoveryModuleLoadPei.c
+ ParseConfigProfile.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SignedCapsulePkg/SignedCapsulePkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ DebugLib
+ HobLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ EdkiiSystemCapsuleLib
+ IniParsingLib
+ PrintLib
+
+[Ppis]
+ gEfiPeiRecoveryModulePpiGuid ## PRODUCES
+ gEfiPeiDeviceRecoveryModulePpiGuid ## CONSUMES
+
+[Guids]
+ gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSystemFmpCapsuleImageTypeIdGuid ## CONSUMES
+ gEfiSignedCapsulePkgTokenSpaceGuid.PcdEdkiiSystemFirmwareFileGuid ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES
+
+[depex]
+ gEfiPeiBootInRecoveryModePpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ RecoveryModuleLoadPeiExtra.uni
+
diff --git a/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.uni b/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.uni
new file mode 100644
index 0000000000..44e6cdc99f
--- /dev/null
+++ b/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Recovery module.
+//
+// Load Recovery capsule and install FV.
+//
+// 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 "Recovery module."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Load Recovery capsule and install FV."
diff --git a/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPeiExtra.uni b/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPeiExtra.uni
new file mode 100644
index 0000000000..56057c6b40
--- /dev/null
+++ b/SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPeiExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// RecoveryModuleLoadPei Localized Strings and Content
+//
+// 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_PROPERTIES_MODULE_NAME
+#language en-US
+"RecoveryModuleLoad PEI Driver"
+
+