+++ /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-2019 Intel Corporation.\r
-\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\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
- EFI_PHYSICAL_ADDRESS Address;\r
- VOID *Buffer;\r
- EFI_CAPSULE_HEADER *CapsuleHeader;\r
- EFI_PEI_HOB_POINTERS Hob;\r
- BOOLEAN HobUpdate;\r
- EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
- UINTN Index;\r
- EFI_GUID mEfiCapsuleHeaderGuid = QUARK_CAPSULE_GUID;\r
-\r
- Index = 0;\r
-\r
- Status = EFI_SUCCESS;\r
- HobUpdate = FALSE;\r
-\r
- ProviderAvailable = TRUE;\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
- Status = DeviceRecoveryModule->GetRecoveryCapsuleInfo (\r
- PeiServices,\r
- DeviceRecoveryModule,\r
- 1,\r
- &RecoveryCapsuleSize,\r
- &DeviceId\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
- Status = DeviceRecoveryModule->LoadRecoveryCapsule (\r
- PeiServices,\r
- DeviceRecoveryModule,\r
- 1,\r
- Buffer\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
- 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