]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Application / CapsuleApp / CapsuleApp.c
... / ...
CommitLineData
1/** @file\r
2 A shell application that triggers capsule update process.\r
3\r
4 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include <Uefi.h>\r
10#include <Library/BaseLib.h>\r
11#include <Library/DebugLib.h>\r
12#include <Library/BaseMemoryLib.h>\r
13#include <Library/MemoryAllocationLib.h>\r
14#include <Library/UefiBootServicesTableLib.h>\r
15#include <Library/UefiRuntimeServicesTableLib.h>\r
16#include <Library/UefiLib.h>\r
17#include <Library/PrintLib.h>\r
18#include <Library/BmpSupportLib.h>\r
19#include <Protocol/GraphicsOutput.h>\r
20#include <Guid/GlobalVariable.h>\r
21#include <Guid/CapsuleReport.h>\r
22#include <Guid/SystemResourceTable.h>\r
23#include <Guid/FmpCapsule.h>\r
24#include <IndustryStandard/WindowsUxCapsule.h>\r
25\r
26#define CAPSULE_HEADER_SIZE 0x20\r
27\r
28#define NESTED_CAPSULE_HEADER_SIZE SIZE_4KB\r
29#define SYSTEM_FIRMWARE_FLAG 0x50000\r
30#define DEVICE_FIRMWARE_FLAG 0x78010\r
31\r
32#define MAJOR_VERSION 1\r
33#define MINOR_VERSION 0\r
34\r
35#define MAX_CAPSULE_NUM 10\r
36\r
37extern UINTN Argc;\r
38extern CHAR16 **Argv;\r
39\r
40//\r
41// Define how many block descriptors we want to test with.\r
42//\r
43UINTN NumberOfDescriptors = 1;\r
44UINTN CapsuleFirstIndex;\r
45UINTN CapsuleLastIndex;\r
46\r
47/**\r
48 Dump capsule information\r
49\r
50 @param[in] CapsuleName The name of the capsule image.\r
51\r
52 @retval EFI_SUCCESS The capsule information is dumped.\r
53 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
54**/\r
55EFI_STATUS\r
56DumpCapsule (\r
57 IN CHAR16 *CapsuleName\r
58 );\r
59\r
60/**\r
61 Dump capsule status variable.\r
62\r
63 @retval EFI_SUCCESS The capsule status variable is dumped.\r
64 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
65**/\r
66EFI_STATUS\r
67DumpCapsuleStatusVariable (\r
68 VOID\r
69 );\r
70\r
71/**\r
72 Dump FMP protocol info.\r
73**/\r
74VOID\r
75DumpFmpData (\r
76 VOID\r
77 );\r
78\r
79/**\r
80 Dump FMP image data.\r
81\r
82 @param[in] ImageTypeId The ImageTypeId of the FMP image.\r
83 It is used to identify the FMP protocol.\r
84 @param[in] ImageIndex The ImageIndex of the FMP image.\r
85 It is the input parameter for FMP->GetImage().\r
86 @param[in] ImageName The file name to hold the output FMP image.\r
87**/\r
88VOID\r
89DumpFmpImage (\r
90 IN EFI_GUID *ImageTypeId,\r
91 IN UINTN ImageIndex,\r
92 IN CHAR16 *ImageName\r
93 );\r
94\r
95/**\r
96 Dump ESRT info.\r
97**/\r
98VOID\r
99DumpEsrtData (\r
100 VOID\r
101 );\r
102\r
103/**\r
104 Dump Provisioned Capsule.\r
105\r
106 @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.\r
107**/\r
108VOID\r
109DumpProvisionedCapsule (\r
110 IN BOOLEAN DumpCapsuleInfo\r
111 );\r
112\r
113/**\r
114 Dump all EFI System Partition.\r
115**/\r
116VOID\r
117DumpAllEfiSysPartition (\r
118 VOID\r
119 );\r
120\r
121/**\r
122 Process Capsule On Disk.\r
123\r
124 @param[in] CapsuleBuffer An array of pointer to capsule images\r
125 @param[in] CapsuleBufferSize An array of UINTN to capsule images size\r
126 @param[in] FilePath An array of capsule images file path\r
127 @param[in] Map File system mapping string\r
128 @param[in] CapsuleNum The count of capsule images\r
129\r
130 @retval EFI_SUCCESS Capsule on disk success.\r
131 @retval others Capsule on disk fail.\r
132\r
133**/\r
134EFI_STATUS\r
135ProcessCapsuleOnDisk (\r
136 IN VOID **CapsuleBuffer,\r
137 IN UINTN *CapsuleBufferSize,\r
138 IN CHAR16 **FilePath,\r
139 IN CHAR16 *Map,\r
140 IN UINTN CapsuleNum\r
141 );\r
142\r
143/**\r
144 Read a file.\r
145\r
146 @param[in] FileName The file to be read.\r
147 @param[out] BufferSize The file buffer size\r
148 @param[out] Buffer The file buffer\r
149\r
150 @retval EFI_SUCCESS Read file successfully\r
151 @retval EFI_NOT_FOUND Shell protocol or file not found\r
152 @retval others Read file failed\r
153**/\r
154EFI_STATUS\r
155ReadFileToBuffer (\r
156 IN CHAR16 *FileName,\r
157 OUT UINTN *BufferSize,\r
158 OUT VOID **Buffer\r
159 );\r
160\r
161/**\r
162 Write a file.\r
163\r
164 @param[in] FileName The file to be written.\r
165 @param[in] BufferSize The file buffer size\r
166 @param[in] Buffer The file buffer\r
167\r
168 @retval EFI_SUCCESS Write file successfully\r
169 @retval EFI_NOT_FOUND Shell protocol not found\r
170 @retval others Write file failed\r
171**/\r
172EFI_STATUS\r
173WriteFileFromBuffer (\r
174 IN CHAR16 *FileName,\r
175 IN UINTN BufferSize,\r
176 IN VOID *Buffer\r
177 );\r
178\r
179/**\r
180\r
181 This function parse application ARG.\r
182\r
183 @return Status\r
184**/\r
185EFI_STATUS\r
186GetArg (\r
187 VOID\r
188 );\r
189\r
190/**\r
191 Create UX capsule.\r
192\r
193 @retval EFI_SUCCESS The capsule header is appended.\r
194 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
195 @retval EFI_OUT_OF_RESOURCES No enough resource to create UX capsule.\r
196**/\r
197EFI_STATUS\r
198CreateBmpFmp (\r
199 VOID\r
200 )\r
201{\r
202 CHAR16 *OutputCapsuleName;\r
203 VOID *BmpBuffer;\r
204 UINTN FileSize;\r
205 CHAR16 *BmpName;\r
206 UINT8 *FullCapsuleBuffer;\r
207 UINTN FullCapsuleBufferSize;\r
208 EFI_DISPLAY_CAPSULE *DisplayCapsule;\r
209 EFI_STATUS Status;\r
210 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;\r
211 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;\r
212 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GopBlt;\r
213 UINTN GopBltSize;\r
214 UINTN Height;\r
215 UINTN Width;\r
216\r
217 Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop);\r
218 if (EFI_ERROR(Status)) {\r
219 Print(L"CapsuleApp: NO GOP is found.\n");\r
220 return EFI_UNSUPPORTED;\r
221 }\r
222 Info = Gop->Mode->Info;\r
223 Print(L"Current GOP: Mode - %d, ", Gop->Mode->Mode);\r
224 Print(L"HorizontalResolution - %d, ", Info->HorizontalResolution);\r
225 Print(L"VerticalResolution - %d\n", Info->VerticalResolution);\r
226 // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth\r
227 // VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight\r
228\r
229 if (Argc != 5) {\r
230 Print(L"CapsuleApp: Incorrect parameter count.\n");\r
231 return EFI_UNSUPPORTED;\r
232 }\r
233\r
234 if (StrCmp(Argv[3], L"-O") != 0) {\r
235 Print(L"CapsuleApp: NO output capsule name.\n");\r
236 return EFI_UNSUPPORTED;\r
237 }\r
238 OutputCapsuleName = Argv[4];\r
239\r
240 BmpBuffer = NULL;\r
241 FileSize = 0;\r
242 FullCapsuleBuffer = NULL;\r
243\r
244 BmpName = Argv[2];\r
245 Status = ReadFileToBuffer(BmpName, &FileSize, &BmpBuffer);\r
246 if (EFI_ERROR(Status)) {\r
247 Print(L"CapsuleApp: BMP image (%s) is not found.\n", BmpName);\r
248 goto Done;\r
249 }\r
250\r
251 GopBlt = NULL;\r
252 Status = TranslateBmpToGopBlt (\r
253 BmpBuffer,\r
254 FileSize,\r
255 &GopBlt,\r
256 &GopBltSize,\r
257 &Height,\r
258 &Width\r
259 );\r
260 if (EFI_ERROR(Status)) {\r
261 Print(L"CapsuleApp: BMP image (%s) is not valid.\n", BmpName);\r
262 goto Done;\r
263 }\r
264 if (GopBlt != NULL) {\r
265 FreePool (GopBlt);\r
266 }\r
267 Print(L"BMP image (%s), Width - %d, Height - %d\n", BmpName, Width, Height);\r
268\r
269 if (Height > Info->VerticalResolution) {\r
270 Status = EFI_INVALID_PARAMETER;\r
271 Print(L"CapsuleApp: BMP image (%s) height is larger than current resolution.\n", BmpName);\r
272 goto Done;\r
273 }\r
274 if (Width > Info->HorizontalResolution) {\r
275 Status = EFI_INVALID_PARAMETER;\r
276 Print(L"CapsuleApp: BMP image (%s) width is larger than current resolution.\n", BmpName);\r
277 goto Done;\r
278 }\r
279\r
280 FullCapsuleBufferSize = sizeof(EFI_DISPLAY_CAPSULE) + FileSize;\r
281 FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);\r
282 if (FullCapsuleBuffer == NULL) {\r
283 Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);\r
284 Status = EFI_OUT_OF_RESOURCES;\r
285 goto Done;\r
286 }\r
287\r
288 DisplayCapsule = (EFI_DISPLAY_CAPSULE *)FullCapsuleBuffer;\r
289 CopyGuid(&DisplayCapsule->CapsuleHeader.CapsuleGuid, &gWindowsUxCapsuleGuid);\r
290 DisplayCapsule->CapsuleHeader.HeaderSize = sizeof(DisplayCapsule->CapsuleHeader);\r
291 DisplayCapsule->CapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;\r
292 DisplayCapsule->CapsuleHeader.CapsuleImageSize = (UINT32)FullCapsuleBufferSize;\r
293\r
294 DisplayCapsule->ImagePayload.Version = 1;\r
295 DisplayCapsule->ImagePayload.Checksum = 0;\r
296 DisplayCapsule->ImagePayload.ImageType = 0; // BMP\r
297 DisplayCapsule->ImagePayload.Reserved = 0;\r
298 DisplayCapsule->ImagePayload.Mode = Gop->Mode->Mode;\r
299\r
300 //\r
301 // Center the bitmap horizontally\r
302 //\r
303 DisplayCapsule->ImagePayload.OffsetX = (UINT32)((Info->HorizontalResolution - Width) / 2);\r
304\r
305 //\r
306 // Put bitmap 3/4 down the display. If bitmap is too tall, then align bottom\r
307 // of bitmap at bottom of display.\r
308 //\r
309 DisplayCapsule->ImagePayload.OffsetY =\r
310 MIN (\r
311 (UINT32)(Info->VerticalResolution - Height),\r
312 (UINT32)(((3 * Info->VerticalResolution) - (2 * Height)) / 4)\r
313 );\r
314\r
315 Print(L"BMP image (%s), OffsetX - %d, OffsetY - %d\n",\r
316 BmpName,\r
317 DisplayCapsule->ImagePayload.OffsetX,\r
318 DisplayCapsule->ImagePayload.OffsetY\r
319 );\r
320\r
321 CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize);\r
322\r
323 DisplayCapsule->ImagePayload.Checksum = CalculateCheckSum8(FullCapsuleBuffer, FullCapsuleBufferSize);\r
324\r
325 Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);\r
326 Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);\r
327\r
328Done:\r
329 if (BmpBuffer != NULL) {\r
330 FreePool(BmpBuffer);\r
331 }\r
332\r
333 if (FullCapsuleBuffer != NULL) {\r
334 FreePool(FullCapsuleBuffer);\r
335 }\r
336\r
337 return Status;\r
338}\r
339\r
340/**\r
341 Get ImageTypeId in the FMP capsule header.\r
342\r
343 @param[in] CapsuleHeader The FMP capsule image header.\r
344\r
345 @return ImageTypeId\r
346**/\r
347EFI_GUID *\r
348GetCapsuleImageTypeId (\r
349 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
350 )\r
351{\r
352 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
353 UINT64 *ItemOffsetList;\r
354 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
355\r
356 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
357 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
358 if (FmpCapsuleHeader->PayloadItemCount == 0) {\r
359 return NULL;\r
360 }\r
361 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[FmpCapsuleHeader->EmbeddedDriverCount]);\r
362 return &ImageHeader->UpdateImageTypeId;\r
363}\r
364\r
365/**\r
366 Get ESRT FwType according to ImageTypeId\r
367\r
368 @param[in] ImageTypeId ImageTypeId of an FMP capsule.\r
369\r
370 @return ESRT FwType\r
371**/\r
372UINT32\r
373GetEsrtFwType (\r
374 IN EFI_GUID *ImageTypeId\r
375 )\r
376{\r
377 EFI_STATUS Status;\r
378 EFI_SYSTEM_RESOURCE_TABLE *Esrt;\r
379 EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;\r
380 UINTN Index;\r
381\r
382 //\r
383 // Check ESRT\r
384 //\r
385 Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);\r
386 if (!EFI_ERROR(Status)) {\r
387 ASSERT(Esrt != NULL);\r
388 EsrtEntry = (VOID *)(Esrt + 1);\r
389 for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {\r
390 if (CompareGuid(&EsrtEntry->FwClass, ImageTypeId)) {\r
391 return EsrtEntry->FwType;\r
392 }\r
393 }\r
394 }\r
395\r
396 return ESRT_FW_TYPE_UNKNOWN;\r
397}\r
398\r
399/**\r
400 Validate if it is valid capsule header\r
401\r
402 This function assumes the caller provided correct CapsuleHeader pointer\r
403 and CapsuleSize.\r
404\r
405 This function validates the fields in EFI_CAPSULE_HEADER.\r
406\r
407 @param[in] CapsuleHeader Points to a capsule header.\r
408 @param[in] CapsuleSize Size of the whole capsule image.\r
409\r
410**/\r
411BOOLEAN\r
412IsValidCapsuleHeader (\r
413 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
414 IN UINT64 CapsuleSize\r
415 )\r
416{\r
417 if (CapsuleSize < sizeof (EFI_CAPSULE_HEADER)) {\r
418 return FALSE;\r
419 }\r
420 if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {\r
421 return FALSE;\r
422 }\r
423 if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) {\r
424 return FALSE;\r
425 }\r
426 if (CapsuleHeader->HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {\r
427 return FALSE;\r
428 }\r
429\r
430 return TRUE;\r
431}\r
432\r
433/**\r
434 Return if this CapsuleGuid is a FMP capsule GUID or not.\r
435\r
436 @param[in] CapsuleGuid A pointer to EFI_GUID\r
437\r
438 @retval TRUE It is a FMP capsule GUID.\r
439 @retval FALSE It is not a FMP capsule GUID.\r
440**/\r
441BOOLEAN\r
442IsFmpCapsuleGuid (\r
443 IN EFI_GUID *CapsuleGuid\r
444 )\r
445{\r
446 if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) {\r
447 return TRUE;\r
448 }\r
449\r
450 return FALSE;\r
451}\r
452\r
453/**\r
454 Append a capsule header on top of current image.\r
455 This function follows Windows UEFI Firmware Update Platform document.\r
456\r
457 @retval EFI_SUCCESS The capsule header is appended.\r
458 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
459 @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header.\r
460**/\r
461EFI_STATUS\r
462CreateNestedFmp (\r
463 VOID\r
464 )\r
465{\r
466 CHAR16 *OutputCapsuleName;\r
467 VOID *CapsuleBuffer;\r
468 UINTN FileSize;\r
469 CHAR16 *CapsuleName;\r
470 UINT8 *FullCapsuleBuffer;\r
471 UINTN FullCapsuleBufferSize;\r
472 EFI_CAPSULE_HEADER *NestedCapsuleHeader;\r
473 EFI_GUID *ImageTypeId;\r
474 UINT32 FwType;\r
475 EFI_STATUS Status;\r
476\r
477 if (Argc != 5) {\r
478 Print(L"CapsuleApp: Incorrect parameter count.\n");\r
479 return EFI_UNSUPPORTED;\r
480 }\r
481\r
482 if (StrCmp(Argv[3], L"-O") != 0) {\r
483 Print(L"CapsuleApp: NO output capsule name.\n");\r
484 return EFI_UNSUPPORTED;\r
485 }\r
486 OutputCapsuleName = Argv[4];\r
487\r
488 CapsuleBuffer = NULL;\r
489 FileSize = 0;\r
490 FullCapsuleBuffer = NULL;\r
491\r
492 CapsuleName = Argv[2];\r
493 Status = ReadFileToBuffer(CapsuleName, &FileSize, &CapsuleBuffer);\r
494 if (EFI_ERROR(Status)) {\r
495 Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName);\r
496 goto Done;\r
497 }\r
498 if (!IsValidCapsuleHeader (CapsuleBuffer, FileSize)) {\r
499 Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);\r
500 Status = EFI_INVALID_PARAMETER;\r
501 goto Done;\r
502 }\r
503\r
504 if (!IsFmpCapsuleGuid (&((EFI_CAPSULE_HEADER *) CapsuleBuffer)->CapsuleGuid)) {\r
505 Print(L"CapsuleApp: Capsule image (%s) is not a FMP capsule.\n", CapsuleName);\r
506 Status = EFI_INVALID_PARAMETER;\r
507 goto Done;\r
508 }\r
509\r
510 ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer);\r
511 if (ImageTypeId == NULL) {\r
512 Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n");\r
513 Status = EFI_INVALID_PARAMETER;\r
514 goto Done;\r
515 }\r
516 FwType = GetEsrtFwType(ImageTypeId);\r
517 if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != ESRT_FW_TYPE_DEVICEFIRMWARE)) {\r
518 Print(L"CapsuleApp: Capsule FwType is invalid.\n");\r
519 Status = EFI_INVALID_PARAMETER;\r
520 goto Done;\r
521 }\r
522\r
523 FullCapsuleBufferSize = NESTED_CAPSULE_HEADER_SIZE + FileSize;\r
524 FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);\r
525 if (FullCapsuleBuffer == NULL) {\r
526 Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);\r
527 Status = EFI_OUT_OF_RESOURCES;\r
528 goto Done;\r
529 }\r
530\r
531 NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)FullCapsuleBuffer;\r
532 ZeroMem(NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE);\r
533 CopyGuid(&NestedCapsuleHeader->CapsuleGuid, ImageTypeId);\r
534 NestedCapsuleHeader->HeaderSize = NESTED_CAPSULE_HEADER_SIZE;\r
535 NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_SYSTEMFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;\r
536 NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize;\r
537\r
538 CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize);\r
539\r
540 Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);\r
541 Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);\r
542\r
543Done:\r
544 if (CapsuleBuffer != NULL) {\r
545 FreePool(CapsuleBuffer);\r
546 }\r
547\r
548 if (FullCapsuleBuffer != NULL) {\r
549 FreePool(FullCapsuleBuffer);\r
550 }\r
551\r
552 return Status;\r
553}\r
554\r
555\r
556/**\r
557 Clear capsule status variable.\r
558\r
559 @retval EFI_SUCCESS The capsule status variable is cleared.\r
560**/\r
561EFI_STATUS\r
562ClearCapsuleStatusVariable (\r
563 VOID\r
564 )\r
565{\r
566 EFI_STATUS Status;\r
567 UINT32 Index;\r
568 CHAR16 CapsuleVarName[20];\r
569 CHAR16 *TempVarName;\r
570 BOOLEAN Found;\r
571\r
572 StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");\r
573 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
574 Index = 0;\r
575\r
576 Found = FALSE;\r
577 while (TRUE) {\r
578 UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);\r
579\r
580 Status = gRT->SetVariable (\r
581 CapsuleVarName,\r
582 &gEfiCapsuleReportGuid,\r
583 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
584 0,\r
585 (VOID *)NULL\r
586 );\r
587 if (Status == EFI_NOT_FOUND) {\r
588 //\r
589 // There is no more capsule variables, quit\r
590 //\r
591 break;\r
592 }\r
593 Found = TRUE;\r
594\r
595 Print (L"Clear %s %r\n", CapsuleVarName, Status);\r
596\r
597 Index++;\r
598 if (Index > 0xFFFF) {\r
599 break;\r
600 }\r
601 }\r
602\r
603 if (!Found) {\r
604 Print (L"No any Capsule#### variable found\n");\r
605 }\r
606\r
607 return EFI_SUCCESS;\r
608}\r
609\r
610/**\r
611 Build Gather list for a list of capsule images.\r
612\r
613 @param[in] CapsuleBuffer An array of pointer to capsule images\r
614 @param[in] FileSize An array of UINTN to capsule images size\r
615 @param[in] CapsuleNum The count of capsule images\r
616 @param[out] BlockDescriptors The block descriptors for the capsule images\r
617\r
618 @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.\r
619**/\r
620EFI_STATUS\r
621BuildGatherList (\r
622 IN VOID **CapsuleBuffer,\r
623 IN UINTN *FileSize,\r
624 IN UINTN CapsuleNum,\r
625 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors\r
626 )\r
627{\r
628 EFI_STATUS Status;\r
629 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;\r
630 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors2;\r
631 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;\r
632 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;\r
633 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;\r
634 UINT8 *TempDataPtr;\r
635 UINTN SizeLeft;\r
636 UINTN Size;\r
637 INT32 Count;\r
638 INT32 Number;\r
639 UINTN Index;\r
640\r
641 TempBlockPtr = NULL;\r
642 BlockDescriptors1 = NULL;\r
643 BlockDescriptors2 = NULL;\r
644 BlockDescriptorPre = NULL;\r
645 BlockDescriptorsHeader = NULL;\r
646\r
647 for (Index = 0; Index < CapsuleNum; Index++) {\r
648 //\r
649 // Allocate memory for the descriptors.\r
650 //\r
651 if (NumberOfDescriptors == 1) {\r
652 Count = 2;\r
653 } else {\r
654 Count = (INT32)(NumberOfDescriptors + 2) / 2;\r
655 }\r
656\r
657 Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
658 BlockDescriptors1 = AllocateRuntimeZeroPool (Size);\r
659 if (BlockDescriptors1 == NULL) {\r
660 Print (L"CapsuleApp: failed to allocate memory for descriptors\n");\r
661 Status = EFI_OUT_OF_RESOURCES;\r
662 goto ERREXIT;\r
663 } else {\r
664 Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1);\r
665 Print (L"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer[Index], FileSize[Index]);\r
666 }\r
667\r
668 //\r
669 // Record descirptor header\r
670 //\r
671 if (Index == 0) {\r
672 BlockDescriptorsHeader = BlockDescriptors1;\r
673 }\r
674\r
675 if (BlockDescriptorPre != NULL) {\r
676 BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1;\r
677 BlockDescriptorPre->Length = 0;\r
678 }\r
679\r
680 //\r
681 // Fill them in\r
682 //\r
683 TempBlockPtr = BlockDescriptors1;\r
684 TempDataPtr = CapsuleBuffer[Index];\r
685 SizeLeft = FileSize[Index];\r
686 for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) {\r
687 //\r
688 // Divide remaining data in half\r
689 //\r
690 if (NumberOfDescriptors != 1) {\r
691 if (SizeLeft == 1) {\r
692 Size = 1;\r
693 } else {\r
694 Size = SizeLeft / 2;\r
695 }\r
696 } else {\r
697 Size = SizeLeft;\r
698 }\r
699 TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;\r
700 TempBlockPtr->Length = Size;\r
701 Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);\r
702 SizeLeft -= Size;\r
703 TempDataPtr += Size;\r
704 TempBlockPtr++;\r
705 }\r
706\r
707 //\r
708 // Allocate the second list, point the first block's last entry to point\r
709 // to this one, and fill this one in. Worst case is that the previous\r
710 // list only had one element that pointed here, so we need at least two\r
711 // elements -- one to point to all the data, another to terminate the list.\r
712 //\r
713 if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) {\r
714 Count = (INT32)(NumberOfDescriptors + 2) - Count;\r
715 if (Count == 1) {\r
716 Count++;\r
717 }\r
718\r
719 Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
720 BlockDescriptors2 = AllocateRuntimeZeroPool (Size);\r
721 if (BlockDescriptors2 == NULL) {\r
722 Print (L"CapsuleApp: failed to allocate memory for descriptors\n");\r
723 Status = EFI_OUT_OF_RESOURCES;\r
724 goto ERREXIT;\r
725 }\r
726\r
727 //\r
728 // Point the first list's last element to point to this second list.\r
729 //\r
730 TempBlockPtr->Union.ContinuationPointer = (UINTN) BlockDescriptors2;\r
731\r
732 TempBlockPtr->Length = 0;\r
733 TempBlockPtr = BlockDescriptors2;\r
734 for (Number = 0; Number < Count - 1; Number++) {\r
735 //\r
736 // If second-to-last one, then dump rest to this element\r
737 //\r
738 if (Number == (Count - 2)) {\r
739 Size = SizeLeft;\r
740 } else {\r
741 //\r
742 // Divide remaining data in half\r
743 //\r
744 if (SizeLeft == 1) {\r
745 Size = 1;\r
746 } else {\r
747 Size = SizeLeft / 2;\r
748 }\r
749 }\r
750\r
751 TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;\r
752 TempBlockPtr->Length = Size;\r
753 Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);\r
754 SizeLeft -= Size;\r
755 TempDataPtr += Size;\r
756 TempBlockPtr++;\r
757 if (SizeLeft == 0) {\r
758 break;\r
759 }\r
760 }\r
761 }\r
762\r
763 BlockDescriptorPre = TempBlockPtr;\r
764 BlockDescriptors1 = NULL;\r
765 }\r
766\r
767 //\r
768 // Null-terminate.\r
769 //\r
770 if (TempBlockPtr != NULL) {\r
771 TempBlockPtr->Union.ContinuationPointer = (UINTN)NULL;\r
772 TempBlockPtr->Length = 0;\r
773 *BlockDescriptors = BlockDescriptorsHeader;\r
774 }\r
775\r
776 return EFI_SUCCESS;\r
777\r
778ERREXIT:\r
779 if (BlockDescriptors1 != NULL) {\r
780 FreePool(BlockDescriptors1);\r
781 }\r
782\r
783 if (BlockDescriptors2 != NULL) {\r
784 FreePool(BlockDescriptors2);\r
785 }\r
786\r
787 return Status;\r
788}\r
789\r
790/**\r
791 Clear the Gather list for a list of capsule images.\r
792\r
793 @param[in] BlockDescriptors The block descriptors for the capsule images\r
794 @param[in] CapsuleNum The count of capsule images\r
795**/\r
796VOID\r
797CleanGatherList (\r
798 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors,\r
799 IN UINTN CapsuleNum\r
800 )\r
801{\r
802 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;\r
803 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr1;\r
804 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr2;\r
805 UINTN Index;\r
806\r
807 if (BlockDescriptors != NULL) {\r
808 TempBlockPtr1 = BlockDescriptors;\r
809 while (1){\r
810 TempBlockPtr = TempBlockPtr1;\r
811 for (Index = 0; Index < CapsuleNum; Index++) {\r
812 if (TempBlockPtr[Index].Length == 0) {\r
813 break;\r
814 }\r
815 }\r
816\r
817 if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) {\r
818 break;\r
819 }\r
820\r
821 TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr[Index].Union.ContinuationPointer);\r
822 FreePool(TempBlockPtr1);\r
823 TempBlockPtr1 = TempBlockPtr2;\r
824 }\r
825 }\r
826}\r
827\r
828/**\r
829 Print APP usage.\r
830**/\r
831VOID\r
832PrintUsage (\r
833 VOID\r
834 )\r
835{\r
836 Print(L"CapsuleApp: usage\n");\r
837 Print(L" CapsuleApp <Capsule...> [-NR] [-OD [FSx]]\n");\r
838 Print(L" CapsuleApp -S\n");\r
839 Print(L" CapsuleApp -C\n");\r
840 Print(L" CapsuleApp -P\n");\r
841 Print(L" CapsuleApp -E\n");\r
842 Print(L" CapsuleApp -L\n");\r
843 Print(L" CapsuleApp -L INFO\n");\r
844 Print(L" CapsuleApp -F\n");\r
845 Print(L" CapsuleApp -G <BMP> -O <Capsule>\n");\r
846 Print(L" CapsuleApp -N <Capsule> -O <NestedCapsule>\n");\r
847 Print(L" CapsuleApp -D <Capsule>\n");\r
848 Print(L" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");\r
849 Print(L"Parameter:\n");\r
850 Print(L" -NR: No reset will be triggered for the capsule\n");\r
851 Print(L" with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET.\n");\r
852 Print(L" -OD: Delivery of Capsules via file on Mass Storage device.");\r
853 Print(L" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
854 Print(L" which is defined in UEFI specification.\n");\r
855 Print(L" -C: Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
856 Print(L" which is defined in UEFI specification.\n");\r
857 Print(L" -P: Dump UEFI FMP protocol info, or get image with specified\n");\r
858 Print(L" ImageTypeId and Index (decimal format) to a file if 'GET'\n");\r
859 Print(L" option is used.\n");\r
860 Print(L" -E: Dump UEFI ESRT table info.\n");\r
861 Print(L" -L: Dump provisioned capsule image information.\n");\r
862 Print(L" -F: Dump all EFI System Partition.\n");\r
863 Print(L" -G: Convert a BMP file to be an UX capsule,\n");\r
864 Print(L" according to Windows Firmware Update document\n");\r
865 Print(L" -N: Append a Capsule Header to an existing FMP capsule image\n");\r
866 Print(L" with its ImageTypeId supported by the system,\n");\r
867 Print(L" according to Windows Firmware Update document\n");\r
868 Print(L" -O: Output new Capsule file name\n");\r
869 Print(L" -D: Dump Capsule image header information, image payload\n");\r
870 Print(L" information if it is an UX capsule and FMP header\n");\r
871 Print(L" information if it is a FMP capsule.\n");\r
872}\r
873\r
874/**\r
875 Update Capsule image.\r
876\r
877 @param[in] ImageHandle The image handle.\r
878 @param[in] SystemTable The system table.\r
879\r
880 @retval EFI_SUCCESS Command completed successfully.\r
881 @retval EFI_UNSUPPORTED Command usage unsupported.\r
882 @retval EFI_INVALID_PARAMETER Command usage invalid.\r
883 @retval EFI_NOT_FOUND The input file can't be found.\r
884**/\r
885EFI_STATUS\r
886EFIAPI\r
887UefiMain (\r
888 IN EFI_HANDLE ImageHandle,\r
889 IN EFI_SYSTEM_TABLE *SystemTable\r
890 )\r
891{\r
892 EFI_STATUS Status;\r
893 RETURN_STATUS RStatus;\r
894 UINTN CapsuleBufferSize[MAX_CAPSULE_NUM];\r
895 VOID *CapsuleBuffer[MAX_CAPSULE_NUM];\r
896 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;\r
897 EFI_CAPSULE_HEADER *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];\r
898 UINT64 MaxCapsuleSize;\r
899 EFI_RESET_TYPE ResetType;\r
900 BOOLEAN NeedReset;\r
901 BOOLEAN NoReset;\r
902 BOOLEAN CapsuleOnDisk;\r
903 CHAR16 *CapsuleName;\r
904 CHAR16 *CapsuleNames[MAX_CAPSULE_NUM];\r
905 CHAR16 *MapFsStr;\r
906 UINTN CapsuleNum;\r
907 UINTN Index;\r
908 UINTN ParaOdIndex;\r
909 UINTN ParaNrIndex;\r
910 EFI_GUID ImageTypeId;\r
911 UINTN ImageIndex;\r
912\r
913 BlockDescriptors = NULL;\r
914 MapFsStr = NULL;\r
915 CapsuleNum = 0;\r
916\r
917 Status = GetArg();\r
918 if (EFI_ERROR(Status)) {\r
919 Print(L"Please use UEFI SHELL to run this application!\n", Status);\r
920 return Status;\r
921 }\r
922 if (Argc < 2) {\r
923 PrintUsage();\r
924 return EFI_UNSUPPORTED;\r
925 }\r
926 if (StrCmp(Argv[1], L"-D") == 0) {\r
927 if (Argc != 3) {\r
928 Print(L"CapsuleApp: Incorrect parameter count.\n");\r
929 return EFI_UNSUPPORTED;\r
930 }\r
931 Status = DumpCapsule(Argv[2]);\r
932 return Status;\r
933 }\r
934 if (StrCmp(Argv[1], L"-G") == 0) {\r
935 Status = CreateBmpFmp();\r
936 return Status;\r
937 }\r
938 if (StrCmp(Argv[1], L"-N") == 0) {\r
939 Status = CreateNestedFmp();\r
940 return Status;\r
941 }\r
942 if (StrCmp(Argv[1], L"-S") == 0) {\r
943 Status = DumpCapsuleStatusVariable();\r
944 return EFI_SUCCESS;\r
945 }\r
946 if (StrCmp(Argv[1], L"-C") == 0) {\r
947 Status = ClearCapsuleStatusVariable();\r
948 return Status;\r
949 }\r
950 if (StrCmp(Argv[1], L"-P") == 0) {\r
951 if (Argc == 2) {\r
952 DumpFmpData();\r
953 }\r
954 if (Argc >= 3) {\r
955 if (StrCmp(Argv[2], L"GET") != 0) {\r
956 Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[2]);\r
957 return EFI_UNSUPPORTED;\r
958 } else {\r
959 if (Argc != 7) {\r
960 Print(L"CapsuleApp: Incorrect parameter count.\n");\r
961 return EFI_UNSUPPORTED;\r
962 }\r
963\r
964 //\r
965 // FMP->GetImage()\r
966 //\r
967 RStatus = StrToGuid (Argv[3], &ImageTypeId);\r
968 if (RETURN_ERROR (RStatus) || (Argv[3][GUID_STRING_LENGTH] != L'\0')) {\r
969 Print (L"Invalid ImageTypeId - %s\n", Argv[3]);\r
970 return EFI_INVALID_PARAMETER;\r
971 }\r
972 ImageIndex = StrDecimalToUintn(Argv[4]);\r
973 if (StrCmp(Argv[5], L"-O") != 0) {\r
974 Print(L"CapsuleApp: NO output file name.\n");\r
975 return EFI_UNSUPPORTED;\r
976 }\r
977 DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);\r
978 }\r
979 }\r
980 return EFI_SUCCESS;\r
981 }\r
982\r
983 if (StrCmp(Argv[1], L"-E") == 0) {\r
984 DumpEsrtData();\r
985 return EFI_SUCCESS;\r
986 }\r
987\r
988 if (StrCmp(Argv[1], L"-L") == 0) {\r
989 if (Argc >= 3 && StrCmp(Argv[2], L"INFO") == 0) {\r
990 DumpProvisionedCapsule(TRUE);\r
991 } else {\r
992 DumpProvisionedCapsule(FALSE);\r
993 }\r
994 return EFI_SUCCESS;\r
995 }\r
996\r
997 if (StrCmp(Argv[1], L"-F") == 0) {\r
998 DumpAllEfiSysPartition();\r
999 return EFI_SUCCESS;\r
1000 }\r
1001\r
1002 if (Argv[1][0] == L'-') {\r
1003 Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]);\r
1004 return EFI_UNSUPPORTED;\r
1005 }\r
1006\r
1007 CapsuleFirstIndex = 1;\r
1008 NoReset = FALSE;\r
1009 CapsuleOnDisk = FALSE;\r
1010 ParaOdIndex = 0;\r
1011 ParaNrIndex = 0;\r
1012\r
1013 for (Index = 1; Index < Argc; Index++) {\r
1014 if (StrCmp(Argv[Index], L"-OD") == 0) {\r
1015 ParaOdIndex = Index;\r
1016 CapsuleOnDisk = TRUE;\r
1017 } else if (StrCmp(Argv[Index], L"-NR") == 0) {\r
1018 ParaNrIndex = Index;\r
1019 NoReset = TRUE;\r
1020 }\r
1021 }\r
1022\r
1023 if (ParaOdIndex != 0) {\r
1024 if (ParaOdIndex == Argc - 1) {\r
1025 MapFsStr = NULL;\r
1026 } else if (ParaOdIndex == Argc - 2) {\r
1027 MapFsStr = Argv[Argc-1];\r
1028 } else {\r
1029 Print (L"CapsuleApp: Invalid Position for -OD Options\n");\r
1030 Status = EFI_INVALID_PARAMETER;\r
1031 goto Done;\r
1032 }\r
1033\r
1034 if (ParaNrIndex != 0) {\r
1035 if (ParaNrIndex + 1 == ParaOdIndex) {\r
1036 CapsuleLastIndex = ParaNrIndex - 1;\r
1037 } else {\r
1038 Print (L"CapsuleApp: Invalid Position for -NR Options\n");\r
1039 Status = EFI_INVALID_PARAMETER;\r
1040 goto Done;\r
1041 }\r
1042 } else {\r
1043 CapsuleLastIndex = ParaOdIndex - 1;\r
1044 }\r
1045 } else {\r
1046 if (ParaNrIndex != 0) {\r
1047 if (ParaNrIndex == Argc -1) {\r
1048 CapsuleLastIndex = ParaNrIndex - 1;\r
1049 } else {\r
1050 Print (L"CapsuleApp: Invalid Position for -NR Options\n");\r
1051 Status = EFI_INVALID_PARAMETER;\r
1052 goto Done;\r
1053 }\r
1054 } else {\r
1055 CapsuleLastIndex = Argc - 1;\r
1056 }\r
1057 }\r
1058\r
1059 CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;\r
1060\r
1061 if (CapsuleFirstIndex > CapsuleLastIndex) {\r
1062 Print(L"CapsuleApp: NO capsule image.\n");\r
1063 return EFI_UNSUPPORTED;\r
1064 }\r
1065 if (CapsuleNum > MAX_CAPSULE_NUM) {\r
1066 Print(L"CapsuleApp: Too many capsule images.\n");\r
1067 return EFI_UNSUPPORTED;\r
1068 }\r
1069\r
1070 ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));\r
1071 ZeroMem(&CapsuleBufferSize, sizeof(CapsuleBufferSize));\r
1072 BlockDescriptors = NULL;\r
1073\r
1074 for (Index = 0; Index < CapsuleNum; Index++) {\r
1075 CapsuleName = Argv[CapsuleFirstIndex + Index];\r
1076 Status = ReadFileToBuffer(CapsuleName, &CapsuleBufferSize[Index], &CapsuleBuffer[Index]);\r
1077 if (EFI_ERROR(Status)) {\r
1078 Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);\r
1079 goto Done;\r
1080 }\r
1081 if (!IsValidCapsuleHeader (CapsuleBuffer[Index], CapsuleBufferSize[Index])) {\r
1082 Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);\r
1083 return EFI_INVALID_PARAMETER;\r
1084 }\r
1085 CapsuleNames[Index] = CapsuleName;\r
1086 }\r
1087\r
1088 //\r
1089 // Every capsule use 2 descriptor 1 for data 1 for end\r
1090 //\r
1091 Status = BuildGatherList(CapsuleBuffer, CapsuleBufferSize, CapsuleNum, &BlockDescriptors);\r
1092 if (EFI_ERROR(Status)) {\r
1093 goto Done;\r
1094 }\r
1095\r
1096 //\r
1097 // Call the runtime service capsule.\r
1098 //\r
1099 NeedReset = FALSE;\r
1100 for (Index = 0; Index < CapsuleNum; Index++) {\r
1101 CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index];\r
1102 if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
1103 NeedReset = TRUE;\r
1104 }\r
1105 }\r
1106 CapsuleHeaderArray[CapsuleNum] = NULL;\r
1107\r
1108 //\r
1109 // Inquire platform capability of UpdateCapsule.\r
1110 //\r
1111 Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);\r
1112 if (EFI_ERROR(Status)) {\r
1113 Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);\r
1114 goto Done;\r
1115 }\r
1116\r
1117 for (Index = 0; Index < CapsuleNum; Index++) {\r
1118 if (CapsuleBufferSize[Index] > MaxCapsuleSize) {\r
1119 Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);\r
1120 Status = EFI_UNSUPPORTED;\r
1121 goto Done;\r
1122 }\r
1123 }\r
1124\r
1125 //\r
1126 // Check whether is capsule on disk.\r
1127 //\r
1128 if (CapsuleOnDisk) {\r
1129 Status = ProcessCapsuleOnDisk (CapsuleBuffer, CapsuleBufferSize, CapsuleNames, MapFsStr, CapsuleNum);\r
1130 if (Status != EFI_SUCCESS) {\r
1131 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
1132 goto Done;\r
1133 } else {\r
1134 if (!NoReset) {\r
1135 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
1136 } else {\r
1137 goto Done;\r
1138 }\r
1139 }\r
1140 }\r
1141\r
1142 //\r
1143 // Check whether the input capsule image has the flag of persist across system reset.\r
1144 //\r
1145 if (NeedReset) {\r
1146 Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);\r
1147 if (Status != EFI_SUCCESS) {\r
1148 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
1149 goto Done;\r
1150 }\r
1151 //\r
1152 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,\r
1153 // a system reset should have been triggered by gRT->UpdateCapsule() calling above.\r
1154 //\r
1155 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,\r
1156 // check if -NR (no-reset) has been specified or not.\r
1157 //\r
1158 if (!NoReset) {\r
1159 //\r
1160 // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,\r
1161 // trigger a system reset to process capsule persist across a system reset.\r
1162 //\r
1163 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
1164 }\r
1165 } else {\r
1166 //\r
1167 // For capsule who has no reset flag, only call UpdateCapsule Service without a\r
1168 // system reset. The service will process the capsule immediately.\r
1169 //\r
1170 Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);\r
1171 if (Status != EFI_SUCCESS) {\r
1172 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
1173 }\r
1174 }\r
1175\r
1176 Status = EFI_SUCCESS;\r
1177\r
1178Done:\r
1179 for (Index = 0; Index < CapsuleNum; Index++) {\r
1180 if (CapsuleBuffer[Index] != NULL) {\r
1181 FreePool (CapsuleBuffer[Index]);\r
1182 }\r
1183 }\r
1184\r
1185 CleanGatherList(BlockDescriptors, CapsuleNum);\r
1186\r
1187 return Status;\r
1188}\r