]> git.proxmox.com Git - mirror_edk2.git/blob - QuarkPlatformPkg/Platform/Pei/PlatformInit/Generic/Recovery.c
f6a076f757ecdfd32c95a0bf6fce824b8c30f039
[mirror_edk2.git] / QuarkPlatformPkg / Platform / Pei / PlatformInit / Generic / Recovery.c
1 /** @file
2 Install Platform EFI_PEI_RECOVERY_MODULE_PPI and Implementation of
3 EFI_PEI_LOAD_RECOVERY_CAPSULE service.
4
5 Copyright (c) 2013-2016 Intel Corporation.
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "CommonHeader.h"
12 #include "PlatformEarlyInit.h"
13
14 #include <Ppi/BlockIo.h>
15
16 //
17 // Capsule Types supported in this platform module
18 //
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>
24
25 #include <Ppi/RecoveryModule.h>
26 #include <Ppi/DeviceRecoveryModule.h>
27
28 #include <Library/PeiServicesLib.h>
29
30 //
31 // Required Service
32 //
33 EFI_STATUS
34 EFIAPI
35 PlatformRecoveryModule (
36 IN EFI_PEI_SERVICES **PeiServices,
37 IN EFI_PEI_RECOVERY_MODULE_PPI *This
38 );
39
40 VOID
41 AssertNoCapsulesError (
42 IN EFI_PEI_SERVICES **PeiServices
43 );
44
45 VOID
46 AssertMediaDeviceError (
47 IN EFI_PEI_SERVICES **PeiServices
48 );
49
50 VOID
51 ReportLoadCapsuleSuccess (
52 IN EFI_PEI_SERVICES **PeiServices
53 );
54
55 VOID
56 CheckIfMediaPresentOnBlockIoDevice (
57 IN EFI_PEI_SERVICES **PeiServices,
58 IN OUT BOOLEAN *MediaDeviceError,
59 IN OUT BOOLEAN *MediaPresent
60 );
61
62 //
63 // Module globals
64 //
65 EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi = { PlatformRecoveryModule };
66
67 EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList = {
68 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
69 &gEfiPeiRecoveryModulePpiGuid,
70 &mRecoveryPpi
71 };
72
73 EFI_STATUS
74 EFIAPI
75 PeimInitializeRecovery (
76 IN EFI_PEI_SERVICES **PeiServices
77 )
78 /*++
79
80 Routine Description:
81
82 Provide the functionality of the Recovery Module.
83
84 Arguments:
85
86 PeiServices - General purpose services available to every PEIM.
87
88 Returns:
89
90 EFI_SUCCESS - If the interface could be successfully
91 installed.
92
93 --*/
94 {
95 EFI_STATUS Status;
96
97 Status = PeiServicesInstallPpi (&mRecoveryPpiList);
98
99 return Status;
100 }
101
102 EFI_STATUS
103 EFIAPI
104 PlatformRecoveryModule (
105 IN EFI_PEI_SERVICES **PeiServices,
106 IN EFI_PEI_RECOVERY_MODULE_PPI *This
107 )
108 /*++
109
110 Routine Description:
111
112 Provide the functionality of the Platform Recovery Module.
113
114 Arguments:
115
116 PeiServices - General purpose services available to every PEIM.
117 This - Pointer to EFI_PEI_RECOVERY_MODULE_PPI.
118
119 Returns:
120
121 EFI_SUCCESS - If the interface could be successfully
122 installed.
123 EFI_UNSUPPORTED - Not supported.
124
125 --*/
126 {
127 EFI_STATUS Status;
128 EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *DeviceRecoveryModule;
129 UINTN NumberOfImageProviders;
130 BOOLEAN ProviderAvailable;
131 UINTN NumberRecoveryCapsules;
132 UINTN RecoveryCapsuleSize;
133 EFI_GUID DeviceId;
134 EFI_PHYSICAL_ADDRESS Address;
135 VOID *Buffer;
136 EFI_CAPSULE_HEADER *CapsuleHeader;
137 EFI_PEI_HOB_POINTERS Hob;
138 BOOLEAN HobUpdate;
139 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
140 UINTN Index;
141 EFI_GUID mEfiCapsuleHeaderGuid = QUARK_CAPSULE_GUID;
142
143 Index = 0;
144
145 Status = EFI_SUCCESS;
146 HobUpdate = FALSE;
147
148 ProviderAvailable = TRUE;
149 NumberOfImageProviders = 0;
150
151 DeviceRecoveryModule = NULL;
152
153 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Entry\n"));
154
155 //
156 // Search the platform for some recovery capsule if the DXE IPL
157 // discovered a recovery condition and has requested a load.
158 //
159 while (ProviderAvailable) {
160
161 Status = PeiServicesLocatePpi (
162 &gEfiPeiDeviceRecoveryModulePpiGuid,
163 Index,
164 NULL,
165 (VOID **)&DeviceRecoveryModule
166 );
167
168 if (!EFI_ERROR (Status)) {
169 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Device Recovery PPI located\n"));
170 NumberOfImageProviders++;
171
172 Status = DeviceRecoveryModule->GetNumberRecoveryCapsules (
173 PeiServices,
174 DeviceRecoveryModule,
175 &NumberRecoveryCapsules
176 );
177
178 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Number Of Recovery Capsules: %d\n", NumberRecoveryCapsules));
179
180 if (NumberRecoveryCapsules == 0) {
181 Index++;
182 } else {
183 break;
184 }
185 } else {
186 ProviderAvailable = FALSE;
187 }
188 }
189 //
190 // The number of recovery capsules is 0.
191 //
192 if (!ProviderAvailable) {
193 AssertNoCapsulesError (PeiServices);
194 }
195 //
196 // If there is an image provider, get the capsule ID
197 //
198 if (ProviderAvailable) {
199 RecoveryCapsuleSize = 0;
200 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
201 Status = DeviceRecoveryModule->GetRecoveryCapsuleInfo (
202 PeiServices,
203 DeviceRecoveryModule,
204 0,
205 &RecoveryCapsuleSize,
206 &DeviceId
207 );
208 } else {
209 Status = DeviceRecoveryModule->GetRecoveryCapsuleInfo (
210 PeiServices,
211 DeviceRecoveryModule,
212 1,
213 &RecoveryCapsuleSize,
214 &DeviceId
215 );
216
217
218 }
219
220 if (EFI_ERROR (Status)) {
221 return Status;
222 }
223
224 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Capsule Size: %d\n", RecoveryCapsuleSize));
225
226 //
227 // Only support the 2 capsule types known
228 // Future enhancement is to rank-order the selection
229 //
230 if ((!CompareGuid (&DeviceId, &gPeiCapsuleOnFatIdeDiskGuid)) &&
231 (!CompareGuid (&DeviceId, &gPeiCapsuleOnDataCDGuid)) &&
232 (!CompareGuid (&DeviceId, &gPeiCapsuleOnFatUsbDiskGuid))
233 ) {
234 return EFI_UNSUPPORTED;
235 }
236
237 Buffer = NULL;
238 Address = (UINTN) AllocatePages ((RecoveryCapsuleSize - 1) / 0x1000 + 1);
239 ASSERT (Address);
240
241 Buffer = (UINT8 *) (UINTN) Address;
242 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
243 Status = DeviceRecoveryModule->LoadRecoveryCapsule (
244 PeiServices,
245 DeviceRecoveryModule,
246 0,
247 Buffer
248 );
249 } else {
250 Status = DeviceRecoveryModule->LoadRecoveryCapsule (
251 PeiServices,
252 DeviceRecoveryModule,
253 1,
254 Buffer
255 );
256
257 }
258
259 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "LoadRecoveryCapsule Returns: %r\n", Status));
260
261 if (Status == EFI_DEVICE_ERROR) {
262 AssertMediaDeviceError (PeiServices);
263 }
264
265 if (EFI_ERROR (Status)) {
266 return Status;
267 } else {
268 ReportLoadCapsuleSuccess (PeiServices);
269 }
270
271 //
272 // Update FV Hob if found
273 //
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));
279
280 if (Hob.FirmwareVolume->BaseAddress == (UINTN) PcdGet32 (PcdFlashFvMainBase)) {
281 HobUpdate = TRUE;
282 //
283 // This looks like the Hob we are interested in
284 //
285 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Hob Updated\n"));
286 Hob.FirmwareVolume->BaseAddress = (UINTN) Buffer;
287 Hob.FirmwareVolume->Length = RecoveryCapsuleSize;
288 }
289 }
290
291 Hob.Raw = GET_NEXT_HOB (Hob);
292 }
293 //
294 // Check if the top of the file is a firmware volume header
295 //
296 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer;
297 CapsuleHeader = (EFI_CAPSULE_HEADER *) Buffer;
298 if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
299 //
300 // build FV Hob if it is not built before
301 //
302 if (!HobUpdate) {
303 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "FV Hob is not found, Build FV Hob then..\n"));
304 BuildFvHob (
305 (UINTN) Buffer,
306 FvHeader->FvLength
307 );
308
309 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Install FV Info PPI..\n"));
310
311 PeiServicesInstallFvInfoPpi (
312 NULL,
313 Buffer,
314 (UINT32) FvHeader->FvLength,
315 NULL,
316 NULL
317 );
318 }
319 //
320 // Point to the location immediately after the FV.
321 //
322 CapsuleHeader = (EFI_CAPSULE_HEADER *) ((UINT8 *) Buffer + FvHeader->FvLength);
323 }
324
325 //
326 // Check if pointer is still within the buffer
327 //
328 if ((UINTN) CapsuleHeader < (UINTN) ((UINT8 *) Buffer + RecoveryCapsuleSize)) {
329
330 //
331 // Check if it is a capsule
332 //
333 if (CompareGuid ((EFI_GUID *) CapsuleHeader, &mEfiCapsuleHeaderGuid)) {
334
335 //
336 // Set bootmode to capsule update so the capsule hob gets the right bootmode in the hob header.
337 //
338 Status = PeiServicesSetBootMode (BOOT_ON_FLASH_UPDATE);
339 if (EFI_ERROR (Status)) {
340 return Status;
341 }
342
343 //
344 // Build capsule hob
345 //
346 BuildCvHob ((EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleHeader, (UINT64)CapsuleHeader->CapsuleImageSize);
347 }
348 }
349 }
350
351 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Module Returning: %r\n", Status));
352 return Status;
353 }
354
355 /*
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.
362 */
363 VOID
364 AssertNoCapsulesError (
365 IN EFI_PEI_SERVICES **PeiServices
366 )
367 {
368 BOOLEAN MediaDeviceError;
369 BOOLEAN MediaPresent;
370
371 MediaDeviceError = TRUE;
372 MediaPresent = FALSE;
373
374 CheckIfMediaPresentOnBlockIoDevice (PeiServices, &MediaDeviceError, &MediaPresent);
375 /* if (MediaDeviceError) {
376 ReportStatusCode (
377 (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
378 (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_DEVICE_ERROR)
379 );
380
381 } else if (!MediaPresent) {
382 ReportStatusCode (
383 (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
384 (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_NOT_PRESENT)
385 );
386
387 } else {
388 ReportStatusCode (
389 (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
390 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_EC_NO_RECOVERY_CAPSULE)
391 );
392 }*/
393 //
394 // Hang.
395 //
396 CpuDeadLoop();
397 }
398
399 #define MAX_BLOCK_IO_PPI 32
400
401 /*
402 CheckIfMediaPresentOnBlockIoDevice:
403 Checks to see whether there was a media device error or to see if there is media present.
404 */
405 VOID
406 CheckIfMediaPresentOnBlockIoDevice (
407 IN EFI_PEI_SERVICES **PeiServices,
408 IN OUT BOOLEAN *MediaDeviceError,
409 IN OUT BOOLEAN *MediaPresent
410 )
411 {
412 EFI_STATUS Status;
413 UINTN BlockIoPpiInstance;
414 EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
415 UINTN NumberBlockDevices;
416 EFI_PEI_BLOCK_IO_MEDIA Media;
417
418 *MediaDeviceError = TRUE;
419 *MediaPresent = FALSE;
420
421 for (BlockIoPpiInstance = 0; BlockIoPpiInstance < MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {
422 Status = PeiServicesLocatePpi (
423 &gEfiPeiVirtualBlockIoPpiGuid,
424 BlockIoPpiInstance,
425 NULL,
426 (VOID **)&BlockIoPpi
427 );
428 if (EFI_ERROR (Status)) {
429 //
430 // Done with all Block Io Ppis
431 //
432 break;
433 }
434
435 Status = BlockIoPpi->GetNumberOfBlockDevices (
436 PeiServices,
437 BlockIoPpi,
438 &NumberBlockDevices
439 );
440 if (EFI_ERROR (Status) || (NumberBlockDevices == 0)) {
441 continue;
442 }
443 //
444 // Just retrieve the first block
445 //
446 Status = BlockIoPpi->GetBlockDeviceMediaInfo (
447 PeiServices,
448 BlockIoPpi,
449 0,
450 &Media
451 );
452 if (!EFI_ERROR (Status)) {
453 *MediaDeviceError = FALSE;
454 if (Media.MediaPresent) {
455 *MediaPresent = TRUE;
456 break;
457 }
458 }
459 }
460 }
461
462 VOID
463 AssertMediaDeviceError (
464 IN EFI_PEI_SERVICES **PeiServices
465 )
466 {
467 /* ReportStatusCode (
468 (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
469 (EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_DEVICE_ERROR)
470 );
471 */
472 CpuDeadLoop ();
473 }
474
475 VOID
476 ReportLoadCapsuleSuccess (
477 IN EFI_PEI_SERVICES **PeiServices
478 )
479 {
480 //
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.
483 //
484 /* ReportStatusCode (
485 EFI_PROGRESS_CODE,
486 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_CAPSULE_LOAD_SUCCESS)
487 );*/
488 }
489