]> git.proxmox.com Git - mirror_edk2.git/blob - SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.c
SignedCapsulePkg: Apply uncrustify changes
[mirror_edk2.git] / SignedCapsulePkg / Universal / RecoveryModuleLoadPei / RecoveryModuleLoadPei.c
1 /** @file
2 Recovery module.
3
4 Caution: This module requires additional review when modified.
5 This module will have external input - capsule image.
6 This external input must be validated carefully to avoid security issue like
7 buffer overflow, integer overflow.
8
9 ProcessRecoveryCapsule(), ProcessFmpCapsuleImage(), ProcessRecoveryImage(),
10 ValidateFmpCapsule() will receive untrusted input and do basic validation.
11
12 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
13 SPDX-License-Identifier: BSD-2-Clause-Patent
14
15 **/
16
17 //
18 // The package level header files this module uses
19 //
20 #include <Uefi.h>
21 #include <PiPei.h>
22 //
23 // The protocols, PPI and GUID definitions for this module
24 //
25 #include <Ppi/MasterBootMode.h>
26 #include <Ppi/BootInRecoveryMode.h>
27 #include <Ppi/RecoveryModule.h>
28 #include <Ppi/DeviceRecoveryModule.h>
29 #include <Ppi/FirmwareVolumeInfo.h>
30 #include <Guid/FirmwareFileSystem2.h>
31 #include <Guid/FmpCapsule.h>
32 #include <Guid/EdkiiSystemFmpCapsule.h>
33
34 //
35 // The Library classes this module consumes
36 //
37 #include <Library/DebugLib.h>
38 #include <Library/PeimEntryPoint.h>
39 #include <Library/PeiServicesLib.h>
40 #include <Library/HobLib.h>
41 #include <Library/BaseMemoryLib.h>
42 #include <Library/MemoryAllocationLib.h>
43 #include <Library/PcdLib.h>
44
45 #include "RecoveryModuleLoadPei.h"
46
47 /**
48 Loads a DXE capsule from some media into memory and updates the HOB table
49 with the DXE firmware volume information.
50
51 @param[in] PeiServices General-purpose services that are available to every PEIM.
52 @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
53
54 @retval EFI_SUCCESS The capsule was loaded correctly.
55 @retval EFI_DEVICE_ERROR A device error occurred.
56 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
57
58 **/
59 EFI_STATUS
60 EFIAPI
61 LoadRecoveryCapsule (
62 IN EFI_PEI_SERVICES **PeiServices,
63 IN EFI_PEI_RECOVERY_MODULE_PPI *This
64 );
65
66 EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi = {
67 LoadRecoveryCapsule
68 };
69
70 EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList = {
71 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
72 &gEfiPeiRecoveryModulePpiGuid,
73 &mRecoveryPpi
74 };
75
76 /**
77 Parse Config data file to get the updated data array.
78
79 @param[in] DataBuffer Config raw file buffer.
80 @param[in] BufferSize Size of raw buffer.
81 @param[in, out] ConfigHeader Pointer to the config header.
82 @param[in, out] RecoveryArray Pointer to the config of recovery data.
83
84 @retval EFI_NOT_FOUND No config data is found.
85 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
86 @retval EFI_SUCCESS Parse the config file successfully.
87
88 **/
89 EFI_STATUS
90 ParseRecoveryDataFile (
91 IN UINT8 *DataBuffer,
92 IN UINTN BufferSize,
93 IN OUT CONFIG_HEADER *ConfigHeader,
94 IN OUT RECOVERY_CONFIG_DATA **RecoveryArray
95 );
96
97 /**
98 Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.
99
100 @param[in] FmpImageHeader A pointer to EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
101
102 @return TRUE It is a system FMP.
103 @return FALSE It is a device FMP.
104 **/
105 BOOLEAN
106 IsSystemFmpImage (
107 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *FmpImageHeader
108 )
109 {
110 GUID *Guid;
111 UINTN Count;
112 UINTN Index;
113
114 Guid = PcdGetPtr (PcdSystemFmpCapsuleImageTypeIdGuid);
115 Count = PcdGetSize (PcdSystemFmpCapsuleImageTypeIdGuid) / sizeof (GUID);
116
117 for (Index = 0; Index < Count; Index++, Guid++) {
118 if (CompareGuid (&FmpImageHeader->UpdateImageTypeId, Guid)) {
119 return TRUE;
120 }
121 }
122
123 return FALSE;
124 }
125
126 /**
127 Return if this CapsuleGuid is a FMP capsule GUID or not.
128
129 @param[in] CapsuleGuid A pointer to EFI_GUID
130
131 @return TRUE It is a FMP capsule GUID.
132 @return FALSE It is not a FMP capsule GUID.
133 **/
134 BOOLEAN
135 IsFmpCapsuleGuid (
136 IN EFI_GUID *CapsuleGuid
137 )
138 {
139 if (CompareGuid (&gEfiFmpCapsuleGuid, CapsuleGuid)) {
140 return TRUE;
141 }
142
143 return FALSE;
144 }
145
146 /**
147 This function assumes the input Capsule image already passes basic check in
148 ValidateFmpCapsule().
149
150 Criteria of system FMP capsule is:
151 1) FmpCapsuleHeader->EmbeddedDriverCount is 0.
152 2) FmpCapsuleHeader->PayloadItemCount is not 0.
153 3) All ImageHeader->UpdateImageTypeId matches PcdSystemFmpCapsuleImageTypeIdGuid.
154
155 @param[in] CapsuleHeader Points to a capsule header.
156
157 @retval TRUE Input capsule is a correct system FMP capsule.
158 @retval FALSE Input capsule is not a correct system FMP capsule.
159 **/
160 BOOLEAN
161 IsSystemFmpCapsuleImage (
162 IN EFI_CAPSULE_HEADER *CapsuleHeader
163 )
164 {
165 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
166 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
167 UINT64 *ItemOffsetList;
168 UINT32 ItemNum;
169 UINTN Index;
170
171 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
172
173 if (FmpCapsuleHeader->EmbeddedDriverCount != 0) {
174 return FALSE;
175 }
176
177 if (FmpCapsuleHeader->PayloadItemCount == 0) {
178 return FALSE;
179 }
180
181 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
182
183 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
184
185 for (Index = 0; Index < ItemNum; Index++) {
186 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
187 if (!IsSystemFmpImage (ImageHeader)) {
188 return FALSE;
189 }
190 }
191
192 return TRUE;
193 }
194
195 /**
196 Validate if it is valid capsule header
197
198 This function assumes the caller provided correct CapsuleHeader pointer
199 and CapsuleSize.
200
201 This function validates the fields in EFI_CAPSULE_HEADER.
202
203 @param[in] CapsuleHeader Points to a capsule header.
204 @param[in] CapsuleSize Size of the whole capsule image.
205
206 **/
207 BOOLEAN
208 IsValidCapsuleHeader (
209 IN EFI_CAPSULE_HEADER *CapsuleHeader,
210 IN UINT64 CapsuleSize
211 )
212 {
213 if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
214 return FALSE;
215 }
216
217 if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
218 return FALSE;
219 }
220
221 return TRUE;
222 }
223
224 /**
225 Validate Fmp capsules layout.
226
227 Caution: This function may receive untrusted input.
228
229 This function assumes the caller validated the capsule by using
230 IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
231 The capsule buffer size is CapsuleHeader->CapsuleImageSize.
232
233 This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
234 and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
235
236 @param[in] CapsuleHeader Points to a capsule header.
237 @param[out] IsSystemFmp If it is a system FMP.
238 @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.
239
240 @retval EFI_SUCCESS Input capsule is a correct FMP capsule.
241 @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.
242 **/
243 EFI_STATUS
244 ValidateFmpCapsule (
245 IN EFI_CAPSULE_HEADER *CapsuleHeader,
246 OUT BOOLEAN *IsSystemFmp OPTIONAL,
247 OUT UINT16 *EmbeddedDriverCount OPTIONAL
248 )
249 {
250 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
251 UINT8 *EndOfCapsule;
252 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
253 UINT8 *EndOfPayload;
254 UINT64 *ItemOffsetList;
255 UINT32 ItemNum;
256 UINTN Index;
257 UINTN FmpCapsuleSize;
258 UINTN FmpCapsuleHeaderSize;
259 UINT64 FmpImageSize;
260 UINTN FmpImageHeaderSize;
261
262 if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
263 DEBUG ((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
264 return EFI_INVALID_PARAMETER;
265 }
266
267 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
268 EndOfCapsule = (UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize;
269 FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;
270
271 if (FmpCapsuleSize < sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {
272 DEBUG ((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));
273 return EFI_INVALID_PARAMETER;
274 }
275
276 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
277 if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
278 DEBUG ((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));
279 return EFI_INVALID_PARAMETER;
280 }
281
282 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
283
284 // No overflow
285 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
286
287 if ((FmpCapsuleSize - sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof (UINT64) < ItemNum) {
288 DEBUG ((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));
289 return EFI_INVALID_PARAMETER;
290 }
291
292 FmpCapsuleHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof (UINT64)*ItemNum;
293
294 // Check ItemOffsetList
295 for (Index = 0; Index < ItemNum; Index++) {
296 if (ItemOffsetList[Index] >= FmpCapsuleSize) {
297 DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));
298 return EFI_INVALID_PARAMETER;
299 }
300
301 if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {
302 DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));
303 return EFI_INVALID_PARAMETER;
304 }
305
306 //
307 // All the address in ItemOffsetList must be stored in ascending order
308 //
309 if (Index > 0) {
310 if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {
311 DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index, ItemOffsetList[Index - 1]));
312 return EFI_INVALID_PARAMETER;
313 }
314 }
315 }
316
317 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
318 for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
319 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
320 if (Index == ItemNum - 1) {
321 EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);
322 } else {
323 EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];
324 }
325
326 FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];
327
328 if (FmpImageSize < OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance)) {
329 DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize));
330 return EFI_INVALID_PARAMETER;
331 }
332
333 FmpImageHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);
334 if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||
335 (ImageHeader->Version < 1))
336 {
337 DEBUG ((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));
338 return EFI_INVALID_PARAMETER;
339 }
340
341 ///
342 /// Current Init ImageHeader version is 3. UpdateHardwareInstance field was added in version 2
343 /// and ImageCapsuleSupport field was added in version 3
344 ///
345 if (ImageHeader->Version == 1) {
346 FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
347 } else if (ImageHeader->Version == 2) {
348 FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
349 }
350
351 // No overflow
352 if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {
353 DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));
354 return EFI_INVALID_PARAMETER;
355 }
356 }
357
358 if (ItemNum == 0) {
359 //
360 // No driver & payload element in FMP
361 //
362 EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
363 if (EndOfPayload != EndOfCapsule) {
364 DEBUG ((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));
365 return EFI_INVALID_PARAMETER;
366 }
367
368 return EFI_UNSUPPORTED;
369 }
370
371 //
372 // Check in system FMP capsule
373 //
374 if (IsSystemFmp != NULL) {
375 *IsSystemFmp = IsSystemFmpCapsuleImage (CapsuleHeader);
376 }
377
378 if (EmbeddedDriverCount != NULL) {
379 *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;
380 }
381
382 return EFI_SUCCESS;
383 }
384
385 /**
386 Recovery module entrypoint
387
388 @param[in] FileHandle Handle of the file being invoked.
389 @param[in] PeiServices Describes the list of possible PEI Services.
390
391 @return EFI_SUCCESS Recovery module is initialized.
392 **/
393 EFI_STATUS
394 EFIAPI
395 InitializeRecoveryModule (
396 IN EFI_PEI_FILE_HANDLE FileHandle,
397 IN CONST EFI_PEI_SERVICES **PeiServices
398 )
399 {
400 EFI_STATUS Status;
401 UINTN BootMode;
402
403 BootMode = GetBootModeHob ();
404 ASSERT (BootMode == BOOT_IN_RECOVERY_MODE);
405
406 Status = (**PeiServices).InstallPpi (PeiServices, &mRecoveryPpiList);
407 ASSERT_EFI_ERROR (Status);
408
409 return Status;
410 }
411
412 /**
413 Create hob and install FvInfo PPI for recovery capsule.
414
415 @param[in] FvImage Points to the DXE FV image.
416 @param[in] FvImageSize The length of the DXE FV image in bytes.
417
418 @retval EFI_SUCCESS Create hob and install FvInfo PPI successfully.
419 @retval EFI_VOLUME_CORRUPTED The input data is not an FV.
420 @retval EFI_OUT_OF_RESOURCES No enough resource to process the input data.
421 **/
422 EFI_STATUS
423 EFIAPI
424 CreateHobForRecoveryCapsule (
425 IN VOID *FvImage,
426 IN UINTN FvImageSize
427 )
428 {
429 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
430 UINT32 FvAlignment;
431 UINT64 FvLength;
432 VOID *NewFvBuffer;
433
434 //
435 // FvImage should be at its required alignment.
436 //
437 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvImage;
438 //
439 // Validate FV Header, if not as expected, return
440 //
441 if (ReadUnaligned32 (&FvHeader->Signature) != EFI_FVH_SIGNATURE) {
442 DEBUG ((DEBUG_ERROR, "CreateHobForRecoveryCapsule (Fv Signature Error)\n"));
443 return EFI_VOLUME_CORRUPTED;
444 }
445
446 //
447 // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
448 // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
449 // its initial linked location and maintain its alignment.
450 //
451 if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
452 //
453 // Get FvHeader alignment
454 //
455 FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);
456 //
457 // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
458 //
459 if (FvAlignment < 8) {
460 FvAlignment = 8;
461 }
462
463 //
464 // Allocate the aligned buffer for the FvImage.
465 //
466 if ((UINTN)FvHeader % FvAlignment != 0) {
467 DEBUG ((DEBUG_INFO, "CreateHobForRecoveryCapsule (FvHeader 0x%lx is not aligned)\n", (UINT64)(UINTN)FvHeader));
468 FvLength = ReadUnaligned64 (&FvHeader->FvLength);
469 NewFvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN)FvLength), FvAlignment);
470 if (NewFvBuffer == NULL) {
471 DEBUG ((DEBUG_ERROR, "CreateHobForRecoveryCapsule (Not enough resource to allocate 0x%lx bytes)\n", FvLength));
472 return EFI_OUT_OF_RESOURCES;
473 }
474
475 CopyMem (NewFvBuffer, FvHeader, (UINTN)FvLength);
476 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)NewFvBuffer;
477 }
478 }
479
480 BuildFvHob ((UINT64)(UINTN)FvHeader, FvHeader->FvLength);
481 DEBUG ((DEBUG_INFO, "BuildFvHob (FV in recovery) - 0x%lx - 0x%lx\n", (UINT64)(UINTN)FvHeader, FvHeader->FvLength));
482
483 PeiServicesInstallFvInfoPpi (
484 &FvHeader->FileSystemGuid,
485 (VOID *)FvHeader,
486 (UINT32)FvHeader->FvLength,
487 NULL,
488 NULL
489 );
490
491 return EFI_SUCCESS;
492 }
493
494 /**
495 Create recovery context based upon System Firmware image and config file.
496
497 @param[in] SystemFirmwareImage Points to the System Firmware image.
498 @param[in] SystemFirmwareImageSize The length of the System Firmware image in bytes.
499 @param[in] ConfigImage Points to the config file image.
500 @param[in] ConfigImageSize The length of the config file image in bytes.
501
502 @retval EFI_SUCCESS Process Recovery Image successfully.
503 **/
504 EFI_STATUS
505 RecoverImage (
506 IN VOID *SystemFirmwareImage,
507 IN UINTN SystemFirmwareImageSize,
508 IN VOID *ConfigImage,
509 IN UINTN ConfigImageSize
510 )
511 {
512 EFI_STATUS Status;
513 RECOVERY_CONFIG_DATA *ConfigData;
514 RECOVERY_CONFIG_DATA *RecoveryConfigData;
515 CONFIG_HEADER ConfigHeader;
516 UINTN Index;
517
518 if (ConfigImage == NULL) {
519 DEBUG ((DEBUG_INFO, "RecoverImage (NoConfig)\n"));
520 Status = CreateHobForRecoveryCapsule (
521 SystemFirmwareImage,
522 SystemFirmwareImageSize
523 );
524 return Status;
525 }
526
527 ConfigData = NULL;
528 ZeroMem (&ConfigHeader, sizeof (ConfigHeader));
529 Status = ParseRecoveryDataFile (
530 ConfigImage,
531 ConfigImageSize,
532 &ConfigHeader,
533 &ConfigData
534 );
535 DEBUG ((DEBUG_INFO, "ParseRecoveryDataFile - %r\n", Status));
536 if (EFI_ERROR (Status)) {
537 return Status;
538 }
539
540 DEBUG ((DEBUG_INFO, "ConfigHeader.NumOfRecovery - 0x%x\n", ConfigHeader.NumOfRecovery));
541 DEBUG ((DEBUG_INFO, "PcdEdkiiSystemFirmwareFileGuid - %g\n", PcdGetPtr (PcdEdkiiSystemFirmwareFileGuid)));
542
543 Index = 0;
544 RecoveryConfigData = ConfigData;
545 while (Index < ConfigHeader.NumOfRecovery) {
546 if (CompareGuid (&RecoveryConfigData->FileGuid, PcdGetPtr (PcdEdkiiSystemFirmwareFileGuid))) {
547 DEBUG ((DEBUG_INFO, "FileGuid - %g (processing)\n", &RecoveryConfigData->FileGuid));
548 Status = CreateHobForRecoveryCapsule (
549 (UINT8 *)SystemFirmwareImage + RecoveryConfigData->ImageOffset,
550 RecoveryConfigData->Length
551 );
552 //
553 // Shall updates be serialized so that if a recovery FV is not successfully completed,
554 // the remaining updates won't be performed.
555 //
556 if (EFI_ERROR (Status)) {
557 break;
558 }
559 } else {
560 DEBUG ((DEBUG_INFO, "FileGuid - %g (ignored)\n", &RecoveryConfigData->FileGuid));
561 }
562
563 Index++;
564 RecoveryConfigData++;
565 }
566
567 return Status;
568 }
569
570 /**
571 Process recovery image.
572
573 Caution: This function may receive untrusted input.
574
575 @param[in] Image Points to the recovery image.
576 @param[in] Length The length of the recovery image in bytes.
577
578 @retval EFI_SUCCESS Process Recovery Image successfully.
579 @retval EFI_SECURITY_VIOLATION Recovery image is not processed due to security violation.
580 **/
581 EFI_STATUS
582 ProcessRecoveryImage (
583 IN VOID *Image,
584 IN UINTN Length
585 )
586 {
587 UINT32 LastAttemptVersion;
588 UINT32 LastAttemptStatus;
589 EFI_STATUS Status;
590 VOID *SystemFirmwareImage;
591 UINTN SystemFirmwareImageSize;
592 VOID *ConfigImage;
593 UINTN ConfigImageSize;
594 VOID *AuthenticatedImage;
595 UINTN AuthenticatedImageSize;
596
597 AuthenticatedImage = NULL;
598 AuthenticatedImageSize = 0;
599
600 Status = CapsuleAuthenticateSystemFirmware (Image, Length, TRUE, &LastAttemptVersion, &LastAttemptStatus, &AuthenticatedImage, &AuthenticatedImageSize);
601 if (EFI_ERROR (Status)) {
602 DEBUG ((DEBUG_INFO, "CapsuleAuthenticateSystemFirmware - %r\n", Status));
603 return Status;
604 }
605
606 ExtractSystemFirmwareImage (AuthenticatedImage, AuthenticatedImageSize, &SystemFirmwareImage, &SystemFirmwareImageSize);
607 ExtractConfigImage (AuthenticatedImage, AuthenticatedImageSize, &ConfigImage, &ConfigImageSize);
608
609 Status = RecoverImage (SystemFirmwareImage, SystemFirmwareImageSize, ConfigImage, ConfigImageSize);
610 if (EFI_ERROR (Status)) {
611 DEBUG ((DEBUG_INFO, "RecoverImage - %r\n", Status));
612 return Status;
613 }
614
615 return EFI_SUCCESS;
616 }
617
618 /**
619 Process Firmware management protocol data capsule.
620
621 Caution: This function may receive untrusted input.
622
623 This function assumes the caller validated the capsule by using
624 ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
625 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
626 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
627
628 @param[in] CapsuleHeader Points to a capsule header.
629 @param[in] IsSystemFmp If this capsule is a system FMP capsule.
630
631 @retval EFI_SUCCESS Process Capsule Image successfully.
632 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
633 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
634 @retval EFI_OUT_OF_RESOURCES Not enough memory.
635 **/
636 EFI_STATUS
637 ProcessFmpCapsuleImage (
638 IN EFI_CAPSULE_HEADER *CapsuleHeader,
639 IN BOOLEAN IsSystemFmp
640 )
641 {
642 EFI_STATUS Status;
643 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
644 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
645 UINT8 *Image;
646 UINT64 *ItemOffsetList;
647 UINTN ItemIndex;
648
649 if (!IsSystemFmp) {
650 return EFI_UNSUPPORTED;
651 }
652
653 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
654 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
655
656 for (ItemIndex = 0; ItemIndex < FmpCapsuleHeader->PayloadItemCount; ItemIndex++) {
657 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemIndex]);
658 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
659 Image = (UINT8 *)(ImageHeader + 1);
660 } else {
661 //
662 // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, only match ImageTypeId.
663 // Header should exclude UpdateHardwareInstance field.
664 // If version is 2 Header should exclude ImageCapsuleSupport field.
665 //
666 if (ImageHeader->Version == 1) {
667 Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
668 } else {
669 Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
670 }
671 }
672
673 Status = ProcessRecoveryImage (Image, ImageHeader->UpdateImageSize);
674 if (EFI_ERROR (Status)) {
675 return Status;
676 }
677 }
678
679 return EFI_SUCCESS;
680 }
681
682 /**
683 Process recovery capsule image.
684
685 Caution: This function may receive untrusted input.
686
687 @param[in] CapsuleBuffer The capsule image buffer.
688 @param[in] CapsuleSize The size of the capsule image in bytes.
689
690 @retval EFI_SUCCESS The recovery capsule is processed.
691 @retval EFI_SECURITY_VIOLATION The recovery capsule is not process because of security violation.
692 @retval EFI_NOT_FOUND The recovery capsule is not process because of unrecognization.
693 **/
694 EFI_STATUS
695 EFIAPI
696 ProcessRecoveryCapsule (
697 IN VOID *CapsuleBuffer,
698 IN UINTN CapsuleSize
699 )
700 {
701 EFI_STATUS Status;
702 BOOLEAN IsSystemFmp;
703 EFI_CAPSULE_HEADER *CapsuleHeader;
704
705 CapsuleHeader = CapsuleBuffer;
706 if (!IsValidCapsuleHeader (CapsuleHeader, CapsuleSize)) {
707 DEBUG ((DEBUG_ERROR, "CapsuleImageSize incorrect\n"));
708 return EFI_SECURITY_VIOLATION;
709 }
710
711 //
712 // Check FMP capsule layout
713 //
714 if (IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
715 DEBUG ((DEBUG_INFO, "CreateHobForRecoveryCapsule\n"));
716
717 DEBUG ((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));
718 DEBUG ((DEBUG_INFO, "ValidateFmpCapsule ...\n"));
719 Status = ValidateFmpCapsule (CapsuleHeader, &IsSystemFmp, NULL);
720 DEBUG ((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));
721 if (EFI_ERROR (Status)) {
722 return Status;
723 }
724
725 //
726 // Process EFI FMP Capsule
727 //
728 DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
729 Status = ProcessFmpCapsuleImage (CapsuleHeader, IsSystemFmp);
730 DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
731
732 DEBUG ((DEBUG_INFO, "CreateHobForRecoveryCapsule Done\n"));
733 return Status;
734 }
735
736 return EFI_UNSUPPORTED;
737 }
738
739 /**
740 Loads a DXE capsule from some media into memory and updates the HOB table
741 with the DXE firmware volume information.
742
743 @param[in] PeiServices General-purpose services that are available to every PEIM.
744 @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
745
746 @retval EFI_SUCCESS The capsule was loaded correctly.
747 @retval EFI_DEVICE_ERROR A device error occurred.
748 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
749
750 **/
751 EFI_STATUS
752 EFIAPI
753 LoadRecoveryCapsule (
754 IN EFI_PEI_SERVICES **PeiServices,
755 IN EFI_PEI_RECOVERY_MODULE_PPI *This
756 )
757 {
758 EFI_STATUS Status;
759 EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *DeviceRecoveryPpi;
760 UINTN NumberRecoveryCapsules;
761 UINTN Instance;
762 UINTN CapsuleInstance;
763 UINTN CapsuleSize;
764 EFI_GUID CapsuleType;
765 VOID *CapsuleBuffer;
766
767 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Recovery Entry\n"));
768
769 for (Instance = 0; ; Instance++) {
770 Status = PeiServicesLocatePpi (
771 &gEfiPeiDeviceRecoveryModulePpiGuid,
772 Instance,
773 NULL,
774 (VOID **)&DeviceRecoveryPpi
775 );
776 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - LocateRecoveryPpi (%d) - %r\n", Instance, Status));
777 if (EFI_ERROR (Status)) {
778 break;
779 }
780
781 NumberRecoveryCapsules = 0;
782 Status = DeviceRecoveryPpi->GetNumberRecoveryCapsules (
783 (EFI_PEI_SERVICES **)PeiServices,
784 DeviceRecoveryPpi,
785 &NumberRecoveryCapsules
786 );
787 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - GetNumberRecoveryCapsules (%d) - %r\n", NumberRecoveryCapsules, Status));
788 if (EFI_ERROR (Status)) {
789 continue;
790 }
791
792 for (CapsuleInstance = 1; CapsuleInstance <= NumberRecoveryCapsules; CapsuleInstance++) {
793 CapsuleSize = 0;
794 Status = DeviceRecoveryPpi->GetRecoveryCapsuleInfo (
795 (EFI_PEI_SERVICES **)PeiServices,
796 DeviceRecoveryPpi,
797 CapsuleInstance,
798 &CapsuleSize,
799 &CapsuleType
800 );
801 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - GetRecoveryCapsuleInfo (%d - %x) - %r\n", CapsuleInstance, CapsuleSize, Status));
802 if (EFI_ERROR (Status)) {
803 break;
804 }
805
806 CapsuleBuffer = AllocatePages (EFI_SIZE_TO_PAGES (CapsuleSize));
807 if (CapsuleBuffer == NULL) {
808 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - AllocatePool fail\n"));
809 continue;
810 }
811
812 Status = DeviceRecoveryPpi->LoadRecoveryCapsule (
813 (EFI_PEI_SERVICES **)PeiServices,
814 DeviceRecoveryPpi,
815 CapsuleInstance,
816 CapsuleBuffer
817 );
818 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance, Status));
819 if (EFI_ERROR (Status)) {
820 FreePages (CapsuleBuffer, EFI_SIZE_TO_PAGES (CapsuleSize));
821 break;
822 }
823
824 //
825 // good, load capsule buffer
826 //
827 Status = ProcessRecoveryCapsule (CapsuleBuffer, CapsuleSize);
828 return Status;
829 }
830 }
831
832 return EFI_NOT_FOUND;
833 }