]> git.proxmox.com Git - mirror_edk2.git/blob - SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.c
SignedCapsulePkg/Universal: Fix various typos
[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 if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
217 return FALSE;
218 }
219 return TRUE;
220 }
221
222 /**
223 Validate Fmp capsules layout.
224
225 Caution: This function may receive untrusted input.
226
227 This function assumes the caller validated the capsule by using
228 IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
229 The capsule buffer size is CapsuleHeader->CapsuleImageSize.
230
231 This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
232 and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
233
234 @param[in] CapsuleHeader Points to a capsule header.
235 @param[out] IsSystemFmp If it is a system FMP.
236 @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.
237
238 @retval EFI_SUCCESS Input capsule is a correct FMP capsule.
239 @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.
240 **/
241 EFI_STATUS
242 ValidateFmpCapsule (
243 IN EFI_CAPSULE_HEADER *CapsuleHeader,
244 OUT BOOLEAN *IsSystemFmp, OPTIONAL
245 OUT UINT16 *EmbeddedDriverCount OPTIONAL
246 )
247 {
248 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
249 UINT8 *EndOfCapsule;
250 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
251 UINT8 *EndOfPayload;
252 UINT64 *ItemOffsetList;
253 UINT32 ItemNum;
254 UINTN Index;
255 UINTN FmpCapsuleSize;
256 UINTN FmpCapsuleHeaderSize;
257 UINT64 FmpImageSize;
258 UINTN FmpImageHeaderSize;
259
260 if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
261 DEBUG((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
262 return EFI_INVALID_PARAMETER;
263 }
264
265 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
266 EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;
267 FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;
268
269 if (FmpCapsuleSize < sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {
270 DEBUG((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));
271 return EFI_INVALID_PARAMETER;
272 }
273
274 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
275 if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
276 DEBUG((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));
277 return EFI_INVALID_PARAMETER;
278 }
279 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
280
281 // No overflow
282 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
283
284 if ((FmpCapsuleSize - sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof(UINT64) < ItemNum) {
285 DEBUG((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));
286 return EFI_INVALID_PARAMETER;
287 }
288 FmpCapsuleHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof(UINT64)*ItemNum;
289
290 // Check ItemOffsetList
291 for (Index = 0; Index < ItemNum; Index++) {
292 if (ItemOffsetList[Index] >= FmpCapsuleSize) {
293 DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));
294 return EFI_INVALID_PARAMETER;
295 }
296 if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {
297 DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));
298 return EFI_INVALID_PARAMETER;
299 }
300 //
301 // All the address in ItemOffsetList must be stored in ascending order
302 //
303 if (Index > 0) {
304 if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {
305 DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index, ItemOffsetList[Index - 1]));
306 return EFI_INVALID_PARAMETER;
307 }
308 }
309 }
310
311 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
312 for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
313 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
314 if (Index == ItemNum - 1) {
315 EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);
316 } else {
317 EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];
318 }
319 FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];
320
321 if (FmpImageSize < OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance)) {
322 DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize));
323 return EFI_INVALID_PARAMETER;
324 }
325 FmpImageHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);
326 if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||
327 (ImageHeader->Version < 1)) {
328 DEBUG((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));
329 return EFI_INVALID_PARAMETER;
330 }
331 if (ImageHeader->Version < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
332 FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
333 }
334
335 // No overflow
336 if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {
337 DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));
338 return EFI_INVALID_PARAMETER;
339 }
340 }
341
342 if (ItemNum == 0) {
343 //
344 // No driver & payload element in FMP
345 //
346 EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
347 if (EndOfPayload != EndOfCapsule) {
348 DEBUG((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));
349 return EFI_INVALID_PARAMETER;
350 }
351 return EFI_UNSUPPORTED;
352 }
353
354 //
355 // Check in system FMP capsule
356 //
357 if (IsSystemFmp != NULL) {
358 *IsSystemFmp = IsSystemFmpCapsuleImage(CapsuleHeader);
359 }
360
361 if (EmbeddedDriverCount != NULL) {
362 *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;
363 }
364
365 return EFI_SUCCESS;
366 }
367
368 /**
369 Recovery module entrypoint
370
371 @param[in] FileHandle Handle of the file being invoked.
372 @param[in] PeiServices Describes the list of possible PEI Services.
373
374 @return EFI_SUCCESS Recovery module is initialized.
375 **/
376 EFI_STATUS
377 EFIAPI
378 InitializeRecoveryModule (
379 IN EFI_PEI_FILE_HANDLE FileHandle,
380 IN CONST EFI_PEI_SERVICES **PeiServices
381 )
382 {
383 EFI_STATUS Status;
384 UINTN BootMode;
385
386 BootMode = GetBootModeHob();
387 ASSERT(BootMode == BOOT_IN_RECOVERY_MODE);
388
389 Status = (**PeiServices).InstallPpi (PeiServices, &mRecoveryPpiList);
390 ASSERT_EFI_ERROR (Status);
391
392 return Status;
393 }
394
395 /**
396 Create hob and install FvInfo PPI for recovery capsule.
397
398 @param[in] FvImage Points to the DXE FV image.
399 @param[in] FvImageSize The length of the DXE FV image in bytes.
400
401 @retval EFI_SUCCESS Create hob and install FvInfo PPI successfully.
402 @retval EFI_VOLUME_CORRUPTED The input data is not an FV.
403 @retval EFI_OUT_OF_RESOURCES No enough resource to process the input data.
404 **/
405 EFI_STATUS
406 EFIAPI
407 CreateHobForRecoveryCapsule (
408 IN VOID *FvImage,
409 IN UINTN FvImageSize
410 )
411 {
412 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
413 UINT32 FvAlignment;
414 UINT64 FvLength;
415 VOID *NewFvBuffer;
416
417 //
418 // FvImage should be at its required alignment.
419 //
420 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage;
421 //
422 // Validate FV Header, if not as expected, return
423 //
424 if (ReadUnaligned32 (&FvHeader->Signature) != EFI_FVH_SIGNATURE) {
425 DEBUG((DEBUG_ERROR, "CreateHobForRecoveryCapsule (Fv Signature Error)\n"));
426 return EFI_VOLUME_CORRUPTED;
427 }
428 //
429 // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
430 // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
431 // its initial linked location and maintain its alignment.
432 //
433 if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
434 //
435 // Get FvHeader alignment
436 //
437 FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);
438 //
439 // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
440 //
441 if (FvAlignment < 8) {
442 FvAlignment = 8;
443 }
444 //
445 // Allocate the aligned buffer for the FvImage.
446 //
447 if ((UINTN) FvHeader % FvAlignment != 0) {
448 DEBUG((DEBUG_INFO, "CreateHobForRecoveryCapsule (FvHeader 0x%lx is not aligned)\n", (UINT64)(UINTN)FvHeader));
449 FvLength = ReadUnaligned64 (&FvHeader->FvLength);
450 NewFvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN) FvLength), FvAlignment);
451 if (NewFvBuffer == NULL) {
452 DEBUG((DEBUG_ERROR, "CreateHobForRecoveryCapsule (Not enough resource to allocate 0x%lx bytes)\n", FvLength));
453 return EFI_OUT_OF_RESOURCES;
454 }
455 CopyMem (NewFvBuffer, FvHeader, (UINTN) FvLength);
456 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) NewFvBuffer;
457 }
458 }
459
460 BuildFvHob((UINT64)(UINTN)FvHeader, FvHeader->FvLength);
461 DEBUG((DEBUG_INFO, "BuildFvHob (FV in recovery) - 0x%lx - 0x%lx\n", (UINT64)(UINTN)FvHeader, FvHeader->FvLength));
462
463 PeiServicesInstallFvInfoPpi(
464 &FvHeader->FileSystemGuid,
465 (VOID *)FvHeader,
466 (UINT32)FvHeader->FvLength,
467 NULL,
468 NULL
469 );
470
471 return EFI_SUCCESS;
472 }
473
474 /**
475 Create recovery context based upon System Firmware image and config file.
476
477 @param[in] SystemFirmwareImage Points to the System Firmware image.
478 @param[in] SystemFirmwareImageSize The length of the System Firmware image in bytes.
479 @param[in] ConfigImage Points to the config file image.
480 @param[in] ConfigImageSize The length of the config file image in bytes.
481
482 @retval EFI_SUCCESS Process Recovery Image successfully.
483 **/
484 EFI_STATUS
485 RecoverImage (
486 IN VOID *SystemFirmwareImage,
487 IN UINTN SystemFirmwareImageSize,
488 IN VOID *ConfigImage,
489 IN UINTN ConfigImageSize
490 )
491 {
492 EFI_STATUS Status;
493 RECOVERY_CONFIG_DATA *ConfigData;
494 RECOVERY_CONFIG_DATA *RecoveryConfigData;
495 CONFIG_HEADER ConfigHeader;
496 UINTN Index;
497
498 if (ConfigImage == NULL) {
499 DEBUG((DEBUG_INFO, "RecoverImage (NoConfig)\n"));
500 Status = CreateHobForRecoveryCapsule(
501 SystemFirmwareImage,
502 SystemFirmwareImageSize
503 );
504 return Status;
505 }
506
507 ConfigData = NULL;
508 ZeroMem (&ConfigHeader, sizeof(ConfigHeader));
509 Status = ParseRecoveryDataFile (
510 ConfigImage,
511 ConfigImageSize,
512 &ConfigHeader,
513 &ConfigData
514 );
515 DEBUG((DEBUG_INFO, "ParseRecoveryDataFile - %r\n", Status));
516 if (EFI_ERROR(Status)) {
517 return Status;
518 }
519 DEBUG((DEBUG_INFO, "ConfigHeader.NumOfRecovery - 0x%x\n", ConfigHeader.NumOfRecovery));
520 DEBUG((DEBUG_INFO, "PcdEdkiiSystemFirmwareFileGuid - %g\n", PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid)));
521
522 Index = 0;
523 RecoveryConfigData = ConfigData;
524 while (Index < ConfigHeader.NumOfRecovery) {
525 if (CompareGuid(&RecoveryConfigData->FileGuid, PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid))) {
526 DEBUG((DEBUG_INFO, "FileGuid - %g (processing)\n", &RecoveryConfigData->FileGuid));
527 Status = CreateHobForRecoveryCapsule (
528 (UINT8 *)SystemFirmwareImage + RecoveryConfigData->ImageOffset,
529 RecoveryConfigData->Length
530 );
531 //
532 // Shall updates be serialized so that if a recovery FV is not successfully completed,
533 // the remaining updates won't be performed.
534 //
535 if (EFI_ERROR (Status)) {
536 break;
537 }
538 } else {
539 DEBUG((DEBUG_INFO, "FileGuid - %g (ignored)\n", &RecoveryConfigData->FileGuid));
540 }
541
542 Index++;
543 RecoveryConfigData++;
544 }
545
546 return Status;
547 }
548
549 /**
550 Process recovery image.
551
552 Caution: This function may receive untrusted input.
553
554 @param[in] Image Points to the recovery image.
555 @param[in] Length The length of the recovery image in bytes.
556
557 @retval EFI_SUCCESS Process Recovery Image successfully.
558 @retval EFI_SECURITY_VIOLATION Recovery image is not processed due to security violation.
559 **/
560 EFI_STATUS
561 ProcessRecoveryImage (
562 IN VOID *Image,
563 IN UINTN Length
564 )
565 {
566 UINT32 LastAttemptVersion;
567 UINT32 LastAttemptStatus;
568 EFI_STATUS Status;
569 VOID *SystemFirmwareImage;
570 UINTN SystemFirmwareImageSize;
571 VOID *ConfigImage;
572 UINTN ConfigImageSize;
573 VOID *AuthenticatedImage;
574 UINTN AuthenticatedImageSize;
575
576 AuthenticatedImage = NULL;
577 AuthenticatedImageSize = 0;
578
579 Status = CapsuleAuthenticateSystemFirmware(Image, Length, TRUE, &LastAttemptVersion, &LastAttemptStatus, &AuthenticatedImage, &AuthenticatedImageSize);
580 if (EFI_ERROR(Status)) {
581 DEBUG((DEBUG_INFO, "CapsuleAuthenticateSystemFirmware - %r\n", Status));
582 return Status;
583 }
584
585 ExtractSystemFirmwareImage(AuthenticatedImage, AuthenticatedImageSize, &SystemFirmwareImage, &SystemFirmwareImageSize);
586 ExtractConfigImage(AuthenticatedImage, AuthenticatedImageSize, &ConfigImage, &ConfigImageSize);
587
588 Status = RecoverImage(SystemFirmwareImage, SystemFirmwareImageSize, ConfigImage, ConfigImageSize);
589 if (EFI_ERROR(Status)) {
590 DEBUG((DEBUG_INFO, "RecoverImage - %r\n", Status));
591 return Status;
592 }
593
594 return EFI_SUCCESS;
595 }
596
597 /**
598 Process Firmware management protocol data capsule.
599
600 Caution: This function may receive untrusted input.
601
602 This function assumes the caller validated the capsule by using
603 ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
604 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
605 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
606
607 @param[in] CapsuleHeader Points to a capsule header.
608 @param[in] IsSystemFmp If this capsule is a system FMP capsule.
609
610 @retval EFI_SUCCESS Process Capsule Image successfully.
611 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
612 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
613 @retval EFI_OUT_OF_RESOURCES Not enough memory.
614 **/
615 EFI_STATUS
616 ProcessFmpCapsuleImage (
617 IN EFI_CAPSULE_HEADER *CapsuleHeader,
618 IN BOOLEAN IsSystemFmp
619 )
620 {
621 EFI_STATUS Status;
622 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
623 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
624 UINT8 *Image;
625 UINT64 *ItemOffsetList;
626 UINTN ItemIndex;
627
628 if (!IsSystemFmp) {
629 return EFI_UNSUPPORTED;
630 }
631
632 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
633 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
634
635 for (ItemIndex = 0; ItemIndex < FmpCapsuleHeader->PayloadItemCount; ItemIndex++) {
636 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemIndex]);
637 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
638 Image = (UINT8 *)(ImageHeader + 1);
639 } else {
640 //
641 // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, only match ImageTypeId.
642 // Header should exclude UpdateHardwareInstance field
643 //
644 Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
645 }
646
647 Status = ProcessRecoveryImage (Image, ImageHeader->UpdateImageSize);
648 if (EFI_ERROR(Status)) {
649 return Status;
650 }
651 }
652
653 return EFI_SUCCESS;
654 }
655
656 /**
657 Process recovery capsule image.
658
659 Caution: This function may receive untrusted input.
660
661 @param[in] CapsuleBuffer The capsule image buffer.
662 @param[in] CapsuleSize The size of the capsule image in bytes.
663
664 @retval EFI_SUCCESS The recovery capsule is processed.
665 @retval EFI_SECURITY_VIOLATION The recovery capsule is not process because of security violation.
666 @retval EFI_NOT_FOUND The recovery capsule is not process because of unrecognization.
667 **/
668 EFI_STATUS
669 EFIAPI
670 ProcessRecoveryCapsule (
671 IN VOID *CapsuleBuffer,
672 IN UINTN CapsuleSize
673 )
674 {
675 EFI_STATUS Status;
676 BOOLEAN IsSystemFmp;
677 EFI_CAPSULE_HEADER *CapsuleHeader;
678
679 CapsuleHeader = CapsuleBuffer;
680 if (!IsValidCapsuleHeader (CapsuleHeader, CapsuleSize)) {
681 DEBUG((DEBUG_ERROR, "CapsuleImageSize incorrect\n"));
682 return EFI_SECURITY_VIOLATION;
683 }
684
685 //
686 // Check FMP capsule layout
687 //
688 if (IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {
689 DEBUG((DEBUG_INFO, "CreateHobForRecoveryCapsule\n"));
690
691 DEBUG((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));
692 DEBUG((DEBUG_INFO, "ValidateFmpCapsule ...\n"));
693 Status = ValidateFmpCapsule(CapsuleHeader, &IsSystemFmp, NULL);
694 DEBUG((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));
695 if (EFI_ERROR(Status)) {
696 return Status;
697 }
698
699 //
700 // Process EFI FMP Capsule
701 //
702 DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
703 Status = ProcessFmpCapsuleImage(CapsuleHeader, IsSystemFmp);
704 DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
705
706 DEBUG((DEBUG_INFO, "CreateHobForRecoveryCapsule Done\n"));
707 return Status;
708 }
709
710 return EFI_UNSUPPORTED;
711 }
712
713 /**
714 Loads a DXE capsule from some media into memory and updates the HOB table
715 with the DXE firmware volume information.
716
717 @param[in] PeiServices General-purpose services that are available to every PEIM.
718 @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
719
720 @retval EFI_SUCCESS The capsule was loaded correctly.
721 @retval EFI_DEVICE_ERROR A device error occurred.
722 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
723
724 **/
725 EFI_STATUS
726 EFIAPI
727 LoadRecoveryCapsule (
728 IN EFI_PEI_SERVICES **PeiServices,
729 IN EFI_PEI_RECOVERY_MODULE_PPI *This
730 )
731 {
732 EFI_STATUS Status;
733 EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *DeviceRecoveryPpi;
734 UINTN NumberRecoveryCapsules;
735 UINTN Instance;
736 UINTN CapsuleInstance;
737 UINTN CapsuleSize;
738 EFI_GUID CapsuleType;
739 VOID *CapsuleBuffer;
740
741 DEBUG((DEBUG_INFO | DEBUG_LOAD, "Recovery Entry\n"));
742
743 for (Instance = 0; ; Instance++) {
744 Status = PeiServicesLocatePpi (
745 &gEfiPeiDeviceRecoveryModulePpiGuid,
746 Instance,
747 NULL,
748 (VOID **)&DeviceRecoveryPpi
749 );
750 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - LocateRecoveryPpi (%d) - %r\n", Instance, Status));
751 if (EFI_ERROR (Status)) {
752 break;
753 }
754 NumberRecoveryCapsules = 0;
755 Status = DeviceRecoveryPpi->GetNumberRecoveryCapsules (
756 (EFI_PEI_SERVICES **)PeiServices,
757 DeviceRecoveryPpi,
758 &NumberRecoveryCapsules
759 );
760 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - GetNumberRecoveryCapsules (%d) - %r\n", NumberRecoveryCapsules, Status));
761 if (EFI_ERROR (Status)) {
762 continue;
763 }
764 for (CapsuleInstance = 1; CapsuleInstance <= NumberRecoveryCapsules; CapsuleInstance++) {
765 CapsuleSize = 0;
766 Status = DeviceRecoveryPpi->GetRecoveryCapsuleInfo (
767 (EFI_PEI_SERVICES **)PeiServices,
768 DeviceRecoveryPpi,
769 CapsuleInstance,
770 &CapsuleSize,
771 &CapsuleType
772 );
773 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - GetRecoveryCapsuleInfo (%d - %x) - %r\n", CapsuleInstance, CapsuleSize, Status));
774 if (EFI_ERROR (Status)) {
775 break;
776 }
777
778 CapsuleBuffer = AllocatePages (EFI_SIZE_TO_PAGES(CapsuleSize));
779 if (CapsuleBuffer == NULL) {
780 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - AllocatePool fail\n"));
781 continue;
782 }
783 Status = DeviceRecoveryPpi->LoadRecoveryCapsule (
784 (EFI_PEI_SERVICES **)PeiServices,
785 DeviceRecoveryPpi,
786 CapsuleInstance,
787 CapsuleBuffer
788 );
789 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance, Status));
790 if (EFI_ERROR (Status)) {
791 FreePages (CapsuleBuffer, EFI_SIZE_TO_PAGES(CapsuleSize));
792 break;
793 }
794 //
795 // good, load capsule buffer
796 //
797 Status = ProcessRecoveryCapsule (CapsuleBuffer, CapsuleSize);
798 return Status;
799 }
800 }
801
802 return EFI_NOT_FOUND;
803 }