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