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