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