]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
MdeModulePkg/CapsuleApp: Enhance CapsuleApp to support Capsule-on-Disk
[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
592bad04
JY
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <Uefi.h>\r
16#include <Library/BaseLib.h>\r
17#include <Library/DebugLib.h>\r
18#include <Library/BaseMemoryLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/UefiBootServicesTableLib.h>\r
21#include <Library/UefiRuntimeServicesTableLib.h>\r
22#include <Library/UefiLib.h>\r
23#include <Library/PrintLib.h>\r
bf9b044e 24#include <Library/BmpSupportLib.h>\r
592bad04 25#include <Protocol/GraphicsOutput.h>\r
97473291 26#include <Guid/GlobalVariable.h>\r
592bad04
JY
27#include <Guid/CapsuleReport.h>\r
28#include <Guid/SystemResourceTable.h>\r
29#include <Guid/FmpCapsule.h>\r
30#include <IndustryStandard/WindowsUxCapsule.h>\r
31\r
32#define CAPSULE_HEADER_SIZE 0x20\r
33\r
34#define NESTED_CAPSULE_HEADER_SIZE SIZE_4KB\r
35#define SYSTEM_FIRMWARE_FLAG 0x50000\r
36#define DEVICE_FIRMWARE_FLAG 0x78010\r
37\r
592bad04
JY
38#define MAJOR_VERSION 1\r
39#define MINOR_VERSION 0\r
40\r
41#define MAX_CAPSULE_NUM 10\r
42\r
43extern UINTN Argc;\r
44extern CHAR16 **Argv;\r
45\r
46//\r
47// Define how many block descriptors we want to test with.\r
48//\r
49UINTN NumberOfDescriptors = 1;\r
50UINTN CapsuleFirstIndex;\r
51UINTN CapsuleLastIndex;\r
52\r
53/**\r
54 Dump capsule information\r
55\r
56 @param[in] CapsuleName The name of the capsule image.\r
57\r
58 @retval EFI_SUCCESS The capsule information is dumped.\r
59 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
60**/\r
61EFI_STATUS\r
62DumpCapsule (\r
63 IN CHAR16 *CapsuleName\r
64 );\r
65\r
66/**\r
67 Dump capsule status variable.\r
68\r
69 @retval EFI_SUCCESS The capsule status variable is dumped.\r
70 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
71**/\r
72EFI_STATUS\r
8b03c82d 73DumpCapsuleStatusVariable (\r
592bad04
JY
74 VOID\r
75 );\r
76\r
77/**\r
78 Dump FMP protocol info.\r
79**/\r
80VOID\r
81DumpFmpData (\r
82 VOID\r
83 );\r
84\r
1e09ec09
JY
85/**\r
86 Dump FMP image data.\r
87\r
88 @param[in] ImageTypeId The ImageTypeId of the FMP image.\r
89 It is used to identify the FMP protocol.\r
90 @param[in] ImageIndex The ImageIndex of the FMP image.\r
91 It is the input parameter for FMP->GetImage().\r
92 @param[in] ImageName The file name to hold the output FMP image.\r
93**/\r
94VOID\r
95DumpFmpImage (\r
96 IN EFI_GUID *ImageTypeId,\r
97 IN UINTN ImageIndex,\r
98 IN CHAR16 *ImageName\r
99 );\r
100\r
592bad04
JY
101/**\r
102 Dump ESRT info.\r
103**/\r
104VOID\r
105DumpEsrtData (\r
106 VOID\r
107 );\r
108\r
97473291
CC
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
592bad04
JY
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
8b17683a
SZ
157 @retval EFI_NOT_FOUND Shell protocol or file not found\r
158 @retval others Read file failed\r
592bad04
JY
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
8b17683a
SZ
175 @retval EFI_NOT_FOUND Shell protocol not found\r
176 @retval others Write file failed\r
592bad04
JY
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
bf9b044e
MK
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
592bad04
JY
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
bf9b044e 228 Info = Gop->Mode->Info;\r
592bad04 229 Print(L"Current GOP: Mode - %d, ", Gop->Mode->Mode);\r
bf9b044e
MK
230 Print(L"HorizontalResolution - %d, ", Info->HorizontalResolution);\r
231 Print(L"VerticalResolution - %d\n", Info->VerticalResolution);\r
592bad04
JY
232 // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth\r
233 // VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight\r
234\r
235 if (Argc != 5) {\r
10944bc3 236 Print(L"CapsuleApp: Incorrect parameter count.\n");\r
592bad04
JY
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
bf9b044e
MK
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
592bad04
JY
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
bf9b044e
MK
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
592bad04
JY
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
fb57c30b
SZ
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
592bad04
JY
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
10944bc3 484 Print(L"CapsuleApp: Incorrect parameter count.\n");\r
592bad04
JY
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
fb57c30b
SZ
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
592bad04
JY
515\r
516 ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer);\r
517 if (ImageTypeId == NULL) {\r
518 Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n");\r
fb57c30b 519 Status = EFI_INVALID_PARAMETER;\r
592bad04
JY
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
fb57c30b 525 Status = EFI_INVALID_PARAMETER;\r
592bad04
JY
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
99fd3043 541 NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_SYSTEMFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;\r
592bad04
JY
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
8b03c82d 576 BOOLEAN Found;\r
592bad04
JY
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
8b03c82d 582 Found = FALSE;\r
592bad04
JY
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
8b03c82d 593 if (Status == EFI_NOT_FOUND) {\r
592bad04 594 //\r
8b03c82d 595 // There is no more capsule variables, quit\r
592bad04
JY
596 //\r
597 break;\r
598 }\r
8b03c82d
SZ
599 Found = TRUE;\r
600\r
601 Print (L"Clear %s %r\n", CapsuleVarName, Status);\r
592bad04
JY
602\r
603 Index++;\r
604 if (Index > 0xFFFF) {\r
605 break;\r
606 }\r
607 }\r
608\r
8b03c82d
SZ
609 if (!Found) {\r
610 Print (L"No any Capsule#### variable found\n");\r
611 }\r
612\r
592bad04
JY
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
94f5c600 671 Print (L"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer[Index], FileSize[Index]);\r
592bad04
JY
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
845f7cfe 827 TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr[Index].Union.ContinuationPointer);\r
592bad04
JY
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
97473291 843 Print(L" CapsuleApp <Capsule...> [-NR] [-OD [FSx]]\n");\r
592bad04
JY
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
97473291
CC
848 Print(L" CapsuleApp -L\n");\r
849 Print(L" CapsuleApp -L INFO\n");\r
850 Print(L" CapsuleApp -F\n");\r
592bad04
JY
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
1e09ec09 854 Print(L" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");\r
592bad04 855 Print(L"Parameter:\n");\r
97473291
CC
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
592bad04
JY
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
0c6f94da 861 Print(L" -C: Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
592bad04 862 Print(L" which is defined in UEFI specification.\n");\r
5410502f 863 Print(L" -P: Dump UEFI FMP protocol info, or get image with specified\n");\r
16299ec8
SZ
864 Print(L" ImageTypeId and Index (decimal format) to a file if 'GET'\n");\r
865 Print(L" option is used.\n");\r
592bad04 866 Print(L" -E: Dump UEFI ESRT table info.\n");\r
97473291
CC
867 Print(L" -L: Dump provisioned capsule image information.\n");\r
868 Print(L" -F: Dump all EFI System Partition.\n");\r
045bb323 869 Print(L" -G: Convert a BMP file to be an UX capsule,\n");\r
592bad04 870 Print(L" according to Windows Firmware Update document\n");\r
e70d9b8c
SZ
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
592bad04
JY
873 Print(L" according to Windows Firmware Update document\n");\r
874 Print(L" -O: Output new Capsule file name\n");\r
16299ec8
SZ
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
592bad04
JY
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
10944bc3
SZ
887 @retval EFI_UNSUPPORTED Command usage unsupported.\r
888 @retval EFI_INVALID_PARAMETER Command usage invalid.\r
592bad04
JY
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
787f6744 899 RETURN_STATUS RStatus;\r
97473291 900 UINTN CapsuleBufferSize[MAX_CAPSULE_NUM];\r
592bad04
JY
901 VOID *CapsuleBuffer[MAX_CAPSULE_NUM];\r
902 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;\r
4436f722
SZ
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
97473291 908 BOOLEAN CapsuleOnDisk;\r
4436f722 909 CHAR16 *CapsuleName;\r
97473291
CC
910 CHAR16 *CapsuleNames[MAX_CAPSULE_NUM];\r
911 CHAR16 *MapFsStr;\r
4436f722
SZ
912 UINTN CapsuleNum;\r
913 UINTN Index;\r
97473291
CC
914 UINTN ParaOdIndex;\r
915 UINTN ParaNrIndex;\r
4436f722
SZ
916 EFI_GUID ImageTypeId;\r
917 UINTN ImageIndex;\r
592bad04 918\r
97473291
CC
919 MapFsStr = NULL;\r
920 CapsuleNum = 0;\r
921\r
592bad04
JY
922 Status = GetArg();\r
923 if (EFI_ERROR(Status)) {\r
924 Print(L"Please use UEFI SHELL to run this application!\n", Status);\r
925 return Status;\r
926 }\r
927 if (Argc < 2) {\r
928 PrintUsage();\r
10944bc3 929 return EFI_UNSUPPORTED;\r
592bad04
JY
930 }\r
931 if (StrCmp(Argv[1], L"-D") == 0) {\r
10944bc3
SZ
932 if (Argc != 3) {\r
933 Print(L"CapsuleApp: Incorrect parameter count.\n");\r
934 return EFI_UNSUPPORTED;\r
1c6dd45b 935 }\r
592bad04
JY
936 Status = DumpCapsule(Argv[2]);\r
937 return Status;\r
938 }\r
939 if (StrCmp(Argv[1], L"-G") == 0) {\r
940 Status = CreateBmpFmp();\r
941 return Status;\r
942 }\r
943 if (StrCmp(Argv[1], L"-N") == 0) {\r
944 Status = CreateNestedFmp();\r
945 return Status;\r
946 }\r
947 if (StrCmp(Argv[1], L"-S") == 0) {\r
8b03c82d 948 Status = DumpCapsuleStatusVariable();\r
592bad04
JY
949 return EFI_SUCCESS;\r
950 }\r
951 if (StrCmp(Argv[1], L"-C") == 0) {\r
952 Status = ClearCapsuleStatusVariable();\r
953 return Status;\r
954 }\r
955 if (StrCmp(Argv[1], L"-P") == 0) {\r
1e09ec09
JY
956 if (Argc == 2) {\r
957 DumpFmpData();\r
958 }\r
959 if (Argc >= 3) {\r
5410502f
SZ
960 if (StrCmp(Argv[2], L"GET") != 0) {\r
961 Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[2]);\r
962 return EFI_UNSUPPORTED;\r
963 } else {\r
964 if (Argc != 7) {\r
965 Print(L"CapsuleApp: Incorrect parameter count.\n");\r
966 return EFI_UNSUPPORTED;\r
967 }\r
968\r
1e09ec09
JY
969 //\r
970 // FMP->GetImage()\r
971 //\r
787f6744
RN
972 RStatus = StrToGuid (Argv[3], &ImageTypeId);\r
973 if (RETURN_ERROR (RStatus) || (Argv[3][GUID_STRING_LENGTH] != L'\0')) {\r
1e09ec09 974 Print (L"Invalid ImageTypeId - %s\n", Argv[3]);\r
787f6744 975 return EFI_INVALID_PARAMETER;\r
1e09ec09
JY
976 }\r
977 ImageIndex = StrDecimalToUintn(Argv[4]);\r
5410502f
SZ
978 if (StrCmp(Argv[5], L"-O") != 0) {\r
979 Print(L"CapsuleApp: NO output file name.\n");\r
980 return EFI_UNSUPPORTED;\r
1e09ec09 981 }\r
5410502f 982 DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);\r
1e09ec09
JY
983 }\r
984 }\r
592bad04
JY
985 return EFI_SUCCESS;\r
986 }\r
95dd7a6e 987\r
592bad04
JY
988 if (StrCmp(Argv[1], L"-E") == 0) {\r
989 DumpEsrtData();\r
990 return EFI_SUCCESS;\r
991 }\r
95dd7a6e 992\r
97473291
CC
993 if (StrCmp(Argv[1], L"-L") == 0) {\r
994 if (Argc >= 3 && StrCmp(Argv[2], L"INFO") == 0) {\r
995 DumpProvisionedCapsule(TRUE);\r
996 } else {\r
997 DumpProvisionedCapsule(FALSE);\r
998 }\r
999 return EFI_SUCCESS;\r
1000 }\r
1001\r
1002 if (StrCmp(Argv[1], L"-F") == 0) {\r
1003 DumpAllEfiSysPartition();\r
1004 return EFI_SUCCESS;\r
1005 }\r
1006\r
95dd7a6e
SZ
1007 if (Argv[1][0] == L'-') {\r
1008 Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]);\r
1009 return EFI_UNSUPPORTED;\r
1010 }\r
1011\r
592bad04 1012 CapsuleFirstIndex = 1;\r
7043a90e 1013 NoReset = FALSE;\r
97473291
CC
1014 CapsuleOnDisk = FALSE;\r
1015 ParaOdIndex = 0;\r
1016 ParaNrIndex = 0;\r
1017\r
1018 for (Index = 1; Index < Argc; Index++) {\r
1019 if (StrCmp(Argv[Index], L"-OD") == 0) {\r
1020 ParaOdIndex = Index;\r
1021 CapsuleOnDisk = TRUE;\r
1022 } else if (StrCmp(Argv[Index], L"-NR") == 0) {\r
1023 ParaNrIndex = Index;\r
1024 NoReset = TRUE;\r
1025 }\r
1026 }\r
1027\r
1028 if (ParaOdIndex != 0) {\r
1029 if (ParaOdIndex == Argc - 1) {\r
1030 MapFsStr = NULL;\r
1031 } else if (ParaOdIndex == Argc - 2) {\r
1032 MapFsStr = Argv[Argc-1];\r
1033 } else {\r
1034 Print (L"CapsuleApp: Invalid Position for -OD Options\n");\r
1035 Status = EFI_INVALID_PARAMETER;\r
1036 goto Done;\r
1037 }\r
1038\r
1039 if (ParaNrIndex != 0) {\r
1040 if (ParaNrIndex + 1 == ParaOdIndex) {\r
1041 CapsuleLastIndex = ParaNrIndex - 1;\r
1042 } else {\r
1043 Print (L"CapsuleApp: Invalid Position for -NR Options\n");\r
1044 Status = EFI_INVALID_PARAMETER;\r
1045 goto Done;\r
1046 }\r
1047 } else {\r
1048 CapsuleLastIndex = ParaOdIndex - 1;\r
1049 }\r
7043a90e 1050 } else {\r
97473291
CC
1051 if (ParaNrIndex != 0) {\r
1052 if (ParaNrIndex == Argc -1) {\r
1053 CapsuleLastIndex = ParaNrIndex - 1;\r
1054 } else {\r
1055 Print (L"CapsuleApp: Invalid Position for -NR Options\n");\r
1056 Status = EFI_INVALID_PARAMETER;\r
1057 goto Done;\r
1058 }\r
1059 } else {\r
1060 CapsuleLastIndex = Argc - 1;\r
1061 }\r
7043a90e 1062 }\r
97473291 1063\r
592bad04
JY
1064 CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;\r
1065\r
1066 if (CapsuleFirstIndex > CapsuleLastIndex) {\r
1067 Print(L"CapsuleApp: NO capsule image.\n");\r
1068 return EFI_UNSUPPORTED;\r
1069 }\r
1070 if (CapsuleNum > MAX_CAPSULE_NUM) {\r
1071 Print(L"CapsuleApp: Too many capsule images.\n");\r
1072 return EFI_UNSUPPORTED;\r
1073 }\r
1074\r
1075 ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));\r
97473291 1076 ZeroMem(&CapsuleBufferSize, sizeof(CapsuleBufferSize));\r
592bad04
JY
1077 BlockDescriptors = NULL;\r
1078\r
1079 for (Index = 0; Index < CapsuleNum; Index++) {\r
1080 CapsuleName = Argv[CapsuleFirstIndex + Index];\r
97473291 1081 Status = ReadFileToBuffer(CapsuleName, &CapsuleBufferSize[Index], &CapsuleBuffer[Index]);\r
592bad04
JY
1082 if (EFI_ERROR(Status)) {\r
1083 Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);\r
1084 goto Done;\r
1085 }\r
97473291 1086 if (!IsValidCapsuleHeader (CapsuleBuffer[Index], CapsuleBufferSize[Index])) {\r
d9c640b9
SZ
1087 Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);\r
1088 return EFI_INVALID_PARAMETER;\r
1089 }\r
97473291 1090 CapsuleNames[Index] = CapsuleName;\r
592bad04
JY
1091 }\r
1092\r
1093 //\r
1094 // Every capsule use 2 descriptor 1 for data 1 for end\r
1095 //\r
97473291 1096 Status = BuildGatherList(CapsuleBuffer, CapsuleBufferSize, CapsuleNum, &BlockDescriptors);\r
592bad04
JY
1097 if (EFI_ERROR(Status)) {\r
1098 goto Done;\r
1099 }\r
1100\r
1101 //\r
1102 // Call the runtime service capsule.\r
1103 //\r
1104 NeedReset = FALSE;\r
1105 for (Index = 0; Index < CapsuleNum; Index++) {\r
1106 CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index];\r
1107 if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
1108 NeedReset = TRUE;\r
1109 }\r
1110 }\r
1111 CapsuleHeaderArray[CapsuleNum] = NULL;\r
1112\r
1113 //\r
1114 // Inquire platform capability of UpdateCapsule.\r
1115 //\r
1116 Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);\r
1117 if (EFI_ERROR(Status)) {\r
1118 Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);\r
1119 goto Done;\r
1120 }\r
1121\r
1122 for (Index = 0; Index < CapsuleNum; Index++) {\r
97473291 1123 if (CapsuleBufferSize[Index] > MaxCapsuleSize) {\r
592bad04
JY
1124 Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);\r
1125 Status = EFI_UNSUPPORTED;\r
1126 goto Done;\r
1127 }\r
1128 }\r
1129\r
97473291
CC
1130 //\r
1131 // Check whether is capsule on disk.\r
1132 //\r
1133 if (CapsuleOnDisk) {\r
1134 Status = ProcessCapsuleOnDisk (CapsuleBuffer, CapsuleBufferSize, CapsuleNames, MapFsStr, CapsuleNum);\r
1135 if (Status != EFI_SUCCESS) {\r
1136 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
1137 goto Done;\r
1138 } else {\r
1139 if (!NoReset) {\r
1140 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
1141 } else {\r
1142 goto Done;\r
1143 }\r
1144 }\r
1145 }\r
1146\r
592bad04
JY
1147 //\r
1148 // Check whether the input capsule image has the flag of persist across system reset.\r
1149 //\r
1150 if (NeedReset) {\r
1151 Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);\r
1152 if (Status != EFI_SUCCESS) {\r
1153 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
1154 goto Done;\r
1155 }\r
1156 //\r
7043a90e
SZ
1157 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,\r
1158 // a system reset should have been triggered by gRT->UpdateCapsule() calling above.\r
1159 //\r
1160 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,\r
1161 // check if -NR (no-reset) has been specified or not.\r
592bad04 1162 //\r
7043a90e
SZ
1163 if (!NoReset) {\r
1164 //\r
1165 // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,\r
1166 // trigger a system reset to process capsule persist across a system reset.\r
1167 //\r
1168 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
1169 }\r
592bad04
JY
1170 } else {\r
1171 //\r
1172 // For capsule who has no reset flag, only call UpdateCapsule Service without a\r
1173 // system reset. The service will process the capsule immediately.\r
1174 //\r
1175 Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);\r
1176 if (Status != EFI_SUCCESS) {\r
1177 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
1178 }\r
1179 }\r
1180\r
1181 Status = EFI_SUCCESS;\r
1182\r
1183Done:\r
1184 for (Index = 0; Index < CapsuleNum; Index++) {\r
1185 if (CapsuleBuffer[Index] != NULL) {\r
1186 FreePool (CapsuleBuffer[Index]);\r
1187 }\r
1188 }\r
1189\r
1190 CleanGatherList(BlockDescriptors, CapsuleNum);\r
1191\r
1192 return Status;\r
1193}\r