BaseTools: enable FixedAtBuild (VOID*) PCD use in the [DEPEX] section
[mirror_edk2.git] / MdeModulePkg / Application / CapsuleApp / CapsuleApp.c
CommitLineData
592bad04
JY
1/** @file\r
2 A shell application that triggers capsule update process.\r
3\r
845f7cfe 4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
592bad04
JY
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <Uefi.h>\r
16#include <Library/BaseLib.h>\r
17#include <Library/DebugLib.h>\r
18#include <Library/BaseMemoryLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/UefiBootServicesTableLib.h>\r
21#include <Library/UefiRuntimeServicesTableLib.h>\r
22#include <Library/UefiLib.h>\r
23#include <Library/PrintLib.h>\r
bf9b044e 24#include <Library/BmpSupportLib.h>\r
592bad04 25#include <Protocol/GraphicsOutput.h>\r
592bad04
JY
26#include <Guid/GlobalVariable.h>\r
27#include <Guid/CapsuleReport.h>\r
28#include <Guid/SystemResourceTable.h>\r
29#include <Guid/FmpCapsule.h>\r
30#include <IndustryStandard/WindowsUxCapsule.h>\r
31\r
32#define CAPSULE_HEADER_SIZE 0x20\r
33\r
34#define NESTED_CAPSULE_HEADER_SIZE SIZE_4KB\r
35#define SYSTEM_FIRMWARE_FLAG 0x50000\r
36#define DEVICE_FIRMWARE_FLAG 0x78010\r
37\r
592bad04
JY
38#define MAJOR_VERSION 1\r
39#define MINOR_VERSION 0\r
40\r
41#define MAX_CAPSULE_NUM 10\r
42\r
43extern UINTN Argc;\r
44extern CHAR16 **Argv;\r
45\r
46//\r
47// Define how many block descriptors we want to test with.\r
48//\r
49UINTN NumberOfDescriptors = 1;\r
50UINTN CapsuleFirstIndex;\r
51UINTN CapsuleLastIndex;\r
52\r
53/**\r
54 Dump capsule information\r
55\r
56 @param[in] CapsuleName The name of the capsule image.\r
57\r
58 @retval EFI_SUCCESS The capsule information is dumped.\r
59 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
60**/\r
61EFI_STATUS\r
62DumpCapsule (\r
63 IN CHAR16 *CapsuleName\r
64 );\r
65\r
66/**\r
67 Dump capsule status variable.\r
68\r
69 @retval EFI_SUCCESS The capsule status variable is dumped.\r
70 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
71**/\r
72EFI_STATUS\r
73DmpCapsuleStatusVariable (\r
74 VOID\r
75 );\r
76\r
77/**\r
78 Dump FMP protocol info.\r
79**/\r
80VOID\r
81DumpFmpData (\r
82 VOID\r
83 );\r
84\r
1e09ec09
JY
85/**\r
86 Dump FMP image data.\r
87\r
88 @param[in] ImageTypeId The ImageTypeId of the FMP image.\r
89 It is used to identify the FMP protocol.\r
90 @param[in] ImageIndex The ImageIndex of the FMP image.\r
91 It is the input parameter for FMP->GetImage().\r
92 @param[in] ImageName The file name to hold the output FMP image.\r
93**/\r
94VOID\r
95DumpFmpImage (\r
96 IN EFI_GUID *ImageTypeId,\r
97 IN UINTN ImageIndex,\r
98 IN CHAR16 *ImageName\r
99 );\r
100\r
592bad04
JY
101/**\r
102 Dump ESRT info.\r
103**/\r
104VOID\r
105DumpEsrtData (\r
106 VOID\r
107 );\r
108\r
109/**\r
110 Read a file.\r
111\r
112 @param[in] FileName The file to be read.\r
113 @param[out] BufferSize The file buffer size\r
114 @param[out] Buffer The file buffer\r
115\r
116 @retval EFI_SUCCESS Read file successfully\r
8b17683a
SZ
117 @retval EFI_NOT_FOUND Shell protocol or file not found\r
118 @retval others Read file failed\r
592bad04
JY
119**/\r
120EFI_STATUS\r
121ReadFileToBuffer (\r
122 IN CHAR16 *FileName,\r
123 OUT UINTN *BufferSize,\r
124 OUT VOID **Buffer\r
125 );\r
126\r
127/**\r
128 Write a file.\r
129\r
130 @param[in] FileName The file to be written.\r
131 @param[in] BufferSize The file buffer size\r
132 @param[in] Buffer The file buffer\r
133\r
134 @retval EFI_SUCCESS Write file successfully\r
8b17683a
SZ
135 @retval EFI_NOT_FOUND Shell protocol not found\r
136 @retval others Write file failed\r
592bad04
JY
137**/\r
138EFI_STATUS\r
139WriteFileFromBuffer (\r
140 IN CHAR16 *FileName,\r
141 IN UINTN BufferSize,\r
142 IN VOID *Buffer\r
143 );\r
144\r
145/**\r
146\r
147 This function parse application ARG.\r
148\r
149 @return Status\r
150**/\r
151EFI_STATUS\r
152GetArg (\r
153 VOID\r
154 );\r
155\r
156/**\r
157 Create UX capsule.\r
158\r
159 @retval EFI_SUCCESS The capsule header is appended.\r
160 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
161 @retval EFI_OUT_OF_RESOURCES No enough resource to create UX capsule.\r
162**/\r
163EFI_STATUS\r
164CreateBmpFmp (\r
165 VOID\r
166 )\r
167{\r
168 CHAR16 *OutputCapsuleName;\r
169 VOID *BmpBuffer;\r
170 UINTN FileSize;\r
171 CHAR16 *BmpName;\r
172 UINT8 *FullCapsuleBuffer;\r
173 UINTN FullCapsuleBufferSize;\r
174 EFI_DISPLAY_CAPSULE *DisplayCapsule;\r
175 EFI_STATUS Status;\r
176 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;\r
bf9b044e
MK
177 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;\r
178 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GopBlt;\r
179 UINTN GopBltSize;\r
180 UINTN Height;\r
181 UINTN Width;\r
592bad04
JY
182\r
183 Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop);\r
184 if (EFI_ERROR(Status)) {\r
185 Print(L"CapsuleApp: NO GOP is found.\n");\r
186 return EFI_UNSUPPORTED;\r
187 }\r
bf9b044e 188 Info = Gop->Mode->Info;\r
592bad04 189 Print(L"Current GOP: Mode - %d, ", Gop->Mode->Mode);\r
bf9b044e
MK
190 Print(L"HorizontalResolution - %d, ", Info->HorizontalResolution);\r
191 Print(L"VerticalResolution - %d\n", Info->VerticalResolution);\r
592bad04
JY
192 // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth\r
193 // VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight\r
194\r
195 if (Argc != 5) {\r
196 Print(L"CapsuleApp: Invalid Parameter.\n");\r
197 return EFI_UNSUPPORTED;\r
198 }\r
199\r
200 if (StrCmp(Argv[3], L"-O") != 0) {\r
201 Print(L"CapsuleApp: NO output capsule name.\n");\r
202 return EFI_UNSUPPORTED;\r
203 }\r
204 OutputCapsuleName = Argv[4];\r
205\r
206 BmpBuffer = NULL;\r
207 FileSize = 0;\r
208 FullCapsuleBuffer = NULL;\r
209\r
210 BmpName = Argv[2];\r
211 Status = ReadFileToBuffer(BmpName, &FileSize, &BmpBuffer);\r
212 if (EFI_ERROR(Status)) {\r
213 Print(L"CapsuleApp: BMP image (%s) is not found.\n", BmpName);\r
214 goto Done;\r
215 }\r
216\r
bf9b044e
MK
217 GopBlt = NULL;\r
218 Status = TranslateBmpToGopBlt (\r
219 BmpBuffer,\r
220 FileSize,\r
221 &GopBlt,\r
222 &GopBltSize,\r
223 &Height,\r
224 &Width\r
225 );\r
226 if (EFI_ERROR(Status)) {\r
227 Print(L"CapsuleApp: BMP image (%s) is not valid.\n", BmpName);\r
228 goto Done;\r
229 }\r
230 if (GopBlt != NULL) {\r
231 FreePool (GopBlt);\r
232 }\r
233 Print(L"BMP image (%s), Width - %d, Height - %d\n", BmpName, Width, Height);\r
234\r
235 if (Height > Info->VerticalResolution) {\r
236 Status = EFI_INVALID_PARAMETER;\r
237 Print(L"CapsuleApp: BMP image (%s) height is larger than current resolution.\n", BmpName);\r
238 goto Done;\r
239 }\r
240 if (Width > Info->HorizontalResolution) {\r
241 Status = EFI_INVALID_PARAMETER;\r
242 Print(L"CapsuleApp: BMP image (%s) width is larger than current resolution.\n", BmpName);\r
243 goto Done;\r
244 }\r
245\r
592bad04
JY
246 FullCapsuleBufferSize = sizeof(EFI_DISPLAY_CAPSULE) + FileSize;\r
247 FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);\r
248 if (FullCapsuleBuffer == NULL) {\r
249 Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);\r
250 Status = EFI_OUT_OF_RESOURCES;\r
251 goto Done;\r
252 }\r
253\r
254 DisplayCapsule = (EFI_DISPLAY_CAPSULE *)FullCapsuleBuffer;\r
255 CopyGuid(&DisplayCapsule->CapsuleHeader.CapsuleGuid, &gWindowsUxCapsuleGuid);\r
256 DisplayCapsule->CapsuleHeader.HeaderSize = sizeof(DisplayCapsule->CapsuleHeader);\r
257 DisplayCapsule->CapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;\r
258 DisplayCapsule->CapsuleHeader.CapsuleImageSize = (UINT32)FullCapsuleBufferSize;\r
259\r
260 DisplayCapsule->ImagePayload.Version = 1;\r
261 DisplayCapsule->ImagePayload.Checksum = 0;\r
262 DisplayCapsule->ImagePayload.ImageType = 0; // BMP\r
263 DisplayCapsule->ImagePayload.Reserved = 0;\r
264 DisplayCapsule->ImagePayload.Mode = Gop->Mode->Mode;\r
bf9b044e
MK
265\r
266 //\r
267 // Center the bitmap horizontally\r
268 //\r
269 DisplayCapsule->ImagePayload.OffsetX = (UINT32)((Info->HorizontalResolution - Width) / 2);\r
270\r
271 //\r
272 // Put bitmap 3/4 down the display. If bitmap is too tall, then align bottom\r
273 // of bitmap at bottom of display.\r
274 //\r
275 DisplayCapsule->ImagePayload.OffsetY =\r
276 MIN (\r
277 (UINT32)(Info->VerticalResolution - Height),\r
278 (UINT32)(((3 * Info->VerticalResolution) - (2 * Height)) / 4)\r
279 );\r
280\r
281 Print(L"BMP image (%s), OffsetX - %d, OffsetY - %d\n",\r
282 BmpName,\r
283 DisplayCapsule->ImagePayload.OffsetX,\r
284 DisplayCapsule->ImagePayload.OffsetY\r
285 );\r
592bad04
JY
286\r
287 CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize);\r
288\r
289 DisplayCapsule->ImagePayload.Checksum = CalculateCheckSum8(FullCapsuleBuffer, FullCapsuleBufferSize);\r
290\r
291 Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);\r
292 Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);\r
293\r
294Done:\r
295 if (BmpBuffer != NULL) {\r
296 FreePool(BmpBuffer);\r
297 }\r
298\r
299 if (FullCapsuleBuffer != NULL) {\r
300 FreePool(FullCapsuleBuffer);\r
301 }\r
302\r
303 return Status;\r
304}\r
305\r
306/**\r
307 Get ImageTypeId in the FMP capsule header.\r
308\r
309 @param[in] CapsuleHeader The FMP capsule image header.\r
310\r
311 @return ImageTypeId\r
312**/\r
313EFI_GUID *\r
314GetCapsuleImageTypeId (\r
315 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
316 )\r
317{\r
318 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
319 UINT64 *ItemOffsetList;\r
320 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
321\r
322 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
323 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
324 if (FmpCapsuleHeader->PayloadItemCount == 0) {\r
325 return NULL;\r
326 }\r
327 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[FmpCapsuleHeader->EmbeddedDriverCount]);\r
328 return &ImageHeader->UpdateImageTypeId;\r
329}\r
330\r
331/**\r
332 Get ESRT FwType according to ImageTypeId\r
333\r
334 @param[in] ImageTypeId ImageTypeId of an FMP capsule.\r
335\r
336 @return ESRT FwType\r
337**/\r
338UINT32\r
339GetEsrtFwType (\r
340 IN EFI_GUID *ImageTypeId\r
341 )\r
342{\r
343 EFI_STATUS Status;\r
344 EFI_SYSTEM_RESOURCE_TABLE *Esrt;\r
345 EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;\r
346 UINTN Index;\r
347\r
348 //\r
349 // Check ESRT\r
350 //\r
351 Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);\r
352 if (!EFI_ERROR(Status)) {\r
353 ASSERT(Esrt != NULL);\r
354 EsrtEntry = (VOID *)(Esrt + 1);\r
355 for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {\r
356 if (CompareGuid(&EsrtEntry->FwClass, ImageTypeId)) {\r
357 return EsrtEntry->FwType;\r
358 }\r
359 }\r
360 }\r
361\r
362 return ESRT_FW_TYPE_UNKNOWN;\r
363}\r
364\r
365/**\r
366 Append a capsule header on top of current image.\r
367 This function follows Windows UEFI Firmware Update Platform document.\r
368\r
369 @retval EFI_SUCCESS The capsule header is appended.\r
370 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
371 @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header.\r
372**/\r
373EFI_STATUS\r
374CreateNestedFmp (\r
375 VOID\r
376 )\r
377{\r
378 CHAR16 *OutputCapsuleName;\r
379 VOID *CapsuleBuffer;\r
380 UINTN FileSize;\r
381 CHAR16 *CapsuleName;\r
382 UINT8 *FullCapsuleBuffer;\r
383 UINTN FullCapsuleBufferSize;\r
384 EFI_CAPSULE_HEADER *NestedCapsuleHeader;\r
385 EFI_GUID *ImageTypeId;\r
386 UINT32 FwType;\r
387 EFI_STATUS Status;\r
388\r
389 if (Argc != 5) {\r
390 Print(L"CapsuleApp: Invalid Parameter.\n");\r
391 return EFI_UNSUPPORTED;\r
392 }\r
393\r
394 if (StrCmp(Argv[3], L"-O") != 0) {\r
395 Print(L"CapsuleApp: NO output capsule name.\n");\r
396 return EFI_UNSUPPORTED;\r
397 }\r
398 OutputCapsuleName = Argv[4];\r
399\r
400 CapsuleBuffer = NULL;\r
401 FileSize = 0;\r
402 FullCapsuleBuffer = NULL;\r
403\r
404 CapsuleName = Argv[2];\r
405 Status = ReadFileToBuffer(CapsuleName, &FileSize, &CapsuleBuffer);\r
406 if (EFI_ERROR(Status)) {\r
407 Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName);\r
408 goto Done;\r
409 }\r
410\r
411 ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer);\r
412 if (ImageTypeId == NULL) {\r
413 Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n");\r
414 goto Done;\r
415 }\r
416 FwType = GetEsrtFwType(ImageTypeId);\r
417 if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != ESRT_FW_TYPE_DEVICEFIRMWARE)) {\r
418 Print(L"CapsuleApp: Capsule FwType is invalid.\n");\r
419 goto Done;\r
420 }\r
421\r
422 FullCapsuleBufferSize = NESTED_CAPSULE_HEADER_SIZE + FileSize;\r
423 FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);\r
424 if (FullCapsuleBuffer == NULL) {\r
425 Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);\r
426 Status = EFI_OUT_OF_RESOURCES;\r
427 goto Done;\r
428 }\r
429\r
430 NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)FullCapsuleBuffer;\r
431 ZeroMem(NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE);\r
432 CopyGuid(&NestedCapsuleHeader->CapsuleGuid, ImageTypeId);\r
433 NestedCapsuleHeader->HeaderSize = NESTED_CAPSULE_HEADER_SIZE;\r
99fd3043 434 NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_SYSTEMFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;\r
592bad04
JY
435 NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize;\r
436\r
437 CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize);\r
438\r
439 Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);\r
440 Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);\r
441\r
442Done:\r
443 if (CapsuleBuffer != NULL) {\r
444 FreePool(CapsuleBuffer);\r
445 }\r
446\r
447 if (FullCapsuleBuffer != NULL) {\r
448 FreePool(FullCapsuleBuffer);\r
449 }\r
450\r
451 return Status;\r
452}\r
453\r
454\r
455/**\r
456 Clear capsule status variable.\r
457\r
458 @retval EFI_SUCCESS The capsule status variable is cleared.\r
459**/\r
460EFI_STATUS\r
461ClearCapsuleStatusVariable (\r
462 VOID\r
463 )\r
464{\r
465 EFI_STATUS Status;\r
466 UINT32 Index;\r
467 CHAR16 CapsuleVarName[20];\r
468 CHAR16 *TempVarName;\r
469\r
470 StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");\r
471 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
472 Index = 0;\r
473\r
474 while (TRUE) {\r
475 UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);\r
476\r
477 Status = gRT->SetVariable (\r
478 CapsuleVarName,\r
479 &gEfiCapsuleReportGuid,\r
480 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
481 0,\r
482 (VOID *)NULL\r
483 );\r
484 if (EFI_ERROR(Status)) {\r
485 //\r
486 // There is no capsule variables, quit\r
487 //\r
488 break;\r
489 }\r
490\r
491 Index++;\r
492 if (Index > 0xFFFF) {\r
493 break;\r
494 }\r
495 }\r
496\r
497 return EFI_SUCCESS;\r
498}\r
499\r
500/**\r
501 Build Gather list for a list of capsule images.\r
502\r
503 @param[in] CapsuleBuffer An array of pointer to capsule images\r
504 @param[in] FileSize An array of UINTN to capsule images size\r
505 @param[in] CapsuleNum The count of capsule images\r
506 @param[out] BlockDescriptors The block descriptors for the capsule images\r
507\r
508 @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.\r
509**/\r
510EFI_STATUS\r
511BuildGatherList (\r
512 IN VOID **CapsuleBuffer,\r
513 IN UINTN *FileSize,\r
514 IN UINTN CapsuleNum,\r
515 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors\r
516 )\r
517{\r
518 EFI_STATUS Status;\r
519 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;\r
520 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors2;\r
521 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;\r
522 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;\r
523 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;\r
524 UINT8 *TempDataPtr;\r
525 UINTN SizeLeft;\r
526 UINTN Size;\r
527 INT32 Count;\r
528 INT32 Number;\r
529 UINTN Index;\r
530\r
531 TempBlockPtr = NULL;\r
532 BlockDescriptors1 = NULL;\r
533 BlockDescriptors2 = NULL;\r
534 BlockDescriptorPre = NULL;\r
535 BlockDescriptorsHeader = NULL;\r
536\r
537 for (Index = 0; Index < CapsuleNum; Index++) {\r
538 //\r
539 // Allocate memory for the descriptors.\r
540 //\r
541 if (NumberOfDescriptors == 1) {\r
542 Count = 2;\r
543 } else {\r
544 Count = (INT32)(NumberOfDescriptors + 2) / 2;\r
545 }\r
546\r
547 Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
548 BlockDescriptors1 = AllocateRuntimeZeroPool (Size);\r
549 if (BlockDescriptors1 == NULL) {\r
550 Print (L"CapsuleApp: failed to allocate memory for descriptors\n");\r
551 Status = EFI_OUT_OF_RESOURCES;\r
552 goto ERREXIT;\r
553 } else {\r
554 Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1);\r
94f5c600 555 Print (L"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer[Index], FileSize[Index]);\r
592bad04
JY
556 }\r
557\r
558 //\r
559 // Record descirptor header\r
560 //\r
561 if (Index == 0) {\r
562 BlockDescriptorsHeader = BlockDescriptors1;\r
563 }\r
564\r
565 if (BlockDescriptorPre != NULL) {\r
566 BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1;\r
567 BlockDescriptorPre->Length = 0;\r
568 }\r
569\r
570 //\r
571 // Fill them in\r
572 //\r
573 TempBlockPtr = BlockDescriptors1;\r
574 TempDataPtr = CapsuleBuffer[Index];\r
575 SizeLeft = FileSize[Index];\r
576 for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) {\r
577 //\r
578 // Divide remaining data in half\r
579 //\r
580 if (NumberOfDescriptors != 1) {\r
581 if (SizeLeft == 1) {\r
582 Size = 1;\r
583 } else {\r
584 Size = SizeLeft / 2;\r
585 }\r
586 } else {\r
587 Size = SizeLeft;\r
588 }\r
589 TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;\r
590 TempBlockPtr->Length = Size;\r
591 Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);\r
592 SizeLeft -= Size;\r
593 TempDataPtr += Size;\r
594 TempBlockPtr++;\r
595 }\r
596\r
597 //\r
598 // Allocate the second list, point the first block's last entry to point\r
599 // to this one, and fill this one in. Worst case is that the previous\r
600 // list only had one element that pointed here, so we need at least two\r
601 // elements -- one to point to all the data, another to terminate the list.\r
602 //\r
603 if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) {\r
604 Count = (INT32)(NumberOfDescriptors + 2) - Count;\r
605 if (Count == 1) {\r
606 Count++;\r
607 }\r
608\r
609 Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
610 BlockDescriptors2 = AllocateRuntimeZeroPool (Size);\r
611 if (BlockDescriptors2 == NULL) {\r
612 Print (L"CapsuleApp: failed to allocate memory for descriptors\n");\r
613 Status = EFI_OUT_OF_RESOURCES;\r
614 goto ERREXIT;\r
615 }\r
616\r
617 //\r
618 // Point the first list's last element to point to this second list.\r
619 //\r
620 TempBlockPtr->Union.ContinuationPointer = (UINTN) BlockDescriptors2;\r
621\r
622 TempBlockPtr->Length = 0;\r
623 TempBlockPtr = BlockDescriptors2;\r
624 for (Number = 0; Number < Count - 1; Number++) {\r
625 //\r
626 // If second-to-last one, then dump rest to this element\r
627 //\r
628 if (Number == (Count - 2)) {\r
629 Size = SizeLeft;\r
630 } else {\r
631 //\r
632 // Divide remaining data in half\r
633 //\r
634 if (SizeLeft == 1) {\r
635 Size = 1;\r
636 } else {\r
637 Size = SizeLeft / 2;\r
638 }\r
639 }\r
640\r
641 TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;\r
642 TempBlockPtr->Length = Size;\r
643 Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);\r
644 SizeLeft -= Size;\r
645 TempDataPtr += Size;\r
646 TempBlockPtr++;\r
647 if (SizeLeft == 0) {\r
648 break;\r
649 }\r
650 }\r
651 }\r
652\r
653 BlockDescriptorPre = TempBlockPtr;\r
654 BlockDescriptors1 = NULL;\r
655 }\r
656\r
657 //\r
658 // Null-terminate.\r
659 //\r
660 if (TempBlockPtr != NULL) {\r
661 TempBlockPtr->Union.ContinuationPointer = (UINTN)NULL;\r
662 TempBlockPtr->Length = 0;\r
663 *BlockDescriptors = BlockDescriptorsHeader;\r
664 }\r
665\r
666 return EFI_SUCCESS;\r
667\r
668ERREXIT:\r
669 if (BlockDescriptors1 != NULL) {\r
670 FreePool(BlockDescriptors1);\r
671 }\r
672\r
673 if (BlockDescriptors2 != NULL) {\r
674 FreePool(BlockDescriptors2);\r
675 }\r
676\r
677 return Status;\r
678}\r
679\r
680/**\r
681 Clear the Gather list for a list of capsule images.\r
682\r
683 @param[in] BlockDescriptors The block descriptors for the capsule images\r
684 @param[in] CapsuleNum The count of capsule images\r
685**/\r
686VOID\r
687CleanGatherList (\r
688 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors,\r
689 IN UINTN CapsuleNum\r
690 )\r
691{\r
692 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;\r
693 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr1;\r
694 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr2;\r
695 UINTN Index;\r
696\r
697 if (BlockDescriptors != NULL) {\r
698 TempBlockPtr1 = BlockDescriptors;\r
699 while (1){\r
700 TempBlockPtr = TempBlockPtr1;\r
701 for (Index = 0; Index < CapsuleNum; Index++) {\r
702 if (TempBlockPtr[Index].Length == 0) {\r
703 break;\r
704 }\r
705 }\r
706\r
707 if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) {\r
708 break;\r
709 }\r
710\r
845f7cfe 711 TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr[Index].Union.ContinuationPointer);\r
592bad04
JY
712 FreePool(TempBlockPtr1);\r
713 TempBlockPtr1 = TempBlockPtr2;\r
714 }\r
715 }\r
716}\r
717\r
718/**\r
719 Print APP usage.\r
720**/\r
721VOID\r
722PrintUsage (\r
723 VOID\r
724 )\r
725{\r
726 Print(L"CapsuleApp: usage\n");\r
7043a90e 727 Print(L" CapsuleApp <Capsule...> [-NR]\n");\r
592bad04
JY
728 Print(L" CapsuleApp -S\n");\r
729 Print(L" CapsuleApp -C\n");\r
730 Print(L" CapsuleApp -P\n");\r
731 Print(L" CapsuleApp -E\n");\r
732 Print(L" CapsuleApp -G <BMP> -O <Capsule>\n");\r
733 Print(L" CapsuleApp -N <Capsule> -O <NestedCapsule>\n");\r
734 Print(L" CapsuleApp -D <Capsule>\n");\r
1e09ec09 735 Print(L" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");\r
592bad04 736 Print(L"Parameter:\n");\r
7043a90e
SZ
737 Print(L" -NR: No reset will be triggered for the capsule\n");\r
738 Print(L" with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET.\n");\r
592bad04
JY
739 Print(L" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
740 Print(L" which is defined in UEFI specification.\n");\r
0c6f94da 741 Print(L" -C: Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
592bad04
JY
742 Print(L" which is defined in UEFI specification.\n");\r
743 Print(L" -P: Dump UEFI FMP protocol info.\n");\r
744 Print(L" -E: Dump UEFI ESRT table info.\n");\r
045bb323 745 Print(L" -G: Convert a BMP file to be an UX capsule,\n");\r
592bad04
JY
746 Print(L" according to Windows Firmware Update document\n");\r
747 Print(L" -N: Append a Capsule Header to an existing capsule image,\n");\r
748 Print(L" according to Windows Firmware Update document\n");\r
749 Print(L" -O: Output new Capsule file name\n");\r
045bb323
SZ
750 Print(L" -D: Dump Capsule image header information, image payload information if it is an UX capsule\n");\r
751 Print(L" and FMP header information if it is a FMP capsule.\n");\r
592bad04
JY
752}\r
753\r
754/**\r
755 Update Capsule image.\r
756\r
757 @param[in] ImageHandle The image handle.\r
758 @param[in] SystemTable The system table.\r
759\r
760 @retval EFI_SUCCESS Command completed successfully.\r
761 @retval EFI_INVALID_PARAMETER Command usage error.\r
762 @retval EFI_NOT_FOUND The input file can't be found.\r
763**/\r
764EFI_STATUS\r
765EFIAPI\r
766UefiMain (\r
767 IN EFI_HANDLE ImageHandle,\r
768 IN EFI_SYSTEM_TABLE *SystemTable\r
769 )\r
770{\r
771 EFI_STATUS Status;\r
787f6744 772 RETURN_STATUS RStatus;\r
592bad04
JY
773 UINTN FileSize[MAX_CAPSULE_NUM];\r
774 VOID *CapsuleBuffer[MAX_CAPSULE_NUM];\r
775 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;\r
776 EFI_CAPSULE_HEADER *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];\r
777 UINT64 MaxCapsuleSize;\r
778 EFI_RESET_TYPE ResetType;\r
779 BOOLEAN NeedReset;\r
7043a90e 780 BOOLEAN NoReset;\r
592bad04
JY
781 CHAR16 *CapsuleName;\r
782 UINTN CapsuleNum;\r
783 UINTN Index;\r
784\r
785 Status = GetArg();\r
786 if (EFI_ERROR(Status)) {\r
787 Print(L"Please use UEFI SHELL to run this application!\n", Status);\r
788 return Status;\r
789 }\r
790 if (Argc < 2) {\r
791 PrintUsage();\r
792 return EFI_INVALID_PARAMETER;\r
793 }\r
794 if (StrCmp(Argv[1], L"-D") == 0) {\r
1c6dd45b
SZ
795 if (Argc < 3) {\r
796 Print(L"CapsuleApp: NO input capsule name.\n");\r
797 return EFI_INVALID_PARAMETER;\r
798 }\r
592bad04
JY
799 Status = DumpCapsule(Argv[2]);\r
800 return Status;\r
801 }\r
802 if (StrCmp(Argv[1], L"-G") == 0) {\r
803 Status = CreateBmpFmp();\r
804 return Status;\r
805 }\r
806 if (StrCmp(Argv[1], L"-N") == 0) {\r
807 Status = CreateNestedFmp();\r
808 return Status;\r
809 }\r
810 if (StrCmp(Argv[1], L"-S") == 0) {\r
811 Status = DmpCapsuleStatusVariable();\r
812 return EFI_SUCCESS;\r
813 }\r
814 if (StrCmp(Argv[1], L"-C") == 0) {\r
815 Status = ClearCapsuleStatusVariable();\r
816 return Status;\r
817 }\r
818 if (StrCmp(Argv[1], L"-P") == 0) {\r
1e09ec09
JY
819 if (Argc == 2) {\r
820 DumpFmpData();\r
821 }\r
822 if (Argc >= 3) {\r
823 if (StrCmp(Argv[2], L"GET") == 0) {\r
824 EFI_GUID ImageTypeId;\r
825 UINTN ImageIndex;\r
826 //\r
827 // FMP->GetImage()\r
828 //\r
787f6744
RN
829 RStatus = StrToGuid (Argv[3], &ImageTypeId);\r
830 if (RETURN_ERROR (RStatus) || (Argv[3][GUID_STRING_LENGTH] != L'\0')) {\r
1e09ec09 831 Print (L"Invalid ImageTypeId - %s\n", Argv[3]);\r
787f6744 832 return EFI_INVALID_PARAMETER;\r
1e09ec09
JY
833 }\r
834 ImageIndex = StrDecimalToUintn(Argv[4]);\r
835 if (StrCmp(Argv[5], L"-O") == 0) {\r
836 DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);\r
837 }\r
838 }\r
839 }\r
592bad04
JY
840 return EFI_SUCCESS;\r
841 }\r
842 if (StrCmp(Argv[1], L"-E") == 0) {\r
843 DumpEsrtData();\r
844 return EFI_SUCCESS;\r
845 }\r
846 CapsuleFirstIndex = 1;\r
7043a90e
SZ
847 NoReset = FALSE;\r
848 if ((Argc > 1) && (StrCmp(Argv[Argc - 1], L"-NR") == 0)) {\r
849 NoReset = TRUE;\r
850 CapsuleLastIndex = Argc - 2;\r
851 } else {\r
852 CapsuleLastIndex = Argc - 1;\r
853 }\r
592bad04
JY
854 CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;\r
855\r
856 if (CapsuleFirstIndex > CapsuleLastIndex) {\r
857 Print(L"CapsuleApp: NO capsule image.\n");\r
858 return EFI_UNSUPPORTED;\r
859 }\r
860 if (CapsuleNum > MAX_CAPSULE_NUM) {\r
861 Print(L"CapsuleApp: Too many capsule images.\n");\r
862 return EFI_UNSUPPORTED;\r
863 }\r
864\r
865 ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));\r
866 ZeroMem(&FileSize, sizeof(FileSize));\r
867 BlockDescriptors = NULL;\r
868\r
869 for (Index = 0; Index < CapsuleNum; Index++) {\r
870 CapsuleName = Argv[CapsuleFirstIndex + Index];\r
871 Status = ReadFileToBuffer(CapsuleName, &FileSize[Index], &CapsuleBuffer[Index]);\r
872 if (EFI_ERROR(Status)) {\r
873 Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);\r
874 goto Done;\r
875 }\r
876 }\r
877\r
878 //\r
879 // Every capsule use 2 descriptor 1 for data 1 for end\r
880 //\r
881 Status = BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, &BlockDescriptors);\r
882 if (EFI_ERROR(Status)) {\r
883 goto Done;\r
884 }\r
885\r
886 //\r
887 // Call the runtime service capsule.\r
888 //\r
889 NeedReset = FALSE;\r
890 for (Index = 0; Index < CapsuleNum; Index++) {\r
891 CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index];\r
892 if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
893 NeedReset = TRUE;\r
894 }\r
895 }\r
896 CapsuleHeaderArray[CapsuleNum] = NULL;\r
897\r
898 //\r
899 // Inquire platform capability of UpdateCapsule.\r
900 //\r
901 Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);\r
902 if (EFI_ERROR(Status)) {\r
903 Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);\r
904 goto Done;\r
905 }\r
906\r
907 for (Index = 0; Index < CapsuleNum; Index++) {\r
908 if (FileSize[Index] > MaxCapsuleSize) {\r
909 Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);\r
910 Status = EFI_UNSUPPORTED;\r
911 goto Done;\r
912 }\r
913 }\r
914\r
915 //\r
916 // Check whether the input capsule image has the flag of persist across system reset.\r
917 //\r
918 if (NeedReset) {\r
919 Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);\r
920 if (Status != EFI_SUCCESS) {\r
921 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
922 goto Done;\r
923 }\r
924 //\r
7043a90e
SZ
925 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,\r
926 // a system reset should have been triggered by gRT->UpdateCapsule() calling above.\r
927 //\r
928 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,\r
929 // check if -NR (no-reset) has been specified or not.\r
592bad04 930 //\r
7043a90e
SZ
931 if (!NoReset) {\r
932 //\r
933 // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,\r
934 // trigger a system reset to process capsule persist across a system reset.\r
935 //\r
936 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
937 }\r
592bad04
JY
938 } else {\r
939 //\r
940 // For capsule who has no reset flag, only call UpdateCapsule Service without a\r
941 // system reset. The service will process the capsule immediately.\r
942 //\r
943 Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);\r
944 if (Status != EFI_SUCCESS) {\r
945 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
946 }\r
947 }\r
948\r
949 Status = EFI_SUCCESS;\r
950\r
951Done:\r
952 for (Index = 0; Index < CapsuleNum; Index++) {\r
953 if (CapsuleBuffer[Index] != NULL) {\r
954 FreePool (CapsuleBuffer[Index]);\r
955 }\r
956 }\r
957\r
958 CleanGatherList(BlockDescriptors, CapsuleNum);\r
959\r
960 return Status;\r
961}\r