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