]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
MdeModulePkg CapsuleApp: Prompt info for -C option
[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
8b03c82d 73DumpCapsuleStatusVariable (\r
592bad04
JY
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
10944bc3 196 Print(L"CapsuleApp: Incorrect parameter count.\n");\r
592bad04
JY
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
10944bc3 390 Print(L"CapsuleApp: Incorrect parameter count.\n");\r
592bad04
JY
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
8b03c82d 469 BOOLEAN Found;\r
592bad04
JY
470\r
471 StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");\r
472 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
473 Index = 0;\r
474\r
8b03c82d 475 Found = FALSE;\r
592bad04
JY
476 while (TRUE) {\r
477 UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);\r
478\r
479 Status = gRT->SetVariable (\r
480 CapsuleVarName,\r
481 &gEfiCapsuleReportGuid,\r
482 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
483 0,\r
484 (VOID *)NULL\r
485 );\r
8b03c82d 486 if (Status == EFI_NOT_FOUND) {\r
592bad04 487 //\r
8b03c82d 488 // There is no more capsule variables, quit\r
592bad04
JY
489 //\r
490 break;\r
491 }\r
8b03c82d
SZ
492 Found = TRUE;\r
493\r
494 Print (L"Clear %s %r\n", CapsuleVarName, Status);\r
592bad04
JY
495\r
496 Index++;\r
497 if (Index > 0xFFFF) {\r
498 break;\r
499 }\r
500 }\r
501\r
8b03c82d
SZ
502 if (!Found) {\r
503 Print (L"No any Capsule#### variable found\n");\r
504 }\r
505\r
592bad04
JY
506 return EFI_SUCCESS;\r
507}\r
508\r
509/**\r
510 Build Gather list for a list of capsule images.\r
511\r
512 @param[in] CapsuleBuffer An array of pointer to capsule images\r
513 @param[in] FileSize An array of UINTN to capsule images size\r
514 @param[in] CapsuleNum The count of capsule images\r
515 @param[out] BlockDescriptors The block descriptors for the capsule images\r
516\r
517 @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.\r
518**/\r
519EFI_STATUS\r
520BuildGatherList (\r
521 IN VOID **CapsuleBuffer,\r
522 IN UINTN *FileSize,\r
523 IN UINTN CapsuleNum,\r
524 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors\r
525 )\r
526{\r
527 EFI_STATUS Status;\r
528 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;\r
529 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors2;\r
530 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;\r
531 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;\r
532 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;\r
533 UINT8 *TempDataPtr;\r
534 UINTN SizeLeft;\r
535 UINTN Size;\r
536 INT32 Count;\r
537 INT32 Number;\r
538 UINTN Index;\r
539\r
540 TempBlockPtr = NULL;\r
541 BlockDescriptors1 = NULL;\r
542 BlockDescriptors2 = NULL;\r
543 BlockDescriptorPre = NULL;\r
544 BlockDescriptorsHeader = NULL;\r
545\r
546 for (Index = 0; Index < CapsuleNum; Index++) {\r
547 //\r
548 // Allocate memory for the descriptors.\r
549 //\r
550 if (NumberOfDescriptors == 1) {\r
551 Count = 2;\r
552 } else {\r
553 Count = (INT32)(NumberOfDescriptors + 2) / 2;\r
554 }\r
555\r
556 Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
557 BlockDescriptors1 = AllocateRuntimeZeroPool (Size);\r
558 if (BlockDescriptors1 == NULL) {\r
559 Print (L"CapsuleApp: failed to allocate memory for descriptors\n");\r
560 Status = EFI_OUT_OF_RESOURCES;\r
561 goto ERREXIT;\r
562 } else {\r
563 Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1);\r
94f5c600 564 Print (L"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer[Index], FileSize[Index]);\r
592bad04
JY
565 }\r
566\r
567 //\r
568 // Record descirptor header\r
569 //\r
570 if (Index == 0) {\r
571 BlockDescriptorsHeader = BlockDescriptors1;\r
572 }\r
573\r
574 if (BlockDescriptorPre != NULL) {\r
575 BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1;\r
576 BlockDescriptorPre->Length = 0;\r
577 }\r
578\r
579 //\r
580 // Fill them in\r
581 //\r
582 TempBlockPtr = BlockDescriptors1;\r
583 TempDataPtr = CapsuleBuffer[Index];\r
584 SizeLeft = FileSize[Index];\r
585 for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) {\r
586 //\r
587 // Divide remaining data in half\r
588 //\r
589 if (NumberOfDescriptors != 1) {\r
590 if (SizeLeft == 1) {\r
591 Size = 1;\r
592 } else {\r
593 Size = SizeLeft / 2;\r
594 }\r
595 } else {\r
596 Size = SizeLeft;\r
597 }\r
598 TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;\r
599 TempBlockPtr->Length = Size;\r
600 Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);\r
601 SizeLeft -= Size;\r
602 TempDataPtr += Size;\r
603 TempBlockPtr++;\r
604 }\r
605\r
606 //\r
607 // Allocate the second list, point the first block's last entry to point\r
608 // to this one, and fill this one in. Worst case is that the previous\r
609 // list only had one element that pointed here, so we need at least two\r
610 // elements -- one to point to all the data, another to terminate the list.\r
611 //\r
612 if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) {\r
613 Count = (INT32)(NumberOfDescriptors + 2) - Count;\r
614 if (Count == 1) {\r
615 Count++;\r
616 }\r
617\r
618 Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
619 BlockDescriptors2 = AllocateRuntimeZeroPool (Size);\r
620 if (BlockDescriptors2 == NULL) {\r
621 Print (L"CapsuleApp: failed to allocate memory for descriptors\n");\r
622 Status = EFI_OUT_OF_RESOURCES;\r
623 goto ERREXIT;\r
624 }\r
625\r
626 //\r
627 // Point the first list's last element to point to this second list.\r
628 //\r
629 TempBlockPtr->Union.ContinuationPointer = (UINTN) BlockDescriptors2;\r
630\r
631 TempBlockPtr->Length = 0;\r
632 TempBlockPtr = BlockDescriptors2;\r
633 for (Number = 0; Number < Count - 1; Number++) {\r
634 //\r
635 // If second-to-last one, then dump rest to this element\r
636 //\r
637 if (Number == (Count - 2)) {\r
638 Size = SizeLeft;\r
639 } else {\r
640 //\r
641 // Divide remaining data in half\r
642 //\r
643 if (SizeLeft == 1) {\r
644 Size = 1;\r
645 } else {\r
646 Size = SizeLeft / 2;\r
647 }\r
648 }\r
649\r
650 TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;\r
651 TempBlockPtr->Length = Size;\r
652 Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);\r
653 SizeLeft -= Size;\r
654 TempDataPtr += Size;\r
655 TempBlockPtr++;\r
656 if (SizeLeft == 0) {\r
657 break;\r
658 }\r
659 }\r
660 }\r
661\r
662 BlockDescriptorPre = TempBlockPtr;\r
663 BlockDescriptors1 = NULL;\r
664 }\r
665\r
666 //\r
667 // Null-terminate.\r
668 //\r
669 if (TempBlockPtr != NULL) {\r
670 TempBlockPtr->Union.ContinuationPointer = (UINTN)NULL;\r
671 TempBlockPtr->Length = 0;\r
672 *BlockDescriptors = BlockDescriptorsHeader;\r
673 }\r
674\r
675 return EFI_SUCCESS;\r
676\r
677ERREXIT:\r
678 if (BlockDescriptors1 != NULL) {\r
679 FreePool(BlockDescriptors1);\r
680 }\r
681\r
682 if (BlockDescriptors2 != NULL) {\r
683 FreePool(BlockDescriptors2);\r
684 }\r
685\r
686 return Status;\r
687}\r
688\r
689/**\r
690 Clear the Gather list for a list of capsule images.\r
691\r
692 @param[in] BlockDescriptors The block descriptors for the capsule images\r
693 @param[in] CapsuleNum The count of capsule images\r
694**/\r
695VOID\r
696CleanGatherList (\r
697 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors,\r
698 IN UINTN CapsuleNum\r
699 )\r
700{\r
701 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;\r
702 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr1;\r
703 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr2;\r
704 UINTN Index;\r
705\r
706 if (BlockDescriptors != NULL) {\r
707 TempBlockPtr1 = BlockDescriptors;\r
708 while (1){\r
709 TempBlockPtr = TempBlockPtr1;\r
710 for (Index = 0; Index < CapsuleNum; Index++) {\r
711 if (TempBlockPtr[Index].Length == 0) {\r
712 break;\r
713 }\r
714 }\r
715\r
716 if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) {\r
717 break;\r
718 }\r
719\r
845f7cfe 720 TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr[Index].Union.ContinuationPointer);\r
592bad04
JY
721 FreePool(TempBlockPtr1);\r
722 TempBlockPtr1 = TempBlockPtr2;\r
723 }\r
724 }\r
725}\r
726\r
d9c640b9
SZ
727/**\r
728 Validate if it is valid capsule header\r
729\r
730 This function assumes the caller provided correct CapsuleHeader pointer\r
731 and CapsuleSize.\r
732\r
733 This function validates the fields in EFI_CAPSULE_HEADER.\r
734\r
735 @param[in] CapsuleHeader Points to a capsule header.\r
736 @param[in] CapsuleSize Size of the whole capsule image.\r
737\r
738**/\r
739BOOLEAN\r
740IsValidCapsuleHeader (\r
741 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
742 IN UINT64 CapsuleSize\r
743 )\r
744{\r
745 if (CapsuleSize < sizeof (EFI_CAPSULE_HEADER)) {\r
746 return FALSE;\r
747 }\r
748 if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {\r
749 return FALSE;\r
750 }\r
751 if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) {\r
752 return FALSE;\r
753 }\r
754 if (CapsuleHeader->HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {\r
755 return FALSE;\r
756 }\r
757\r
758 return TRUE;\r
759}\r
760\r
592bad04
JY
761/**\r
762 Print APP usage.\r
763**/\r
764VOID\r
765PrintUsage (\r
766 VOID\r
767 )\r
768{\r
769 Print(L"CapsuleApp: usage\n");\r
7043a90e 770 Print(L" CapsuleApp <Capsule...> [-NR]\n");\r
592bad04
JY
771 Print(L" CapsuleApp -S\n");\r
772 Print(L" CapsuleApp -C\n");\r
773 Print(L" CapsuleApp -P\n");\r
774 Print(L" CapsuleApp -E\n");\r
775 Print(L" CapsuleApp -G <BMP> -O <Capsule>\n");\r
776 Print(L" CapsuleApp -N <Capsule> -O <NestedCapsule>\n");\r
777 Print(L" CapsuleApp -D <Capsule>\n");\r
1e09ec09 778 Print(L" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");\r
592bad04 779 Print(L"Parameter:\n");\r
16299ec8
SZ
780 Print(L" -NR: No reset will be triggered for the capsule with\n");\r
781 Print(L" CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without\n");\r
782 Print(L" CAPSULE_FLAGS_INITIATE_RESET.\n");\r
592bad04
JY
783 Print(L" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
784 Print(L" which is defined in UEFI specification.\n");\r
0c6f94da 785 Print(L" -C: Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
592bad04 786 Print(L" which is defined in UEFI specification.\n");\r
5410502f 787 Print(L" -P: Dump UEFI FMP protocol info, or get image with specified\n");\r
16299ec8
SZ
788 Print(L" ImageTypeId and Index (decimal format) to a file if 'GET'\n");\r
789 Print(L" option is used.\n");\r
592bad04 790 Print(L" -E: Dump UEFI ESRT table info.\n");\r
045bb323 791 Print(L" -G: Convert a BMP file to be an UX capsule,\n");\r
592bad04 792 Print(L" according to Windows Firmware Update document\n");\r
e70d9b8c
SZ
793 Print(L" -N: Append a Capsule Header to an existing FMP capsule image\n");\r
794 Print(L" with its ImageTypeId supported by the system,\n");\r
592bad04
JY
795 Print(L" according to Windows Firmware Update document\n");\r
796 Print(L" -O: Output new Capsule file name\n");\r
16299ec8
SZ
797 Print(L" -D: Dump Capsule image header information, image payload\n");\r
798 Print(L" information if it is an UX capsule and FMP header\n");\r
799 Print(L" information if it is a FMP capsule.\n");\r
592bad04
JY
800}\r
801\r
802/**\r
803 Update Capsule image.\r
804\r
805 @param[in] ImageHandle The image handle.\r
806 @param[in] SystemTable The system table.\r
807\r
808 @retval EFI_SUCCESS Command completed successfully.\r
10944bc3
SZ
809 @retval EFI_UNSUPPORTED Command usage unsupported.\r
810 @retval EFI_INVALID_PARAMETER Command usage invalid.\r
592bad04
JY
811 @retval EFI_NOT_FOUND The input file can't be found.\r
812**/\r
813EFI_STATUS\r
814EFIAPI\r
815UefiMain (\r
816 IN EFI_HANDLE ImageHandle,\r
817 IN EFI_SYSTEM_TABLE *SystemTable\r
818 )\r
819{\r
820 EFI_STATUS Status;\r
787f6744 821 RETURN_STATUS RStatus;\r
592bad04
JY
822 UINTN FileSize[MAX_CAPSULE_NUM];\r
823 VOID *CapsuleBuffer[MAX_CAPSULE_NUM];\r
824 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;\r
4436f722
SZ
825 EFI_CAPSULE_HEADER *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];\r
826 UINT64 MaxCapsuleSize;\r
827 EFI_RESET_TYPE ResetType;\r
828 BOOLEAN NeedReset;\r
829 BOOLEAN NoReset;\r
830 CHAR16 *CapsuleName;\r
831 UINTN CapsuleNum;\r
832 UINTN Index;\r
833 EFI_GUID ImageTypeId;\r
834 UINTN ImageIndex;\r
592bad04
JY
835\r
836 Status = GetArg();\r
837 if (EFI_ERROR(Status)) {\r
838 Print(L"Please use UEFI SHELL to run this application!\n", Status);\r
839 return Status;\r
840 }\r
841 if (Argc < 2) {\r
842 PrintUsage();\r
10944bc3 843 return EFI_UNSUPPORTED;\r
592bad04
JY
844 }\r
845 if (StrCmp(Argv[1], L"-D") == 0) {\r
10944bc3
SZ
846 if (Argc != 3) {\r
847 Print(L"CapsuleApp: Incorrect parameter count.\n");\r
848 return EFI_UNSUPPORTED;\r
1c6dd45b 849 }\r
592bad04
JY
850 Status = DumpCapsule(Argv[2]);\r
851 return Status;\r
852 }\r
853 if (StrCmp(Argv[1], L"-G") == 0) {\r
854 Status = CreateBmpFmp();\r
855 return Status;\r
856 }\r
857 if (StrCmp(Argv[1], L"-N") == 0) {\r
858 Status = CreateNestedFmp();\r
859 return Status;\r
860 }\r
861 if (StrCmp(Argv[1], L"-S") == 0) {\r
8b03c82d 862 Status = DumpCapsuleStatusVariable();\r
592bad04
JY
863 return EFI_SUCCESS;\r
864 }\r
865 if (StrCmp(Argv[1], L"-C") == 0) {\r
866 Status = ClearCapsuleStatusVariable();\r
867 return Status;\r
868 }\r
869 if (StrCmp(Argv[1], L"-P") == 0) {\r
1e09ec09
JY
870 if (Argc == 2) {\r
871 DumpFmpData();\r
872 }\r
873 if (Argc >= 3) {\r
5410502f
SZ
874 if (StrCmp(Argv[2], L"GET") != 0) {\r
875 Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[2]);\r
876 return EFI_UNSUPPORTED;\r
877 } else {\r
878 if (Argc != 7) {\r
879 Print(L"CapsuleApp: Incorrect parameter count.\n");\r
880 return EFI_UNSUPPORTED;\r
881 }\r
882\r
1e09ec09
JY
883 //\r
884 // FMP->GetImage()\r
885 //\r
787f6744
RN
886 RStatus = StrToGuid (Argv[3], &ImageTypeId);\r
887 if (RETURN_ERROR (RStatus) || (Argv[3][GUID_STRING_LENGTH] != L'\0')) {\r
1e09ec09 888 Print (L"Invalid ImageTypeId - %s\n", Argv[3]);\r
787f6744 889 return EFI_INVALID_PARAMETER;\r
1e09ec09
JY
890 }\r
891 ImageIndex = StrDecimalToUintn(Argv[4]);\r
5410502f
SZ
892 if (StrCmp(Argv[5], L"-O") != 0) {\r
893 Print(L"CapsuleApp: NO output file name.\n");\r
894 return EFI_UNSUPPORTED;\r
1e09ec09 895 }\r
5410502f 896 DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);\r
1e09ec09
JY
897 }\r
898 }\r
592bad04
JY
899 return EFI_SUCCESS;\r
900 }\r
95dd7a6e 901\r
592bad04
JY
902 if (StrCmp(Argv[1], L"-E") == 0) {\r
903 DumpEsrtData();\r
904 return EFI_SUCCESS;\r
905 }\r
95dd7a6e
SZ
906\r
907 if (Argv[1][0] == L'-') {\r
908 Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]);\r
909 return EFI_UNSUPPORTED;\r
910 }\r
911\r
592bad04 912 CapsuleFirstIndex = 1;\r
7043a90e
SZ
913 NoReset = FALSE;\r
914 if ((Argc > 1) && (StrCmp(Argv[Argc - 1], L"-NR") == 0)) {\r
915 NoReset = TRUE;\r
916 CapsuleLastIndex = Argc - 2;\r
917 } else {\r
918 CapsuleLastIndex = Argc - 1;\r
919 }\r
592bad04
JY
920 CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;\r
921\r
922 if (CapsuleFirstIndex > CapsuleLastIndex) {\r
923 Print(L"CapsuleApp: NO capsule image.\n");\r
924 return EFI_UNSUPPORTED;\r
925 }\r
926 if (CapsuleNum > MAX_CAPSULE_NUM) {\r
927 Print(L"CapsuleApp: Too many capsule images.\n");\r
928 return EFI_UNSUPPORTED;\r
929 }\r
930\r
931 ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));\r
932 ZeroMem(&FileSize, sizeof(FileSize));\r
933 BlockDescriptors = NULL;\r
934\r
935 for (Index = 0; Index < CapsuleNum; Index++) {\r
936 CapsuleName = Argv[CapsuleFirstIndex + Index];\r
937 Status = ReadFileToBuffer(CapsuleName, &FileSize[Index], &CapsuleBuffer[Index]);\r
938 if (EFI_ERROR(Status)) {\r
939 Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);\r
940 goto Done;\r
941 }\r
d9c640b9
SZ
942 if (!IsValidCapsuleHeader (CapsuleBuffer[Index], FileSize[Index])) {\r
943 Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);\r
944 return EFI_INVALID_PARAMETER;\r
945 }\r
592bad04
JY
946 }\r
947\r
948 //\r
949 // Every capsule use 2 descriptor 1 for data 1 for end\r
950 //\r
951 Status = BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, &BlockDescriptors);\r
952 if (EFI_ERROR(Status)) {\r
953 goto Done;\r
954 }\r
955\r
956 //\r
957 // Call the runtime service capsule.\r
958 //\r
959 NeedReset = FALSE;\r
960 for (Index = 0; Index < CapsuleNum; Index++) {\r
961 CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index];\r
962 if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
963 NeedReset = TRUE;\r
964 }\r
965 }\r
966 CapsuleHeaderArray[CapsuleNum] = NULL;\r
967\r
968 //\r
969 // Inquire platform capability of UpdateCapsule.\r
970 //\r
971 Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);\r
972 if (EFI_ERROR(Status)) {\r
973 Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);\r
974 goto Done;\r
975 }\r
976\r
977 for (Index = 0; Index < CapsuleNum; Index++) {\r
978 if (FileSize[Index] > MaxCapsuleSize) {\r
979 Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);\r
980 Status = EFI_UNSUPPORTED;\r
981 goto Done;\r
982 }\r
983 }\r
984\r
985 //\r
986 // Check whether the input capsule image has the flag of persist across system reset.\r
987 //\r
988 if (NeedReset) {\r
989 Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);\r
990 if (Status != EFI_SUCCESS) {\r
991 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
992 goto Done;\r
993 }\r
994 //\r
7043a90e
SZ
995 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,\r
996 // a system reset should have been triggered by gRT->UpdateCapsule() calling above.\r
997 //\r
998 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,\r
999 // check if -NR (no-reset) has been specified or not.\r
592bad04 1000 //\r
7043a90e
SZ
1001 if (!NoReset) {\r
1002 //\r
1003 // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,\r
1004 // trigger a system reset to process capsule persist across a system reset.\r
1005 //\r
1006 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
1007 }\r
592bad04
JY
1008 } else {\r
1009 //\r
1010 // For capsule who has no reset flag, only call UpdateCapsule Service without a\r
1011 // system reset. The service will process the capsule immediately.\r
1012 //\r
1013 Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);\r
1014 if (Status != EFI_SUCCESS) {\r
1015 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
1016 }\r
1017 }\r
1018\r
1019 Status = EFI_SUCCESS;\r
1020\r
1021Done:\r
1022 for (Index = 0; Index < CapsuleNum; Index++) {\r
1023 if (CapsuleBuffer[Index] != NULL) {\r
1024 FreePool (CapsuleBuffer[Index]);\r
1025 }\r
1026 }\r
1027\r
1028 CleanGatherList(BlockDescriptors, CapsuleNum);\r
1029\r
1030 return Status;\r
1031}\r