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