--- /dev/null
+/** @file\r
+Install Platform EFI_PEI_RECOVERY_MODULE_PPI and Implementation of\r
+EFI_PEI_LOAD_RECOVERY_CAPSULE service.\r
+\r
+Copyright (c) 2013 Intel Corporation.\r
+\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 "CommonHeader.h"\r
+#include "PlatformEarlyInit.h"\r
+\r
+#include <Ppi/BlockIo.h>\r
+\r
+//\r
+// Capsule Types supported in this platform module\r
+//\r
+#include <Guid/CapsuleOnFatFloppyDisk.h>\r
+#include <Guid/CapsuleOnFatIdeDisk.h>\r
+#include <Guid/CapsuleOnFatUsbDisk.h>\r
+#include <Guid/CapsuleOnDataCD.h>\r
+#include <Guid/QuarkCapsuleGuid.h>\r
+\r
+#include <Ppi/RecoveryModule.h>\r
+#include <Ppi/DeviceRecoveryModule.h>\r
+\r
+#include <Library/PeiServicesLib.h>\r
+\r
+//\r
+// Required Service\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+PlatformRecoveryModule (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_MODULE_PPI *This\r
+ );\r
+\r
+VOID\r
+AssertNoCapsulesError (\r
+ IN EFI_PEI_SERVICES **PeiServices\r
+ );\r
+\r
+VOID\r
+AssertMediaDeviceError (\r
+ IN EFI_PEI_SERVICES **PeiServices\r
+ );\r
+\r
+VOID\r
+ReportLoadCapsuleSuccess (\r
+ IN EFI_PEI_SERVICES **PeiServices\r
+ );\r
+\r
+VOID\r
+CheckIfMediaPresentOnBlockIoDevice (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN OUT BOOLEAN *MediaDeviceError,\r
+ IN OUT BOOLEAN *MediaPresent\r
+ );\r
+\r
+//\r
+// Module globals\r
+//\r
+EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi = { PlatformRecoveryModule };\r
+\r
+EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList = {\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gEfiPeiRecoveryModulePpiGuid,\r
+ &mRecoveryPpi\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PeimInitializeRecovery (\r
+ IN EFI_PEI_SERVICES **PeiServices\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Provide the functionality of the Recovery Module.\r
+\r
+Arguments:\r
+\r
+ PeiServices - General purpose services available to every PEIM.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - If the interface could be successfully\r
+ installed.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = PeiServicesInstallPpi (&mRecoveryPpiList);\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PlatformRecoveryModule (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_MODULE_PPI *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Provide the functionality of the Platform Recovery Module.\r
+\r
+Arguments:\r
+\r
+ PeiServices - General purpose services available to every PEIM.\r
+ This - Pointer to EFI_PEI_RECOVERY_MODULE_PPI.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - If the interface could be successfully\r
+ installed.\r
+ EFI_UNSUPPORTED - Not supported.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *DeviceRecoveryModule;\r
+ UINTN NumberOfImageProviders;\r
+ BOOLEAN ProviderAvailable;\r
+ UINTN NumberRecoveryCapsules;\r
+ UINTN RecoveryCapsuleSize;\r
+ EFI_GUID DeviceId;\r
+ BOOLEAN ImageFound;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+ VOID *Buffer;\r
+ EFI_CAPSULE_HEADER *CapsuleHeader;\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ EFI_PEI_HOB_POINTERS HobOld;\r
+ BOOLEAN HobUpdate;\r
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
+ UINTN Index;\r
+ EFI_STATUS AuthStatus;\r
+ EFI_GUID mEfiCapsuleHeaderGuid = QUARK_CAPSULE_GUID;\r
+\r
+ Index = 0;\r
+\r
+ Status = EFI_SUCCESS;\r
+ AuthStatus = EFI_SUCCESS;\r
+ HobUpdate = FALSE;\r
+\r
+ ProviderAvailable = TRUE;\r
+ ImageFound = FALSE;\r
+ NumberOfImageProviders = 0;\r
+\r
+ DeviceRecoveryModule = NULL;\r
+\r
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Entry\n"));\r
+\r
+ //\r
+ // Search the platform for some recovery capsule if the DXE IPL\r
+ // discovered a recovery condition and has requested a load.\r
+ //\r
+ while (ProviderAvailable) {\r
+\r
+ Status = PeiServicesLocatePpi (\r
+ &gEfiPeiDeviceRecoveryModulePpiGuid,\r
+ Index,\r
+ NULL,\r
+ (VOID **)&DeviceRecoveryModule\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Device Recovery PPI located\n"));\r
+ NumberOfImageProviders++;\r
+\r
+ Status = DeviceRecoveryModule->GetNumberRecoveryCapsules (\r
+ PeiServices,\r
+ DeviceRecoveryModule,\r
+ &NumberRecoveryCapsules\r
+ );\r
+\r
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Number Of Recovery Capsules: %d\n", NumberRecoveryCapsules));\r
+\r
+ if (NumberRecoveryCapsules == 0) {\r
+ Index++;\r
+ } else {\r
+ break;\r
+ }\r
+ } else {\r
+ ProviderAvailable = FALSE;\r
+ }\r
+ }\r
+ //\r
+ // The number of recovery capsules is 0.\r
+ //\r
+ if (!ProviderAvailable) {\r
+ AssertNoCapsulesError (PeiServices);\r
+ }\r
+ //\r
+ // If there is an image provider, get the capsule ID\r
+ //\r
+ if (ProviderAvailable) {\r
+ RecoveryCapsuleSize = 0;\r
+ if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
+ Status = DeviceRecoveryModule->GetRecoveryCapsuleInfo (\r
+ PeiServices,\r
+ DeviceRecoveryModule,\r
+ 0,\r
+ &RecoveryCapsuleSize,\r
+ &DeviceId\r
+ );\r
+ } else {\r
+ Status = DeviceRecoveryModule->GetRecoveryCapsuleInfo (\r
+ PeiServices,\r
+ DeviceRecoveryModule,\r
+ 1,\r
+ &RecoveryCapsuleSize,\r
+ &DeviceId\r
+ );\r
+\r
+\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Capsule Size: %d\n", RecoveryCapsuleSize));\r
+\r
+ //\r
+ // Only support the 2 capsule types known\r
+ // Future enhancement is to rank-order the selection\r
+ //\r
+ if ((!CompareGuid (&DeviceId, &gPeiCapsuleOnFatIdeDiskGuid)) &&\r
+ (!CompareGuid (&DeviceId, &gPeiCapsuleOnDataCDGuid)) &&\r
+ (!CompareGuid (&DeviceId, &gPeiCapsuleOnFatUsbDiskGuid))\r
+ ) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Buffer = NULL;\r
+ Address = (UINTN) AllocatePages ((RecoveryCapsuleSize - 1) / 0x1000 + 1);\r
+ ASSERT (Address);\r
+\r
+ Buffer = (UINT8 *) (UINTN) Address;\r
+ if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
+ Status = DeviceRecoveryModule->LoadRecoveryCapsule (\r
+ PeiServices,\r
+ DeviceRecoveryModule,\r
+ 0,\r
+ Buffer\r
+ );\r
+ } else {\r
+ Status = DeviceRecoveryModule->LoadRecoveryCapsule (\r
+ PeiServices,\r
+ DeviceRecoveryModule,\r
+ 1,\r
+ Buffer\r
+ );\r
+\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "LoadRecoveryCapsule Returns: %r\n", Status));\r
+\r
+ if (Status == EFI_DEVICE_ERROR) {\r
+ AssertMediaDeviceError (PeiServices);\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ } else {\r
+ ReportLoadCapsuleSuccess (PeiServices);\r
+ }\r
+\r
+ //\r
+ // Update FV Hob if found\r
+ //\r
+ Buffer = (VOID *)((UINT8 *) Buffer);\r
+ Status = PeiServicesGetHobList ((VOID **)&Hob.Raw);\r
+ HobOld.Raw = Hob.Raw;\r
+ while (!END_OF_HOB_LIST (Hob)) {\r
+ if (Hob.Header->HobType == EFI_HOB_TYPE_FV) {\r
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Hob FV Length: %x\n", Hob.FirmwareVolume->Length));\r
+\r
+ if (Hob.FirmwareVolume->BaseAddress == (UINTN) PcdGet32 (PcdFlashFvMainBase)) {\r
+ HobUpdate = TRUE;\r
+ //\r
+ // This looks like the Hob we are interested in\r
+ //\r
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Hob Updated\n"));\r
+ Hob.FirmwareVolume->BaseAddress = (UINTN) Buffer;\r
+ Hob.FirmwareVolume->Length = RecoveryCapsuleSize;\r
+ }\r
+ }\r
+\r
+ Hob.Raw = GET_NEXT_HOB (Hob);\r
+ }\r
+ //\r
+ // Check if the top of the file is a firmware volume header\r
+ //\r
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer;\r
+ CapsuleHeader = (EFI_CAPSULE_HEADER *) Buffer;\r
+ if (FvHeader->Signature == EFI_FVH_SIGNATURE) {\r
+ //\r
+ // build FV Hob if it is not built before\r
+ //\r
+ if (!HobUpdate) {\r
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "FV Hob is not found, Build FV Hob then..\n"));\r
+ BuildFvHob (\r
+ (UINTN) Buffer,\r
+ FvHeader->FvLength\r
+ );\r
+\r
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Install FV Info PPI..\n"));\r
+\r
+ PeiServicesInstallFvInfoPpi (\r
+ NULL,\r
+ Buffer,\r
+ (UINT32) FvHeader->FvLength,\r
+ NULL,\r
+ NULL\r
+ );\r
+ }\r
+ //\r
+ // Point to the location immediately after the FV.\r
+ //\r
+ CapsuleHeader = (EFI_CAPSULE_HEADER *) ((UINT8 *) Buffer + FvHeader->FvLength);\r
+ }\r
+\r
+ //\r
+ // Check if pointer is still within the buffer\r
+ //\r
+ if ((UINTN) CapsuleHeader < (UINTN) ((UINT8 *) Buffer + RecoveryCapsuleSize)) {\r
+\r
+ //\r
+ // Check if it is a capsule\r
+ //\r
+ if (CompareGuid ((EFI_GUID *) CapsuleHeader, &mEfiCapsuleHeaderGuid)) {\r
+\r
+ //\r
+ // Set bootmode to capsule update so the capsule hob gets the right bootmode in the hob header.\r
+ //\r
+ Status = PeiServicesSetBootMode (BOOT_ON_FLASH_UPDATE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Build capsule hob\r
+ //\r
+ BuildCvHob ((EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleHeader, (UINT64)CapsuleHeader->CapsuleImageSize);\r
+ }\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Module Returning: %r\n", Status));\r
+ return Status;\r
+}\r
+\r
+/*\r
+ AssertNoCapsulesError:\r
+ There were no recovery capsules found.\r
+ Case 1: Report the error that no recovery block io device/media is readable and assert.\r
+ Case 2: Report the error that there is no media present on any recovery block io device and assert.\r
+ Case 3: There is media present on some recovery block io device,\r
+ but there is no recovery capsule on it. Report the error and assert.\r
+*/\r
+VOID\r
+AssertNoCapsulesError (\r
+ IN EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ BOOLEAN MediaDeviceError;\r
+ BOOLEAN MediaPresent;\r
+\r
+ MediaDeviceError = TRUE;\r
+ MediaPresent = FALSE;\r
+\r
+ CheckIfMediaPresentOnBlockIoDevice (PeiServices, &MediaDeviceError, &MediaPresent);\r
+/* if (MediaDeviceError) {\r
+ ReportStatusCode (\r
+ (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),\r
+ (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_DEVICE_ERROR)\r
+ );\r
+\r
+ } else if (!MediaPresent) {\r
+ ReportStatusCode (\r
+ (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),\r
+ (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_NOT_PRESENT)\r
+ );\r
+\r
+ } else {\r
+ ReportStatusCode (\r
+ (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),\r
+ (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_EC_NO_RECOVERY_CAPSULE)\r
+ );\r
+ }*/\r
+ //\r
+ // Hang.\r
+ //\r
+ CpuDeadLoop();\r
+}\r
+\r
+#define MAX_BLOCK_IO_PPI 32\r
+\r
+/*\r
+ CheckIfMediaPresentOnBlockIoDevice:\r
+ Checks to see whether there was a media device error or to see if there is media present.\r
+*/\r
+VOID\r
+CheckIfMediaPresentOnBlockIoDevice (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN OUT BOOLEAN *MediaDeviceError,\r
+ IN OUT BOOLEAN *MediaPresent\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BlockIoPpiInstance;\r
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;\r
+ UINTN NumberBlockDevices;\r
+ EFI_PEI_BLOCK_IO_MEDIA Media;\r
+\r
+ *MediaDeviceError = TRUE;\r
+ *MediaPresent = FALSE;\r
+\r
+ for (BlockIoPpiInstance = 0; BlockIoPpiInstance < MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {\r
+ Status = PeiServicesLocatePpi (\r
+ &gEfiPeiVirtualBlockIoPpiGuid,\r
+ BlockIoPpiInstance,\r
+ NULL,\r
+ (VOID **)&BlockIoPpi\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Done with all Block Io Ppis\r
+ //\r
+ break;\r
+ }\r
+\r
+ Status = BlockIoPpi->GetNumberOfBlockDevices (\r
+ PeiServices,\r
+ BlockIoPpi,\r
+ &NumberBlockDevices\r
+ );\r
+ if (EFI_ERROR (Status) || (NumberBlockDevices == 0)) {\r
+ continue;\r
+ }\r
+ //\r
+ // Just retrieve the first block\r
+ //\r
+ Status = BlockIoPpi->GetBlockDeviceMediaInfo (\r
+ PeiServices,\r
+ BlockIoPpi,\r
+ 0,\r
+ &Media\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ *MediaDeviceError = FALSE;\r
+ if (Media.MediaPresent) {\r
+ *MediaPresent = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+VOID\r
+AssertMediaDeviceError (\r
+ IN EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+/* ReportStatusCode (\r
+ (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),\r
+ (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_DEVICE_ERROR)\r
+ );\r
+*/\r
+ CpuDeadLoop ();\r
+}\r
+\r
+VOID\r
+ReportLoadCapsuleSuccess (\r
+ IN EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ //\r
+ // EFI_SW_PEI_PC_CAPSULE_START: (from the status code spec):\r
+ // Loaded the recovery capsule. About to hand off control to the capsule.\r
+ //\r
+/* ReportStatusCode (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_CAPSULE_LOAD_SUCCESS)\r
+ );*/\r
+}\r
+\r