IntelSiliconPkg: Replace BSD License with BSD+Patent License
[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
e98212cb
CC
919 BlockDescriptors = NULL;\r
920 MapFsStr = NULL;\r
921 CapsuleNum = 0;\r
97473291 922\r
592bad04
JY
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
10944bc3 930 return EFI_UNSUPPORTED;\r
592bad04
JY
931 }\r
932 if (StrCmp(Argv[1], L"-D") == 0) {\r
10944bc3
SZ
933 if (Argc != 3) {\r
934 Print(L"CapsuleApp: Incorrect parameter count.\n");\r
935 return EFI_UNSUPPORTED;\r
1c6dd45b 936 }\r
592bad04
JY
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
8b03c82d 949 Status = DumpCapsuleStatusVariable();\r
592bad04
JY
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
1e09ec09
JY
957 if (Argc == 2) {\r
958 DumpFmpData();\r
959 }\r
960 if (Argc >= 3) {\r
5410502f
SZ
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
1e09ec09
JY
970 //\r
971 // FMP->GetImage()\r
972 //\r
787f6744
RN
973 RStatus = StrToGuid (Argv[3], &ImageTypeId);\r
974 if (RETURN_ERROR (RStatus) || (Argv[3][GUID_STRING_LENGTH] != L'\0')) {\r
1e09ec09 975 Print (L"Invalid ImageTypeId - %s\n", Argv[3]);\r
787f6744 976 return EFI_INVALID_PARAMETER;\r
1e09ec09
JY
977 }\r
978 ImageIndex = StrDecimalToUintn(Argv[4]);\r
5410502f
SZ
979 if (StrCmp(Argv[5], L"-O") != 0) {\r
980 Print(L"CapsuleApp: NO output file name.\n");\r
981 return EFI_UNSUPPORTED;\r
1e09ec09 982 }\r
5410502f 983 DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);\r
1e09ec09
JY
984 }\r
985 }\r
592bad04
JY
986 return EFI_SUCCESS;\r
987 }\r
95dd7a6e 988\r
592bad04
JY
989 if (StrCmp(Argv[1], L"-E") == 0) {\r
990 DumpEsrtData();\r
991 return EFI_SUCCESS;\r
992 }\r
95dd7a6e 993\r
97473291
CC
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
95dd7a6e
SZ
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
592bad04 1013 CapsuleFirstIndex = 1;\r
7043a90e 1014 NoReset = FALSE;\r
97473291
CC
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
7043a90e 1051 } else {\r
97473291
CC
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
7043a90e 1063 }\r
97473291 1064\r
592bad04
JY
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
97473291 1077 ZeroMem(&CapsuleBufferSize, sizeof(CapsuleBufferSize));\r
592bad04
JY
1078 BlockDescriptors = NULL;\r
1079\r
1080 for (Index = 0; Index < CapsuleNum; Index++) {\r
1081 CapsuleName = Argv[CapsuleFirstIndex + Index];\r
97473291 1082 Status = ReadFileToBuffer(CapsuleName, &CapsuleBufferSize[Index], &CapsuleBuffer[Index]);\r
592bad04
JY
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
97473291 1087 if (!IsValidCapsuleHeader (CapsuleBuffer[Index], CapsuleBufferSize[Index])) {\r
d9c640b9
SZ
1088 Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);\r
1089 return EFI_INVALID_PARAMETER;\r
1090 }\r
97473291 1091 CapsuleNames[Index] = CapsuleName;\r
592bad04
JY
1092 }\r
1093\r
1094 //\r
1095 // Every capsule use 2 descriptor 1 for data 1 for end\r
1096 //\r
97473291 1097 Status = BuildGatherList(CapsuleBuffer, CapsuleBufferSize, CapsuleNum, &BlockDescriptors);\r
592bad04
JY
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
97473291 1124 if (CapsuleBufferSize[Index] > MaxCapsuleSize) {\r
592bad04
JY
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
97473291
CC
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
592bad04
JY
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
7043a90e
SZ
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
592bad04 1163 //\r
7043a90e
SZ
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
592bad04
JY
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