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