]> git.proxmox.com Git - mirror_edk2.git/blob - SignedCapsulePkg/Universal/RecoveryModuleLoadPei/RecoveryModuleLoadPei.c
SignedCapsulePkg: Update RecoveryModuleLoadPei to report the correct FvInfo
[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 - 2017, Intel Corporation. All rights reserved.<BR>
13 This program and the accompanying materials
14 are licensed and made available under the terms and conditions of the BSD License
15 which accompanies this distribution. The full text of the license may be found at
16 http://opensource.org/licenses/bsd-license.php
17
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20
21 **/
22
23 //
24 // The package level header files this module uses
25 //
26 #include <Uefi.h>
27 #include <PiPei.h>
28 //
29 // The protocols, PPI and GUID defintions for this module
30 //
31 #include <Ppi/MasterBootMode.h>
32 #include <Ppi/BootInRecoveryMode.h>
33 #include <Ppi/RecoveryModule.h>
34 #include <Ppi/DeviceRecoveryModule.h>
35 #include <Ppi/FirmwareVolumeInfo.h>
36 #include <Guid/FirmwareFileSystem2.h>
37 #include <Guid/FmpCapsule.h>
38 #include <Guid/EdkiiSystemFmpCapsule.h>
39
40 //
41 // The Library classes this module consumes
42 //
43 #include <Library/DebugLib.h>
44 #include <Library/PeimEntryPoint.h>
45 #include <Library/PeiServicesLib.h>
46 #include <Library/HobLib.h>
47 #include <Library/BaseMemoryLib.h>
48 #include <Library/MemoryAllocationLib.h>
49 #include <Library/PcdLib.h>
50
51 #include "RecoveryModuleLoadPei.h"
52
53 /**
54 Loads a DXE capsule from some media into memory and updates the HOB table
55 with the DXE firmware volume information.
56
57 @param[in] PeiServices General-purpose services that are available to every PEIM.
58 @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
59
60 @retval EFI_SUCCESS The capsule was loaded correctly.
61 @retval EFI_DEVICE_ERROR A device error occurred.
62 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
63
64 **/
65 EFI_STATUS
66 EFIAPI
67 LoadRecoveryCapsule (
68 IN EFI_PEI_SERVICES **PeiServices,
69 IN EFI_PEI_RECOVERY_MODULE_PPI *This
70 );
71
72 EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi = {
73 LoadRecoveryCapsule
74 };
75
76 EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList = {
77 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
78 &gEfiPeiRecoveryModulePpiGuid,
79 &mRecoveryPpi
80 };
81
82 /**
83 Parse Config data file to get the updated data array.
84
85 @param[in] DataBuffer Config raw file buffer.
86 @param[in] BufferSize Size of raw buffer.
87 @param[in, out] ConfigHeader Pointer to the config header.
88 @param[in, out] RecoveryArray Pointer to the config of recovery data.
89
90 @retval EFI_NOT_FOUND No config data is found.
91 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
92 @retval EFI_SUCCESS Parse the config file successfully.
93
94 **/
95 EFI_STATUS
96 ParseRecoveryDataFile (
97 IN UINT8 *DataBuffer,
98 IN UINTN BufferSize,
99 IN OUT CONFIG_HEADER *ConfigHeader,
100 IN OUT RECOVERY_CONFIG_DATA **RecoveryArray
101 );
102
103 /**
104 Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.
105
106 @param[in] FmpImageHeader A pointer to EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
107
108 @return TRUE It is a system FMP.
109 @return FALSE It is a device FMP.
110 **/
111 BOOLEAN
112 IsSystemFmpImage (
113 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *FmpImageHeader
114 )
115 {
116 GUID *Guid;
117 UINTN Count;
118 UINTN Index;
119
120 Guid = PcdGetPtr(PcdSystemFmpCapsuleImageTypeIdGuid);
121 Count = PcdGetSize(PcdSystemFmpCapsuleImageTypeIdGuid) / sizeof(GUID);
122
123 for (Index = 0; Index < Count; Index++, Guid++) {
124 if (CompareGuid(&FmpImageHeader->UpdateImageTypeId, Guid)) {
125 return TRUE;
126 }
127 }
128
129 return FALSE;
130 }
131
132 /**
133 Return if this CapsuleGuid is a FMP capsule GUID or not.
134
135 @param[in] CapsuleGuid A pointer to EFI_GUID
136
137 @return TRUE It is a FMP capsule GUID.
138 @return FALSE It is not a FMP capsule GUID.
139 **/
140 BOOLEAN
141 IsFmpCapsuleGuid (
142 IN EFI_GUID *CapsuleGuid
143 )
144 {
145 if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) {
146 return TRUE;
147 }
148
149 return FALSE;
150 }
151
152 /**
153 This function assumes the input Capusule image already passes basic check in
154 ValidateFmpCapsule().
155
156 Criteria of system FMP capsule is:
157 1) FmpCapsuleHeader->EmbeddedDriverCount is 0.
158 2) FmpCapsuleHeader->PayloadItemCount is not 0.
159 3) All ImageHeader->UpdateImageTypeId matches PcdSystemFmpCapsuleImageTypeIdGuid.
160
161 @param[in] CapsuleHeader Points to a capsule header.
162
163 @retval TRUE Input capsule is a correct system FMP capsule.
164 @retval FALSE Input capsule is not a correct system FMP capsule.
165 **/
166 BOOLEAN
167 IsSystemFmpCapsuleImage (
168 IN EFI_CAPSULE_HEADER *CapsuleHeader
169 )
170 {
171 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
172 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
173 UINT64 *ItemOffsetList;
174 UINT32 ItemNum;
175 UINTN Index;
176
177 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
178
179 if (FmpCapsuleHeader->EmbeddedDriverCount != 0) {
180 return FALSE;
181 }
182
183 if (FmpCapsuleHeader->PayloadItemCount == 0) {
184 return FALSE;
185 }
186
187 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
188
189 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
190
191 for (Index = 0; Index < ItemNum; Index++) {
192 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
193 if (!IsSystemFmpImage(ImageHeader)) {
194 return FALSE;
195 }
196 }
197
198 return TRUE;
199 }
200
201 /**
202 Validate if it is valid capsule header
203
204 This function assumes the caller provided correct CapsuleHeader pointer
205 and CapsuleSize.
206
207 This function validates the fields in EFI_CAPSULE_HEADER.
208
209 @param[in] CapsuleHeader Points to a capsule header.
210 @param[in] CapsuleSize Size of the whole capsule image.
211
212 **/
213 BOOLEAN
214 IsValidCapsuleHeader (
215 IN EFI_CAPSULE_HEADER *CapsuleHeader,
216 IN UINT64 CapsuleSize
217 )
218 {
219 if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
220 return FALSE;
221 }
222 if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
223 return FALSE;
224 }
225 return TRUE;
226 }
227
228 /**
229 Validate Fmp capsules layout.
230
231 Caution: This function may receive untrusted input.
232
233 This function assumes the caller validated the capsule by using
234 IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
235 The capsule buffer size is CapsuleHeader->CapsuleImageSize.
236
237 This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
238 and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
239
240 @param[in] CapsuleHeader Points to a capsule header.
241 @param[out] IsSystemFmp If it is a system FMP.
242 @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.
243
244 @retval EFI_SUCESS Input capsule is a correct FMP capsule.
245 @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.
246 **/
247 EFI_STATUS
248 ValidateFmpCapsule (
249 IN EFI_CAPSULE_HEADER *CapsuleHeader,
250 OUT BOOLEAN *IsSystemFmp, OPTIONAL
251 OUT UINT16 *EmbeddedDriverCount OPTIONAL
252 )
253 {
254 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
255 UINT8 *EndOfCapsule;
256 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
257 UINT8 *EndOfPayload;
258 UINT64 *ItemOffsetList;
259 UINT32 ItemNum;
260 UINTN Index;
261 UINTN FmpCapsuleSize;
262 UINTN FmpCapsuleHeaderSize;
263 UINT64 FmpImageSize;
264 UINTN FmpImageHeaderSize;
265
266 if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
267 DEBUG((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
268 return EFI_INVALID_PARAMETER;
269 }
270
271 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
272 EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;
273 FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;
274
275 if (FmpCapsuleSize < sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {
276 DEBUG((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));
277 return EFI_INVALID_PARAMETER;
278 }
279
280 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
281 if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
282 DEBUG((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));
283 return EFI_INVALID_PARAMETER;
284 }
285 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
286
287 // No overflow
288 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
289
290 if ((FmpCapsuleSize - sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof(UINT64) < ItemNum) {
291 DEBUG((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));
292 return EFI_INVALID_PARAMETER;
293 }
294 FmpCapsuleHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof(UINT64)*ItemNum;
295
296 // Check ItemOffsetList
297 for (Index = 0; Index < ItemNum; Index++) {
298 if (ItemOffsetList[Index] >= FmpCapsuleSize) {
299 DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));
300 return EFI_INVALID_PARAMETER;
301 }
302 if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {
303 DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));
304 return EFI_INVALID_PARAMETER;
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 FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];
326
327 if (FmpImageSize < OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance)) {
328 DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize));
329 return EFI_INVALID_PARAMETER;
330 }
331 FmpImageHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);
332 if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||
333 (ImageHeader->Version < 1)) {
334 DEBUG((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));
335 return EFI_INVALID_PARAMETER;
336 }
337 if (ImageHeader->Version < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
338 FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
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_SUCESS 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_SUCESS 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_SUCESS 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_SUCESS 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 //
650 Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
651 }
652
653 Status = ProcessRecoveryImage (Image, ImageHeader->UpdateImageSize);
654 if (EFI_ERROR(Status)) {
655 return Status;
656 }
657 }
658
659 return EFI_SUCCESS;
660 }
661
662 /**
663 Process recovery capsule image.
664
665 Caution: This function may receive untrusted input.
666
667 @param[in] CapsuleBuffer The capsule image buffer.
668 @param[in] CapsuleSize The size of the capsule image in bytes.
669
670 @retval EFI_SUCCESS The recovery capsule is processed.
671 @retval EFI_SECURITY_VIOLATION The recovery capsule is not process because of security violation.
672 @retval EFI_NOT_FOUND The recovery capsule is not process because of unrecognization.
673 **/
674 EFI_STATUS
675 EFIAPI
676 ProcessRecoveryCapsule (
677 IN VOID *CapsuleBuffer,
678 IN UINTN CapsuleSize
679 )
680 {
681 EFI_STATUS Status;
682 BOOLEAN IsSystemFmp;
683 EFI_CAPSULE_HEADER *CapsuleHeader;
684
685 CapsuleHeader = CapsuleBuffer;
686 if (!IsValidCapsuleHeader (CapsuleHeader, CapsuleSize)) {
687 DEBUG((DEBUG_ERROR, "CapsuleImageSize incorrect\n"));
688 return EFI_SECURITY_VIOLATION;
689 }
690
691 //
692 // Check FMP capsule layout
693 //
694 if (IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {
695 DEBUG((DEBUG_INFO, "CreateHobForRecoveryCapsule\n"));
696
697 DEBUG((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));
698 DEBUG((DEBUG_INFO, "ValidateFmpCapsule ...\n"));
699 Status = ValidateFmpCapsule(CapsuleHeader, &IsSystemFmp, NULL);
700 DEBUG((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));
701 if (EFI_ERROR(Status)) {
702 return Status;
703 }
704
705 //
706 // Press EFI FMP Capsule
707 //
708 DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
709 Status = ProcessFmpCapsuleImage(CapsuleHeader, IsSystemFmp);
710 DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
711
712 DEBUG((DEBUG_INFO, "CreateHobForRecoveryCapsule Done\n"));
713 return Status;
714 }
715
716 return EFI_UNSUPPORTED;
717 }
718
719 /**
720 Loads a DXE capsule from some media into memory and updates the HOB table
721 with the DXE firmware volume information.
722
723 @param[in] PeiServices General-purpose services that are available to every PEIM.
724 @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
725
726 @retval EFI_SUCCESS The capsule was loaded correctly.
727 @retval EFI_DEVICE_ERROR A device error occurred.
728 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
729
730 **/
731 EFI_STATUS
732 EFIAPI
733 LoadRecoveryCapsule (
734 IN EFI_PEI_SERVICES **PeiServices,
735 IN EFI_PEI_RECOVERY_MODULE_PPI *This
736 )
737 {
738 EFI_STATUS Status;
739 EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *DeviceRecoveryPpi;
740 UINTN NumberRecoveryCapsules;
741 UINTN Instance;
742 UINTN CapsuleInstance;
743 UINTN CapsuleSize;
744 EFI_GUID CapsuleType;
745 VOID *CapsuleBuffer;
746
747 DEBUG((DEBUG_INFO | DEBUG_LOAD, "Recovery Entry\n"));
748
749 for (Instance = 0; ; Instance++) {
750 Status = PeiServicesLocatePpi (
751 &gEfiPeiDeviceRecoveryModulePpiGuid,
752 Instance,
753 NULL,
754 (VOID **)&DeviceRecoveryPpi
755 );
756 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - LocateRecoveryPpi (%d) - %r\n", Instance, Status));
757 if (EFI_ERROR (Status)) {
758 break;
759 }
760 NumberRecoveryCapsules = 0;
761 Status = DeviceRecoveryPpi->GetNumberRecoveryCapsules (
762 (EFI_PEI_SERVICES **)PeiServices,
763 DeviceRecoveryPpi,
764 &NumberRecoveryCapsules
765 );
766 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - GetNumberRecoveryCapsules (%d) - %r\n", NumberRecoveryCapsules, Status));
767 if (EFI_ERROR (Status)) {
768 continue;
769 }
770 for (CapsuleInstance = 1; CapsuleInstance <= NumberRecoveryCapsules; CapsuleInstance++) {
771 CapsuleSize = 0;
772 Status = DeviceRecoveryPpi->GetRecoveryCapsuleInfo (
773 (EFI_PEI_SERVICES **)PeiServices,
774 DeviceRecoveryPpi,
775 FeaturePcdGet(PcdFrameworkCompatibilitySupport) ? CapsuleInstance - 1 : CapsuleInstance,
776 &CapsuleSize,
777 &CapsuleType
778 );
779 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - GetRecoveryCapsuleInfo (%d - %x) - %r\n", CapsuleInstance, CapsuleSize, Status));
780 if (EFI_ERROR (Status)) {
781 break;
782 }
783
784 CapsuleBuffer = AllocatePages (EFI_SIZE_TO_PAGES(CapsuleSize));
785 if (CapsuleBuffer == NULL) {
786 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - AllocatePool fail\n"));
787 continue;
788 }
789 Status = DeviceRecoveryPpi->LoadRecoveryCapsule (
790 (EFI_PEI_SERVICES **)PeiServices,
791 DeviceRecoveryPpi,
792 FeaturePcdGet(PcdFrameworkCompatibilitySupport) ? CapsuleInstance - 1 : CapsuleInstance,
793 CapsuleBuffer
794 );
795 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance, Status));
796 if (EFI_ERROR (Status)) {
797 FreePages (CapsuleBuffer, EFI_SIZE_TO_PAGES(CapsuleSize));
798 break;
799 }
800 //
801 // good, load capsule buffer
802 //
803 Status = ProcessRecoveryCapsule (CapsuleBuffer, CapsuleSize);
804 return Status;
805 }
806 }
807
808 return EFI_NOT_FOUND;
809 }