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