]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
ArmVirtPkg: Add SafeIntLib and BmpSupportLib to DSC files
[mirror_edk2.git] / MdeModulePkg / Library / DxeCapsuleLibFmp / DxeCapsuleLib.c
CommitLineData
d2a16030
JY
1/** @file\r
2 DXE capsule library.\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 SupportCapsuleImage(), ProcessCapsuleImage(), IsValidCapsuleHeader(),\r
1ec2e7d0
MK
10 ValidateFmpCapsule(), and DisplayCapsuleImage() receives untrusted input and\r
11 performs basic validation.\r
d2a16030 12\r
1ec2e7d0 13 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
d2a16030
JY
14 This program and the accompanying materials\r
15 are licensed and made available under the terms and conditions of the BSD License\r
16 which accompanies this distribution. The full text of the license may be found at\r
17 http://opensource.org/licenses/bsd-license.php\r
18\r
19 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
20 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
21\r
22**/\r
23\r
24#include <PiDxe.h>\r
25\r
d2a16030
JY
26#include <IndustryStandard/WindowsUxCapsule.h>\r
27\r
28#include <Guid/FmpCapsule.h>\r
29#include <Guid/SystemResourceTable.h>\r
30#include <Guid/EventGroup.h>\r
31\r
32#include <Library/BaseLib.h>\r
33#include <Library/DebugLib.h>\r
34#include <Library/BaseMemoryLib.h>\r
35#include <Library/DxeServicesTableLib.h>\r
36#include <Library/UefiBootServicesTableLib.h>\r
37#include <Library/UefiRuntimeServicesTableLib.h>\r
38#include <Library/MemoryAllocationLib.h>\r
39#include <Library/CapsuleLib.h>\r
40#include <Library/DevicePathLib.h>\r
41#include <Library/UefiLib.h>\r
42#include <Library/PcdLib.h>\r
1ec2e7d0 43#include <Library/BmpSupportLib.h>\r
d2a16030
JY
44\r
45#include <Protocol/GraphicsOutput.h>\r
46#include <Protocol/EsrtManagement.h>\r
47#include <Protocol/FirmwareManagement.h>\r
48#include <Protocol/DevicePath.h>\r
49\r
03286264
DB
50EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable = NULL;\r
51BOOLEAN mIsVirtualAddrConverted = FALSE;\r
d948cf83 52\r
96b17e00
HW
53BOOLEAN mDxeCapsuleLibEndOfDxe = FALSE;\r
54EFI_EVENT mDxeCapsuleLibEndOfDxeEvent = NULL;\r
d2a16030
JY
55\r
56/**\r
57 Initialize capsule related variables.\r
58**/\r
59VOID\r
60InitCapsuleVariable (\r
61 VOID\r
62 );\r
63\r
d2a16030
JY
64/**\r
65 Record capsule status variable.\r
66\r
67 @param[in] CapsuleHeader The capsule image header\r
68 @param[in] CapsuleStatus The capsule process stauts\r
69\r
70 @retval EFI_SUCCESS The capsule status variable is recorded.\r
71 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
72**/\r
73EFI_STATUS\r
74RecordCapsuleStatusVariable (\r
75 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
76 IN EFI_STATUS CapsuleStatus\r
77 );\r
78\r
79/**\r
80 Record FMP capsule status variable.\r
81\r
82 @param[in] CapsuleHeader The capsule image header\r
83 @param[in] CapsuleStatus The capsule process stauts\r
84 @param[in] PayloadIndex FMP payload index\r
85 @param[in] ImageHeader FMP image header\r
8f6db161 86 @param[in] FmpDevicePath DevicePath associated with the FMP producer\r
d2a16030
JY
87\r
88 @retval EFI_SUCCESS The capsule status variable is recorded.\r
89 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
90**/\r
91EFI_STATUS\r
92RecordFmpCapsuleStatusVariable (\r
93 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
94 IN EFI_STATUS CapsuleStatus,\r
95 IN UINTN PayloadIndex,\r
8f6db161
JY
96 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,\r
97 IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL\r
d2a16030
JY
98 );\r
99\r
100/**\r
101 Function indicate the current completion progress of the firmware\r
102 update. Platform may override with own specific progress function.\r
103\r
104 @param[in] Completion A value between 1 and 100 indicating the current completion progress of the firmware update\r
105\r
106 @retval EFI_SUCESS Input capsule is a correct FMP capsule.\r
107**/\r
108EFI_STATUS\r
109EFIAPI\r
110Update_Image_Progress (\r
111 IN UINTN Completion\r
112 )\r
113{\r
114 return EFI_SUCCESS;\r
115}\r
116\r
117/**\r
118 Return if this CapsuleGuid is a FMP capsule GUID or not.\r
119\r
120 @param[in] CapsuleGuid A pointer to EFI_GUID\r
121\r
122 @retval TRUE It is a FMP capsule GUID.\r
123 @retval FALSE It is not a FMP capsule GUID.\r
124**/\r
125BOOLEAN\r
126IsFmpCapsuleGuid (\r
127 IN EFI_GUID *CapsuleGuid\r
128 )\r
129{\r
130 if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) {\r
131 return TRUE;\r
132 }\r
133\r
134 return FALSE;\r
135}\r
136\r
137/**\r
138 Validate if it is valid capsule header\r
139\r
140 Caution: This function may receive untrusted input.\r
141\r
142 This function assumes the caller provided correct CapsuleHeader pointer\r
143 and CapsuleSize.\r
144\r
145 This function validates the fields in EFI_CAPSULE_HEADER.\r
146\r
147 @param[in] CapsuleHeader Points to a capsule header.\r
148 @param[in] CapsuleSize Size of the whole capsule image.\r
149\r
150**/\r
151BOOLEAN\r
152IsValidCapsuleHeader (\r
153 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
154 IN UINT64 CapsuleSize\r
155 )\r
156{\r
157 if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {\r
158 return FALSE;\r
159 }\r
160 if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {\r
161 return FALSE;\r
162 }\r
163 return TRUE;\r
164}\r
165\r
166/**\r
167 Validate Fmp capsules layout.\r
168\r
169 Caution: This function may receive untrusted input.\r
170\r
171 This function assumes the caller validated the capsule by using\r
172 IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.\r
173 The capsule buffer size is CapsuleHeader->CapsuleImageSize.\r
174\r
175 This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\r
176 and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.\r
177\r
178 This function need support nested FMP capsule.\r
179\r
180 @param[in] CapsuleHeader Points to a capsule header.\r
181 @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.\r
182\r
183 @retval EFI_SUCESS Input capsule is a correct FMP capsule.\r
184 @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.\r
185**/\r
186EFI_STATUS\r
187ValidateFmpCapsule (\r
188 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
189 OUT UINT16 *EmbeddedDriverCount OPTIONAL\r
190 )\r
191{\r
192 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
193 UINT8 *EndOfCapsule;\r
194 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
195 UINT8 *EndOfPayload;\r
196 UINT64 *ItemOffsetList;\r
197 UINT32 ItemNum;\r
198 UINTN Index;\r
199 UINTN FmpCapsuleSize;\r
200 UINTN FmpCapsuleHeaderSize;\r
201 UINT64 FmpImageSize;\r
202 UINTN FmpImageHeaderSize;\r
203\r
204 if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {\r
205 return ValidateFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), EmbeddedDriverCount);\r
206 }\r
207\r
208 if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {\r
209 DEBUG((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));\r
210 return EFI_INVALID_PARAMETER;\r
211 }\r
212\r
213 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);\r
214 EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;\r
215 FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;\r
216\r
217 if (FmpCapsuleSize < sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {\r
218 DEBUG((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));\r
219 return EFI_INVALID_PARAMETER;\r
220 }\r
221\r
222 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\r
223 if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {\r
224 DEBUG((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));\r
225 return EFI_INVALID_PARAMETER;\r
226 }\r
227 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
228\r
229 // No overflow\r
230 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;\r
231\r
232 if ((FmpCapsuleSize - sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof(UINT64) < ItemNum) {\r
233 DEBUG((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));\r
234 return EFI_INVALID_PARAMETER;\r
235 }\r
236 FmpCapsuleHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof(UINT64)*ItemNum;\r
237\r
238 // Check ItemOffsetList\r
239 for (Index = 0; Index < ItemNum; Index++) {\r
240 if (ItemOffsetList[Index] >= FmpCapsuleSize) {\r
241 DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));\r
242 return EFI_INVALID_PARAMETER;\r
243 }\r
244 if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {\r
245 DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));\r
246 return EFI_INVALID_PARAMETER;\r
247 }\r
248 //\r
249 // All the address in ItemOffsetList must be stored in ascending order\r
250 //\r
251 if (Index > 0) {\r
252 if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {\r
253 DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index, ItemOffsetList[Index - 1]));\r
254 return EFI_INVALID_PARAMETER;\r
255 }\r
256 }\r
257 }\r
258\r
259 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\r
260 for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {\r
261 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
262 if (Index == ItemNum - 1) {\r
263 EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);\r
264 } else {\r
265 EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];\r
266 }\r
267 FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];\r
268\r
269 if (FmpImageSize < OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance)) {\r
270 DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize));\r
271 return EFI_INVALID_PARAMETER;\r
272 }\r
273 FmpImageHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);\r
274 if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||\r
275 (ImageHeader->Version < 1)) {\r
276 DEBUG((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));\r
277 return EFI_INVALID_PARAMETER;\r
278 }\r
279 if (ImageHeader->Version < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
280 FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);\r
281 }\r
282\r
283 // No overflow\r
284 if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {\r
285 DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));\r
286 return EFI_INVALID_PARAMETER;\r
287 }\r
288 }\r
289\r
290 if (ItemNum == 0) {\r
291 //\r
292 // No driver & payload element in FMP\r
293 //\r
294 EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);\r
295 if (EndOfPayload != EndOfCapsule) {\r
296 DEBUG((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));\r
297 return EFI_INVALID_PARAMETER;\r
298 }\r
299 return EFI_UNSUPPORTED;\r
300 }\r
301\r
302 if (EmbeddedDriverCount != NULL) {\r
303 *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;\r
304 }\r
305\r
306 return EFI_SUCCESS;\r
307}\r
308\r
d2a16030
JY
309/**\r
310 Those capsules supported by the firmwares.\r
311\r
312 Caution: This function may receive untrusted input.\r
313\r
314 @param[in] CapsuleHeader Points to a capsule header.\r
315\r
316 @retval EFI_SUCESS Input capsule is supported by firmware.\r
317 @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.\r
318**/\r
319EFI_STATUS\r
320DisplayCapsuleImage (\r
321 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
322 )\r
323{\r
324 DISPLAY_DISPLAY_PAYLOAD *ImagePayload;\r
325 UINTN PayloadSize;\r
326 EFI_STATUS Status;\r
327 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;\r
328 UINTN BltSize;\r
329 UINTN Height;\r
330 UINTN Width;\r
331 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
332\r
333 ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)(CapsuleHeader + 1);\r
16f69227 334 PayloadSize = CapsuleHeader->CapsuleImageSize - sizeof(EFI_CAPSULE_HEADER);\r
d2a16030
JY
335\r
336 if (ImagePayload->Version != 1) {\r
337 return EFI_UNSUPPORTED;\r
338 }\r
339 if (CalculateCheckSum8((UINT8 *)CapsuleHeader, CapsuleHeader->CapsuleImageSize) != 0) {\r
340 return EFI_UNSUPPORTED;\r
341 }\r
342 //\r
343 // Only Support Bitmap by now\r
344 //\r
345 if (ImagePayload->ImageType != 0) {\r
346 return EFI_UNSUPPORTED;\r
347 }\r
348\r
349 //\r
350 // Try to open GOP\r
351 //\r
352 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);\r
353 if (EFI_ERROR (Status)) {\r
354 Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&GraphicsOutput);\r
355 if (EFI_ERROR(Status)) {\r
356 return EFI_UNSUPPORTED;\r
357 }\r
358 }\r
359\r
360 if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) {\r
361 return EFI_UNSUPPORTED;\r
362 }\r
363\r
364 Blt = NULL;\r
365 Width = 0;\r
366 Height = 0;\r
1ec2e7d0 367 Status = TranslateBmpToGopBlt (\r
d2a16030
JY
368 ImagePayload + 1,\r
369 PayloadSize - sizeof(DISPLAY_DISPLAY_PAYLOAD),\r
1ec2e7d0 370 &Blt,\r
d2a16030
JY
371 &BltSize,\r
372 &Height,\r
373 &Width\r
374 );\r
375\r
376 if (EFI_ERROR (Status)) {\r
377 return Status;\r
378 }\r
379\r
380 Status = GraphicsOutput->Blt (\r
381 GraphicsOutput,\r
382 Blt,\r
383 EfiBltBufferToVideo,\r
384 0,\r
385 0,\r
386 (UINTN) ImagePayload->OffsetX,\r
387 (UINTN) ImagePayload->OffsetY,\r
388 Width,\r
389 Height,\r
390 Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
391 );\r
392\r
393 FreePool(Blt);\r
394\r
395 return Status;\r
396}\r
397\r
398/**\r
399 Dump FMP information.\r
400\r
401 @param[in] ImageInfoSize The size of ImageInfo, in bytes.\r
402 @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
403 @param[in] DescriptorVersion The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
404 @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
405 @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.\r
406 @param[in] PackageVersion The version of package.\r
407 @param[in] PackageVersionName The version name of package.\r
408**/\r
409VOID\r
410DumpFmpImageInfo (\r
411 IN UINTN ImageInfoSize,\r
412 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,\r
413 IN UINT32 DescriptorVersion,\r
414 IN UINT8 DescriptorCount,\r
415 IN UINTN DescriptorSize,\r
416 IN UINT32 PackageVersion,\r
417 IN CHAR16 *PackageVersionName\r
418 )\r
419{\r
420 EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo;\r
421 UINTN Index;\r
422\r
423 DEBUG((DEBUG_VERBOSE, " DescriptorVersion - 0x%x\n", DescriptorVersion));\r
424 DEBUG((DEBUG_VERBOSE, " DescriptorCount - 0x%x\n", DescriptorCount));\r
425 DEBUG((DEBUG_VERBOSE, " DescriptorSize - 0x%x\n", DescriptorSize));\r
426 DEBUG((DEBUG_VERBOSE, " PackageVersion - 0x%x\n", PackageVersion));\r
427 DEBUG((DEBUG_VERBOSE, " PackageVersionName - %s\n\n", PackageVersionName));\r
428 CurrentImageInfo = ImageInfo;\r
429 for (Index = 0; Index < DescriptorCount; Index++) {\r
430 DEBUG((DEBUG_VERBOSE, " ImageDescriptor (%d)\n", Index));\r
431 DEBUG((DEBUG_VERBOSE, " ImageIndex - 0x%x\n", CurrentImageInfo->ImageIndex));\r
432 DEBUG((DEBUG_VERBOSE, " ImageTypeId - %g\n", &CurrentImageInfo->ImageTypeId));\r
433 DEBUG((DEBUG_VERBOSE, " ImageId - 0x%lx\n", CurrentImageInfo->ImageId));\r
434 DEBUG((DEBUG_VERBOSE, " ImageIdName - %s\n", CurrentImageInfo->ImageIdName));\r
435 DEBUG((DEBUG_VERBOSE, " Version - 0x%x\n", CurrentImageInfo->Version));\r
436 DEBUG((DEBUG_VERBOSE, " VersionName - %s\n", CurrentImageInfo->VersionName));\r
437 DEBUG((DEBUG_VERBOSE, " Size - 0x%x\n", CurrentImageInfo->Size));\r
438 DEBUG((DEBUG_VERBOSE, " AttributesSupported - 0x%lx\n", CurrentImageInfo->AttributesSupported));\r
439 DEBUG((DEBUG_VERBOSE, " AttributesSetting - 0x%lx\n", CurrentImageInfo->AttributesSetting));\r
440 DEBUG((DEBUG_VERBOSE, " Compatibilities - 0x%lx\n", CurrentImageInfo->Compatibilities));\r
441 if (DescriptorVersion > 1) {\r
442 DEBUG((DEBUG_VERBOSE, " LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion));\r
443 if (DescriptorVersion > 2) {\r
444 DEBUG((DEBUG_VERBOSE, " LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion));\r
445 DEBUG((DEBUG_VERBOSE, " LastAttemptStatus - 0x%x\n", CurrentImageInfo->LastAttemptStatus));\r
446 DEBUG((DEBUG_VERBOSE, " HardwareInstance - 0x%lx\n", CurrentImageInfo->HardwareInstance));\r
447 }\r
448 }\r
449 //\r
450 // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version\r
451 //\r
452 CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);\r
453 }\r
454}\r
455\r
456/**\r
457 Dump a non-nested FMP capsule.\r
458\r
459 @param[in] CapsuleHeader A pointer to CapsuleHeader\r
460**/\r
461VOID\r
462DumpFmpCapsule (\r
463 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
464 )\r
465{\r
466 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
467 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
468 UINTN Index;\r
469 UINT64 *ItemOffsetList;\r
470\r
471 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
472\r
473 DEBUG((DEBUG_VERBOSE, "FmpCapsule:\n"));\r
474 DEBUG((DEBUG_VERBOSE, " Version - 0x%x\n", FmpCapsuleHeader->Version));\r
475 DEBUG((DEBUG_VERBOSE, " EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount));\r
476 DEBUG((DEBUG_VERBOSE, " PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount));\r
477\r
478 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
479 for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {\r
480 DEBUG((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));\r
481 }\r
16f69227 482 for (; Index < (UINT32)FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; Index++) {\r
d2a16030
JY
483 DEBUG((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));\r
484 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
485\r
486 DEBUG((DEBUG_VERBOSE, " ImageHeader:\n"));\r
487 DEBUG((DEBUG_VERBOSE, " Version - 0x%x\n", ImageHeader->Version));\r
488 DEBUG((DEBUG_VERBOSE, " UpdateImageTypeId - %g\n", &ImageHeader->UpdateImageTypeId));\r
489 DEBUG((DEBUG_VERBOSE, " UpdateImageIndex - 0x%x\n", ImageHeader->UpdateImageIndex));\r
490 DEBUG((DEBUG_VERBOSE, " UpdateImageSize - 0x%x\n", ImageHeader->UpdateImageSize));\r
491 DEBUG((DEBUG_VERBOSE, " UpdateVendorCodeSize - 0x%x\n", ImageHeader->UpdateVendorCodeSize));\r
492 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
493 DEBUG((DEBUG_VERBOSE, " UpdateHardwareInstance - 0x%lx\n", ImageHeader->UpdateHardwareInstance));\r
494 }\r
495 }\r
496}\r
497\r
3f31ea1b
JY
498/**\r
499 Dump all FMP information.\r
500**/\r
501VOID\r
502DumpAllFmpInfo (\r
503 VOID\r
504 )\r
505{\r
506 EFI_STATUS Status;\r
507 EFI_HANDLE *HandleBuffer;\r
508 UINTN NumberOfHandles;\r
509 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
510 UINTN Index;\r
511 UINTN ImageInfoSize;\r
512 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;\r
513 UINT32 FmpImageInfoDescriptorVer;\r
514 UINT8 FmpImageInfoCount;\r
515 UINTN DescriptorSize;\r
516 UINT32 PackageVersion;\r
517 CHAR16 *PackageVersionName;\r
518\r
519 Status = gBS->LocateHandleBuffer (\r
520 ByProtocol,\r
521 &gEfiFirmwareManagementProtocolGuid,\r
522 NULL,\r
523 &NumberOfHandles,\r
524 &HandleBuffer\r
525 );\r
526 if (EFI_ERROR(Status)) {\r
527 return ;\r
528 }\r
529\r
530 for (Index = 0; Index < NumberOfHandles; Index++) {\r
531 Status = gBS->HandleProtocol(\r
532 HandleBuffer[Index],\r
533 &gEfiFirmwareManagementProtocolGuid,\r
534 (VOID **)&Fmp\r
535 );\r
536 if (EFI_ERROR(Status)) {\r
537 continue;\r
538 }\r
539\r
540 ImageInfoSize = 0;\r
541 Status = Fmp->GetImageInfo (\r
542 Fmp,\r
543 &ImageInfoSize,\r
544 NULL,\r
545 NULL,\r
546 NULL,\r
547 NULL,\r
548 NULL,\r
549 NULL\r
550 );\r
551 if (Status != EFI_BUFFER_TOO_SMALL) {\r
552 continue;\r
553 }\r
554\r
555 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
556 if (FmpImageInfoBuf == NULL) {\r
557 continue;\r
558 }\r
559\r
560 PackageVersionName = NULL;\r
561 Status = Fmp->GetImageInfo (\r
562 Fmp,\r
563 &ImageInfoSize, // ImageInfoSize\r
564 FmpImageInfoBuf, // ImageInfo\r
565 &FmpImageInfoDescriptorVer, // DescriptorVersion\r
566 &FmpImageInfoCount, // DescriptorCount\r
567 &DescriptorSize, // DescriptorSize\r
568 &PackageVersion, // PackageVersion\r
569 &PackageVersionName // PackageVersionName\r
570 );\r
571 if (EFI_ERROR(Status)) {\r
572 FreePool(FmpImageInfoBuf);\r
573 continue;\r
574 }\r
575\r
576 DEBUG((DEBUG_INFO, "FMP (%d) ImageInfo:\n", Index));\r
577 DumpFmpImageInfo(\r
578 ImageInfoSize, // ImageInfoSize\r
579 FmpImageInfoBuf, // ImageInfo\r
580 FmpImageInfoDescriptorVer, // DescriptorVersion\r
581 FmpImageInfoCount, // DescriptorCount\r
582 DescriptorSize, // DescriptorSize\r
583 PackageVersion, // PackageVersion\r
584 PackageVersionName // PackageVersionName\r
585 );\r
586\r
587 if (PackageVersionName != NULL) {\r
588 FreePool(PackageVersionName);\r
589 }\r
590\r
591 FreePool(FmpImageInfoBuf);\r
592 }\r
593\r
594 return ;\r
595}\r
596\r
597/**\r
598 Get FMP handle by ImageTypeId and HardwareInstance.\r
599\r
600 @param[in] UpdateImageTypeId Used to identify device firmware targeted by this update.\r
601 @param[in] UpdateHardwareInstance The HardwareInstance to target with this update.\r
602 @param[in,out] NoHandles The number of handles returned in Buffer.\r
603 @param[out] Buffer[out] A pointer to the buffer to return the requested array of handles.\r
604\r
605 @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of\r
606 handles in Buffer was returned in NoHandles.\r
607 @retval EFI_NOT_FOUND No handles match the search.\r
608 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.\r
609**/\r
610EFI_STATUS\r
611GetFmpHandleBufferByType (\r
612 IN EFI_GUID *UpdateImageTypeId,\r
613 IN UINT64 UpdateHardwareInstance,\r
614 IN OUT UINTN *NoHandles,\r
615 OUT EFI_HANDLE **Buffer\r
616 )\r
617{\r
618 EFI_STATUS Status;\r
619 EFI_HANDLE *HandleBuffer;\r
620 UINTN NumberOfHandles;\r
621 EFI_HANDLE *MatchedHandleBuffer;\r
622 UINTN MatchedNumberOfHandles;\r
623 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
624 UINTN Index;\r
625 UINTN ImageInfoSize;\r
626 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;\r
627 UINT32 FmpImageInfoDescriptorVer;\r
628 UINT8 FmpImageInfoCount;\r
629 UINTN DescriptorSize;\r
630 UINT32 PackageVersion;\r
631 CHAR16 *PackageVersionName;\r
632 UINTN Index2;\r
633 EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;\r
634\r
635 *NoHandles = 0;\r
636 *Buffer = NULL;\r
637\r
638 Status = gBS->LocateHandleBuffer (\r
639 ByProtocol,\r
640 &gEfiFirmwareManagementProtocolGuid,\r
641 NULL,\r
642 &NumberOfHandles,\r
643 &HandleBuffer\r
644 );\r
645 if (EFI_ERROR(Status)) {\r
646 return Status;\r
647 }\r
648\r
649 MatchedNumberOfHandles = 0;\r
650 MatchedHandleBuffer = AllocateZeroPool (sizeof(EFI_HANDLE) * NumberOfHandles);\r
651 if (MatchedHandleBuffer == NULL) {\r
652 FreePool (HandleBuffer);\r
653 return EFI_OUT_OF_RESOURCES;\r
654 }\r
655\r
656 for (Index = 0; Index < NumberOfHandles; Index++) {\r
657 Status = gBS->HandleProtocol(\r
658 HandleBuffer[Index],\r
659 &gEfiFirmwareManagementProtocolGuid,\r
660 (VOID **)&Fmp\r
661 );\r
662 if (EFI_ERROR(Status)) {\r
663 continue;\r
664 }\r
665\r
666 ImageInfoSize = 0;\r
667 Status = Fmp->GetImageInfo (\r
668 Fmp,\r
669 &ImageInfoSize,\r
670 NULL,\r
671 NULL,\r
672 NULL,\r
673 NULL,\r
674 NULL,\r
675 NULL\r
676 );\r
677 if (Status != EFI_BUFFER_TOO_SMALL) {\r
678 continue;\r
679 }\r
680\r
681 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
682 if (FmpImageInfoBuf == NULL) {\r
683 continue;\r
684 }\r
685\r
686 PackageVersionName = NULL;\r
687 Status = Fmp->GetImageInfo (\r
688 Fmp,\r
689 &ImageInfoSize, // ImageInfoSize\r
690 FmpImageInfoBuf, // ImageInfo\r
691 &FmpImageInfoDescriptorVer, // DescriptorVersion\r
692 &FmpImageInfoCount, // DescriptorCount\r
693 &DescriptorSize, // DescriptorSize\r
694 &PackageVersion, // PackageVersion\r
695 &PackageVersionName // PackageVersionName\r
696 );\r
697 if (EFI_ERROR(Status)) {\r
698 FreePool(FmpImageInfoBuf);\r
699 continue;\r
700 }\r
701\r
702 if (PackageVersionName != NULL) {\r
703 FreePool(PackageVersionName);\r
704 }\r
705\r
706 TempFmpImageInfo = FmpImageInfoBuf;\r
707 for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {\r
708 //\r
709 // Check if this FMP instance matches\r
710 //\r
711 if (CompareGuid(UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) {\r
712 if ((UpdateHardwareInstance == 0) ||\r
713 ((FmpImageInfoDescriptorVer >= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) &&\r
714 (UpdateHardwareInstance == TempFmpImageInfo->HardwareInstance))) {\r
715 MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];\r
716 MatchedNumberOfHandles++;\r
717 break;\r
718 }\r
719 }\r
720 TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);\r
721 }\r
722 FreePool(FmpImageInfoBuf);\r
723 }\r
724\r
725 if (MatchedNumberOfHandles == 0) {\r
726 return EFI_NOT_FOUND;\r
727 }\r
728\r
729 *NoHandles = MatchedNumberOfHandles;\r
730 *Buffer = MatchedHandleBuffer;\r
731\r
732 return EFI_SUCCESS;\r
733}\r
734\r
735/**\r
736 Return FmpImageInfoDescriptorVer by an FMP handle.\r
737\r
738 @param[in] Handle A FMP handle.\r
739\r
740 @return FmpImageInfoDescriptorVer associated with the FMP.\r
741**/\r
742UINT32\r
743GetFmpImageInfoDescriptorVer (\r
744 IN EFI_HANDLE Handle\r
745 )\r
746{\r
747 EFI_STATUS Status;\r
748 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
749 UINTN ImageInfoSize;\r
750 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;\r
751 UINT32 FmpImageInfoDescriptorVer;\r
752 UINT8 FmpImageInfoCount;\r
753 UINTN DescriptorSize;\r
754 UINT32 PackageVersion;\r
755 CHAR16 *PackageVersionName;\r
756\r
757 Status = gBS->HandleProtocol(\r
758 Handle,\r
759 &gEfiFirmwareManagementProtocolGuid,\r
760 (VOID **)&Fmp\r
761 );\r
762 if (EFI_ERROR(Status)) {\r
763 return 0;\r
764 }\r
765\r
766 ImageInfoSize = 0;\r
767 Status = Fmp->GetImageInfo (\r
768 Fmp,\r
769 &ImageInfoSize,\r
770 NULL,\r
771 NULL,\r
772 NULL,\r
773 NULL,\r
774 NULL,\r
775 NULL\r
776 );\r
777 if (Status != EFI_BUFFER_TOO_SMALL) {\r
778 return 0;\r
779 }\r
780\r
781 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
782 if (FmpImageInfoBuf == NULL) {\r
783 return 0;\r
784 }\r
785\r
786 PackageVersionName = NULL;\r
787 Status = Fmp->GetImageInfo (\r
788 Fmp,\r
789 &ImageInfoSize, // ImageInfoSize\r
790 FmpImageInfoBuf, // ImageInfo\r
791 &FmpImageInfoDescriptorVer, // DescriptorVersion\r
792 &FmpImageInfoCount, // DescriptorCount\r
793 &DescriptorSize, // DescriptorSize\r
794 &PackageVersion, // PackageVersion\r
795 &PackageVersionName // PackageVersionName\r
796 );\r
797 if (EFI_ERROR(Status)) {\r
798 FreePool(FmpImageInfoBuf);\r
799 return 0;\r
800 }\r
801 return FmpImageInfoDescriptorVer;\r
802}\r
803\r
804/**\r
805 Set FMP image data.\r
806\r
807 @param[in] Handle A FMP handle.\r
808 @param[in] ImageHeader The payload image header.\r
809 @param[in] PayloadIndex The index of the payload.\r
810\r
811 @return The status of FMP->SetImage.\r
812**/\r
813EFI_STATUS\r
814SetFmpImageData (\r
815 IN EFI_HANDLE Handle,\r
816 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,\r
817 IN UINTN PayloadIndex\r
818 )\r
819{\r
820 EFI_STATUS Status;\r
821 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
822 UINT8 *Image;\r
823 VOID *VendorCode;\r
824 CHAR16 *AbortReason;\r
825\r
826 Status = gBS->HandleProtocol(\r
827 Handle,\r
828 &gEfiFirmwareManagementProtocolGuid,\r
829 (VOID **)&Fmp\r
830 );\r
831 if (EFI_ERROR(Status)) {\r
832 return Status;\r
833 }\r
834\r
835 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
836 Image = (UINT8 *)(ImageHeader + 1);\r
837 } else {\r
838 //\r
839 // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1,\r
840 // Header should exclude UpdateHardwareInstance field\r
841 //\r
842 Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);\r
843 }\r
844\r
845 if (ImageHeader->UpdateVendorCodeSize == 0) {\r
846 VendorCode = NULL;\r
847 } else {\r
848 VendorCode = Image + ImageHeader->UpdateImageSize;\r
849 }\r
850 AbortReason = NULL;\r
851 DEBUG((DEBUG_INFO, "Fmp->SetImage ...\n"));\r
852 DEBUG((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId));\r
853 DEBUG((DEBUG_INFO, "PayloadIndex - 0x%x, ", PayloadIndex));\r
854 DEBUG((DEBUG_INFO, "ImageIndex - 0x%x ", ImageHeader->UpdateImageIndex));\r
855 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
856 DEBUG((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance));\r
857 }\r
858 DEBUG((DEBUG_INFO, "\n"));\r
859 Status = Fmp->SetImage(\r
860 Fmp,\r
861 ImageHeader->UpdateImageIndex, // ImageIndex\r
862 Image, // Image\r
863 ImageHeader->UpdateImageSize, // ImageSize\r
864 VendorCode, // VendorCode\r
865 Update_Image_Progress, // Progress\r
866 &AbortReason // AbortReason\r
867 );\r
868 DEBUG((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));\r
869 if (AbortReason != NULL) {\r
870 DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));\r
871 FreePool(AbortReason);\r
872 }\r
873\r
874 return Status;\r
875}\r
876\r
877/**\r
878 Start a UEFI image in the FMP payload.\r
879\r
880 @param[in] ImageBuffer A pointer to the memory location containing a copy of the image to be loaded..\r
881 @param[in] ImageSize The size in bytes of ImageBuffer.\r
882\r
883 @return The status of gBS->LoadImage and gBS->StartImage.\r
884**/\r
885EFI_STATUS\r
886StartFmpImage (\r
887 IN VOID *ImageBuffer,\r
888 IN UINTN ImageSize\r
889 )\r
890{\r
891 MEMMAP_DEVICE_PATH MemMapNode;\r
892 EFI_STATUS Status;\r
893 EFI_HANDLE ImageHandle;\r
894 EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;\r
895 UINTN ExitDataSize;\r
896\r
897 SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));\r
898 MemMapNode.Header.Type = HARDWARE_DEVICE_PATH;\r
899 MemMapNode.Header.SubType = HW_MEMMAP_DP;\r
900 MemMapNode.MemoryType = EfiBootServicesCode;\r
901 MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBuffer;\r
902 MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)ImageBuffer + ImageSize - 1);\r
903\r
904 DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);\r
905 if (DriverDevicePath == NULL) {\r
906 return EFI_OUT_OF_RESOURCES;\r
907 }\r
908\r
909 DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));\r
910 Status = gBS->LoadImage(\r
911 FALSE,\r
912 gImageHandle,\r
913 DriverDevicePath,\r
914 ImageBuffer,\r
915 ImageSize,\r
916 &ImageHandle\r
917 );\r
918 DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));\r
919 if (EFI_ERROR(Status)) {\r
920 FreePool(DriverDevicePath);\r
921 return Status;\r
922 }\r
923\r
924 DEBUG((DEBUG_INFO, "FmpCapsule: StartImage ...\n"));\r
925 Status = gBS->StartImage(\r
926 ImageHandle,\r
927 &ExitDataSize,\r
928 NULL\r
929 );\r
930 DEBUG((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status));\r
931 if (EFI_ERROR(Status)) {\r
932 DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));\r
933 }\r
934\r
935 FreePool(DriverDevicePath);\r
936 return Status;\r
937}\r
938\r
939/**\r
940 Record FMP capsule status.\r
941\r
942 @param[in] Handle A FMP handle.\r
943 @param[in] CapsuleHeader The capsule image header\r
944 @param[in] CapsuleStatus The capsule process stauts\r
945 @param[in] PayloadIndex FMP payload index\r
946 @param[in] ImageHeader FMP image header\r
947**/\r
948VOID\r
949RecordFmpCapsuleStatus (\r
950 IN EFI_HANDLE Handle, OPTIONAL\r
951 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
952 IN EFI_STATUS CapsuleStatus,\r
953 IN UINTN PayloadIndex,\r
954 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader\r
955 )\r
956{\r
957 EFI_STATUS Status;\r
958 EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath;\r
959 UINT32 FmpImageInfoDescriptorVer;\r
960 EFI_STATUS StatusEsrt;\r
961 ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;\r
962 EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry;\r
963\r
964 FmpDevicePath = NULL;\r
965 if (Handle != NULL) {\r
966 gBS->HandleProtocol(\r
967 Handle,\r
968 &gEfiDevicePathProtocolGuid,\r
969 (VOID **)&FmpDevicePath\r
970 );\r
971 }\r
972\r
973 RecordFmpCapsuleStatusVariable (\r
974 CapsuleHeader,\r
975 CapsuleStatus,\r
976 PayloadIndex,\r
977 ImageHeader,\r
978 FmpDevicePath\r
979 );\r
980\r
981 //\r
982 // Update corresponding ESRT entry LastAttemp Status\r
983 //\r
984 Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);\r
985 if (EFI_ERROR (Status)) {\r
986 return ;\r
987 }\r
988\r
989 if (Handle == NULL) {\r
990 return ;\r
991 }\r
992\r
993 //\r
994 // Update EsrtEntry For V1, V2 FMP instance.\r
995 // V3 FMP ESRT cache will be synced up through EsrtSyncFmp interface\r
996 //\r
997 FmpImageInfoDescriptorVer = GetFmpImageInfoDescriptorVer (Handle);\r
998 if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) {\r
999 StatusEsrt = EsrtProtocol->GetEsrtEntry(&ImageHeader->UpdateImageTypeId, &EsrtEntry);\r
1000 if (!EFI_ERROR(StatusEsrt)){\r
1001 if (!EFI_ERROR(CapsuleStatus)) {\r
1002 EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
1003 } else {\r
1004 EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
1005 }\r
1006 EsrtEntry.LastAttemptVersion = 0;\r
1007 EsrtProtocol->UpdateEsrtEntry(&EsrtEntry);\r
1008 }\r
1009 }\r
1010}\r
1011\r
d2a16030
JY
1012/**\r
1013 Process Firmware management protocol data capsule.\r
1014\r
1015 This function assumes the caller validated the capsule by using\r
1016 ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,\r
1017 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and\r
1018 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.\r
1019\r
1020 This function need support nested FMP capsule.\r
1021\r
11ee1bc9 1022 @param[in] CapsuleHeader Points to a capsule header.\r
d2a16030
JY
1023\r
1024 @retval EFI_SUCESS Process Capsule Image successfully.\r
1025 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.\r
1026 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.\r
1027 @retval EFI_OUT_OF_RESOURCES Not enough memory.\r
3f31ea1b 1028 @retval EFI_NOT_READY No FMP protocol to handle this FMP capsule.\r
d2a16030
JY
1029**/\r
1030EFI_STATUS\r
1031ProcessFmpCapsuleImage (\r
3f31ea1b 1032 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
d2a16030
JY
1033 )\r
1034{\r
1035 EFI_STATUS Status;\r
d2a16030
JY
1036 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
1037 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
d2a16030
JY
1038 UINT64 *ItemOffsetList;\r
1039 UINT32 ItemNum;\r
1040 UINTN Index;\r
d2a16030 1041 EFI_HANDLE *HandleBuffer;\r
d2a16030 1042 UINTN NumberOfHandles;\r
d2a16030 1043 UINTN DriverLen;\r
3f31ea1b 1044 UINT64 UpdateHardwareInstance;\r
d2a16030 1045 UINTN Index2;\r
3f31ea1b
JY
1046 BOOLEAN NotReady;\r
1047 BOOLEAN Abort;\r
d2a16030
JY
1048\r
1049 if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {\r
3f31ea1b 1050 return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize));\r
d2a16030
JY
1051 }\r
1052\r
3f31ea1b
JY
1053 NotReady = FALSE;\r
1054 Abort = FALSE;\r
d2a16030
JY
1055\r
1056 DumpFmpCapsule(CapsuleHeader);\r
1057\r
1058 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);\r
1059\r
1060 if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {\r
1061 return EFI_INVALID_PARAMETER;\r
1062 }\r
1063 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
1064\r
1065 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;\r
1066\r
1067 //\r
1068 // capsule in which driver count and payload count are both zero is not processed.\r
1069 //\r
1070 if (ItemNum == 0) {\r
d2a16030
JY
1071 return EFI_SUCCESS;\r
1072 }\r
1073\r
d2a16030
JY
1074 //\r
1075 // 1. Try to load & start all the drivers within capsule\r
1076 //\r
d2a16030 1077 for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {\r
3f31ea1b
JY
1078 if ((FmpCapsuleHeader->PayloadItemCount == 0) &&\r
1079 (Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1)) {\r
d2a16030
JY
1080 //\r
1081 // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER\r
1082 //\r
1083 DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];\r
1084 } else {\r
1085 DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];\r
1086 }\r
1087\r
3f31ea1b
JY
1088 Status = StartFmpImage (\r
1089 (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],\r
1090 DriverLen\r
1091 );\r
d2a16030
JY
1092 if (EFI_ERROR(Status)) {\r
1093 DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));\r
3f31ea1b 1094 return Status;\r
d2a16030
JY
1095 }\r
1096 }\r
1097\r
1098 //\r
1099 // 2. Route payload to right FMP instance\r
1100 //\r
1101 DEBUG((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n"));\r
1102\r
3f31ea1b 1103 DumpAllFmpInfo ();\r
8f6db161 1104\r
3f31ea1b
JY
1105 //\r
1106 // Check all the payload entry in capsule payload list\r
1107 //\r
1108 for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {\r
1109 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
d2a16030 1110\r
3f31ea1b
JY
1111 UpdateHardwareInstance = 0;\r
1112 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
1113 UpdateHardwareInstance = ImageHeader->UpdateHardwareInstance;\r
1114 }\r
d2a16030 1115\r
3f31ea1b
JY
1116 Status = GetFmpHandleBufferByType (\r
1117 &ImageHeader->UpdateImageTypeId,\r
1118 UpdateHardwareInstance,\r
1119 &NumberOfHandles,\r
1120 &HandleBuffer\r
1121 );\r
1122 if (EFI_ERROR(Status)) {\r
1123 NotReady = TRUE;\r
1124 RecordFmpCapsuleStatus (\r
1125 NULL,\r
1126 CapsuleHeader,\r
1127 EFI_NOT_READY,\r
1128 Index - FmpCapsuleHeader->EmbeddedDriverCount,\r
1129 ImageHeader\r
1130 );\r
1131 continue;\r
1132 }\r
d2a16030 1133\r
3f31ea1b
JY
1134 for (Index2 = 0; Index2 < NumberOfHandles; Index2++) {\r
1135 if (Abort) {\r
1136 RecordFmpCapsuleStatus (\r
1137 HandleBuffer[Index2],\r
1138 CapsuleHeader,\r
1139 EFI_ABORTED,\r
1140 Index - FmpCapsuleHeader->EmbeddedDriverCount,\r
1141 ImageHeader\r
1142 );\r
d2a16030
JY
1143 continue;\r
1144 }\r
1145\r
3f31ea1b
JY
1146 Status = SetFmpImageData (\r
1147 HandleBuffer[Index2],\r
1148 ImageHeader,\r
1149 Index - FmpCapsuleHeader->EmbeddedDriverCount\r
1150 );\r
1151 if (Status != EFI_SUCCESS) {\r
1152 Abort = TRUE;\r
d2a16030
JY
1153 }\r
1154\r
3f31ea1b
JY
1155 RecordFmpCapsuleStatus (\r
1156 HandleBuffer[Index2],\r
1157 CapsuleHeader,\r
1158 Status,\r
1159 Index - FmpCapsuleHeader->EmbeddedDriverCount,\r
1160 ImageHeader\r
1161 );\r
d2a16030 1162 }\r
3f31ea1b
JY
1163 if (HandleBuffer != NULL) {\r
1164 FreePool(HandleBuffer);\r
d2a16030
JY
1165 }\r
1166 }\r
1167\r
3f31ea1b
JY
1168 if (NotReady) {\r
1169 return EFI_NOT_READY;\r
d2a16030
JY
1170 }\r
1171\r
3f31ea1b
JY
1172 //\r
1173 // always return SUCCESS to indicate this capsule is processed.\r
1174 // The status of SetImage is recorded in capsule result variable.\r
1175 //\r
1176 return EFI_SUCCESS;\r
d2a16030
JY
1177}\r
1178\r
1179/**\r
1180 Return if there is a FMP header below capsule header.\r
1181\r
1182 @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER\r
1183\r
1184 @retval TRUE There is a FMP header below capsule header.\r
1185 @retval FALSE There is not a FMP header below capsule header\r
1186**/\r
1187BOOLEAN\r
1188IsNestedFmpCapsule (\r
1189 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
1190 )\r
1191{\r
1192 EFI_STATUS Status;\r
1193 EFI_SYSTEM_RESOURCE_TABLE *Esrt;\r
1194 EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;\r
1195 UINTN Index;\r
1196 BOOLEAN EsrtGuidFound;\r
1197 EFI_CAPSULE_HEADER *NestedCapsuleHeader;\r
1198 UINTN NestedCapsuleSize;\r
1199 ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;\r
1200 EFI_SYSTEM_RESOURCE_ENTRY Entry;\r
1201\r
1202 EsrtGuidFound = FALSE;\r
056563f1
JY
1203 if (mIsVirtualAddrConverted) {\r
1204 if(mEsrtTable != NULL) {\r
1205 EsrtEntry = (EFI_SYSTEM_RESOURCE_ENTRY *)(mEsrtTable + 1);\r
1206 for (Index = 0; Index < mEsrtTable->FwResourceCount ; Index++, EsrtEntry++) {\r
d2a16030
JY
1207 if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {\r
1208 EsrtGuidFound = TRUE;\r
1209 break;\r
1210 }\r
1211 }\r
1212 }\r
056563f1
JY
1213 } else {\r
1214 //\r
1215 // Check ESRT protocol\r
1216 //\r
1217 Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);\r
1218 if (!EFI_ERROR(Status)) {\r
1219 Status = EsrtProtocol->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &Entry);\r
1220 if (!EFI_ERROR(Status)) {\r
1221 EsrtGuidFound = TRUE;\r
1222 }\r
1223 }\r
1224\r
1225 //\r
1226 // Check ESRT configuration table\r
1227 //\r
1228 if (!EsrtGuidFound) {\r
1229 Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);\r
1230 if (!EFI_ERROR(Status)) {\r
1231 ASSERT (Esrt != NULL);\r
1232 EsrtEntry = (VOID *)(Esrt + 1);\r
1233 for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {\r
1234 if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {\r
1235 EsrtGuidFound = TRUE;\r
1236 break;\r
1237 }\r
1238 }\r
1239 }\r
1240 }\r
d2a16030
JY
1241 }\r
1242 if (!EsrtGuidFound) {\r
1243 return FALSE;\r
1244 }\r
1245\r
1246 //\r
1247 // Check nested capsule header\r
1248 // FMP GUID after ESRT one\r
1249 //\r
1250 NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
1251 NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize - (UINTN)NestedCapsuleHeader;\r
1252 if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) {\r
1253 return FALSE;\r
1254 }\r
1255 if (!IsValidCapsuleHeader(NestedCapsuleHeader, NestedCapsuleSize)) {\r
1256 return FALSE;\r
1257 }\r
1258 if (!IsFmpCapsuleGuid(&NestedCapsuleHeader->CapsuleGuid)) {\r
1259 return FALSE;\r
1260 }\r
1261 DEBUG ((DEBUG_INFO, "IsNestedFmpCapsule\n"));\r
1262 return TRUE;\r
1263}\r
1264\r
1265/**\r
1266 Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.\r
1267\r
1268 @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER\r
1269\r
1270 @retval TRUE It is a system FMP.\r
1271 @retval FALSE It is a device FMP.\r
1272**/\r
1273BOOLEAN\r
1274IsFmpCapsule (\r
1275 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
1276 )\r
1277{\r
1278 if (IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {\r
1279 return TRUE;\r
1280 }\r
1281 if (IsNestedFmpCapsule(CapsuleHeader)) {\r
1282 return TRUE;\r
1283 }\r
1284 return FALSE;\r
1285}\r
1286\r
1287/**\r
1288 Those capsules supported by the firmwares.\r
1289\r
1290 Caution: This function may receive untrusted input.\r
1291\r
1292 @param[in] CapsuleHeader Points to a capsule header.\r
1293\r
1294 @retval EFI_SUCESS Input capsule is supported by firmware.\r
1295 @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.\r
1296 @retval EFI_INVALID_PARAMETER Input capsule layout is not correct\r
1297**/\r
1298EFI_STATUS\r
1299EFIAPI\r
1300SupportCapsuleImage (\r
1301 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
1302 )\r
1303{\r
1304 //\r
1305 // check Display Capsule Guid\r
1306 //\r
1307 if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {\r
1308 return EFI_SUCCESS;\r
1309 }\r
1310\r
1311 if (IsFmpCapsule(CapsuleHeader)) {\r
1312 //\r
1313 // Check layout of FMP capsule\r
1314 //\r
1315 return ValidateFmpCapsule(CapsuleHeader, NULL);\r
1316 }\r
1317 DEBUG((DEBUG_ERROR, "Unknown Capsule Guid - %g\n", &CapsuleHeader->CapsuleGuid));\r
1318 return EFI_UNSUPPORTED;\r
1319}\r
1320\r
1321/**\r
1322 The firmware implements to process the capsule image.\r
1323\r
1324 Caution: This function may receive untrusted input.\r
1325\r
1326 @param[in] CapsuleHeader Points to a capsule header.\r
1327\r
1328 @retval EFI_SUCESS Process Capsule Image successfully.\r
1329 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.\r
1330 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.\r
1331 @retval EFI_OUT_OF_RESOURCES Not enough memory.\r
1332**/\r
1333EFI_STATUS\r
1334EFIAPI\r
1335ProcessCapsuleImage (\r
1336 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
1337 )\r
1338{\r
1339 EFI_STATUS Status;\r
d2a16030
JY
1340\r
1341 if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {\r
3f31ea1b 1342 RecordCapsuleStatusVariable(CapsuleHeader, EFI_UNSUPPORTED);\r
d2a16030
JY
1343 return EFI_UNSUPPORTED;\r
1344 }\r
1345\r
1346 //\r
1347 // Display image in firmware update display capsule\r
1348 //\r
1349 if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {\r
1350 DEBUG((DEBUG_INFO, "ProcessCapsuleImage for WindowsUxCapsule ...\n"));\r
1351 Status = DisplayCapsuleImage(CapsuleHeader);\r
1352 RecordCapsuleStatusVariable(CapsuleHeader, Status);\r
1353 return Status;\r
1354 }\r
1355\r
1356 //\r
1357 // Check FMP capsule layout\r
1358 //\r
1359 if (IsFmpCapsule (CapsuleHeader)) {\r
1360 DEBUG((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));\r
1361 DEBUG((DEBUG_INFO, "ValidateFmpCapsule ...\n"));\r
1362 Status = ValidateFmpCapsule(CapsuleHeader, NULL);\r
1363 DEBUG((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));\r
1364 if (EFI_ERROR(Status)) {\r
3f31ea1b 1365 RecordCapsuleStatusVariable(CapsuleHeader, Status);\r
d2a16030
JY
1366 return Status;\r
1367 }\r
1368\r
1369 //\r
1370 // Press EFI FMP Capsule\r
1371 //\r
1372 DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));\r
3f31ea1b 1373 Status = ProcessFmpCapsuleImage(CapsuleHeader);\r
d2a16030
JY
1374 DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));\r
1375\r
d2a16030
JY
1376 return Status;\r
1377 }\r
1378\r
1379 return EFI_UNSUPPORTED;\r
1380}\r
1381\r
1382/**\r
1383 Callback function executed when the EndOfDxe event group is signaled.\r
1384\r
1385 @param[in] Event Event whose notification function is being invoked.\r
1386 @param[in] Context The pointer to the notification function's context, which\r
1387 is implementation-dependent.\r
1388**/\r
1389VOID\r
1390EFIAPI\r
1391DxeCapsuleLibEndOfDxe (\r
1392 IN EFI_EVENT Event,\r
1393 IN VOID *Context\r
1394 )\r
1395{\r
1396 mDxeCapsuleLibEndOfDxe = TRUE;\r
1397}\r
1398\r
1399/**\r
1400 The constructor function.\r
1401\r
1402 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1403 @param[in] SystemTable A pointer to the EFI System Table.\r
1404\r
1405 @retval EFI_SUCCESS The constructor successfully .\r
1406**/\r
1407EFI_STATUS\r
1408EFIAPI\r
1409DxeCapsuleLibConstructor (\r
1410 IN EFI_HANDLE ImageHandle,\r
1411 IN EFI_SYSTEM_TABLE *SystemTable\r
1412 )\r
1413{\r
d2a16030
JY
1414 EFI_STATUS Status;\r
1415\r
1416 Status = gBS->CreateEventEx (\r
1417 EVT_NOTIFY_SIGNAL,\r
1418 TPL_CALLBACK,\r
1419 DxeCapsuleLibEndOfDxe,\r
1420 NULL,\r
1421 &gEfiEndOfDxeEventGroupGuid,\r
96b17e00 1422 &mDxeCapsuleLibEndOfDxeEvent\r
d2a16030
JY
1423 );\r
1424 ASSERT_EFI_ERROR (Status);\r
1425\r
1426 InitCapsuleVariable();\r
1427\r
1428 return EFI_SUCCESS;\r
1429}\r
96b17e00
HW
1430\r
1431/**\r
1432 The destructor function closes the End of DXE event.\r
1433\r
1434 @param ImageHandle The firmware allocated handle for the EFI image.\r
1435 @param SystemTable A pointer to the EFI System Table.\r
1436\r
1437 @retval EFI_SUCCESS The destructor completed successfully.\r
1438**/\r
1439EFI_STATUS\r
1440EFIAPI\r
1441DxeCapsuleLibDestructor (\r
1442 IN EFI_HANDLE ImageHandle,\r
1443 IN EFI_SYSTEM_TABLE *SystemTable\r
1444 )\r
1445{\r
1446 EFI_STATUS Status;\r
1447\r
1448 //\r
1449 // Close the End of DXE event.\r
1450 //\r
1451 Status = gBS->CloseEvent (mDxeCapsuleLibEndOfDxeEvent);\r
1452 ASSERT_EFI_ERROR (Status);\r
1453\r
1454 return EFI_SUCCESS;\r
1455}\r