2 Install Platform EFI_PEI_RECOVERY_MODULE_PPI and Implementation of
3 EFI_PEI_LOAD_RECOVERY_CAPSULE service.
5 Copyright (c) 2013-2016 Intel Corporation.
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "CommonHeader.h"
12 #include "PlatformEarlyInit.h"
14 #include <Ppi/BlockIo.h>
17 // Capsule Types supported in this platform module
19 #include <Guid/CapsuleOnFatFloppyDisk.h>
20 #include <Guid/CapsuleOnFatIdeDisk.h>
21 #include <Guid/CapsuleOnFatUsbDisk.h>
22 #include <Guid/CapsuleOnDataCD.h>
23 #include <Guid/QuarkCapsuleGuid.h>
25 #include <Ppi/RecoveryModule.h>
26 #include <Ppi/DeviceRecoveryModule.h>
28 #include <Library/PeiServicesLib.h>
35 PlatformRecoveryModule (
36 IN EFI_PEI_SERVICES
**PeiServices
,
37 IN EFI_PEI_RECOVERY_MODULE_PPI
*This
41 AssertNoCapsulesError (
42 IN EFI_PEI_SERVICES
**PeiServices
46 AssertMediaDeviceError (
47 IN EFI_PEI_SERVICES
**PeiServices
51 ReportLoadCapsuleSuccess (
52 IN EFI_PEI_SERVICES
**PeiServices
56 CheckIfMediaPresentOnBlockIoDevice (
57 IN EFI_PEI_SERVICES
**PeiServices
,
58 IN OUT BOOLEAN
*MediaDeviceError
,
59 IN OUT BOOLEAN
*MediaPresent
65 EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi
= { PlatformRecoveryModule
};
67 EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList
= {
68 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
69 &gEfiPeiRecoveryModulePpiGuid
,
75 PeimInitializeRecovery (
76 IN EFI_PEI_SERVICES
**PeiServices
82 Provide the functionality of the Recovery Module.
86 PeiServices - General purpose services available to every PEIM.
90 EFI_SUCCESS - If the interface could be successfully
97 Status
= PeiServicesInstallPpi (&mRecoveryPpiList
);
104 PlatformRecoveryModule (
105 IN EFI_PEI_SERVICES
**PeiServices
,
106 IN EFI_PEI_RECOVERY_MODULE_PPI
*This
112 Provide the functionality of the Platform Recovery Module.
116 PeiServices - General purpose services available to every PEIM.
117 This - Pointer to EFI_PEI_RECOVERY_MODULE_PPI.
121 EFI_SUCCESS - If the interface could be successfully
123 EFI_UNSUPPORTED - Not supported.
128 EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*DeviceRecoveryModule
;
129 UINTN NumberOfImageProviders
;
130 BOOLEAN ProviderAvailable
;
131 UINTN NumberRecoveryCapsules
;
132 UINTN RecoveryCapsuleSize
;
134 EFI_PHYSICAL_ADDRESS Address
;
136 EFI_CAPSULE_HEADER
*CapsuleHeader
;
137 EFI_PEI_HOB_POINTERS Hob
;
139 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
141 EFI_GUID mEfiCapsuleHeaderGuid
= QUARK_CAPSULE_GUID
;
145 Status
= EFI_SUCCESS
;
148 ProviderAvailable
= TRUE
;
149 NumberOfImageProviders
= 0;
151 DeviceRecoveryModule
= NULL
;
153 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Recovery Entry\n"));
156 // Search the platform for some recovery capsule if the DXE IPL
157 // discovered a recovery condition and has requested a load.
159 while (ProviderAvailable
) {
161 Status
= PeiServicesLocatePpi (
162 &gEfiPeiDeviceRecoveryModulePpiGuid
,
165 (VOID
**)&DeviceRecoveryModule
168 if (!EFI_ERROR (Status
)) {
169 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Device Recovery PPI located\n"));
170 NumberOfImageProviders
++;
172 Status
= DeviceRecoveryModule
->GetNumberRecoveryCapsules (
174 DeviceRecoveryModule
,
175 &NumberRecoveryCapsules
178 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Number Of Recovery Capsules: %d\n", NumberRecoveryCapsules
));
180 if (NumberRecoveryCapsules
== 0) {
186 ProviderAvailable
= FALSE
;
190 // The number of recovery capsules is 0.
192 if (!ProviderAvailable
) {
193 AssertNoCapsulesError (PeiServices
);
196 // If there is an image provider, get the capsule ID
198 if (ProviderAvailable
) {
199 RecoveryCapsuleSize
= 0;
200 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
201 Status
= DeviceRecoveryModule
->GetRecoveryCapsuleInfo (
203 DeviceRecoveryModule
,
205 &RecoveryCapsuleSize
,
209 Status
= DeviceRecoveryModule
->GetRecoveryCapsuleInfo (
211 DeviceRecoveryModule
,
213 &RecoveryCapsuleSize
,
220 if (EFI_ERROR (Status
)) {
224 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Recovery Capsule Size: %d\n", RecoveryCapsuleSize
));
227 // Only support the 2 capsule types known
228 // Future enhancement is to rank-order the selection
230 if ((!CompareGuid (&DeviceId
, &gPeiCapsuleOnFatIdeDiskGuid
)) &&
231 (!CompareGuid (&DeviceId
, &gPeiCapsuleOnDataCDGuid
)) &&
232 (!CompareGuid (&DeviceId
, &gPeiCapsuleOnFatUsbDiskGuid
))
234 return EFI_UNSUPPORTED
;
238 Address
= (UINTN
) AllocatePages ((RecoveryCapsuleSize
- 1) / 0x1000 + 1);
241 Buffer
= (UINT8
*) (UINTN
) Address
;
242 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
243 Status
= DeviceRecoveryModule
->LoadRecoveryCapsule (
245 DeviceRecoveryModule
,
250 Status
= DeviceRecoveryModule
->LoadRecoveryCapsule (
252 DeviceRecoveryModule
,
259 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "LoadRecoveryCapsule Returns: %r\n", Status
));
261 if (Status
== EFI_DEVICE_ERROR
) {
262 AssertMediaDeviceError (PeiServices
);
265 if (EFI_ERROR (Status
)) {
268 ReportLoadCapsuleSuccess (PeiServices
);
272 // Update FV Hob if found
274 Buffer
= (VOID
*)((UINT8
*) Buffer
);
275 Status
= PeiServicesGetHobList ((VOID
**)&Hob
.Raw
);
276 while (!END_OF_HOB_LIST (Hob
)) {
277 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_FV
) {
278 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Hob FV Length: %x\n", Hob
.FirmwareVolume
->Length
));
280 if (Hob
.FirmwareVolume
->BaseAddress
== (UINTN
) PcdGet32 (PcdFlashFvMainBase
)) {
283 // This looks like the Hob we are interested in
285 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Hob Updated\n"));
286 Hob
.FirmwareVolume
->BaseAddress
= (UINTN
) Buffer
;
287 Hob
.FirmwareVolume
->Length
= RecoveryCapsuleSize
;
291 Hob
.Raw
= GET_NEXT_HOB (Hob
);
294 // Check if the top of the file is a firmware volume header
296 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) Buffer
;
297 CapsuleHeader
= (EFI_CAPSULE_HEADER
*) Buffer
;
298 if (FvHeader
->Signature
== EFI_FVH_SIGNATURE
) {
300 // build FV Hob if it is not built before
303 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "FV Hob is not found, Build FV Hob then..\n"));
309 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Install FV Info PPI..\n"));
311 PeiServicesInstallFvInfoPpi (
314 (UINT32
) FvHeader
->FvLength
,
320 // Point to the location immediately after the FV.
322 CapsuleHeader
= (EFI_CAPSULE_HEADER
*) ((UINT8
*) Buffer
+ FvHeader
->FvLength
);
326 // Check if pointer is still within the buffer
328 if ((UINTN
) CapsuleHeader
< (UINTN
) ((UINT8
*) Buffer
+ RecoveryCapsuleSize
)) {
331 // Check if it is a capsule
333 if (CompareGuid ((EFI_GUID
*) CapsuleHeader
, &mEfiCapsuleHeaderGuid
)) {
336 // Set bootmode to capsule update so the capsule hob gets the right bootmode in the hob header.
338 Status
= PeiServicesSetBootMode (BOOT_ON_FLASH_UPDATE
);
339 if (EFI_ERROR (Status
)) {
346 BuildCvHob ((EFI_PHYSICAL_ADDRESS
)(UINTN
)CapsuleHeader
, (UINT64
)CapsuleHeader
->CapsuleImageSize
);
351 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Recovery Module Returning: %r\n", Status
));
356 AssertNoCapsulesError:
357 There were no recovery capsules found.
358 Case 1: Report the error that no recovery block io device/media is readable and assert.
359 Case 2: Report the error that there is no media present on any recovery block io device and assert.
360 Case 3: There is media present on some recovery block io device,
361 but there is no recovery capsule on it. Report the error and assert.
364 AssertNoCapsulesError (
365 IN EFI_PEI_SERVICES
**PeiServices
368 BOOLEAN MediaDeviceError
;
369 BOOLEAN MediaPresent
;
371 MediaDeviceError
= TRUE
;
372 MediaPresent
= FALSE
;
374 CheckIfMediaPresentOnBlockIoDevice (PeiServices
, &MediaDeviceError
, &MediaPresent
);
375 /* if (MediaDeviceError) {
377 (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
378 (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_DEVICE_ERROR)
381 } else if (!MediaPresent) {
383 (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
384 (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_NOT_PRESENT)
389 (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
390 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_EC_NO_RECOVERY_CAPSULE)
399 #define MAX_BLOCK_IO_PPI 32
402 CheckIfMediaPresentOnBlockIoDevice:
403 Checks to see whether there was a media device error or to see if there is media present.
406 CheckIfMediaPresentOnBlockIoDevice (
407 IN EFI_PEI_SERVICES
**PeiServices
,
408 IN OUT BOOLEAN
*MediaDeviceError
,
409 IN OUT BOOLEAN
*MediaPresent
413 UINTN BlockIoPpiInstance
;
414 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
415 UINTN NumberBlockDevices
;
416 EFI_PEI_BLOCK_IO_MEDIA Media
;
418 *MediaDeviceError
= TRUE
;
419 *MediaPresent
= FALSE
;
421 for (BlockIoPpiInstance
= 0; BlockIoPpiInstance
< MAX_BLOCK_IO_PPI
; BlockIoPpiInstance
++) {
422 Status
= PeiServicesLocatePpi (
423 &gEfiPeiVirtualBlockIoPpiGuid
,
428 if (EFI_ERROR (Status
)) {
430 // Done with all Block Io Ppis
435 Status
= BlockIoPpi
->GetNumberOfBlockDevices (
440 if (EFI_ERROR (Status
) || (NumberBlockDevices
== 0)) {
444 // Just retrieve the first block
446 Status
= BlockIoPpi
->GetBlockDeviceMediaInfo (
452 if (!EFI_ERROR (Status
)) {
453 *MediaDeviceError
= FALSE
;
454 if (Media
.MediaPresent
) {
455 *MediaPresent
= TRUE
;
463 AssertMediaDeviceError (
464 IN EFI_PEI_SERVICES
**PeiServices
467 /* ReportStatusCode (
468 (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
469 (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_DEVICE_ERROR)
476 ReportLoadCapsuleSuccess (
477 IN EFI_PEI_SERVICES
**PeiServices
481 // EFI_SW_PEI_PC_CAPSULE_START: (from the status code spec):
482 // Loaded the recovery capsule. About to hand off control to the capsule.
484 /* ReportStatusCode (
486 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_CAPSULE_LOAD_SUCCESS)