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