]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
MdePkg/UefiDevicePathLib: Use BaseLib string conversion services
[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
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <Uefi.h>\r
16#include <Library/BaseLib.h>\r
17#include <Library/DebugLib.h>\r
18#include <Library/BaseMemoryLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/UefiBootServicesTableLib.h>\r
21#include <Library/UefiRuntimeServicesTableLib.h>\r
22#include <Library/UefiLib.h>\r
23#include <Library/PrintLib.h>\r
24#include <Protocol/LoadedImage.h>\r
25#include <Protocol/SimpleFileSystem.h>\r
26#include <Protocol/GraphicsOutput.h>\r
27#include <Guid/FileInfo.h>\r
28#include <Guid/Gpt.h>\r
29#include <Guid/GlobalVariable.h>\r
30#include <Guid/CapsuleReport.h>\r
31#include <Guid/SystemResourceTable.h>\r
32#include <Guid/FmpCapsule.h>\r
33#include <IndustryStandard/WindowsUxCapsule.h>\r
34\r
35#define CAPSULE_HEADER_SIZE 0x20\r
36\r
37#define NESTED_CAPSULE_HEADER_SIZE SIZE_4KB\r
38#define SYSTEM_FIRMWARE_FLAG 0x50000\r
39#define DEVICE_FIRMWARE_FLAG 0x78010\r
40\r
592bad04
JY
41#define MAJOR_VERSION 1\r
42#define MINOR_VERSION 0\r
43\r
44#define MAX_CAPSULE_NUM 10\r
45\r
46extern UINTN Argc;\r
47extern CHAR16 **Argv;\r
48\r
49//\r
50// Define how many block descriptors we want to test with.\r
51//\r
52UINTN NumberOfDescriptors = 1;\r
53UINTN CapsuleFirstIndex;\r
54UINTN CapsuleLastIndex;\r
55\r
56/**\r
57 Dump capsule information\r
58\r
59 @param[in] CapsuleName The name of the capsule image.\r
60\r
61 @retval EFI_SUCCESS The capsule information is dumped.\r
62 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
63**/\r
64EFI_STATUS\r
65DumpCapsule (\r
66 IN CHAR16 *CapsuleName\r
67 );\r
68\r
69/**\r
70 Dump capsule status variable.\r
71\r
72 @retval EFI_SUCCESS The capsule status variable is dumped.\r
73 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
74**/\r
75EFI_STATUS\r
76DmpCapsuleStatusVariable (\r
77 VOID\r
78 );\r
79\r
80/**\r
81 Dump FMP protocol info.\r
82**/\r
83VOID\r
84DumpFmpData (\r
85 VOID\r
86 );\r
87\r
1e09ec09
JY
88/**\r
89 Dump FMP image data.\r
90\r
91 @param[in] ImageTypeId The ImageTypeId of the FMP image.\r
92 It is used to identify the FMP protocol.\r
93 @param[in] ImageIndex The ImageIndex of the FMP image.\r
94 It is the input parameter for FMP->GetImage().\r
95 @param[in] ImageName The file name to hold the output FMP image.\r
96**/\r
97VOID\r
98DumpFmpImage (\r
99 IN EFI_GUID *ImageTypeId,\r
100 IN UINTN ImageIndex,\r
101 IN CHAR16 *ImageName\r
102 );\r
103\r
592bad04
JY
104/**\r
105 Dump ESRT info.\r
106**/\r
107VOID\r
108DumpEsrtData (\r
109 VOID\r
110 );\r
111\r
112/**\r
113 Read a file.\r
114\r
115 @param[in] FileName The file to be read.\r
116 @param[out] BufferSize The file buffer size\r
117 @param[out] Buffer The file buffer\r
118\r
119 @retval EFI_SUCCESS Read file successfully\r
120 @retval EFI_NOT_FOUND File not found\r
121**/\r
122EFI_STATUS\r
123ReadFileToBuffer (\r
124 IN CHAR16 *FileName,\r
125 OUT UINTN *BufferSize,\r
126 OUT VOID **Buffer\r
127 );\r
128\r
129/**\r
130 Write a file.\r
131\r
132 @param[in] FileName The file to be written.\r
133 @param[in] BufferSize The file buffer size\r
134 @param[in] Buffer The file buffer\r
135\r
136 @retval EFI_SUCCESS Write file successfully\r
137**/\r
138EFI_STATUS\r
139WriteFileFromBuffer (\r
140 IN CHAR16 *FileName,\r
141 IN UINTN BufferSize,\r
142 IN VOID *Buffer\r
143 );\r
144\r
1e09ec09
JY
145/**\r
146 Converts a string to GUID value.\r
147 Guid Format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
148\r
149 @param[in] Str The registry format GUID string that contains the GUID value.\r
150 @param[out] Guid A pointer to the converted GUID value.\r
151\r
152 @retval EFI_SUCCESS The GUID string was successfully converted to the GUID value.\r
153 @retval EFI_UNSUPPORTED The input string is not in registry format.\r
154 @return others Some error occurred when converting part of GUID value.\r
155\r
156**/\r
157EFI_STATUS\r
c608cda5 158InternalStrToGuid (\r
1e09ec09
JY
159 IN CHAR16 *Str,\r
160 OUT EFI_GUID *Guid\r
161 );\r
162\r
592bad04
JY
163/**\r
164\r
165 This function parse application ARG.\r
166\r
167 @return Status\r
168**/\r
169EFI_STATUS\r
170GetArg (\r
171 VOID\r
172 );\r
173\r
174/**\r
175 Create UX capsule.\r
176\r
177 @retval EFI_SUCCESS The capsule header is appended.\r
178 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
179 @retval EFI_OUT_OF_RESOURCES No enough resource to create UX capsule.\r
180**/\r
181EFI_STATUS\r
182CreateBmpFmp (\r
183 VOID\r
184 )\r
185{\r
186 CHAR16 *OutputCapsuleName;\r
187 VOID *BmpBuffer;\r
188 UINTN FileSize;\r
189 CHAR16 *BmpName;\r
190 UINT8 *FullCapsuleBuffer;\r
191 UINTN FullCapsuleBufferSize;\r
192 EFI_DISPLAY_CAPSULE *DisplayCapsule;\r
193 EFI_STATUS Status;\r
194 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;\r
195\r
196 Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop);\r
197 if (EFI_ERROR(Status)) {\r
198 Print(L"CapsuleApp: NO GOP is found.\n");\r
199 return EFI_UNSUPPORTED;\r
200 }\r
201 Print(L"Current GOP: Mode - %d, ", Gop->Mode->Mode);\r
202 Print(L"HorizontalResolution - %d, ", Gop->Mode->Info->HorizontalResolution);\r
203 Print(L"VerticalResolution - %d\n", Gop->Mode->Info->VerticalResolution);\r
204 // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth\r
205 // VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight\r
206\r
207 if (Argc != 5) {\r
208 Print(L"CapsuleApp: Invalid Parameter.\n");\r
209 return EFI_UNSUPPORTED;\r
210 }\r
211\r
212 if (StrCmp(Argv[3], L"-O") != 0) {\r
213 Print(L"CapsuleApp: NO output capsule name.\n");\r
214 return EFI_UNSUPPORTED;\r
215 }\r
216 OutputCapsuleName = Argv[4];\r
217\r
218 BmpBuffer = NULL;\r
219 FileSize = 0;\r
220 FullCapsuleBuffer = NULL;\r
221\r
222 BmpName = Argv[2];\r
223 Status = ReadFileToBuffer(BmpName, &FileSize, &BmpBuffer);\r
224 if (EFI_ERROR(Status)) {\r
225 Print(L"CapsuleApp: BMP image (%s) is not found.\n", BmpName);\r
226 goto Done;\r
227 }\r
228\r
229 FullCapsuleBufferSize = sizeof(EFI_DISPLAY_CAPSULE) + FileSize;\r
230 FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);\r
231 if (FullCapsuleBuffer == NULL) {\r
232 Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);\r
233 Status = EFI_OUT_OF_RESOURCES;\r
234 goto Done;\r
235 }\r
236\r
237 DisplayCapsule = (EFI_DISPLAY_CAPSULE *)FullCapsuleBuffer;\r
238 CopyGuid(&DisplayCapsule->CapsuleHeader.CapsuleGuid, &gWindowsUxCapsuleGuid);\r
239 DisplayCapsule->CapsuleHeader.HeaderSize = sizeof(DisplayCapsule->CapsuleHeader);\r
240 DisplayCapsule->CapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;\r
241 DisplayCapsule->CapsuleHeader.CapsuleImageSize = (UINT32)FullCapsuleBufferSize;\r
242\r
243 DisplayCapsule->ImagePayload.Version = 1;\r
244 DisplayCapsule->ImagePayload.Checksum = 0;\r
245 DisplayCapsule->ImagePayload.ImageType = 0; // BMP\r
246 DisplayCapsule->ImagePayload.Reserved = 0;\r
247 DisplayCapsule->ImagePayload.Mode = Gop->Mode->Mode;\r
248 DisplayCapsule->ImagePayload.OffsetX = 0;\r
249 DisplayCapsule->ImagePayload.OffsetY = 0;\r
250\r
251 CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize);\r
252\r
253 DisplayCapsule->ImagePayload.Checksum = CalculateCheckSum8(FullCapsuleBuffer, FullCapsuleBufferSize);\r
254\r
255 Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);\r
256 Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);\r
257\r
258Done:\r
259 if (BmpBuffer != NULL) {\r
260 FreePool(BmpBuffer);\r
261 }\r
262\r
263 if (FullCapsuleBuffer != NULL) {\r
264 FreePool(FullCapsuleBuffer);\r
265 }\r
266\r
267 return Status;\r
268}\r
269\r
270/**\r
271 Get ImageTypeId in the FMP capsule header.\r
272\r
273 @param[in] CapsuleHeader The FMP capsule image header.\r
274\r
275 @return ImageTypeId\r
276**/\r
277EFI_GUID *\r
278GetCapsuleImageTypeId (\r
279 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
280 )\r
281{\r
282 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
283 UINT64 *ItemOffsetList;\r
284 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
285\r
286 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
287 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
288 if (FmpCapsuleHeader->PayloadItemCount == 0) {\r
289 return NULL;\r
290 }\r
291 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[FmpCapsuleHeader->EmbeddedDriverCount]);\r
292 return &ImageHeader->UpdateImageTypeId;\r
293}\r
294\r
295/**\r
296 Get ESRT FwType according to ImageTypeId\r
297\r
298 @param[in] ImageTypeId ImageTypeId of an FMP capsule.\r
299\r
300 @return ESRT FwType\r
301**/\r
302UINT32\r
303GetEsrtFwType (\r
304 IN EFI_GUID *ImageTypeId\r
305 )\r
306{\r
307 EFI_STATUS Status;\r
308 EFI_SYSTEM_RESOURCE_TABLE *Esrt;\r
309 EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;\r
310 UINTN Index;\r
311\r
312 //\r
313 // Check ESRT\r
314 //\r
315 Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);\r
316 if (!EFI_ERROR(Status)) {\r
317 ASSERT(Esrt != NULL);\r
318 EsrtEntry = (VOID *)(Esrt + 1);\r
319 for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {\r
320 if (CompareGuid(&EsrtEntry->FwClass, ImageTypeId)) {\r
321 return EsrtEntry->FwType;\r
322 }\r
323 }\r
324 }\r
325\r
326 return ESRT_FW_TYPE_UNKNOWN;\r
327}\r
328\r
329/**\r
330 Append a capsule header on top of current image.\r
331 This function follows Windows UEFI Firmware Update Platform document.\r
332\r
333 @retval EFI_SUCCESS The capsule header is appended.\r
334 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
335 @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header.\r
336**/\r
337EFI_STATUS\r
338CreateNestedFmp (\r
339 VOID\r
340 )\r
341{\r
342 CHAR16 *OutputCapsuleName;\r
343 VOID *CapsuleBuffer;\r
344 UINTN FileSize;\r
345 CHAR16 *CapsuleName;\r
346 UINT8 *FullCapsuleBuffer;\r
347 UINTN FullCapsuleBufferSize;\r
348 EFI_CAPSULE_HEADER *NestedCapsuleHeader;\r
349 EFI_GUID *ImageTypeId;\r
350 UINT32 FwType;\r
351 EFI_STATUS Status;\r
352\r
353 if (Argc != 5) {\r
354 Print(L"CapsuleApp: Invalid Parameter.\n");\r
355 return EFI_UNSUPPORTED;\r
356 }\r
357\r
358 if (StrCmp(Argv[3], L"-O") != 0) {\r
359 Print(L"CapsuleApp: NO output capsule name.\n");\r
360 return EFI_UNSUPPORTED;\r
361 }\r
362 OutputCapsuleName = Argv[4];\r
363\r
364 CapsuleBuffer = NULL;\r
365 FileSize = 0;\r
366 FullCapsuleBuffer = NULL;\r
367\r
368 CapsuleName = Argv[2];\r
369 Status = ReadFileToBuffer(CapsuleName, &FileSize, &CapsuleBuffer);\r
370 if (EFI_ERROR(Status)) {\r
371 Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName);\r
372 goto Done;\r
373 }\r
374\r
375 ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer);\r
376 if (ImageTypeId == NULL) {\r
377 Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n");\r
378 goto Done;\r
379 }\r
380 FwType = GetEsrtFwType(ImageTypeId);\r
381 if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != ESRT_FW_TYPE_DEVICEFIRMWARE)) {\r
382 Print(L"CapsuleApp: Capsule FwType is invalid.\n");\r
383 goto Done;\r
384 }\r
385\r
386 FullCapsuleBufferSize = NESTED_CAPSULE_HEADER_SIZE + FileSize;\r
387 FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);\r
388 if (FullCapsuleBuffer == NULL) {\r
389 Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);\r
390 Status = EFI_OUT_OF_RESOURCES;\r
391 goto Done;\r
392 }\r
393\r
394 NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)FullCapsuleBuffer;\r
395 ZeroMem(NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE);\r
396 CopyGuid(&NestedCapsuleHeader->CapsuleGuid, ImageTypeId);\r
397 NestedCapsuleHeader->HeaderSize = NESTED_CAPSULE_HEADER_SIZE;\r
398 NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_DEVICEFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;\r
399 NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize;\r
400\r
401 CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize);\r
402\r
403 Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);\r
404 Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);\r
405\r
406Done:\r
407 if (CapsuleBuffer != NULL) {\r
408 FreePool(CapsuleBuffer);\r
409 }\r
410\r
411 if (FullCapsuleBuffer != NULL) {\r
412 FreePool(FullCapsuleBuffer);\r
413 }\r
414\r
415 return Status;\r
416}\r
417\r
418\r
419/**\r
420 Clear capsule status variable.\r
421\r
422 @retval EFI_SUCCESS The capsule status variable is cleared.\r
423**/\r
424EFI_STATUS\r
425ClearCapsuleStatusVariable (\r
426 VOID\r
427 )\r
428{\r
429 EFI_STATUS Status;\r
430 UINT32 Index;\r
431 CHAR16 CapsuleVarName[20];\r
432 CHAR16 *TempVarName;\r
433\r
434 StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");\r
435 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
436 Index = 0;\r
437\r
438 while (TRUE) {\r
439 UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);\r
440\r
441 Status = gRT->SetVariable (\r
442 CapsuleVarName,\r
443 &gEfiCapsuleReportGuid,\r
444 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
445 0,\r
446 (VOID *)NULL\r
447 );\r
448 if (EFI_ERROR(Status)) {\r
449 //\r
450 // There is no capsule variables, quit\r
451 //\r
452 break;\r
453 }\r
454\r
455 Index++;\r
456 if (Index > 0xFFFF) {\r
457 break;\r
458 }\r
459 }\r
460\r
461 return EFI_SUCCESS;\r
462}\r
463\r
464/**\r
465 Build Gather list for a list of capsule images.\r
466\r
467 @param[in] CapsuleBuffer An array of pointer to capsule images\r
468 @param[in] FileSize An array of UINTN to capsule images size\r
469 @param[in] CapsuleNum The count of capsule images\r
470 @param[out] BlockDescriptors The block descriptors for the capsule images\r
471\r
472 @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.\r
473**/\r
474EFI_STATUS\r
475BuildGatherList (\r
476 IN VOID **CapsuleBuffer,\r
477 IN UINTN *FileSize,\r
478 IN UINTN CapsuleNum,\r
479 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors\r
480 )\r
481{\r
482 EFI_STATUS Status;\r
483 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;\r
484 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors2;\r
485 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;\r
486 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;\r
487 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;\r
488 UINT8 *TempDataPtr;\r
489 UINTN SizeLeft;\r
490 UINTN Size;\r
491 INT32 Count;\r
492 INT32 Number;\r
493 UINTN Index;\r
494\r
495 TempBlockPtr = NULL;\r
496 BlockDescriptors1 = NULL;\r
497 BlockDescriptors2 = NULL;\r
498 BlockDescriptorPre = NULL;\r
499 BlockDescriptorsHeader = NULL;\r
500\r
501 for (Index = 0; Index < CapsuleNum; Index++) {\r
502 //\r
503 // Allocate memory for the descriptors.\r
504 //\r
505 if (NumberOfDescriptors == 1) {\r
506 Count = 2;\r
507 } else {\r
508 Count = (INT32)(NumberOfDescriptors + 2) / 2;\r
509 }\r
510\r
511 Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
512 BlockDescriptors1 = AllocateRuntimeZeroPool (Size);\r
513 if (BlockDescriptors1 == NULL) {\r
514 Print (L"CapsuleApp: failed to allocate memory for descriptors\n");\r
515 Status = EFI_OUT_OF_RESOURCES;\r
516 goto ERREXIT;\r
517 } else {\r
518 Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1);\r
519 Print (L"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer, FileSize);\r
520 }\r
521\r
522 //\r
523 // Record descirptor header\r
524 //\r
525 if (Index == 0) {\r
526 BlockDescriptorsHeader = BlockDescriptors1;\r
527 }\r
528\r
529 if (BlockDescriptorPre != NULL) {\r
530 BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1;\r
531 BlockDescriptorPre->Length = 0;\r
532 }\r
533\r
534 //\r
535 // Fill them in\r
536 //\r
537 TempBlockPtr = BlockDescriptors1;\r
538 TempDataPtr = CapsuleBuffer[Index];\r
539 SizeLeft = FileSize[Index];\r
540 for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) {\r
541 //\r
542 // Divide remaining data in half\r
543 //\r
544 if (NumberOfDescriptors != 1) {\r
545 if (SizeLeft == 1) {\r
546 Size = 1;\r
547 } else {\r
548 Size = SizeLeft / 2;\r
549 }\r
550 } else {\r
551 Size = SizeLeft;\r
552 }\r
553 TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;\r
554 TempBlockPtr->Length = Size;\r
555 Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);\r
556 SizeLeft -= Size;\r
557 TempDataPtr += Size;\r
558 TempBlockPtr++;\r
559 }\r
560\r
561 //\r
562 // Allocate the second list, point the first block's last entry to point\r
563 // to this one, and fill this one in. Worst case is that the previous\r
564 // list only had one element that pointed here, so we need at least two\r
565 // elements -- one to point to all the data, another to terminate the list.\r
566 //\r
567 if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) {\r
568 Count = (INT32)(NumberOfDescriptors + 2) - Count;\r
569 if (Count == 1) {\r
570 Count++;\r
571 }\r
572\r
573 Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
574 BlockDescriptors2 = AllocateRuntimeZeroPool (Size);\r
575 if (BlockDescriptors2 == NULL) {\r
576 Print (L"CapsuleApp: failed to allocate memory for descriptors\n");\r
577 Status = EFI_OUT_OF_RESOURCES;\r
578 goto ERREXIT;\r
579 }\r
580\r
581 //\r
582 // Point the first list's last element to point to this second list.\r
583 //\r
584 TempBlockPtr->Union.ContinuationPointer = (UINTN) BlockDescriptors2;\r
585\r
586 TempBlockPtr->Length = 0;\r
587 TempBlockPtr = BlockDescriptors2;\r
588 for (Number = 0; Number < Count - 1; Number++) {\r
589 //\r
590 // If second-to-last one, then dump rest to this element\r
591 //\r
592 if (Number == (Count - 2)) {\r
593 Size = SizeLeft;\r
594 } else {\r
595 //\r
596 // Divide remaining data in half\r
597 //\r
598 if (SizeLeft == 1) {\r
599 Size = 1;\r
600 } else {\r
601 Size = SizeLeft / 2;\r
602 }\r
603 }\r
604\r
605 TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;\r
606 TempBlockPtr->Length = Size;\r
607 Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);\r
608 SizeLeft -= Size;\r
609 TempDataPtr += Size;\r
610 TempBlockPtr++;\r
611 if (SizeLeft == 0) {\r
612 break;\r
613 }\r
614 }\r
615 }\r
616\r
617 BlockDescriptorPre = TempBlockPtr;\r
618 BlockDescriptors1 = NULL;\r
619 }\r
620\r
621 //\r
622 // Null-terminate.\r
623 //\r
624 if (TempBlockPtr != NULL) {\r
625 TempBlockPtr->Union.ContinuationPointer = (UINTN)NULL;\r
626 TempBlockPtr->Length = 0;\r
627 *BlockDescriptors = BlockDescriptorsHeader;\r
628 }\r
629\r
630 return EFI_SUCCESS;\r
631\r
632ERREXIT:\r
633 if (BlockDescriptors1 != NULL) {\r
634 FreePool(BlockDescriptors1);\r
635 }\r
636\r
637 if (BlockDescriptors2 != NULL) {\r
638 FreePool(BlockDescriptors2);\r
639 }\r
640\r
641 return Status;\r
642}\r
643\r
644/**\r
645 Clear the Gather list for a list of capsule images.\r
646\r
647 @param[in] BlockDescriptors The block descriptors for the capsule images\r
648 @param[in] CapsuleNum The count of capsule images\r
649**/\r
650VOID\r
651CleanGatherList (\r
652 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors,\r
653 IN UINTN CapsuleNum\r
654 )\r
655{\r
656 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;\r
657 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr1;\r
658 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr2;\r
659 UINTN Index;\r
660\r
661 if (BlockDescriptors != NULL) {\r
662 TempBlockPtr1 = BlockDescriptors;\r
663 while (1){\r
664 TempBlockPtr = TempBlockPtr1;\r
665 for (Index = 0; Index < CapsuleNum; Index++) {\r
666 if (TempBlockPtr[Index].Length == 0) {\r
667 break;\r
668 }\r
669 }\r
670\r
671 if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) {\r
672 break;\r
673 }\r
674\r
675 TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr->Union.ContinuationPointer);\r
676 FreePool(TempBlockPtr1);\r
677 TempBlockPtr1 = TempBlockPtr2;\r
678 }\r
679 }\r
680}\r
681\r
682/**\r
683 Print APP usage.\r
684**/\r
685VOID\r
686PrintUsage (\r
687 VOID\r
688 )\r
689{\r
690 Print(L"CapsuleApp: usage\n");\r
691 Print(L" CapsuleApp <Capsule...>\n");\r
692 Print(L" CapsuleApp -S\n");\r
693 Print(L" CapsuleApp -C\n");\r
694 Print(L" CapsuleApp -P\n");\r
695 Print(L" CapsuleApp -E\n");\r
696 Print(L" CapsuleApp -G <BMP> -O <Capsule>\n");\r
697 Print(L" CapsuleApp -N <Capsule> -O <NestedCapsule>\n");\r
698 Print(L" CapsuleApp -D <Capsule>\n");\r
1e09ec09 699 Print(L" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");\r
592bad04
JY
700 Print(L"Parameter:\n");\r
701 Print(L" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
702 Print(L" which is defined in UEFI specification.\n");\r
703 Print(L" -C: Clear capsule report variable (EFI_CAPSULE_RPORT_GUID),\n");\r
704 Print(L" which is defined in UEFI specification.\n");\r
705 Print(L" -P: Dump UEFI FMP protocol info.\n");\r
706 Print(L" -E: Dump UEFI ESRT table info.\n");\r
707 Print(L" -G: Convert a BMP file to be a UX capsule,\n");\r
708 Print(L" according to Windows Firmware Update document\n");\r
709 Print(L" -N: Append a Capsule Header to an existing capsule image,\n");\r
710 Print(L" according to Windows Firmware Update document\n");\r
711 Print(L" -O: Output new Capsule file name\n");\r
712 Print(L" -D: Dump Capsule image header information and FMP header information,\n");\r
713 Print(L" if it is an FMP capsule.\n");\r
714}\r
715\r
716/**\r
717 Update Capsule image.\r
718\r
719 @param[in] ImageHandle The image handle.\r
720 @param[in] SystemTable The system table.\r
721\r
722 @retval EFI_SUCCESS Command completed successfully.\r
723 @retval EFI_INVALID_PARAMETER Command usage error.\r
724 @retval EFI_NOT_FOUND The input file can't be found.\r
725**/\r
726EFI_STATUS\r
727EFIAPI\r
728UefiMain (\r
729 IN EFI_HANDLE ImageHandle,\r
730 IN EFI_SYSTEM_TABLE *SystemTable\r
731 )\r
732{\r
733 EFI_STATUS Status;\r
734 UINTN FileSize[MAX_CAPSULE_NUM];\r
735 VOID *CapsuleBuffer[MAX_CAPSULE_NUM];\r
736 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;\r
737 EFI_CAPSULE_HEADER *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];\r
738 UINT64 MaxCapsuleSize;\r
739 EFI_RESET_TYPE ResetType;\r
740 BOOLEAN NeedReset;\r
741 CHAR16 *CapsuleName;\r
742 UINTN CapsuleNum;\r
743 UINTN Index;\r
744\r
745 Status = GetArg();\r
746 if (EFI_ERROR(Status)) {\r
747 Print(L"Please use UEFI SHELL to run this application!\n", Status);\r
748 return Status;\r
749 }\r
750 if (Argc < 2) {\r
751 PrintUsage();\r
752 return EFI_INVALID_PARAMETER;\r
753 }\r
754 if (StrCmp(Argv[1], L"-D") == 0) {\r
755 Status = DumpCapsule(Argv[2]);\r
756 return Status;\r
757 }\r
758 if (StrCmp(Argv[1], L"-G") == 0) {\r
759 Status = CreateBmpFmp();\r
760 return Status;\r
761 }\r
762 if (StrCmp(Argv[1], L"-N") == 0) {\r
763 Status = CreateNestedFmp();\r
764 return Status;\r
765 }\r
766 if (StrCmp(Argv[1], L"-S") == 0) {\r
767 Status = DmpCapsuleStatusVariable();\r
768 return EFI_SUCCESS;\r
769 }\r
770 if (StrCmp(Argv[1], L"-C") == 0) {\r
771 Status = ClearCapsuleStatusVariable();\r
772 return Status;\r
773 }\r
774 if (StrCmp(Argv[1], L"-P") == 0) {\r
1e09ec09
JY
775 if (Argc == 2) {\r
776 DumpFmpData();\r
777 }\r
778 if (Argc >= 3) {\r
779 if (StrCmp(Argv[2], L"GET") == 0) {\r
780 EFI_GUID ImageTypeId;\r
781 UINTN ImageIndex;\r
782 //\r
783 // FMP->GetImage()\r
784 //\r
c608cda5 785 Status = InternalStrToGuid(Argv[3], &ImageTypeId);\r
1e09ec09
JY
786 if (EFI_ERROR(Status)) {\r
787 Print (L"Invalid ImageTypeId - %s\n", Argv[3]);\r
788 return Status;\r
789 }\r
790 ImageIndex = StrDecimalToUintn(Argv[4]);\r
791 if (StrCmp(Argv[5], L"-O") == 0) {\r
792 DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);\r
793 }\r
794 }\r
795 }\r
592bad04
JY
796 return EFI_SUCCESS;\r
797 }\r
798 if (StrCmp(Argv[1], L"-E") == 0) {\r
799 DumpEsrtData();\r
800 return EFI_SUCCESS;\r
801 }\r
802 CapsuleFirstIndex = 1;\r
803 CapsuleLastIndex = Argc - 1;\r
804 CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;\r
805\r
806 if (CapsuleFirstIndex > CapsuleLastIndex) {\r
807 Print(L"CapsuleApp: NO capsule image.\n");\r
808 return EFI_UNSUPPORTED;\r
809 }\r
810 if (CapsuleNum > MAX_CAPSULE_NUM) {\r
811 Print(L"CapsuleApp: Too many capsule images.\n");\r
812 return EFI_UNSUPPORTED;\r
813 }\r
814\r
815 ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));\r
816 ZeroMem(&FileSize, sizeof(FileSize));\r
817 BlockDescriptors = NULL;\r
818\r
819 for (Index = 0; Index < CapsuleNum; Index++) {\r
820 CapsuleName = Argv[CapsuleFirstIndex + Index];\r
821 Status = ReadFileToBuffer(CapsuleName, &FileSize[Index], &CapsuleBuffer[Index]);\r
822 if (EFI_ERROR(Status)) {\r
823 Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);\r
824 goto Done;\r
825 }\r
826 }\r
827\r
828 //\r
829 // Every capsule use 2 descriptor 1 for data 1 for end\r
830 //\r
831 Status = BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, &BlockDescriptors);\r
832 if (EFI_ERROR(Status)) {\r
833 goto Done;\r
834 }\r
835\r
836 //\r
837 // Call the runtime service capsule.\r
838 //\r
839 NeedReset = FALSE;\r
840 for (Index = 0; Index < CapsuleNum; Index++) {\r
841 CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index];\r
842 if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
843 NeedReset = TRUE;\r
844 }\r
845 }\r
846 CapsuleHeaderArray[CapsuleNum] = NULL;\r
847\r
848 //\r
849 // Inquire platform capability of UpdateCapsule.\r
850 //\r
851 Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);\r
852 if (EFI_ERROR(Status)) {\r
853 Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);\r
854 goto Done;\r
855 }\r
856\r
857 for (Index = 0; Index < CapsuleNum; Index++) {\r
858 if (FileSize[Index] > MaxCapsuleSize) {\r
859 Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);\r
860 Status = EFI_UNSUPPORTED;\r
861 goto Done;\r
862 }\r
863 }\r
864\r
865 //\r
866 // Check whether the input capsule image has the flag of persist across system reset.\r
867 //\r
868 if (NeedReset) {\r
869 Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);\r
870 if (Status != EFI_SUCCESS) {\r
871 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
872 goto Done;\r
873 }\r
874 //\r
875 // For capsule who has reset flag, after calling UpdateCapsule service,triger a\r
876 // system reset to process capsule persist across a system reset.\r
877 //\r
878 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
879 } else {\r
880 //\r
881 // For capsule who has no reset flag, only call UpdateCapsule Service without a\r
882 // system reset. The service will process the capsule immediately.\r
883 //\r
884 Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);\r
885 if (Status != EFI_SUCCESS) {\r
886 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
887 }\r
888 }\r
889\r
890 Status = EFI_SUCCESS;\r
891\r
892Done:\r
893 for (Index = 0; Index < CapsuleNum; Index++) {\r
894 if (CapsuleBuffer[Index] != NULL) {\r
895 FreePool (CapsuleBuffer[Index]);\r
896 }\r
897 }\r
898\r
899 CleanGatherList(BlockDescriptors, CapsuleNum);\r
900\r
901 return Status;\r
902}\r