VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c@ 108793

Last change on this file since 108793 was 105670, checked in by vboxsync, 9 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • Property svn:eol-style set to native
File size: 54.4 KB
Line 
1/** @file
2 DXE capsule library.
3
4 Caution: This module requires additional review when modified.
5 This module will have external input - capsule image.
6 This external input must be validated carefully to avoid security issue like
7 buffer overflow, integer overflow.
8
9 SupportCapsuleImage(), ProcessCapsuleImage(), IsValidCapsuleHeader(),
10 ValidateFmpCapsule(), and DisplayCapsuleImage() receives untrusted input and
11 performs basic validation.
12
13 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
14 SPDX-License-Identifier: BSD-2-Clause-Patent
15
16**/
17
18#include <PiDxe.h>
19
20#include <IndustryStandard/WindowsUxCapsule.h>
21
22#include <Guid/FmpCapsule.h>
23#include <Guid/SystemResourceTable.h>
24#include <Guid/EventGroup.h>
25
26#include <Library/BaseLib.h>
27#include <Library/DebugLib.h>
28#include <Library/BaseMemoryLib.h>
29#include <Library/DxeServicesTableLib.h>
30#include <Library/UefiBootServicesTableLib.h>
31#include <Library/UefiRuntimeServicesTableLib.h>
32#include <Library/MemoryAllocationLib.h>
33#include <Library/CapsuleLib.h>
34#include <Library/DevicePathLib.h>
35#include <Library/UefiLib.h>
36#include <Library/BmpSupportLib.h>
37
38#include <Protocol/GraphicsOutput.h>
39#include <Protocol/EsrtManagement.h>
40#include <Protocol/FirmwareManagement.h>
41#include <Protocol/FirmwareManagementProgress.h>
42#include <Protocol/DevicePath.h>
43
44EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable = NULL;
45
46BOOLEAN mDxeCapsuleLibEndOfDxe = FALSE;
47EFI_EVENT mDxeCapsuleLibEndOfDxeEvent = NULL;
48
49EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL *mFmpProgress = NULL;
50
51/**
52 Initialize capsule related variables.
53**/
54VOID
55InitCapsuleVariable (
56 VOID
57 );
58
59/**
60 Record capsule status variable.
61
62 @param[in] CapsuleHeader The capsule image header
63 @param[in] CapsuleStatus The capsule process stauts
64
65 @retval EFI_SUCCESS The capsule status variable is recorded.
66 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
67**/
68EFI_STATUS
69RecordCapsuleStatusVariable (
70 IN EFI_CAPSULE_HEADER *CapsuleHeader,
71 IN EFI_STATUS CapsuleStatus
72 );
73
74/**
75 Record FMP capsule status variable.
76
77 @param[in] CapsuleHeader The capsule image header
78 @param[in] CapsuleStatus The capsule process stauts
79 @param[in] PayloadIndex FMP payload index
80 @param[in] ImageHeader FMP image header
81 @param[in] FmpDevicePath DevicePath associated with the FMP producer
82 @param[in] CapFileName Capsule file name
83
84 @retval EFI_SUCCESS The capsule status variable is recorded.
85 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
86**/
87EFI_STATUS
88RecordFmpCapsuleStatusVariable (
89 IN EFI_CAPSULE_HEADER *CapsuleHeader,
90 IN EFI_STATUS CapsuleStatus,
91 IN UINTN PayloadIndex,
92 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
93 IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL,
94 IN CHAR16 *CapFileName OPTIONAL
95 );
96
97/**
98 Function indicate the current completion progress of the firmware
99 update. Platform may override with own specific progress function.
100
101 @param[in] Completion A value between 1 and 100 indicating the current
102 completion progress of the firmware update
103
104 @retval EFI_SUCESS The capsule update progress was updated.
105 @retval EFI_INVALID_PARAMETER Completion is greater than 100%.
106**/
107EFI_STATUS
108EFIAPI
109UpdateImageProgress (
110 IN UINTN Completion
111 );
112
113/**
114 Return if this capsule is a capsule name capsule, based upon CapsuleHeader.
115
116 @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
117
118 @retval TRUE It is a capsule name capsule.
119 @retval FALSE It is not a capsule name capsule.
120**/
121BOOLEAN
122IsCapsuleNameCapsule (
123 IN EFI_CAPSULE_HEADER *CapsuleHeader
124 )
125{
126 return CompareGuid (&CapsuleHeader->CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);
127}
128
129/**
130 Return if this CapsuleGuid is a FMP capsule GUID or not.
131
132 @param[in] CapsuleGuid A pointer to EFI_GUID
133
134 @retval TRUE It is a FMP capsule GUID.
135 @retval FALSE It is not a FMP capsule GUID.
136**/
137BOOLEAN
138IsFmpCapsuleGuid (
139 IN EFI_GUID *CapsuleGuid
140 )
141{
142 if (CompareGuid (&gEfiFmpCapsuleGuid, CapsuleGuid)) {
143 return TRUE;
144 }
145
146 return FALSE;
147}
148
149/**
150 Validate if it is valid capsule header
151
152 Caution: This function may receive untrusted input.
153
154 This function assumes the caller provided correct CapsuleHeader pointer
155 and CapsuleSize.
156
157 This function validates the fields in EFI_CAPSULE_HEADER.
158
159 @param[in] CapsuleHeader Points to a capsule header.
160 @param[in] CapsuleSize Size of the whole capsule image.
161
162**/
163BOOLEAN
164IsValidCapsuleHeader (
165 IN EFI_CAPSULE_HEADER *CapsuleHeader,
166 IN UINT64 CapsuleSize
167 )
168{
169 if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
170 return FALSE;
171 }
172
173 if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
174 return FALSE;
175 }
176
177 return TRUE;
178}
179
180/**
181 Validate Fmp capsules layout.
182
183 Caution: This function may receive untrusted input.
184
185 This function assumes the caller validated the capsule by using
186 IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
187 The capsule buffer size is CapsuleHeader->CapsuleImageSize.
188
189 This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
190 and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
191
192 This function need support nested FMP capsule.
193
194 @param[in] CapsuleHeader Points to a capsule header.
195 @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.
196
197 @retval EFI_SUCESS Input capsule is a correct FMP capsule.
198 @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.
199**/
200EFI_STATUS
201ValidateFmpCapsule (
202 IN EFI_CAPSULE_HEADER *CapsuleHeader,
203 OUT UINT16 *EmbeddedDriverCount OPTIONAL
204 )
205{
206 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
207 UINT8 *EndOfCapsule;
208 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
209 UINT8 *EndOfPayload;
210 UINT64 *ItemOffsetList;
211 UINT32 ItemNum;
212 UINTN Index;
213 UINTN FmpCapsuleSize;
214 UINTN FmpCapsuleHeaderSize;
215 UINT64 FmpImageSize;
216 UINTN FmpImageHeaderSize;
217
218 if (!IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
219 return ValidateFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), EmbeddedDriverCount);
220 }
221
222 if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
223 DEBUG ((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
224 return EFI_INVALID_PARAMETER;
225 }
226
227 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
228 EndOfCapsule = (UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize;
229 FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;
230
231 if (FmpCapsuleSize < sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {
232 DEBUG ((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));
233 return EFI_INVALID_PARAMETER;
234 }
235
236 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
237 if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
238 DEBUG ((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));
239 return EFI_INVALID_PARAMETER;
240 }
241
242 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
243
244 // No overflow
245 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
246
247 if ((FmpCapsuleSize - sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof (UINT64) < ItemNum) {
248 DEBUG ((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));
249 return EFI_INVALID_PARAMETER;
250 }
251
252 FmpCapsuleHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof (UINT64)*ItemNum;
253
254 // Check ItemOffsetList
255 for (Index = 0; Index < ItemNum; Index++) {
256 if (ItemOffsetList[Index] >= FmpCapsuleSize) {
257 DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));
258 return EFI_INVALID_PARAMETER;
259 }
260
261 if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {
262 DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));
263 return EFI_INVALID_PARAMETER;
264 }
265
266 //
267 // All the address in ItemOffsetList must be stored in ascending order
268 //
269 if (Index > 0) {
270 if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {
271 DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index - 1, ItemOffsetList[Index - 1]));
272 return EFI_INVALID_PARAMETER;
273 }
274 }
275 }
276
277 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
278 for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
279 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
280 if (Index == ItemNum - 1) {
281 EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);
282 } else {
283 EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];
284 }
285
286 FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];
287
288 FmpImageHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);
289 if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||
290 (ImageHeader->Version < 1))
291 {
292 DEBUG ((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));
293 return EFI_INVALID_PARAMETER;
294 }
295
296 if (ImageHeader->Version == 1) {
297 FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
298 } else if (ImageHeader->Version == 2) {
299 FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
300 }
301
302 if (FmpImageSize < FmpImageHeaderSize) {
303 DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) < FmpImageHeaderSize(0x%x)\n", FmpImageSize, FmpImageHeaderSize));
304 return EFI_INVALID_PARAMETER;
305 }
306
307 // No overflow
308 if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {
309 DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));
310 return EFI_INVALID_PARAMETER;
311 }
312 }
313
314 if (ItemNum == 0) {
315 //
316 // No driver & payload element in FMP
317 //
318 EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
319 if (EndOfPayload != EndOfCapsule) {
320 DEBUG ((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));
321 return EFI_INVALID_PARAMETER;
322 }
323
324 return EFI_UNSUPPORTED;
325 }
326
327 if (EmbeddedDriverCount != NULL) {
328 *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;
329 }
330
331 return EFI_SUCCESS;
332}
333
334/**
335 Those capsules supported by the firmwares.
336
337 Caution: This function may receive untrusted input.
338
339 @param[in] CapsuleHeader Points to a capsule header.
340
341 @retval EFI_SUCESS Input capsule is supported by firmware.
342 @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
343**/
344EFI_STATUS
345DisplayCapsuleImage (
346 IN EFI_CAPSULE_HEADER *CapsuleHeader
347 )
348{
349 DISPLAY_DISPLAY_PAYLOAD *ImagePayload;
350 UINTN PayloadSize;
351 EFI_STATUS Status;
352 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
353 UINTN BltSize;
354 UINTN Height;
355 UINTN Width;
356 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
357
358 //
359 // UX capsule doesn't have extended header entries.
360 //
361 if (CapsuleHeader->HeaderSize != sizeof (EFI_CAPSULE_HEADER)) {
362 return EFI_UNSUPPORTED;
363 }
364
365 ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize);
366 //
367 // (CapsuleImageSize > HeaderSize) is guaranteed by IsValidCapsuleHeader().
368 //
369 PayloadSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
370
371 //
372 // Make sure the image payload at least contain the DISPLAY_DISPLAY_PAYLOAD header.
373 // Further size check is performed by the logic translating BMP to GOP BLT.
374 //
375 if (PayloadSize <= sizeof (DISPLAY_DISPLAY_PAYLOAD)) {
376 return EFI_INVALID_PARAMETER;
377 }
378
379 if (ImagePayload->Version != 1) {
380 return EFI_UNSUPPORTED;
381 }
382
383 if (CalculateCheckSum8 ((UINT8 *)CapsuleHeader, CapsuleHeader->CapsuleImageSize) != 0) {
384 return EFI_UNSUPPORTED;
385 }
386
387 //
388 // Only Support Bitmap by now
389 //
390 if (ImagePayload->ImageType != 0) {
391 return EFI_UNSUPPORTED;
392 }
393
394 //
395 // Try to open GOP
396 //
397 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
398 if (EFI_ERROR (Status)) {
399 Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&GraphicsOutput);
400 if (EFI_ERROR (Status)) {
401 return EFI_UNSUPPORTED;
402 }
403 }
404
405 if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) {
406 return EFI_UNSUPPORTED;
407 }
408
409 Blt = NULL;
410 Width = 0;
411 Height = 0;
412 Status = TranslateBmpToGopBlt (
413 ImagePayload + 1,
414 PayloadSize - sizeof (DISPLAY_DISPLAY_PAYLOAD),
415 &Blt,
416 &BltSize,
417 &Height,
418 &Width
419 );
420
421 if (EFI_ERROR (Status)) {
422 return Status;
423 }
424
425 Status = GraphicsOutput->Blt (
426 GraphicsOutput,
427 Blt,
428 EfiBltBufferToVideo,
429 0,
430 0,
431 (UINTN)ImagePayload->OffsetX,
432 (UINTN)ImagePayload->OffsetY,
433 Width,
434 Height,
435 Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
436 );
437
438 FreePool (Blt);
439
440 return Status;
441}
442
443/**
444 Dump FMP information.
445
446 @param[in] ImageInfoSize The size of ImageInfo, in bytes.
447 @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.
448 @param[in] DescriptorVersion The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
449 @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
450 @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.
451 @param[in] PackageVersion The version of package.
452 @param[in] PackageVersionName The version name of package.
453**/
454VOID
455DumpFmpImageInfo (
456 IN UINTN ImageInfoSize,
457 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
458 IN UINT32 DescriptorVersion,
459 IN UINT8 DescriptorCount,
460 IN UINTN DescriptorSize,
461 IN UINT32 PackageVersion,
462 IN CHAR16 *PackageVersionName
463 )
464{
465 EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo;
466 UINTN Index;
467
468 DEBUG ((DEBUG_VERBOSE, " DescriptorVersion - 0x%x\n", DescriptorVersion));
469 DEBUG ((DEBUG_VERBOSE, " DescriptorCount - 0x%x\n", DescriptorCount));
470 DEBUG ((DEBUG_VERBOSE, " DescriptorSize - 0x%x\n", DescriptorSize));
471 DEBUG ((DEBUG_VERBOSE, " PackageVersion - 0x%x\n", PackageVersion));
472 DEBUG ((DEBUG_VERBOSE, " PackageVersionName - %s\n\n", PackageVersionName));
473 CurrentImageInfo = ImageInfo;
474 for (Index = 0; Index < DescriptorCount; Index++) {
475 DEBUG ((DEBUG_VERBOSE, " ImageDescriptor (%d)\n", Index));
476 DEBUG ((DEBUG_VERBOSE, " ImageIndex - 0x%x\n", CurrentImageInfo->ImageIndex));
477 DEBUG ((DEBUG_VERBOSE, " ImageTypeId - %g\n", &CurrentImageInfo->ImageTypeId));
478 DEBUG ((DEBUG_VERBOSE, " ImageId - 0x%lx\n", CurrentImageInfo->ImageId));
479 DEBUG ((DEBUG_VERBOSE, " ImageIdName - %s\n", CurrentImageInfo->ImageIdName));
480 DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", CurrentImageInfo->Version));
481 DEBUG ((DEBUG_VERBOSE, " VersionName - %s\n", CurrentImageInfo->VersionName));
482 DEBUG ((DEBUG_VERBOSE, " Size - 0x%x\n", CurrentImageInfo->Size));
483 DEBUG ((DEBUG_VERBOSE, " AttributesSupported - 0x%lx\n", CurrentImageInfo->AttributesSupported));
484 DEBUG ((DEBUG_VERBOSE, " AttributesSetting - 0x%lx\n", CurrentImageInfo->AttributesSetting));
485 DEBUG ((DEBUG_VERBOSE, " Compatibilities - 0x%lx\n", CurrentImageInfo->Compatibilities));
486 if (DescriptorVersion > 1) {
487 DEBUG ((DEBUG_VERBOSE, " LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion));
488 if (DescriptorVersion > 2) {
489 DEBUG ((DEBUG_VERBOSE, " LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion));
490 DEBUG ((DEBUG_VERBOSE, " LastAttemptStatus - 0x%x\n", CurrentImageInfo->LastAttemptStatus));
491 DEBUG ((DEBUG_VERBOSE, " HardwareInstance - 0x%lx\n", CurrentImageInfo->HardwareInstance));
492 }
493 }
494
495 //
496 // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
497 //
498 CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);
499 }
500}
501
502/**
503 Dump a non-nested FMP capsule.
504
505 @param[in] CapsuleHeader A pointer to CapsuleHeader
506**/
507VOID
508DumpFmpCapsule (
509 IN EFI_CAPSULE_HEADER *CapsuleHeader
510 )
511{
512 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
513 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
514 UINTN Index;
515 UINT64 *ItemOffsetList;
516
517 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
518
519 DEBUG ((DEBUG_VERBOSE, "FmpCapsule:\n"));
520 DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", FmpCapsuleHeader->Version));
521 DEBUG ((DEBUG_VERBOSE, " EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount));
522 DEBUG ((DEBUG_VERBOSE, " PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount));
523
524 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
525 for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
526 DEBUG ((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));
527 }
528
529 for ( ; Index < (UINT32)FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; Index++) {
530 DEBUG ((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));
531 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
532
533 DEBUG ((DEBUG_VERBOSE, " ImageHeader:\n"));
534 DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", ImageHeader->Version));
535 DEBUG ((DEBUG_VERBOSE, " UpdateImageTypeId - %g\n", &ImageHeader->UpdateImageTypeId));
536 DEBUG ((DEBUG_VERBOSE, " UpdateImageIndex - 0x%x\n", ImageHeader->UpdateImageIndex));
537 DEBUG ((DEBUG_VERBOSE, " UpdateImageSize - 0x%x\n", ImageHeader->UpdateImageSize));
538 DEBUG ((DEBUG_VERBOSE, " UpdateVendorCodeSize - 0x%x\n", ImageHeader->UpdateVendorCodeSize));
539 if (ImageHeader->Version >= 2) {
540 DEBUG ((DEBUG_VERBOSE, " UpdateHardwareInstance - 0x%lx\n", ImageHeader->UpdateHardwareInstance));
541 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
542 DEBUG ((DEBUG_VERBOSE, " ImageCapsuleSupport - 0x%lx\n", ImageHeader->ImageCapsuleSupport));
543 }
544 }
545 }
546}
547
548/**
549 Dump all FMP information.
550**/
551VOID
552DumpAllFmpInfo (
553 VOID
554 )
555{
556 EFI_STATUS Status;
557 EFI_HANDLE *HandleBuffer;
558 UINTN NumberOfHandles;
559 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
560 UINTN Index;
561 UINTN ImageInfoSize;
562 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
563 UINT32 FmpImageInfoDescriptorVer;
564 UINT8 FmpImageInfoCount;
565 UINTN DescriptorSize;
566 UINT32 PackageVersion;
567 CHAR16 *PackageVersionName;
568
569 Status = gBS->LocateHandleBuffer (
570 ByProtocol,
571 &gEfiFirmwareManagementProtocolGuid,
572 NULL,
573 &NumberOfHandles,
574 &HandleBuffer
575 );
576 if (EFI_ERROR (Status)) {
577 return;
578 }
579
580 for (Index = 0; Index < NumberOfHandles; Index++) {
581 Status = gBS->HandleProtocol (
582 HandleBuffer[Index],
583 &gEfiFirmwareManagementProtocolGuid,
584 (VOID **)&Fmp
585 );
586 if (EFI_ERROR (Status)) {
587 continue;
588 }
589
590 ImageInfoSize = 0;
591 Status = Fmp->GetImageInfo (
592 Fmp,
593 &ImageInfoSize,
594 NULL,
595 NULL,
596 NULL,
597 NULL,
598 NULL,
599 NULL
600 );
601 if (Status != EFI_BUFFER_TOO_SMALL) {
602 continue;
603 }
604
605 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
606 if (FmpImageInfoBuf == NULL) {
607 continue;
608 }
609
610 PackageVersionName = NULL;
611 Status = Fmp->GetImageInfo (
612 Fmp,
613 &ImageInfoSize, // ImageInfoSize
614 FmpImageInfoBuf, // ImageInfo
615 &FmpImageInfoDescriptorVer, // DescriptorVersion
616 &FmpImageInfoCount, // DescriptorCount
617 &DescriptorSize, // DescriptorSize
618 &PackageVersion, // PackageVersion
619 &PackageVersionName // PackageVersionName
620 );
621 if (EFI_ERROR (Status)) {
622 FreePool (FmpImageInfoBuf);
623 continue;
624 }
625
626 DEBUG ((DEBUG_INFO, "FMP (%d) ImageInfo:\n", Index));
627 DumpFmpImageInfo (
628 ImageInfoSize, // ImageInfoSize
629 FmpImageInfoBuf, // ImageInfo
630 FmpImageInfoDescriptorVer, // DescriptorVersion
631 FmpImageInfoCount, // DescriptorCount
632 DescriptorSize, // DescriptorSize
633 PackageVersion, // PackageVersion
634 PackageVersionName // PackageVersionName
635 );
636
637 if (PackageVersionName != NULL) {
638 FreePool (PackageVersionName);
639 }
640
641 FreePool (FmpImageInfoBuf);
642 }
643
644 FreePool (HandleBuffer);
645
646 return;
647}
648
649/**
650 Get FMP handle by ImageTypeId and HardwareInstance.
651
652 @param[in] UpdateImageTypeId Used to identify device firmware targeted by this update.
653 @param[in] UpdateHardwareInstance The HardwareInstance to target with this update.
654 @param[out] NoHandles The number of handles returned in HandleBuf.
655 @param[out] HandleBuf A pointer to the buffer to return the requested array of handles.
656 @param[out] ResetRequiredBuf A pointer to the buffer to return reset required flag for
657 the requested array of handles.
658
659 @retval EFI_SUCCESS The array of handles and their reset required flag were returned in
660 HandleBuf and ResetRequiredBuf, and the number of handles in HandleBuf
661 was returned in NoHandles.
662 @retval EFI_NOT_FOUND No handles match the search.
663 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
664**/
665EFI_STATUS
666GetFmpHandleBufferByType (
667 IN EFI_GUID *UpdateImageTypeId,
668 IN UINT64 UpdateHardwareInstance,
669 OUT UINTN *NoHandles OPTIONAL,
670 OUT EFI_HANDLE **HandleBuf OPTIONAL,
671 OUT BOOLEAN **ResetRequiredBuf OPTIONAL
672 )
673{
674 EFI_STATUS Status;
675 EFI_HANDLE *HandleBuffer;
676 UINTN NumberOfHandles;
677 EFI_HANDLE *MatchedHandleBuffer;
678 BOOLEAN *MatchedResetRequiredBuffer;
679 UINTN MatchedNumberOfHandles;
680 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
681 UINTN Index;
682 UINTN ImageInfoSize;
683 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
684 UINT32 FmpImageInfoDescriptorVer;
685 UINT8 FmpImageInfoCount;
686 UINTN DescriptorSize;
687 UINT32 PackageVersion;
688 CHAR16 *PackageVersionName;
689 UINTN Index2;
690 EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;
691
692 if (NoHandles != NULL) {
693 *NoHandles = 0;
694 }
695
696 if (HandleBuf != NULL) {
697 *HandleBuf = NULL;
698 }
699
700 if (ResetRequiredBuf != NULL) {
701 *ResetRequiredBuf = NULL;
702 }
703
704 Status = gBS->LocateHandleBuffer (
705 ByProtocol,
706 &gEfiFirmwareManagementProtocolGuid,
707 NULL,
708 &NumberOfHandles,
709 &HandleBuffer
710 );
711 if (EFI_ERROR (Status)) {
712 return Status;
713 }
714
715 MatchedNumberOfHandles = 0;
716
717 MatchedHandleBuffer = NULL;
718 if (HandleBuf != NULL) {
719 MatchedHandleBuffer = AllocateZeroPool (sizeof (EFI_HANDLE) * NumberOfHandles);
720 if (MatchedHandleBuffer == NULL) {
721 FreePool (HandleBuffer);
722 return EFI_OUT_OF_RESOURCES;
723 }
724 }
725
726 MatchedResetRequiredBuffer = NULL;
727 if (ResetRequiredBuf != NULL) {
728 MatchedResetRequiredBuffer = AllocateZeroPool (sizeof (BOOLEAN) * NumberOfHandles);
729 if (MatchedResetRequiredBuffer == NULL) {
730 if (MatchedHandleBuffer != NULL) {
731 FreePool (MatchedHandleBuffer);
732 }
733
734 FreePool (HandleBuffer);
735 return EFI_OUT_OF_RESOURCES;
736 }
737 }
738
739 for (Index = 0; Index < NumberOfHandles; Index++) {
740 Status = gBS->HandleProtocol (
741 HandleBuffer[Index],
742 &gEfiFirmwareManagementProtocolGuid,
743 (VOID **)&Fmp
744 );
745 if (EFI_ERROR (Status)) {
746 continue;
747 }
748
749 ImageInfoSize = 0;
750 Status = Fmp->GetImageInfo (
751 Fmp,
752 &ImageInfoSize,
753 NULL,
754 NULL,
755 NULL,
756 NULL,
757 NULL,
758 NULL
759 );
760 if (Status != EFI_BUFFER_TOO_SMALL) {
761 continue;
762 }
763
764 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
765 if (FmpImageInfoBuf == NULL) {
766 continue;
767 }
768
769 PackageVersionName = NULL;
770 Status = Fmp->GetImageInfo (
771 Fmp,
772 &ImageInfoSize, // ImageInfoSize
773 FmpImageInfoBuf, // ImageInfo
774 &FmpImageInfoDescriptorVer, // DescriptorVersion
775 &FmpImageInfoCount, // DescriptorCount
776 &DescriptorSize, // DescriptorSize
777 &PackageVersion, // PackageVersion
778 &PackageVersionName // PackageVersionName
779 );
780 if (EFI_ERROR (Status)) {
781 FreePool (FmpImageInfoBuf);
782 continue;
783 }
784
785 if (PackageVersionName != NULL) {
786 FreePool (PackageVersionName);
787 }
788
789 TempFmpImageInfo = FmpImageInfoBuf;
790 for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {
791 //
792 // Check if this FMP instance matches
793 //
794 if (CompareGuid (UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) {
795 if ((UpdateHardwareInstance == 0) ||
796 ((FmpImageInfoDescriptorVer >= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) &&
797 (UpdateHardwareInstance == TempFmpImageInfo->HardwareInstance)))
798 {
799 if (MatchedHandleBuffer != NULL) {
800 MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];
801 }
802
803 if (MatchedResetRequiredBuffer != NULL) {
804 MatchedResetRequiredBuffer[MatchedNumberOfHandles] = (((TempFmpImageInfo->AttributesSupported &
805 IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0) &&
806 ((TempFmpImageInfo->AttributesSetting &
807 IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0));
808 }
809
810 MatchedNumberOfHandles++;
811 break;
812 }
813 }
814
815 TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);
816 }
817
818 FreePool (FmpImageInfoBuf);
819 }
820
821 FreePool (HandleBuffer);
822
823 if (MatchedNumberOfHandles == 0) {
824 return EFI_NOT_FOUND;
825 }
826
827 if (NoHandles != NULL) {
828 *NoHandles = MatchedNumberOfHandles;
829 }
830
831 if (HandleBuf != NULL) {
832 *HandleBuf = MatchedHandleBuffer;
833 }
834
835 if (ResetRequiredBuf != NULL) {
836 *ResetRequiredBuf = MatchedResetRequiredBuffer;
837 }
838
839 return EFI_SUCCESS;
840}
841
842/**
843 Return FmpImageInfoDescriptorVer by an FMP handle.
844
845 @param[in] Handle A FMP handle.
846
847 @return FmpImageInfoDescriptorVer associated with the FMP.
848**/
849UINT32
850GetFmpImageInfoDescriptorVer (
851 IN EFI_HANDLE Handle
852 )
853{
854 EFI_STATUS Status;
855 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
856 UINTN ImageInfoSize;
857 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
858 UINT32 FmpImageInfoDescriptorVer;
859 UINT8 FmpImageInfoCount;
860 UINTN DescriptorSize;
861 UINT32 PackageVersion;
862 CHAR16 *PackageVersionName;
863
864 Status = gBS->HandleProtocol (
865 Handle,
866 &gEfiFirmwareManagementProtocolGuid,
867 (VOID **)&Fmp
868 );
869 if (EFI_ERROR (Status)) {
870 return 0;
871 }
872
873 ImageInfoSize = 0;
874 Status = Fmp->GetImageInfo (
875 Fmp,
876 &ImageInfoSize,
877 NULL,
878 NULL,
879 NULL,
880 NULL,
881 NULL,
882 NULL
883 );
884 if (Status != EFI_BUFFER_TOO_SMALL) {
885 return 0;
886 }
887
888 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
889 if (FmpImageInfoBuf == NULL) {
890 return 0;
891 }
892
893 PackageVersionName = NULL;
894 Status = Fmp->GetImageInfo (
895 Fmp,
896 &ImageInfoSize, // ImageInfoSize
897 FmpImageInfoBuf, // ImageInfo
898 &FmpImageInfoDescriptorVer, // DescriptorVersion
899 &FmpImageInfoCount, // DescriptorCount
900 &DescriptorSize, // DescriptorSize
901 &PackageVersion, // PackageVersion
902 &PackageVersionName // PackageVersionName
903 );
904 if (EFI_ERROR (Status)) {
905 FreePool (FmpImageInfoBuf);
906 return 0;
907 }
908
909 return FmpImageInfoDescriptorVer;
910}
911
912/**
913 Set FMP image data.
914
915 @param[in] Handle A FMP handle.
916 @param[in] ImageHeader The payload image header.
917 @param[in] PayloadIndex The index of the payload.
918
919 @return The status of FMP->SetImage.
920**/
921EFI_STATUS
922SetFmpImageData (
923 IN EFI_HANDLE Handle,
924 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
925 IN UINTN PayloadIndex
926 )
927{
928 EFI_STATUS Status;
929 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
930 UINT8 *Image;
931 VOID *VendorCode;
932 CHAR16 *AbortReason;
933 EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS ProgressCallback;
934
935 Status = gBS->HandleProtocol (
936 Handle,
937 &gEfiFirmwareManagementProtocolGuid,
938 (VOID **)&Fmp
939 );
940 if (EFI_ERROR (Status)) {
941 return Status;
942 }
943
944 //
945 // Lookup Firmware Management Progress Protocol before SetImage() is called
946 // This is an optional protocol that may not be present on Handle.
947 //
948 Status = gBS->HandleProtocol (
949 Handle,
950 &gEdkiiFirmwareManagementProgressProtocolGuid,
951 (VOID **)&mFmpProgress
952 );
953 if (EFI_ERROR (Status)) {
954 mFmpProgress = NULL;
955 }
956
957 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
958 Image = (UINT8 *)(ImageHeader + 1);
959 } else {
960 //
961 // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1,
962 // Header should exclude UpdateHardwareInstance field, and
963 // ImageCapsuleSupport field if version is 2.
964 //
965 if (ImageHeader->Version == 1) {
966 Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
967 } else {
968 Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
969 }
970 }
971
972 if (ImageHeader->UpdateVendorCodeSize == 0) {
973 VendorCode = NULL;
974 } else {
975 VendorCode = Image + ImageHeader->UpdateImageSize;
976 }
977
978 AbortReason = NULL;
979 DEBUG ((DEBUG_INFO, "Fmp->SetImage ...\n"));
980 DEBUG ((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId));
981 DEBUG ((DEBUG_INFO, "PayloadIndex - 0x%x, ", PayloadIndex));
982 DEBUG ((DEBUG_INFO, "ImageIndex - 0x%x ", ImageHeader->UpdateImageIndex));
983 if (ImageHeader->Version >= 2) {
984 DEBUG ((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance));
985 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
986 DEBUG ((DEBUG_INFO, "(ImageCapsuleSupport - 0x%x)", ImageHeader->ImageCapsuleSupport));
987 }
988 }
989
990 DEBUG ((DEBUG_INFO, "\n"));
991
992 //
993 // Before calling SetImage(), reset the progress bar to 0%
994 //
995 ProgressCallback = UpdateImageProgress;
996 Status = UpdateImageProgress (0);
997 if (EFI_ERROR (Status)) {
998 ProgressCallback = NULL;
999 }
1000
1001 Status = Fmp->SetImage (
1002 Fmp,
1003 ImageHeader->UpdateImageIndex, // ImageIndex
1004 Image, // Image
1005 ImageHeader->UpdateImageSize, // ImageSize
1006 VendorCode, // VendorCode
1007 ProgressCallback, // Progress
1008 &AbortReason // AbortReason
1009 );
1010 //
1011 // Set the progress bar to 100% after returning from SetImage()
1012 //
1013 if (ProgressCallback != NULL) {
1014 UpdateImageProgress (100);
1015 }
1016
1017 DEBUG ((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));
1018 if (AbortReason != NULL) {
1019 DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));
1020 FreePool (AbortReason);
1021 }
1022
1023 //
1024 // Clear mFmpProgress after SetImage() returns
1025 //
1026 mFmpProgress = NULL;
1027
1028 return Status;
1029}
1030
1031/**
1032 Start a UEFI image in the FMP payload.
1033
1034 @param[in] ImageBuffer A pointer to the memory location containing a copy of the image to be loaded..
1035 @param[in] ImageSize The size in bytes of ImageBuffer.
1036
1037 @return The status of gBS->LoadImage and gBS->StartImage.
1038**/
1039EFI_STATUS
1040StartFmpImage (
1041 IN VOID *ImageBuffer,
1042 IN UINTN ImageSize
1043 )
1044{
1045 MEMMAP_DEVICE_PATH MemMapNode;
1046 EFI_STATUS Status;
1047 EFI_HANDLE ImageHandle;
1048 EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
1049 UINTN ExitDataSize;
1050
1051 SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));
1052 MemMapNode.Header.Type = HARDWARE_DEVICE_PATH;
1053 MemMapNode.Header.SubType = HW_MEMMAP_DP;
1054 MemMapNode.MemoryType = EfiBootServicesCode;
1055 MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBuffer;
1056 MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)ImageBuffer + ImageSize - 1);
1057
1058 DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);
1059 if (DriverDevicePath == NULL) {
1060 return EFI_OUT_OF_RESOURCES;
1061 }
1062
1063 DEBUG ((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));
1064 Status = gBS->LoadImage (
1065 FALSE,
1066 gImageHandle,
1067 DriverDevicePath,
1068 ImageBuffer,
1069 ImageSize,
1070 &ImageHandle
1071 );
1072 DEBUG ((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));
1073 if (EFI_ERROR (Status)) {
1074 //
1075 // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
1076 // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
1077 // If the caller doesn't have the option to defer the execution of an image, we should
1078 // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
1079 //
1080 if (Status == EFI_SECURITY_VIOLATION) {
1081 gBS->UnloadImage (ImageHandle);
1082 }
1083
1084 FreePool (DriverDevicePath);
1085 return Status;
1086 }
1087
1088 DEBUG ((DEBUG_INFO, "FmpCapsule: StartImage ...\n"));
1089 Status = gBS->StartImage (
1090 ImageHandle,
1091 &ExitDataSize,
1092 NULL
1093 );
1094 DEBUG ((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status));
1095 if (EFI_ERROR (Status)) {
1096 DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
1097 }
1098
1099 FreePool (DriverDevicePath);
1100 return Status;
1101}
1102
1103/**
1104 Record FMP capsule status.
1105
1106 @param[in] Handle A FMP handle.
1107 @param[in] CapsuleHeader The capsule image header
1108 @param[in] CapsuleStatus The capsule process stauts
1109 @param[in] PayloadIndex FMP payload index
1110 @param[in] ImageHeader FMP image header
1111 @param[in] CapFileName Capsule file name
1112**/
1113VOID
1114RecordFmpCapsuleStatus (
1115 IN EFI_HANDLE Handle OPTIONAL,
1116 IN EFI_CAPSULE_HEADER *CapsuleHeader,
1117 IN EFI_STATUS CapsuleStatus,
1118 IN UINTN PayloadIndex,
1119 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
1120 IN CHAR16 *CapFileName OPTIONAL
1121 )
1122{
1123 EFI_STATUS Status;
1124 EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath;
1125 UINT32 FmpImageInfoDescriptorVer;
1126 EFI_STATUS StatusEsrt;
1127 ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;
1128 EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry;
1129
1130 FmpDevicePath = NULL;
1131 if (Handle != NULL) {
1132 gBS->HandleProtocol (
1133 Handle,
1134 &gEfiDevicePathProtocolGuid,
1135 (VOID **)&FmpDevicePath
1136 );
1137 }
1138
1139 RecordFmpCapsuleStatusVariable (
1140 CapsuleHeader,
1141 CapsuleStatus,
1142 PayloadIndex,
1143 ImageHeader,
1144 FmpDevicePath,
1145 CapFileName
1146 );
1147
1148 //
1149 // Update corresponding ESRT entry LastAttemp Status
1150 //
1151 Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
1152 if (EFI_ERROR (Status)) {
1153 return;
1154 }
1155
1156 if (Handle == NULL) {
1157 return;
1158 }
1159
1160 //
1161 // Update EsrtEntry For V1, V2 FMP instance.
1162 // V3 FMP ESRT cache will be synced up through SyncEsrtFmp interface
1163 //
1164 FmpImageInfoDescriptorVer = GetFmpImageInfoDescriptorVer (Handle);
1165 if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) {
1166 StatusEsrt = EsrtProtocol->GetEsrtEntry (&ImageHeader->UpdateImageTypeId, &EsrtEntry);
1167 if (!EFI_ERROR (StatusEsrt)) {
1168 if (!EFI_ERROR (CapsuleStatus)) {
1169 EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
1170 } else {
1171 EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
1172 }
1173
1174 EsrtEntry.LastAttemptVersion = 0;
1175 EsrtProtocol->UpdateEsrtEntry (&EsrtEntry);
1176 }
1177 }
1178}
1179
1180/**
1181 Process Firmware management protocol data capsule.
1182
1183 This function assumes the caller validated the capsule by using
1184 ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
1185 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
1186 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
1187
1188 This function need support nested FMP capsule.
1189
1190 @param[in] CapsuleHeader Points to a capsule header.
1191 @param[in] CapFileName Capsule file name.
1192 @param[out] ResetRequired Indicates whether reset is required or not.
1193
1194 @retval EFI_SUCESS Process Capsule Image successfully.
1195 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
1196 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
1197 @retval EFI_OUT_OF_RESOURCES Not enough memory.
1198 @retval EFI_NOT_READY No FMP protocol to handle this FMP capsule.
1199**/
1200EFI_STATUS
1201ProcessFmpCapsuleImage (
1202 IN EFI_CAPSULE_HEADER *CapsuleHeader,
1203 IN CHAR16 *CapFileName OPTIONAL,
1204 OUT BOOLEAN *ResetRequired OPTIONAL
1205 )
1206{
1207 EFI_STATUS Status;
1208 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
1209 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
1210 UINT64 *ItemOffsetList;
1211 UINT32 ItemNum;
1212 UINTN Index;
1213 EFI_HANDLE *HandleBuffer;
1214 BOOLEAN *ResetRequiredBuffer;
1215 UINTN NumberOfHandles;
1216 UINTN DriverLen;
1217 UINT64 UpdateHardwareInstance;
1218 UINTN Index2;
1219 BOOLEAN NotReady;
1220 BOOLEAN Abort;
1221
1222 if (!IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
1223 return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), CapFileName, ResetRequired);
1224 }
1225
1226 NotReady = FALSE;
1227 Abort = FALSE;
1228
1229 DumpFmpCapsule (CapsuleHeader);
1230
1231 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
1232
1233 if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
1234 return EFI_INVALID_PARAMETER;
1235 }
1236
1237 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
1238
1239 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
1240
1241 //
1242 // capsule in which driver count and payload count are both zero is not processed.
1243 //
1244 if (ItemNum == 0) {
1245 return EFI_SUCCESS;
1246 }
1247
1248 //
1249 // 1. Try to load & start all the drivers within capsule
1250 //
1251 for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
1252 if ((FmpCapsuleHeader->PayloadItemCount == 0) &&
1253 (Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1))
1254 {
1255 //
1256 // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER
1257 //
1258 DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];
1259 } else {
1260 DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];
1261 }
1262
1263 Status = StartFmpImage (
1264 (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],
1265 DriverLen
1266 );
1267 if (EFI_ERROR (Status)) {
1268 DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
1269 return Status;
1270 }
1271 }
1272
1273 //
1274 // 2. Route payload to right FMP instance
1275 //
1276 DEBUG ((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n"));
1277
1278 DumpAllFmpInfo ();
1279
1280 //
1281 // Check all the payload entry in capsule payload list
1282 //
1283 for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
1284 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
1285
1286 UpdateHardwareInstance = 0;
1287 ///
1288 /// UpdateHardwareInstance field was added in Version 2
1289 ///
1290 if (ImageHeader->Version >= 2) {
1291 UpdateHardwareInstance = ImageHeader->UpdateHardwareInstance;
1292 }
1293
1294 Status = GetFmpHandleBufferByType (
1295 &ImageHeader->UpdateImageTypeId,
1296 UpdateHardwareInstance,
1297 &NumberOfHandles,
1298 &HandleBuffer,
1299 &ResetRequiredBuffer
1300 );
1301 if (EFI_ERROR (Status) ||
1302 (HandleBuffer == NULL) ||
1303 (ResetRequiredBuffer == NULL))
1304 {
1305 NotReady = TRUE;
1306 RecordFmpCapsuleStatus (
1307 NULL,
1308 CapsuleHeader,
1309 EFI_NOT_READY,
1310 Index - FmpCapsuleHeader->EmbeddedDriverCount,
1311 ImageHeader,
1312 CapFileName
1313 );
1314 continue;
1315 }
1316
1317 for (Index2 = 0; Index2 < NumberOfHandles; Index2++) {
1318 if (Abort) {
1319 RecordFmpCapsuleStatus (
1320 HandleBuffer[Index2],
1321 CapsuleHeader,
1322 EFI_ABORTED,
1323 Index - FmpCapsuleHeader->EmbeddedDriverCount,
1324 ImageHeader,
1325 CapFileName
1326 );
1327 continue;
1328 }
1329
1330 Status = SetFmpImageData (
1331 HandleBuffer[Index2],
1332 ImageHeader,
1333 Index - FmpCapsuleHeader->EmbeddedDriverCount
1334 );
1335 if (Status != EFI_SUCCESS) {
1336 Abort = TRUE;
1337 } else {
1338 if (ResetRequired != NULL) {
1339 *ResetRequired |= ResetRequiredBuffer[Index2];
1340 }
1341 }
1342
1343 RecordFmpCapsuleStatus (
1344 HandleBuffer[Index2],
1345 CapsuleHeader,
1346 Status,
1347 Index - FmpCapsuleHeader->EmbeddedDriverCount,
1348 ImageHeader,
1349 CapFileName
1350 );
1351 }
1352
1353 if (HandleBuffer != NULL) {
1354 FreePool (HandleBuffer);
1355 }
1356
1357 if (ResetRequiredBuffer != NULL) {
1358 FreePool (ResetRequiredBuffer);
1359 }
1360 }
1361
1362 if (NotReady) {
1363 return EFI_NOT_READY;
1364 }
1365
1366 //
1367 // always return SUCCESS to indicate this capsule is processed.
1368 // The status of SetImage is recorded in capsule result variable.
1369 //
1370 return EFI_SUCCESS;
1371}
1372
1373/**
1374 Return if there is a FMP header below capsule header.
1375
1376 @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
1377
1378 @retval TRUE There is a FMP header below capsule header.
1379 @retval FALSE There is not a FMP header below capsule header
1380**/
1381BOOLEAN
1382IsNestedFmpCapsule (
1383 IN EFI_CAPSULE_HEADER *CapsuleHeader
1384 )
1385{
1386 EFI_STATUS Status;
1387 EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;
1388 UINTN Index;
1389 BOOLEAN EsrtGuidFound;
1390 EFI_CAPSULE_HEADER *NestedCapsuleHeader;
1391 UINTN NestedCapsuleSize;
1392 ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;
1393 EFI_SYSTEM_RESOURCE_ENTRY Entry;
1394
1395 EsrtGuidFound = FALSE;
1396 if (mEsrtTable != NULL) {
1397 EsrtEntry = (EFI_SYSTEM_RESOURCE_ENTRY *)(mEsrtTable + 1);
1398 for (Index = 0; Index < mEsrtTable->FwResourceCount; Index++, EsrtEntry++) {
1399 if (CompareGuid (&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {
1400 EsrtGuidFound = TRUE;
1401 break;
1402 }
1403 }
1404 } else {
1405 //
1406 // Check ESRT protocol
1407 //
1408 Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
1409 if (!EFI_ERROR (Status)) {
1410 Status = EsrtProtocol->GetEsrtEntry (&CapsuleHeader->CapsuleGuid, &Entry);
1411 if (!EFI_ERROR (Status)) {
1412 EsrtGuidFound = TRUE;
1413 }
1414 }
1415
1416 //
1417 // Check Firmware Management Protocols
1418 //
1419 if (!EsrtGuidFound) {
1420 Status = GetFmpHandleBufferByType (
1421 &CapsuleHeader->CapsuleGuid,
1422 0,
1423 NULL,
1424 NULL,
1425 NULL
1426 );
1427 if (!EFI_ERROR (Status)) {
1428 EsrtGuidFound = TRUE;
1429 }
1430 }
1431 }
1432
1433 if (!EsrtGuidFound) {
1434 return FALSE;
1435 }
1436
1437 //
1438 // Check nested capsule header
1439 // FMP GUID after ESRT one
1440 //
1441 NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
1442 NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize - (UINTN)NestedCapsuleHeader;
1443 if (NestedCapsuleSize < sizeof (EFI_CAPSULE_HEADER)) {
1444 return FALSE;
1445 }
1446
1447 if (!IsValidCapsuleHeader (NestedCapsuleHeader, NestedCapsuleSize)) {
1448 return FALSE;
1449 }
1450
1451 if (!IsFmpCapsuleGuid (&NestedCapsuleHeader->CapsuleGuid)) {
1452 return FALSE;
1453 }
1454
1455 DEBUG ((DEBUG_INFO, "IsNestedFmpCapsule\n"));
1456 return TRUE;
1457}
1458
1459/**
1460 Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.
1461
1462 @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
1463
1464 @retval TRUE It is a system FMP.
1465 @retval FALSE It is a device FMP.
1466**/
1467BOOLEAN
1468IsFmpCapsule (
1469 IN EFI_CAPSULE_HEADER *CapsuleHeader
1470 )
1471{
1472 if (IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
1473 return TRUE;
1474 }
1475
1476 if (IsNestedFmpCapsule (CapsuleHeader)) {
1477 return TRUE;
1478 }
1479
1480 return FALSE;
1481}
1482
1483/**
1484 Those capsules supported by the firmwares.
1485
1486 Caution: This function may receive untrusted input.
1487
1488 @param[in] CapsuleHeader Points to a capsule header.
1489
1490 @retval EFI_SUCESS Input capsule is supported by firmware.
1491 @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
1492 @retval EFI_INVALID_PARAMETER Input capsule layout is not correct
1493**/
1494EFI_STATUS
1495EFIAPI
1496SupportCapsuleImage (
1497 IN EFI_CAPSULE_HEADER *CapsuleHeader
1498 )
1499{
1500 //
1501 // check Display Capsule Guid
1502 //
1503 if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
1504 return EFI_SUCCESS;
1505 }
1506
1507 //
1508 // Check capsule file name capsule
1509 //
1510 if (IsCapsuleNameCapsule (CapsuleHeader)) {
1511 return EFI_SUCCESS;
1512 }
1513
1514 if (IsFmpCapsule (CapsuleHeader)) {
1515 //
1516 // Fake capsule header is valid case in QueryCapsuleCpapbilities().
1517 //
1518 if (CapsuleHeader->HeaderSize == CapsuleHeader->CapsuleImageSize) {
1519 return EFI_SUCCESS;
1520 }
1521
1522 //
1523 // Check layout of FMP capsule
1524 //
1525 return ValidateFmpCapsule (CapsuleHeader, NULL);
1526 }
1527
1528 DEBUG ((DEBUG_ERROR, "Unknown Capsule Guid - %g\n", &CapsuleHeader->CapsuleGuid));
1529 return EFI_UNSUPPORTED;
1530}
1531
1532/**
1533 The firmware implements to process the capsule image.
1534
1535 Caution: This function may receive untrusted input.
1536
1537 @param[in] CapsuleHeader Points to a capsule header.
1538 @param[in] CapFileName Capsule file name.
1539 @param[out] ResetRequired Indicates whether reset is required or not.
1540
1541 @retval EFI_SUCESS Process Capsule Image successfully.
1542 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
1543 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
1544 @retval EFI_OUT_OF_RESOURCES Not enough memory.
1545**/
1546EFI_STATUS
1547EFIAPI
1548ProcessThisCapsuleImage (
1549 IN EFI_CAPSULE_HEADER *CapsuleHeader,
1550 IN CHAR16 *CapFileName OPTIONAL,
1551 OUT BOOLEAN *ResetRequired OPTIONAL
1552 )
1553{
1554 EFI_STATUS Status;
1555
1556 if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
1557 RecordCapsuleStatusVariable (CapsuleHeader, EFI_UNSUPPORTED);
1558 return EFI_UNSUPPORTED;
1559 }
1560
1561 //
1562 // Display image in firmware update display capsule
1563 //
1564 if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
1565 DEBUG ((DEBUG_INFO, "ProcessCapsuleImage for WindowsUxCapsule ...\n"));
1566 Status = DisplayCapsuleImage (CapsuleHeader);
1567 RecordCapsuleStatusVariable (CapsuleHeader, Status);
1568 return Status;
1569 }
1570
1571 //
1572 // Check FMP capsule layout
1573 //
1574 if (IsFmpCapsule (CapsuleHeader)) {
1575 DEBUG ((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));
1576 DEBUG ((DEBUG_INFO, "ValidateFmpCapsule ...\n"));
1577 Status = ValidateFmpCapsule (CapsuleHeader, NULL);
1578 DEBUG ((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));
1579 if (EFI_ERROR (Status)) {
1580 RecordCapsuleStatusVariable (CapsuleHeader, Status);
1581 return Status;
1582 }
1583
1584 //
1585 // Process EFI FMP Capsule
1586 //
1587 DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
1588 Status = ProcessFmpCapsuleImage (CapsuleHeader, CapFileName, ResetRequired);
1589 DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
1590
1591 return Status;
1592 }
1593
1594 return EFI_UNSUPPORTED;
1595}
1596
1597/**
1598 The firmware implements to process the capsule image.
1599
1600 Caution: This function may receive untrusted input.
1601
1602 @param[in] CapsuleHeader Points to a capsule header.
1603
1604 @retval EFI_SUCESS Process Capsule Image successfully.
1605 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
1606 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
1607 @retval EFI_OUT_OF_RESOURCES Not enough memory.
1608**/
1609EFI_STATUS
1610EFIAPI
1611ProcessCapsuleImage (
1612 IN EFI_CAPSULE_HEADER *CapsuleHeader
1613 )
1614{
1615 return ProcessThisCapsuleImage (CapsuleHeader, NULL, NULL);
1616}
1617
1618/**
1619 Callback function executed when the EndOfDxe event group is signaled.
1620
1621 @param[in] Event Event whose notification function is being invoked.
1622 @param[in] Context The pointer to the notification function's context, which
1623 is implementation-dependent.
1624**/
1625VOID
1626EFIAPI
1627DxeCapsuleLibEndOfDxe (
1628 IN EFI_EVENT Event,
1629 IN VOID *Context
1630 )
1631{
1632 mDxeCapsuleLibEndOfDxe = TRUE;
1633}
1634
1635/**
1636 The constructor function.
1637
1638 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1639 @param[in] SystemTable A pointer to the EFI System Table.
1640
1641 @retval EFI_SUCCESS The constructor successfully .
1642**/
1643EFI_STATUS
1644EFIAPI
1645DxeCapsuleLibConstructor (
1646 IN EFI_HANDLE ImageHandle,
1647 IN EFI_SYSTEM_TABLE *SystemTable
1648 )
1649{
1650 EFI_STATUS Status;
1651
1652 Status = gBS->CreateEventEx (
1653 EVT_NOTIFY_SIGNAL,
1654 TPL_CALLBACK,
1655 DxeCapsuleLibEndOfDxe,
1656 NULL,
1657 &gEfiEndOfDxeEventGroupGuid,
1658 &mDxeCapsuleLibEndOfDxeEvent
1659 );
1660 ASSERT_EFI_ERROR (Status);
1661
1662 InitCapsuleVariable ();
1663
1664 return EFI_SUCCESS;
1665}
1666
1667/**
1668 The destructor function closes the End of DXE event.
1669
1670 @param ImageHandle The firmware allocated handle for the EFI image.
1671 @param SystemTable A pointer to the EFI System Table.
1672
1673 @retval EFI_SUCCESS The destructor completed successfully.
1674**/
1675EFI_STATUS
1676EFIAPI
1677DxeCapsuleLibDestructor (
1678 IN EFI_HANDLE ImageHandle,
1679 IN EFI_SYSTEM_TABLE *SystemTable
1680 )
1681{
1682 EFI_STATUS Status;
1683
1684 //
1685 // Close the End of DXE event.
1686 //
1687 Status = gBS->CloseEvent (mDxeCapsuleLibEndOfDxeEvent);
1688 ASSERT_EFI_ERROR (Status);
1689
1690 return EFI_SUCCESS;
1691}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette