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