MdeModulePkg/DxeCapsuleLibFmp: Add more check for the UX capsule
[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
d0976b9a
RN
333 //\r
334 // UX capsule doesn't have extended header entries.\r
335 //\r
336 if (CapsuleHeader->HeaderSize != sizeof (EFI_CAPSULE_HEADER)) {\r
337 return EFI_UNSUPPORTED;\r
338 }\r
339 ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)((UINTN) CapsuleHeader + CapsuleHeader->HeaderSize);\r
340 //\r
341 // (CapsuleImageSize > HeaderSize) is guaranteed by IsValidCapsuleHeader().\r
342 //\r
343 PayloadSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;\r
344\r
345 //\r
346 // Make sure the image payload at least contain the DISPLAY_DISPLAY_PAYLOAD header.\r
347 // Further size check is performed by the logic translating BMP to GOP BLT.\r
348 //\r
349 if (PayloadSize <= sizeof (DISPLAY_DISPLAY_PAYLOAD)) {\r
350 return EFI_INVALID_PARAMETER;\r
351 }\r
d2a16030
JY
352\r
353 if (ImagePayload->Version != 1) {\r
354 return EFI_UNSUPPORTED;\r
355 }\r
356 if (CalculateCheckSum8((UINT8 *)CapsuleHeader, CapsuleHeader->CapsuleImageSize) != 0) {\r
357 return EFI_UNSUPPORTED;\r
358 }\r
359 //\r
360 // Only Support Bitmap by now\r
361 //\r
362 if (ImagePayload->ImageType != 0) {\r
363 return EFI_UNSUPPORTED;\r
364 }\r
365\r
366 //\r
367 // Try to open GOP\r
368 //\r
369 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);\r
370 if (EFI_ERROR (Status)) {\r
371 Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&GraphicsOutput);\r
372 if (EFI_ERROR(Status)) {\r
373 return EFI_UNSUPPORTED;\r
374 }\r
375 }\r
376\r
377 if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) {\r
378 return EFI_UNSUPPORTED;\r
379 }\r
380\r
381 Blt = NULL;\r
382 Width = 0;\r
383 Height = 0;\r
1ec2e7d0 384 Status = TranslateBmpToGopBlt (\r
d2a16030
JY
385 ImagePayload + 1,\r
386 PayloadSize - sizeof(DISPLAY_DISPLAY_PAYLOAD),\r
1ec2e7d0 387 &Blt,\r
d2a16030
JY
388 &BltSize,\r
389 &Height,\r
390 &Width\r
391 );\r
392\r
393 if (EFI_ERROR (Status)) {\r
394 return Status;\r
395 }\r
396\r
397 Status = GraphicsOutput->Blt (\r
398 GraphicsOutput,\r
399 Blt,\r
400 EfiBltBufferToVideo,\r
401 0,\r
402 0,\r
403 (UINTN) ImagePayload->OffsetX,\r
404 (UINTN) ImagePayload->OffsetY,\r
405 Width,\r
406 Height,\r
407 Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
408 );\r
409\r
410 FreePool(Blt);\r
411\r
412 return Status;\r
413}\r
414\r
415/**\r
416 Dump FMP information.\r
417\r
418 @param[in] ImageInfoSize The size of ImageInfo, in bytes.\r
419 @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
420 @param[in] DescriptorVersion The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
421 @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
422 @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.\r
423 @param[in] PackageVersion The version of package.\r
424 @param[in] PackageVersionName The version name of package.\r
425**/\r
426VOID\r
427DumpFmpImageInfo (\r
428 IN UINTN ImageInfoSize,\r
429 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,\r
430 IN UINT32 DescriptorVersion,\r
431 IN UINT8 DescriptorCount,\r
432 IN UINTN DescriptorSize,\r
433 IN UINT32 PackageVersion,\r
434 IN CHAR16 *PackageVersionName\r
435 )\r
436{\r
437 EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo;\r
438 UINTN Index;\r
439\r
440 DEBUG((DEBUG_VERBOSE, " DescriptorVersion - 0x%x\n", DescriptorVersion));\r
441 DEBUG((DEBUG_VERBOSE, " DescriptorCount - 0x%x\n", DescriptorCount));\r
442 DEBUG((DEBUG_VERBOSE, " DescriptorSize - 0x%x\n", DescriptorSize));\r
443 DEBUG((DEBUG_VERBOSE, " PackageVersion - 0x%x\n", PackageVersion));\r
444 DEBUG((DEBUG_VERBOSE, " PackageVersionName - %s\n\n", PackageVersionName));\r
445 CurrentImageInfo = ImageInfo;\r
446 for (Index = 0; Index < DescriptorCount; Index++) {\r
447 DEBUG((DEBUG_VERBOSE, " ImageDescriptor (%d)\n", Index));\r
448 DEBUG((DEBUG_VERBOSE, " ImageIndex - 0x%x\n", CurrentImageInfo->ImageIndex));\r
449 DEBUG((DEBUG_VERBOSE, " ImageTypeId - %g\n", &CurrentImageInfo->ImageTypeId));\r
450 DEBUG((DEBUG_VERBOSE, " ImageId - 0x%lx\n", CurrentImageInfo->ImageId));\r
451 DEBUG((DEBUG_VERBOSE, " ImageIdName - %s\n", CurrentImageInfo->ImageIdName));\r
452 DEBUG((DEBUG_VERBOSE, " Version - 0x%x\n", CurrentImageInfo->Version));\r
453 DEBUG((DEBUG_VERBOSE, " VersionName - %s\n", CurrentImageInfo->VersionName));\r
454 DEBUG((DEBUG_VERBOSE, " Size - 0x%x\n", CurrentImageInfo->Size));\r
455 DEBUG((DEBUG_VERBOSE, " AttributesSupported - 0x%lx\n", CurrentImageInfo->AttributesSupported));\r
456 DEBUG((DEBUG_VERBOSE, " AttributesSetting - 0x%lx\n", CurrentImageInfo->AttributesSetting));\r
457 DEBUG((DEBUG_VERBOSE, " Compatibilities - 0x%lx\n", CurrentImageInfo->Compatibilities));\r
458 if (DescriptorVersion > 1) {\r
459 DEBUG((DEBUG_VERBOSE, " LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion));\r
460 if (DescriptorVersion > 2) {\r
461 DEBUG((DEBUG_VERBOSE, " LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion));\r
462 DEBUG((DEBUG_VERBOSE, " LastAttemptStatus - 0x%x\n", CurrentImageInfo->LastAttemptStatus));\r
463 DEBUG((DEBUG_VERBOSE, " HardwareInstance - 0x%lx\n", CurrentImageInfo->HardwareInstance));\r
464 }\r
465 }\r
466 //\r
467 // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version\r
468 //\r
469 CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);\r
470 }\r
471}\r
472\r
473/**\r
474 Dump a non-nested FMP capsule.\r
475\r
476 @param[in] CapsuleHeader A pointer to CapsuleHeader\r
477**/\r
478VOID\r
479DumpFmpCapsule (\r
480 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
481 )\r
482{\r
483 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
484 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
485 UINTN Index;\r
486 UINT64 *ItemOffsetList;\r
487\r
488 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
489\r
490 DEBUG((DEBUG_VERBOSE, "FmpCapsule:\n"));\r
491 DEBUG((DEBUG_VERBOSE, " Version - 0x%x\n", FmpCapsuleHeader->Version));\r
492 DEBUG((DEBUG_VERBOSE, " EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount));\r
493 DEBUG((DEBUG_VERBOSE, " PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount));\r
494\r
495 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
496 for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {\r
497 DEBUG((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));\r
498 }\r
16f69227 499 for (; Index < (UINT32)FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; Index++) {\r
d2a16030
JY
500 DEBUG((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));\r
501 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
502\r
503 DEBUG((DEBUG_VERBOSE, " ImageHeader:\n"));\r
504 DEBUG((DEBUG_VERBOSE, " Version - 0x%x\n", ImageHeader->Version));\r
505 DEBUG((DEBUG_VERBOSE, " UpdateImageTypeId - %g\n", &ImageHeader->UpdateImageTypeId));\r
506 DEBUG((DEBUG_VERBOSE, " UpdateImageIndex - 0x%x\n", ImageHeader->UpdateImageIndex));\r
507 DEBUG((DEBUG_VERBOSE, " UpdateImageSize - 0x%x\n", ImageHeader->UpdateImageSize));\r
508 DEBUG((DEBUG_VERBOSE, " UpdateVendorCodeSize - 0x%x\n", ImageHeader->UpdateVendorCodeSize));\r
509 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
510 DEBUG((DEBUG_VERBOSE, " UpdateHardwareInstance - 0x%lx\n", ImageHeader->UpdateHardwareInstance));\r
511 }\r
512 }\r
513}\r
514\r
3f31ea1b
JY
515/**\r
516 Dump all FMP information.\r
517**/\r
518VOID\r
519DumpAllFmpInfo (\r
520 VOID\r
521 )\r
522{\r
523 EFI_STATUS Status;\r
524 EFI_HANDLE *HandleBuffer;\r
525 UINTN NumberOfHandles;\r
526 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
527 UINTN Index;\r
528 UINTN ImageInfoSize;\r
529 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;\r
530 UINT32 FmpImageInfoDescriptorVer;\r
531 UINT8 FmpImageInfoCount;\r
532 UINTN DescriptorSize;\r
533 UINT32 PackageVersion;\r
534 CHAR16 *PackageVersionName;\r
535\r
536 Status = gBS->LocateHandleBuffer (\r
537 ByProtocol,\r
538 &gEfiFirmwareManagementProtocolGuid,\r
539 NULL,\r
540 &NumberOfHandles,\r
541 &HandleBuffer\r
542 );\r
543 if (EFI_ERROR(Status)) {\r
544 return ;\r
545 }\r
546\r
547 for (Index = 0; Index < NumberOfHandles; Index++) {\r
548 Status = gBS->HandleProtocol(\r
549 HandleBuffer[Index],\r
550 &gEfiFirmwareManagementProtocolGuid,\r
551 (VOID **)&Fmp\r
552 );\r
553 if (EFI_ERROR(Status)) {\r
554 continue;\r
555 }\r
556\r
557 ImageInfoSize = 0;\r
558 Status = Fmp->GetImageInfo (\r
559 Fmp,\r
560 &ImageInfoSize,\r
561 NULL,\r
562 NULL,\r
563 NULL,\r
564 NULL,\r
565 NULL,\r
566 NULL\r
567 );\r
568 if (Status != EFI_BUFFER_TOO_SMALL) {\r
569 continue;\r
570 }\r
571\r
572 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
573 if (FmpImageInfoBuf == NULL) {\r
574 continue;\r
575 }\r
576\r
577 PackageVersionName = NULL;\r
578 Status = Fmp->GetImageInfo (\r
579 Fmp,\r
580 &ImageInfoSize, // ImageInfoSize\r
581 FmpImageInfoBuf, // ImageInfo\r
582 &FmpImageInfoDescriptorVer, // DescriptorVersion\r
583 &FmpImageInfoCount, // DescriptorCount\r
584 &DescriptorSize, // DescriptorSize\r
585 &PackageVersion, // PackageVersion\r
586 &PackageVersionName // PackageVersionName\r
587 );\r
588 if (EFI_ERROR(Status)) {\r
589 FreePool(FmpImageInfoBuf);\r
590 continue;\r
591 }\r
592\r
593 DEBUG((DEBUG_INFO, "FMP (%d) ImageInfo:\n", Index));\r
594 DumpFmpImageInfo(\r
595 ImageInfoSize, // ImageInfoSize\r
596 FmpImageInfoBuf, // ImageInfo\r
597 FmpImageInfoDescriptorVer, // DescriptorVersion\r
598 FmpImageInfoCount, // DescriptorCount\r
599 DescriptorSize, // DescriptorSize\r
600 PackageVersion, // PackageVersion\r
601 PackageVersionName // PackageVersionName\r
602 );\r
603\r
604 if (PackageVersionName != NULL) {\r
605 FreePool(PackageVersionName);\r
606 }\r
607\r
608 FreePool(FmpImageInfoBuf);\r
609 }\r
610\r
611 return ;\r
612}\r
613\r
614/**\r
615 Get FMP handle by ImageTypeId and HardwareInstance.\r
616\r
617 @param[in] UpdateImageTypeId Used to identify device firmware targeted by this update.\r
618 @param[in] UpdateHardwareInstance The HardwareInstance to target with this update.\r
619 @param[in,out] NoHandles The number of handles returned in Buffer.\r
620 @param[out] Buffer[out] A pointer to the buffer to return the requested array of handles.\r
621\r
622 @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of\r
623 handles in Buffer was returned in NoHandles.\r
624 @retval EFI_NOT_FOUND No handles match the search.\r
625 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.\r
626**/\r
627EFI_STATUS\r
628GetFmpHandleBufferByType (\r
629 IN EFI_GUID *UpdateImageTypeId,\r
630 IN UINT64 UpdateHardwareInstance,\r
631 IN OUT UINTN *NoHandles,\r
632 OUT EFI_HANDLE **Buffer\r
633 )\r
634{\r
635 EFI_STATUS Status;\r
636 EFI_HANDLE *HandleBuffer;\r
637 UINTN NumberOfHandles;\r
638 EFI_HANDLE *MatchedHandleBuffer;\r
639 UINTN MatchedNumberOfHandles;\r
640 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
641 UINTN Index;\r
642 UINTN ImageInfoSize;\r
643 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;\r
644 UINT32 FmpImageInfoDescriptorVer;\r
645 UINT8 FmpImageInfoCount;\r
646 UINTN DescriptorSize;\r
647 UINT32 PackageVersion;\r
648 CHAR16 *PackageVersionName;\r
649 UINTN Index2;\r
650 EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;\r
651\r
652 *NoHandles = 0;\r
653 *Buffer = NULL;\r
654\r
655 Status = gBS->LocateHandleBuffer (\r
656 ByProtocol,\r
657 &gEfiFirmwareManagementProtocolGuid,\r
658 NULL,\r
659 &NumberOfHandles,\r
660 &HandleBuffer\r
661 );\r
662 if (EFI_ERROR(Status)) {\r
663 return Status;\r
664 }\r
665\r
666 MatchedNumberOfHandles = 0;\r
667 MatchedHandleBuffer = AllocateZeroPool (sizeof(EFI_HANDLE) * NumberOfHandles);\r
668 if (MatchedHandleBuffer == NULL) {\r
669 FreePool (HandleBuffer);\r
670 return EFI_OUT_OF_RESOURCES;\r
671 }\r
672\r
673 for (Index = 0; Index < NumberOfHandles; Index++) {\r
674 Status = gBS->HandleProtocol(\r
675 HandleBuffer[Index],\r
676 &gEfiFirmwareManagementProtocolGuid,\r
677 (VOID **)&Fmp\r
678 );\r
679 if (EFI_ERROR(Status)) {\r
680 continue;\r
681 }\r
682\r
683 ImageInfoSize = 0;\r
684 Status = Fmp->GetImageInfo (\r
685 Fmp,\r
686 &ImageInfoSize,\r
687 NULL,\r
688 NULL,\r
689 NULL,\r
690 NULL,\r
691 NULL,\r
692 NULL\r
693 );\r
694 if (Status != EFI_BUFFER_TOO_SMALL) {\r
695 continue;\r
696 }\r
697\r
698 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
699 if (FmpImageInfoBuf == NULL) {\r
700 continue;\r
701 }\r
702\r
703 PackageVersionName = NULL;\r
704 Status = Fmp->GetImageInfo (\r
705 Fmp,\r
706 &ImageInfoSize, // ImageInfoSize\r
707 FmpImageInfoBuf, // ImageInfo\r
708 &FmpImageInfoDescriptorVer, // DescriptorVersion\r
709 &FmpImageInfoCount, // DescriptorCount\r
710 &DescriptorSize, // DescriptorSize\r
711 &PackageVersion, // PackageVersion\r
712 &PackageVersionName // PackageVersionName\r
713 );\r
714 if (EFI_ERROR(Status)) {\r
715 FreePool(FmpImageInfoBuf);\r
716 continue;\r
717 }\r
718\r
719 if (PackageVersionName != NULL) {\r
720 FreePool(PackageVersionName);\r
721 }\r
722\r
723 TempFmpImageInfo = FmpImageInfoBuf;\r
724 for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {\r
725 //\r
726 // Check if this FMP instance matches\r
727 //\r
728 if (CompareGuid(UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) {\r
729 if ((UpdateHardwareInstance == 0) ||\r
730 ((FmpImageInfoDescriptorVer >= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) &&\r
731 (UpdateHardwareInstance == TempFmpImageInfo->HardwareInstance))) {\r
732 MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];\r
733 MatchedNumberOfHandles++;\r
734 break;\r
735 }\r
736 }\r
737 TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);\r
738 }\r
739 FreePool(FmpImageInfoBuf);\r
740 }\r
741\r
742 if (MatchedNumberOfHandles == 0) {\r
743 return EFI_NOT_FOUND;\r
744 }\r
745\r
746 *NoHandles = MatchedNumberOfHandles;\r
747 *Buffer = MatchedHandleBuffer;\r
748\r
749 return EFI_SUCCESS;\r
750}\r
751\r
752/**\r
753 Return FmpImageInfoDescriptorVer by an FMP handle.\r
754\r
755 @param[in] Handle A FMP handle.\r
756\r
757 @return FmpImageInfoDescriptorVer associated with the FMP.\r
758**/\r
759UINT32\r
760GetFmpImageInfoDescriptorVer (\r
761 IN EFI_HANDLE Handle\r
762 )\r
763{\r
764 EFI_STATUS Status;\r
765 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
766 UINTN ImageInfoSize;\r
767 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;\r
768 UINT32 FmpImageInfoDescriptorVer;\r
769 UINT8 FmpImageInfoCount;\r
770 UINTN DescriptorSize;\r
771 UINT32 PackageVersion;\r
772 CHAR16 *PackageVersionName;\r
773\r
774 Status = gBS->HandleProtocol(\r
775 Handle,\r
776 &gEfiFirmwareManagementProtocolGuid,\r
777 (VOID **)&Fmp\r
778 );\r
779 if (EFI_ERROR(Status)) {\r
780 return 0;\r
781 }\r
782\r
783 ImageInfoSize = 0;\r
784 Status = Fmp->GetImageInfo (\r
785 Fmp,\r
786 &ImageInfoSize,\r
787 NULL,\r
788 NULL,\r
789 NULL,\r
790 NULL,\r
791 NULL,\r
792 NULL\r
793 );\r
794 if (Status != EFI_BUFFER_TOO_SMALL) {\r
795 return 0;\r
796 }\r
797\r
798 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
799 if (FmpImageInfoBuf == NULL) {\r
800 return 0;\r
801 }\r
802\r
803 PackageVersionName = NULL;\r
804 Status = Fmp->GetImageInfo (\r
805 Fmp,\r
806 &ImageInfoSize, // ImageInfoSize\r
807 FmpImageInfoBuf, // ImageInfo\r
808 &FmpImageInfoDescriptorVer, // DescriptorVersion\r
809 &FmpImageInfoCount, // DescriptorCount\r
810 &DescriptorSize, // DescriptorSize\r
811 &PackageVersion, // PackageVersion\r
812 &PackageVersionName // PackageVersionName\r
813 );\r
814 if (EFI_ERROR(Status)) {\r
815 FreePool(FmpImageInfoBuf);\r
816 return 0;\r
817 }\r
818 return FmpImageInfoDescriptorVer;\r
819}\r
820\r
821/**\r
822 Set FMP image data.\r
823\r
824 @param[in] Handle A FMP handle.\r
825 @param[in] ImageHeader The payload image header.\r
826 @param[in] PayloadIndex The index of the payload.\r
827\r
828 @return The status of FMP->SetImage.\r
829**/\r
830EFI_STATUS\r
831SetFmpImageData (\r
832 IN EFI_HANDLE Handle,\r
833 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,\r
834 IN UINTN PayloadIndex\r
835 )\r
836{\r
837 EFI_STATUS Status;\r
838 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
839 UINT8 *Image;\r
840 VOID *VendorCode;\r
841 CHAR16 *AbortReason;\r
842\r
843 Status = gBS->HandleProtocol(\r
844 Handle,\r
845 &gEfiFirmwareManagementProtocolGuid,\r
846 (VOID **)&Fmp\r
847 );\r
848 if (EFI_ERROR(Status)) {\r
849 return Status;\r
850 }\r
851\r
852 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
853 Image = (UINT8 *)(ImageHeader + 1);\r
854 } else {\r
855 //\r
856 // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1,\r
857 // Header should exclude UpdateHardwareInstance field\r
858 //\r
859 Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);\r
860 }\r
861\r
862 if (ImageHeader->UpdateVendorCodeSize == 0) {\r
863 VendorCode = NULL;\r
864 } else {\r
865 VendorCode = Image + ImageHeader->UpdateImageSize;\r
866 }\r
867 AbortReason = NULL;\r
868 DEBUG((DEBUG_INFO, "Fmp->SetImage ...\n"));\r
869 DEBUG((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId));\r
870 DEBUG((DEBUG_INFO, "PayloadIndex - 0x%x, ", PayloadIndex));\r
871 DEBUG((DEBUG_INFO, "ImageIndex - 0x%x ", ImageHeader->UpdateImageIndex));\r
872 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
873 DEBUG((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance));\r
874 }\r
875 DEBUG((DEBUG_INFO, "\n"));\r
876 Status = Fmp->SetImage(\r
877 Fmp,\r
878 ImageHeader->UpdateImageIndex, // ImageIndex\r
879 Image, // Image\r
880 ImageHeader->UpdateImageSize, // ImageSize\r
881 VendorCode, // VendorCode\r
882 Update_Image_Progress, // Progress\r
883 &AbortReason // AbortReason\r
884 );\r
885 DEBUG((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));\r
886 if (AbortReason != NULL) {\r
887 DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));\r
888 FreePool(AbortReason);\r
889 }\r
890\r
891 return Status;\r
892}\r
893\r
894/**\r
895 Start a UEFI image in the FMP payload.\r
896\r
897 @param[in] ImageBuffer A pointer to the memory location containing a copy of the image to be loaded..\r
898 @param[in] ImageSize The size in bytes of ImageBuffer.\r
899\r
900 @return The status of gBS->LoadImage and gBS->StartImage.\r
901**/\r
902EFI_STATUS\r
903StartFmpImage (\r
904 IN VOID *ImageBuffer,\r
905 IN UINTN ImageSize\r
906 )\r
907{\r
908 MEMMAP_DEVICE_PATH MemMapNode;\r
909 EFI_STATUS Status;\r
910 EFI_HANDLE ImageHandle;\r
911 EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;\r
912 UINTN ExitDataSize;\r
913\r
914 SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));\r
915 MemMapNode.Header.Type = HARDWARE_DEVICE_PATH;\r
916 MemMapNode.Header.SubType = HW_MEMMAP_DP;\r
917 MemMapNode.MemoryType = EfiBootServicesCode;\r
918 MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBuffer;\r
919 MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)ImageBuffer + ImageSize - 1);\r
920\r
921 DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);\r
922 if (DriverDevicePath == NULL) {\r
923 return EFI_OUT_OF_RESOURCES;\r
924 }\r
925\r
926 DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));\r
927 Status = gBS->LoadImage(\r
928 FALSE,\r
929 gImageHandle,\r
930 DriverDevicePath,\r
931 ImageBuffer,\r
932 ImageSize,\r
933 &ImageHandle\r
934 );\r
935 DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));\r
936 if (EFI_ERROR(Status)) {\r
937 FreePool(DriverDevicePath);\r
938 return Status;\r
939 }\r
940\r
941 DEBUG((DEBUG_INFO, "FmpCapsule: StartImage ...\n"));\r
942 Status = gBS->StartImage(\r
943 ImageHandle,\r
944 &ExitDataSize,\r
945 NULL\r
946 );\r
947 DEBUG((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status));\r
948 if (EFI_ERROR(Status)) {\r
949 DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));\r
950 }\r
951\r
952 FreePool(DriverDevicePath);\r
953 return Status;\r
954}\r
955\r
956/**\r
957 Record FMP capsule status.\r
958\r
959 @param[in] Handle A FMP handle.\r
960 @param[in] CapsuleHeader The capsule image header\r
961 @param[in] CapsuleStatus The capsule process stauts\r
962 @param[in] PayloadIndex FMP payload index\r
963 @param[in] ImageHeader FMP image header\r
964**/\r
965VOID\r
966RecordFmpCapsuleStatus (\r
967 IN EFI_HANDLE Handle, OPTIONAL\r
968 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
969 IN EFI_STATUS CapsuleStatus,\r
970 IN UINTN PayloadIndex,\r
971 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader\r
972 )\r
973{\r
974 EFI_STATUS Status;\r
975 EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath;\r
976 UINT32 FmpImageInfoDescriptorVer;\r
977 EFI_STATUS StatusEsrt;\r
978 ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;\r
979 EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry;\r
980\r
981 FmpDevicePath = NULL;\r
982 if (Handle != NULL) {\r
983 gBS->HandleProtocol(\r
984 Handle,\r
985 &gEfiDevicePathProtocolGuid,\r
986 (VOID **)&FmpDevicePath\r
987 );\r
988 }\r
989\r
990 RecordFmpCapsuleStatusVariable (\r
991 CapsuleHeader,\r
992 CapsuleStatus,\r
993 PayloadIndex,\r
994 ImageHeader,\r
995 FmpDevicePath\r
996 );\r
997\r
998 //\r
999 // Update corresponding ESRT entry LastAttemp Status\r
1000 //\r
1001 Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);\r
1002 if (EFI_ERROR (Status)) {\r
1003 return ;\r
1004 }\r
1005\r
1006 if (Handle == NULL) {\r
1007 return ;\r
1008 }\r
1009\r
1010 //\r
1011 // Update EsrtEntry For V1, V2 FMP instance.\r
1012 // V3 FMP ESRT cache will be synced up through EsrtSyncFmp interface\r
1013 //\r
1014 FmpImageInfoDescriptorVer = GetFmpImageInfoDescriptorVer (Handle);\r
1015 if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) {\r
1016 StatusEsrt = EsrtProtocol->GetEsrtEntry(&ImageHeader->UpdateImageTypeId, &EsrtEntry);\r
1017 if (!EFI_ERROR(StatusEsrt)){\r
1018 if (!EFI_ERROR(CapsuleStatus)) {\r
1019 EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
1020 } else {\r
1021 EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
1022 }\r
1023 EsrtEntry.LastAttemptVersion = 0;\r
1024 EsrtProtocol->UpdateEsrtEntry(&EsrtEntry);\r
1025 }\r
1026 }\r
1027}\r
1028\r
d2a16030
JY
1029/**\r
1030 Process Firmware management protocol data capsule.\r
1031\r
1032 This function assumes the caller validated the capsule by using\r
1033 ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,\r
1034 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and\r
1035 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.\r
1036\r
1037 This function need support nested FMP capsule.\r
1038\r
11ee1bc9 1039 @param[in] CapsuleHeader Points to a capsule header.\r
d2a16030
JY
1040\r
1041 @retval EFI_SUCESS Process Capsule Image successfully.\r
1042 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.\r
1043 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.\r
1044 @retval EFI_OUT_OF_RESOURCES Not enough memory.\r
3f31ea1b 1045 @retval EFI_NOT_READY No FMP protocol to handle this FMP capsule.\r
d2a16030
JY
1046**/\r
1047EFI_STATUS\r
1048ProcessFmpCapsuleImage (\r
3f31ea1b 1049 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
d2a16030
JY
1050 )\r
1051{\r
1052 EFI_STATUS Status;\r
d2a16030
JY
1053 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
1054 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
d2a16030
JY
1055 UINT64 *ItemOffsetList;\r
1056 UINT32 ItemNum;\r
1057 UINTN Index;\r
d2a16030 1058 EFI_HANDLE *HandleBuffer;\r
d2a16030 1059 UINTN NumberOfHandles;\r
d2a16030 1060 UINTN DriverLen;\r
3f31ea1b 1061 UINT64 UpdateHardwareInstance;\r
d2a16030 1062 UINTN Index2;\r
3f31ea1b
JY
1063 BOOLEAN NotReady;\r
1064 BOOLEAN Abort;\r
d2a16030
JY
1065\r
1066 if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {\r
3f31ea1b 1067 return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize));\r
d2a16030
JY
1068 }\r
1069\r
3f31ea1b
JY
1070 NotReady = FALSE;\r
1071 Abort = FALSE;\r
d2a16030
JY
1072\r
1073 DumpFmpCapsule(CapsuleHeader);\r
1074\r
1075 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);\r
1076\r
1077 if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {\r
1078 return EFI_INVALID_PARAMETER;\r
1079 }\r
1080 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
1081\r
1082 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;\r
1083\r
1084 //\r
1085 // capsule in which driver count and payload count are both zero is not processed.\r
1086 //\r
1087 if (ItemNum == 0) {\r
d2a16030
JY
1088 return EFI_SUCCESS;\r
1089 }\r
1090\r
d2a16030
JY
1091 //\r
1092 // 1. Try to load & start all the drivers within capsule\r
1093 //\r
d2a16030 1094 for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {\r
3f31ea1b
JY
1095 if ((FmpCapsuleHeader->PayloadItemCount == 0) &&\r
1096 (Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1)) {\r
d2a16030
JY
1097 //\r
1098 // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER\r
1099 //\r
1100 DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];\r
1101 } else {\r
1102 DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];\r
1103 }\r
1104\r
3f31ea1b
JY
1105 Status = StartFmpImage (\r
1106 (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],\r
1107 DriverLen\r
1108 );\r
d2a16030
JY
1109 if (EFI_ERROR(Status)) {\r
1110 DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));\r
3f31ea1b 1111 return Status;\r
d2a16030
JY
1112 }\r
1113 }\r
1114\r
1115 //\r
1116 // 2. Route payload to right FMP instance\r
1117 //\r
1118 DEBUG((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n"));\r
1119\r
3f31ea1b 1120 DumpAllFmpInfo ();\r
8f6db161 1121\r
3f31ea1b
JY
1122 //\r
1123 // Check all the payload entry in capsule payload list\r
1124 //\r
1125 for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {\r
1126 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
d2a16030 1127\r
3f31ea1b
JY
1128 UpdateHardwareInstance = 0;\r
1129 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
1130 UpdateHardwareInstance = ImageHeader->UpdateHardwareInstance;\r
1131 }\r
d2a16030 1132\r
3f31ea1b
JY
1133 Status = GetFmpHandleBufferByType (\r
1134 &ImageHeader->UpdateImageTypeId,\r
1135 UpdateHardwareInstance,\r
1136 &NumberOfHandles,\r
1137 &HandleBuffer\r
1138 );\r
1139 if (EFI_ERROR(Status)) {\r
1140 NotReady = TRUE;\r
1141 RecordFmpCapsuleStatus (\r
1142 NULL,\r
1143 CapsuleHeader,\r
1144 EFI_NOT_READY,\r
1145 Index - FmpCapsuleHeader->EmbeddedDriverCount,\r
1146 ImageHeader\r
1147 );\r
1148 continue;\r
1149 }\r
d2a16030 1150\r
3f31ea1b
JY
1151 for (Index2 = 0; Index2 < NumberOfHandles; Index2++) {\r
1152 if (Abort) {\r
1153 RecordFmpCapsuleStatus (\r
1154 HandleBuffer[Index2],\r
1155 CapsuleHeader,\r
1156 EFI_ABORTED,\r
1157 Index - FmpCapsuleHeader->EmbeddedDriverCount,\r
1158 ImageHeader\r
1159 );\r
d2a16030
JY
1160 continue;\r
1161 }\r
1162\r
3f31ea1b
JY
1163 Status = SetFmpImageData (\r
1164 HandleBuffer[Index2],\r
1165 ImageHeader,\r
1166 Index - FmpCapsuleHeader->EmbeddedDriverCount\r
1167 );\r
1168 if (Status != EFI_SUCCESS) {\r
1169 Abort = TRUE;\r
d2a16030
JY
1170 }\r
1171\r
3f31ea1b
JY
1172 RecordFmpCapsuleStatus (\r
1173 HandleBuffer[Index2],\r
1174 CapsuleHeader,\r
1175 Status,\r
1176 Index - FmpCapsuleHeader->EmbeddedDriverCount,\r
1177 ImageHeader\r
1178 );\r
d2a16030 1179 }\r
3f31ea1b
JY
1180 if (HandleBuffer != NULL) {\r
1181 FreePool(HandleBuffer);\r
d2a16030
JY
1182 }\r
1183 }\r
1184\r
3f31ea1b
JY
1185 if (NotReady) {\r
1186 return EFI_NOT_READY;\r
d2a16030
JY
1187 }\r
1188\r
3f31ea1b
JY
1189 //\r
1190 // always return SUCCESS to indicate this capsule is processed.\r
1191 // The status of SetImage is recorded in capsule result variable.\r
1192 //\r
1193 return EFI_SUCCESS;\r
d2a16030
JY
1194}\r
1195\r
1196/**\r
1197 Return if there is a FMP header below capsule header.\r
1198\r
1199 @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER\r
1200\r
1201 @retval TRUE There is a FMP header below capsule header.\r
1202 @retval FALSE There is not a FMP header below capsule header\r
1203**/\r
1204BOOLEAN\r
1205IsNestedFmpCapsule (\r
1206 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
1207 )\r
1208{\r
1209 EFI_STATUS Status;\r
d2a16030
JY
1210 EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;\r
1211 UINTN Index;\r
1212 BOOLEAN EsrtGuidFound;\r
1213 EFI_CAPSULE_HEADER *NestedCapsuleHeader;\r
1214 UINTN NestedCapsuleSize;\r
1215 ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;\r
1216 EFI_SYSTEM_RESOURCE_ENTRY Entry;\r
7f0301e3
KM
1217 EFI_HANDLE *HandleBuffer;\r
1218 UINTN NumberOfHandles;\r
d2a16030
JY
1219\r
1220 EsrtGuidFound = FALSE;\r
056563f1
JY
1221 if (mIsVirtualAddrConverted) {\r
1222 if(mEsrtTable != NULL) {\r
1223 EsrtEntry = (EFI_SYSTEM_RESOURCE_ENTRY *)(mEsrtTable + 1);\r
1224 for (Index = 0; Index < mEsrtTable->FwResourceCount ; Index++, EsrtEntry++) {\r
d2a16030
JY
1225 if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {\r
1226 EsrtGuidFound = TRUE;\r
1227 break;\r
1228 }\r
1229 }\r
1230 }\r
056563f1
JY
1231 } else {\r
1232 //\r
1233 // Check ESRT protocol\r
1234 //\r
1235 Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);\r
1236 if (!EFI_ERROR(Status)) {\r
1237 Status = EsrtProtocol->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &Entry);\r
1238 if (!EFI_ERROR(Status)) {\r
1239 EsrtGuidFound = TRUE;\r
1240 }\r
1241 }\r
1242\r
1243 //\r
7f0301e3 1244 // Check Firmware Management Protocols\r
056563f1
JY
1245 //\r
1246 if (!EsrtGuidFound) {\r
7f0301e3
KM
1247 HandleBuffer = NULL;\r
1248 Status = GetFmpHandleBufferByType (\r
1249 &CapsuleHeader->CapsuleGuid,\r
1250 0,\r
1251 &NumberOfHandles,\r
1252 &HandleBuffer\r
1253 );\r
056563f1 1254 if (!EFI_ERROR(Status)) {\r
7f0301e3
KM
1255 EsrtGuidFound = TRUE;\r
1256 }\r
1257 if (HandleBuffer != NULL) {\r
1258 FreePool (HandleBuffer);\r
056563f1
JY
1259 }\r
1260 }\r
d2a16030
JY
1261 }\r
1262 if (!EsrtGuidFound) {\r
1263 return FALSE;\r
1264 }\r
1265\r
1266 //\r
1267 // Check nested capsule header\r
1268 // FMP GUID after ESRT one\r
1269 //\r
1270 NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
1271 NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize - (UINTN)NestedCapsuleHeader;\r
1272 if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) {\r
1273 return FALSE;\r
1274 }\r
1275 if (!IsValidCapsuleHeader(NestedCapsuleHeader, NestedCapsuleSize)) {\r
1276 return FALSE;\r
1277 }\r
1278 if (!IsFmpCapsuleGuid(&NestedCapsuleHeader->CapsuleGuid)) {\r
1279 return FALSE;\r
1280 }\r
1281 DEBUG ((DEBUG_INFO, "IsNestedFmpCapsule\n"));\r
1282 return TRUE;\r
1283}\r
1284\r
1285/**\r
1286 Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.\r
1287\r
1288 @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER\r
1289\r
1290 @retval TRUE It is a system FMP.\r
1291 @retval FALSE It is a device FMP.\r
1292**/\r
1293BOOLEAN\r
1294IsFmpCapsule (\r
1295 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
1296 )\r
1297{\r
1298 if (IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {\r
1299 return TRUE;\r
1300 }\r
1301 if (IsNestedFmpCapsule(CapsuleHeader)) {\r
1302 return TRUE;\r
1303 }\r
1304 return FALSE;\r
1305}\r
1306\r
1307/**\r
1308 Those capsules supported by the firmwares.\r
1309\r
1310 Caution: This function may receive untrusted input.\r
1311\r
1312 @param[in] CapsuleHeader Points to a capsule header.\r
1313\r
1314 @retval EFI_SUCESS Input capsule is supported by firmware.\r
1315 @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.\r
1316 @retval EFI_INVALID_PARAMETER Input capsule layout is not correct\r
1317**/\r
1318EFI_STATUS\r
1319EFIAPI\r
1320SupportCapsuleImage (\r
1321 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
1322 )\r
1323{\r
1324 //\r
1325 // check Display Capsule Guid\r
1326 //\r
1327 if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {\r
1328 return EFI_SUCCESS;\r
1329 }\r
1330\r
1331 if (IsFmpCapsule(CapsuleHeader)) {\r
1332 //\r
1333 // Check layout of FMP capsule\r
1334 //\r
1335 return ValidateFmpCapsule(CapsuleHeader, NULL);\r
1336 }\r
1337 DEBUG((DEBUG_ERROR, "Unknown Capsule Guid - %g\n", &CapsuleHeader->CapsuleGuid));\r
1338 return EFI_UNSUPPORTED;\r
1339}\r
1340\r
1341/**\r
1342 The firmware implements to process the capsule image.\r
1343\r
1344 Caution: This function may receive untrusted input.\r
1345\r
1346 @param[in] CapsuleHeader Points to a capsule header.\r
1347\r
1348 @retval EFI_SUCESS Process Capsule Image successfully.\r
1349 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.\r
1350 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.\r
1351 @retval EFI_OUT_OF_RESOURCES Not enough memory.\r
1352**/\r
1353EFI_STATUS\r
1354EFIAPI\r
1355ProcessCapsuleImage (\r
1356 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
1357 )\r
1358{\r
1359 EFI_STATUS Status;\r
d2a16030
JY
1360\r
1361 if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {\r
3f31ea1b 1362 RecordCapsuleStatusVariable(CapsuleHeader, EFI_UNSUPPORTED);\r
d2a16030
JY
1363 return EFI_UNSUPPORTED;\r
1364 }\r
1365\r
1366 //\r
1367 // Display image in firmware update display capsule\r
1368 //\r
1369 if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {\r
1370 DEBUG((DEBUG_INFO, "ProcessCapsuleImage for WindowsUxCapsule ...\n"));\r
1371 Status = DisplayCapsuleImage(CapsuleHeader);\r
1372 RecordCapsuleStatusVariable(CapsuleHeader, Status);\r
1373 return Status;\r
1374 }\r
1375\r
1376 //\r
1377 // Check FMP capsule layout\r
1378 //\r
1379 if (IsFmpCapsule (CapsuleHeader)) {\r
1380 DEBUG((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));\r
1381 DEBUG((DEBUG_INFO, "ValidateFmpCapsule ...\n"));\r
1382 Status = ValidateFmpCapsule(CapsuleHeader, NULL);\r
1383 DEBUG((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));\r
1384 if (EFI_ERROR(Status)) {\r
3f31ea1b 1385 RecordCapsuleStatusVariable(CapsuleHeader, Status);\r
d2a16030
JY
1386 return Status;\r
1387 }\r
1388\r
1389 //\r
1390 // Press EFI FMP Capsule\r
1391 //\r
1392 DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));\r
3f31ea1b 1393 Status = ProcessFmpCapsuleImage(CapsuleHeader);\r
d2a16030
JY
1394 DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));\r
1395\r
d2a16030
JY
1396 return Status;\r
1397 }\r
1398\r
1399 return EFI_UNSUPPORTED;\r
1400}\r
1401\r
1402/**\r
1403 Callback function executed when the EndOfDxe event group is signaled.\r
1404\r
1405 @param[in] Event Event whose notification function is being invoked.\r
1406 @param[in] Context The pointer to the notification function's context, which\r
1407 is implementation-dependent.\r
1408**/\r
1409VOID\r
1410EFIAPI\r
1411DxeCapsuleLibEndOfDxe (\r
1412 IN EFI_EVENT Event,\r
1413 IN VOID *Context\r
1414 )\r
1415{\r
1416 mDxeCapsuleLibEndOfDxe = TRUE;\r
1417}\r
1418\r
1419/**\r
1420 The constructor function.\r
1421\r
1422 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1423 @param[in] SystemTable A pointer to the EFI System Table.\r
1424\r
1425 @retval EFI_SUCCESS The constructor successfully .\r
1426**/\r
1427EFI_STATUS\r
1428EFIAPI\r
1429DxeCapsuleLibConstructor (\r
1430 IN EFI_HANDLE ImageHandle,\r
1431 IN EFI_SYSTEM_TABLE *SystemTable\r
1432 )\r
1433{\r
d2a16030
JY
1434 EFI_STATUS Status;\r
1435\r
1436 Status = gBS->CreateEventEx (\r
1437 EVT_NOTIFY_SIGNAL,\r
1438 TPL_CALLBACK,\r
1439 DxeCapsuleLibEndOfDxe,\r
1440 NULL,\r
1441 &gEfiEndOfDxeEventGroupGuid,\r
96b17e00 1442 &mDxeCapsuleLibEndOfDxeEvent\r
d2a16030
JY
1443 );\r
1444 ASSERT_EFI_ERROR (Status);\r
1445\r
1446 InitCapsuleVariable();\r
1447\r
1448 return EFI_SUCCESS;\r
1449}\r
96b17e00
HW
1450\r
1451/**\r
1452 The destructor function closes the End of DXE event.\r
1453\r
1454 @param ImageHandle The firmware allocated handle for the EFI image.\r
1455 @param SystemTable A pointer to the EFI System Table.\r
1456\r
1457 @retval EFI_SUCCESS The destructor completed successfully.\r
1458**/\r
1459EFI_STATUS\r
1460EFIAPI\r
1461DxeCapsuleLibDestructor (\r
1462 IN EFI_HANDLE ImageHandle,\r
1463 IN EFI_SYSTEM_TABLE *SystemTable\r
1464 )\r
1465{\r
1466 EFI_STATUS Status;\r
1467\r
1468 //\r
1469 // Close the End of DXE event.\r
1470 //\r
1471 Status = gBS->CloseEvent (mDxeCapsuleLibEndOfDxeEvent);\r
1472 ASSERT_EFI_ERROR (Status);\r
1473\r
1474 return EFI_SUCCESS;\r
1475}\r