2 Install Platform EFI_PEI_RECOVERY_MODULE_PPI and Implementation of
3 EFI_PEI_LOAD_RECOVERY_CAPSULE service.
5 Copyright (c) 2013 Intel Corporation.
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "CommonHeader.h"
18 #include "PlatformEarlyInit.h"
20 #include <Ppi/BlockIo.h>
23 // Capsule Types supported in this platform module
25 #include <Guid/CapsuleOnFatFloppyDisk.h>
26 #include <Guid/CapsuleOnFatIdeDisk.h>
27 #include <Guid/CapsuleOnFatUsbDisk.h>
28 #include <Guid/CapsuleOnDataCD.h>
29 #include <Guid/QuarkCapsuleGuid.h>
31 #include <Ppi/RecoveryModule.h>
32 #include <Ppi/DeviceRecoveryModule.h>
34 #include <Library/PeiServicesLib.h>
41 PlatformRecoveryModule (
42 IN EFI_PEI_SERVICES
**PeiServices
,
43 IN EFI_PEI_RECOVERY_MODULE_PPI
*This
47 AssertNoCapsulesError (
48 IN EFI_PEI_SERVICES
**PeiServices
52 AssertMediaDeviceError (
53 IN EFI_PEI_SERVICES
**PeiServices
57 ReportLoadCapsuleSuccess (
58 IN EFI_PEI_SERVICES
**PeiServices
62 CheckIfMediaPresentOnBlockIoDevice (
63 IN EFI_PEI_SERVICES
**PeiServices
,
64 IN OUT BOOLEAN
*MediaDeviceError
,
65 IN OUT BOOLEAN
*MediaPresent
71 EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi
= { PlatformRecoveryModule
};
73 EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList
= {
74 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
75 &gEfiPeiRecoveryModulePpiGuid
,
81 PeimInitializeRecovery (
82 IN EFI_PEI_SERVICES
**PeiServices
88 Provide the functionality of the Recovery Module.
92 PeiServices - General purpose services available to every PEIM.
96 EFI_SUCCESS - If the interface could be successfully
103 Status
= PeiServicesInstallPpi (&mRecoveryPpiList
);
110 PlatformRecoveryModule (
111 IN EFI_PEI_SERVICES
**PeiServices
,
112 IN EFI_PEI_RECOVERY_MODULE_PPI
*This
118 Provide the functionality of the Platform Recovery Module.
122 PeiServices - General purpose services available to every PEIM.
123 This - Pointer to EFI_PEI_RECOVERY_MODULE_PPI.
127 EFI_SUCCESS - If the interface could be successfully
129 EFI_UNSUPPORTED - Not supported.
134 EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*DeviceRecoveryModule
;
135 UINTN NumberOfImageProviders
;
136 BOOLEAN ProviderAvailable
;
137 UINTN NumberRecoveryCapsules
;
138 UINTN RecoveryCapsuleSize
;
141 EFI_PHYSICAL_ADDRESS Address
;
143 EFI_CAPSULE_HEADER
*CapsuleHeader
;
144 EFI_PEI_HOB_POINTERS Hob
;
145 EFI_PEI_HOB_POINTERS HobOld
;
147 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
149 EFI_STATUS AuthStatus
;
150 EFI_GUID mEfiCapsuleHeaderGuid
= QUARK_CAPSULE_GUID
;
154 Status
= EFI_SUCCESS
;
155 AuthStatus
= EFI_SUCCESS
;
158 ProviderAvailable
= TRUE
;
160 NumberOfImageProviders
= 0;
162 DeviceRecoveryModule
= NULL
;
164 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Recovery Entry\n"));
167 // Search the platform for some recovery capsule if the DXE IPL
168 // discovered a recovery condition and has requested a load.
170 while (ProviderAvailable
) {
172 Status
= PeiServicesLocatePpi (
173 &gEfiPeiDeviceRecoveryModulePpiGuid
,
176 (VOID
**)&DeviceRecoveryModule
179 if (!EFI_ERROR (Status
)) {
180 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Device Recovery PPI located\n"));
181 NumberOfImageProviders
++;
183 Status
= DeviceRecoveryModule
->GetNumberRecoveryCapsules (
185 DeviceRecoveryModule
,
186 &NumberRecoveryCapsules
189 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Number Of Recovery Capsules: %d\n", NumberRecoveryCapsules
));
191 if (NumberRecoveryCapsules
== 0) {
197 ProviderAvailable
= FALSE
;
201 // The number of recovery capsules is 0.
203 if (!ProviderAvailable
) {
204 AssertNoCapsulesError (PeiServices
);
207 // If there is an image provider, get the capsule ID
209 if (ProviderAvailable
) {
210 RecoveryCapsuleSize
= 0;
211 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
212 Status
= DeviceRecoveryModule
->GetRecoveryCapsuleInfo (
214 DeviceRecoveryModule
,
216 &RecoveryCapsuleSize
,
220 Status
= DeviceRecoveryModule
->GetRecoveryCapsuleInfo (
222 DeviceRecoveryModule
,
224 &RecoveryCapsuleSize
,
231 if (EFI_ERROR (Status
)) {
235 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Recovery Capsule Size: %d\n", RecoveryCapsuleSize
));
238 // Only support the 2 capsule types known
239 // Future enhancement is to rank-order the selection
241 if ((!CompareGuid (&DeviceId
, &gPeiCapsuleOnFatIdeDiskGuid
)) &&
242 (!CompareGuid (&DeviceId
, &gPeiCapsuleOnDataCDGuid
)) &&
243 (!CompareGuid (&DeviceId
, &gPeiCapsuleOnFatUsbDiskGuid
))
245 return EFI_UNSUPPORTED
;
249 Address
= (UINTN
) AllocatePages ((RecoveryCapsuleSize
- 1) / 0x1000 + 1);
252 Buffer
= (UINT8
*) (UINTN
) Address
;
253 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
254 Status
= DeviceRecoveryModule
->LoadRecoveryCapsule (
256 DeviceRecoveryModule
,
261 Status
= DeviceRecoveryModule
->LoadRecoveryCapsule (
263 DeviceRecoveryModule
,
270 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "LoadRecoveryCapsule Returns: %r\n", Status
));
272 if (Status
== EFI_DEVICE_ERROR
) {
273 AssertMediaDeviceError (PeiServices
);
276 if (EFI_ERROR (Status
)) {
279 ReportLoadCapsuleSuccess (PeiServices
);
283 // Update FV Hob if found
285 Buffer
= (VOID
*)((UINT8
*) Buffer
);
286 Status
= PeiServicesGetHobList ((VOID
**)&Hob
.Raw
);
287 HobOld
.Raw
= Hob
.Raw
;
288 while (!END_OF_HOB_LIST (Hob
)) {
289 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_FV
) {
290 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Hob FV Length: %x\n", Hob
.FirmwareVolume
->Length
));
292 if (Hob
.FirmwareVolume
->BaseAddress
== (UINTN
) PcdGet32 (PcdFlashFvMainBase
)) {
295 // This looks like the Hob we are interested in
297 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Hob Updated\n"));
298 Hob
.FirmwareVolume
->BaseAddress
= (UINTN
) Buffer
;
299 Hob
.FirmwareVolume
->Length
= RecoveryCapsuleSize
;
303 Hob
.Raw
= GET_NEXT_HOB (Hob
);
306 // Check if the top of the file is a firmware volume header
308 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) Buffer
;
309 CapsuleHeader
= (EFI_CAPSULE_HEADER
*) Buffer
;
310 if (FvHeader
->Signature
== EFI_FVH_SIGNATURE
) {
312 // build FV Hob if it is not built before
315 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "FV Hob is not found, Build FV Hob then..\n"));
321 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Install FV Info PPI..\n"));
323 PeiServicesInstallFvInfoPpi (
326 (UINT32
) FvHeader
->FvLength
,
332 // Point to the location immediately after the FV.
334 CapsuleHeader
= (EFI_CAPSULE_HEADER
*) ((UINT8
*) Buffer
+ FvHeader
->FvLength
);
338 // Check if pointer is still within the buffer
340 if ((UINTN
) CapsuleHeader
< (UINTN
) ((UINT8
*) Buffer
+ RecoveryCapsuleSize
)) {
343 // Check if it is a capsule
345 if (CompareGuid ((EFI_GUID
*) CapsuleHeader
, &mEfiCapsuleHeaderGuid
)) {
348 // Set bootmode to capsule update so the capsule hob gets the right bootmode in the hob header.
350 Status
= PeiServicesSetBootMode (BOOT_ON_FLASH_UPDATE
);
351 if (EFI_ERROR (Status
)) {
358 BuildCvHob ((EFI_PHYSICAL_ADDRESS
)(UINTN
)CapsuleHeader
, (UINT64
)CapsuleHeader
->CapsuleImageSize
);
363 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Recovery Module Returning: %r\n", Status
));
368 AssertNoCapsulesError:
369 There were no recovery capsules found.
370 Case 1: Report the error that no recovery block io device/media is readable and assert.
371 Case 2: Report the error that there is no media present on any recovery block io device and assert.
372 Case 3: There is media present on some recovery block io device,
373 but there is no recovery capsule on it. Report the error and assert.
376 AssertNoCapsulesError (
377 IN EFI_PEI_SERVICES
**PeiServices
380 BOOLEAN MediaDeviceError
;
381 BOOLEAN MediaPresent
;
383 MediaDeviceError
= TRUE
;
384 MediaPresent
= FALSE
;
386 CheckIfMediaPresentOnBlockIoDevice (PeiServices
, &MediaDeviceError
, &MediaPresent
);
387 /* if (MediaDeviceError) {
389 (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
390 (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_DEVICE_ERROR)
393 } else if (!MediaPresent) {
395 (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
396 (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_NOT_PRESENT)
401 (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
402 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_EC_NO_RECOVERY_CAPSULE)
411 #define MAX_BLOCK_IO_PPI 32
414 CheckIfMediaPresentOnBlockIoDevice:
415 Checks to see whether there was a media device error or to see if there is media present.
418 CheckIfMediaPresentOnBlockIoDevice (
419 IN EFI_PEI_SERVICES
**PeiServices
,
420 IN OUT BOOLEAN
*MediaDeviceError
,
421 IN OUT BOOLEAN
*MediaPresent
425 UINTN BlockIoPpiInstance
;
426 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
427 UINTN NumberBlockDevices
;
428 EFI_PEI_BLOCK_IO_MEDIA Media
;
430 *MediaDeviceError
= TRUE
;
431 *MediaPresent
= FALSE
;
433 for (BlockIoPpiInstance
= 0; BlockIoPpiInstance
< MAX_BLOCK_IO_PPI
; BlockIoPpiInstance
++) {
434 Status
= PeiServicesLocatePpi (
435 &gEfiPeiVirtualBlockIoPpiGuid
,
440 if (EFI_ERROR (Status
)) {
442 // Done with all Block Io Ppis
447 Status
= BlockIoPpi
->GetNumberOfBlockDevices (
452 if (EFI_ERROR (Status
) || (NumberBlockDevices
== 0)) {
456 // Just retrieve the first block
458 Status
= BlockIoPpi
->GetBlockDeviceMediaInfo (
464 if (!EFI_ERROR (Status
)) {
465 *MediaDeviceError
= FALSE
;
466 if (Media
.MediaPresent
) {
467 *MediaPresent
= TRUE
;
475 AssertMediaDeviceError (
476 IN EFI_PEI_SERVICES
**PeiServices
479 /* ReportStatusCode (
480 (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
481 (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_DEVICE_ERROR)
488 ReportLoadCapsuleSuccess (
489 IN EFI_PEI_SERVICES
**PeiServices
493 // EFI_SW_PEI_PC_CAPSULE_START: (from the status code spec):
494 // Loaded the recovery capsule. About to hand off control to the capsule.
496 /* ReportStatusCode (
498 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_CAPSULE_LOAD_SUCCESS)