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