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