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