2 Publishes ESRT table from Firmware Management Protocol instances
4 Copyright (c) 2016, Microsoft Corporation
5 Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10 1. Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
20 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
24 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <Library/BaseLib.h>
31 #include <Library/BaseMemoryLib.h>
32 #include <Library/MemoryAllocationLib.h>
33 #include <Library/UefiBootServicesTableLib.h>
34 #include <Library/DebugLib.h>
35 #include <Library/PcdLib.h>
36 #include <Library/UefiLib.h>
37 #include <Protocol/FirmwareManagement.h>
38 #include <Guid/EventGroup.h>
39 #include <Guid/SystemResourceTable.h>
42 // Print ESRT to debug console
47 IN EFI_SYSTEM_RESOURCE_TABLE
*Table
51 // Number of ESRT entries to grow by each time we run out of room
53 #define GROWTH_STEP 10
58 EFI_EVENT mEsrtReadyToBootEvent
;
59 EFI_SYSTEM_RESOURCE_TABLE
*mTable
= NULL
;
60 BOOLEAN mEsrtInstalled
= FALSE
;
61 EFI_EVENT mFmpInstallEvent
;
62 VOID
*mFmpInstallEventRegistration
= NULL
;
65 Install EFI System Resource Table into the UEFI Configuration Table
71 InstallEfiSystemResourceTableInUefiConfigurationTable (
78 if (!mEsrtInstalled
) {
80 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Can't install ESRT table because it is NULL. \n"));
81 Status
= EFI_OUT_OF_RESOURCES
;
82 } else if (mTable
->FwResourceCount
== 0) {
83 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Can't install ESRT table because it has zero Entries. \n"));
84 Status
= EFI_UNSUPPORTED
;
87 // Install the pointer into config table
89 Status
= gBS
->InstallConfigurationTable (&gEfiSystemResourceTableGuid
, mTable
);
90 if (EFI_ERROR (Status
)) {
91 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Can't install ESRT table. Status: %r. \n", Status
));
93 DEBUG ((DEBUG_INFO
, "EsrtFmpDxe: Installed ESRT table. \n"));
94 mEsrtInstalled
= TRUE
;
102 Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.
104 @param[in] FmpImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR
106 @return TRUE It is a system FMP.
107 @return FALSE It is a device FMP.
111 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR
*FmpImageInfo
118 Guid
= PcdGetPtr (PcdSystemFmpCapsuleImageTypeIdGuid
);
119 Count
= PcdGetSize (PcdSystemFmpCapsuleImageTypeIdGuid
) / sizeof(GUID
);
121 for (Index
= 0; Index
< Count
; Index
++, Guid
++) {
122 if (CompareGuid (&FmpImageInfo
->ImageTypeId
, Guid
)) {
131 Function to create a single ESRT Entry and add it to the ESRT
132 given a FMP descriptor. If the guid is already in the ESRT it
133 will be ignored. The ESRT will grow if it does not have enough room.
141 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR
*FmpImageInfoBuf
,
146 EFI_SYSTEM_RESOURCE_ENTRY
*Entry
;
148 EFI_SYSTEM_RESOURCE_TABLE
*NewTable
;
154 // Get our ESRT table. This should never be null at this point
156 if (mTable
== NULL
) {
157 return EFI_DEVICE_ERROR
;
160 Entry
= (EFI_SYSTEM_RESOURCE_ENTRY
*)(mTable
+ 1);
162 // Make sure Guid isn't already in the list
164 for (Index
= 0; Index
< mTable
->FwResourceCount
; Index
++) {
165 if (CompareGuid (&Entry
->FwClass
, &FmpImageInfoBuf
->ImageTypeId
)) {
166 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: ESRT Entry already exists for FMP Instance with GUID %g\n", &Entry
->FwClass
));
167 return EFI_INVALID_PARAMETER
;
173 // Grow table if needed
175 if (mTable
->FwResourceCount
>= mTable
->FwResourceCountMax
) {
177 // Can't grow table after installed.
178 // Only because didn't add support for this.
179 // Would need to re-install ESRT in system table if wanted to support
181 if (mEsrtInstalled
) {
182 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to install entry because ESRT table needed to grow after table already installed. \n"));
183 return EFI_OUT_OF_RESOURCES
;
186 NewSize
= ((mTable
->FwResourceCountMax
+ GROWTH_STEP
) * sizeof (EFI_SYSTEM_RESOURCE_ENTRY
)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE
);
187 NewTable
= AllocateRuntimeZeroPool (NewSize
);
188 if (NewTable
== NULL
) {
189 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to allocate memory larger table for ESRT. \n"));
190 return EFI_OUT_OF_RESOURCES
;
193 // Copy the whole old table into new table buffer
198 ((mTable
->FwResourceCountMax
) * sizeof (EFI_SYSTEM_RESOURCE_ENTRY
)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE
)
203 NewTable
->FwResourceCountMax
= NewTable
->FwResourceCountMax
+ GROWTH_STEP
;
209 // Reassign pointer to new table.
215 // ESRT table has enough room for the new entry so add new entry
217 Entry
= (EFI_SYSTEM_RESOURCE_ENTRY
*)(((UINT8
*)mTable
) + sizeof (EFI_SYSTEM_RESOURCE_TABLE
));
219 // Move to the location of new entry
221 Entry
= Entry
+ mTable
->FwResourceCount
;
223 // Increment resource count
225 mTable
->FwResourceCount
++;
227 CopyGuid (&Entry
->FwClass
, &FmpImageInfoBuf
->ImageTypeId
);
229 if (IsSystemFmp (FmpImageInfoBuf
)) {
230 DEBUG ((DEBUG_INFO
, "EsrtFmpDxe: Found an ESRT entry for a System Device.\n"));
231 Entry
->FwType
= (UINT32
)(ESRT_FW_TYPE_SYSTEMFIRMWARE
);
233 Entry
->FwType
= (UINT32
)(ESRT_FW_TYPE_DEVICEFIRMWARE
);
236 Entry
->FwVersion
= FmpImageInfoBuf
->Version
;
237 Entry
->LowestSupportedFwVersion
= 0;
238 Entry
->CapsuleFlags
= 0;
239 Entry
->LastAttemptVersion
= 0;
240 Entry
->LastAttemptStatus
= 0;
243 // VERSION 2 has Lowest Supported
245 if (FmpVersion
>= 2) {
246 Entry
->LowestSupportedFwVersion
= FmpImageInfoBuf
->LowestSupportedImageVersion
;
250 // VERSION 3 supports last attempt values
252 if (FmpVersion
>= 3) {
253 Entry
->LastAttemptVersion
= FmpImageInfoBuf
->LastAttemptVersion
;
254 Entry
->LastAttemptStatus
= FmpImageInfoBuf
->LastAttemptStatus
;
261 Notify function for every Firmware Management Protocol being installed.
262 Get the descriptors from FMP Instance and create ESRT entries (ESRE)
264 @param[in] Event The Event that is being processed.
265 @param[in] Context The Event Context.
270 FmpInstallProtocolNotify (
278 EFI_FIRMWARE_MANAGEMENT_PROTOCOL
*Fmp
;
279 UINTN DescriptorSize
;
280 EFI_FIRMWARE_IMAGE_DESCRIPTOR
*FmpImageInfoBuf
;
281 EFI_FIRMWARE_IMAGE_DESCRIPTOR
*FmpImageInfoBufOrg
;
282 UINT8 FmpImageInfoCount
;
283 UINT32 FmpImageInfoDescriptorVer
;
285 UINT32 PackageVersion
;
286 CHAR16
*PackageVersionName
;
288 Status
= EFI_SUCCESS
;
291 PackageVersionName
= NULL
;
292 FmpImageInfoBuf
= NULL
;
293 FmpImageInfoBufOrg
= NULL
;
296 DEBUG ((DEBUG_INFO
, "FMP Installed Notify\n"));
298 BufferSize
= sizeof (EFI_HANDLE
);
299 Status
= gBS
->LocateHandle (ByRegisterNotify
, NULL
, mFmpInstallEventRegistration
, &BufferSize
, &Handle
);
300 if (EFI_ERROR (Status
)) {
301 DEBUG ((DEBUG_WARN
, "EsrtFmpDxe: Failed to Locate handle from notify value. Status: %r\n", Status
));
305 Status
= gBS
->HandleProtocol (Handle
, &gEfiFirmwareManagementProtocolGuid
, (VOID
**)&Fmp
);
306 if (EFI_ERROR (Status
)) {
307 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to get FMP for a handle 0x%x\n", Handle
));
312 Status
= Fmp
->GetImageInfo (
314 &ImageInfoSize
, // Buffer Size (in this case 0)
315 NULL
, // NULL so we can get size
316 &FmpImageInfoDescriptorVer
, // DescriptorVersion
317 &FmpImageInfoCount
, // DescriptorCount
318 &DescriptorSize
, // DescriptorSize
319 &PackageVersion
, // PackageVersion
320 &PackageVersionName
// PackageVersionName
323 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
324 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Unexpected Failure in GetImageInfo. Status = %r\n", Status
));
328 FmpImageInfoBuf
= NULL
;
329 FmpImageInfoBuf
= AllocateZeroPool (ImageInfoSize
);
330 if (FmpImageInfoBuf
== NULL
) {
331 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to get memory for descriptors.\n"));
335 FmpImageInfoBufOrg
= FmpImageInfoBuf
;
336 PackageVersionName
= NULL
;
337 Status
= Fmp
->GetImageInfo (
339 &ImageInfoSize
, // ImageInfoSize
340 FmpImageInfoBuf
, // ImageInfo
341 &FmpImageInfoDescriptorVer
, // DescriptorVersion
342 &FmpImageInfoCount
, // DescriptorCount
343 &DescriptorSize
, // DescriptorSize
344 &PackageVersion
, // PackageVersion
345 &PackageVersionName
// PackageVersionName
347 if (EFI_ERROR (Status
)) {
348 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failure in GetImageInfo. Status = %r\n", Status
));
353 // Check each descriptor and read from the one specified
355 while (FmpImageInfoCount
> 0) {
357 // If the descriptor has the IN USE bit set, create ESRT entry otherwise ignore.
359 if ((FmpImageInfoBuf
->AttributesSetting
& FmpImageInfoBuf
->AttributesSupported
& IMAGE_ATTRIBUTE_IN_USE
) == IMAGE_ATTRIBUTE_IN_USE
) {
363 CreateEsrtEntry (FmpImageInfoBuf
, FmpImageInfoDescriptorVer
);
367 // Increment the buffer pointer ahead by the size of the descriptor
369 FmpImageInfoBuf
= (EFI_FIRMWARE_IMAGE_DESCRIPTOR
*)(((UINT8
*)FmpImageInfoBuf
) + DescriptorSize
);
372 if (PackageVersionName
!= NULL
) {
373 FreePool (PackageVersionName
);
374 PackageVersionName
= NULL
;
376 if (FmpImageInfoBufOrg
!= NULL
) {
377 FreePool (FmpImageInfoBufOrg
);
378 FmpImageInfoBufOrg
= NULL
;
383 if (FmpImageInfoBufOrg
!= NULL
) {
384 FreePool (FmpImageInfoBufOrg
);
390 Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
391 install the Efi System Resource Table.
393 @param[in] Event The Event that is being processed.
394 @param[in] Context The Event Context.
399 EsrtReadyToBootEventNotify (
404 InstallEfiSystemResourceTableInUefiConfigurationTable ();
407 // Print table on debug builds
415 The module Entry Point of the Efi System Resource Table DXE driver.
417 @param[in] ImageHandle The firmware allocated handle for the EFI image.
418 @param[in] SystemTable A pointer to the EFI System Table.
420 @retval EFI_SUCCESS The entry point is executed successfully.
421 @retval Other Some error occurs when executing this entry point.
427 IN EFI_HANDLE ImageHandle
,
428 IN EFI_SYSTEM_TABLE
*SystemTable
434 // Allocate Memory for table
436 mTable
= AllocateRuntimeZeroPool (
437 (GROWTH_STEP
* sizeof (EFI_SYSTEM_RESOURCE_ENTRY
)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE
)
439 ASSERT (mTable
!= NULL
);
440 if (mTable
== NULL
) {
441 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to allocate memory for ESRT.\n"));
442 return EFI_OUT_OF_RESOURCES
;
445 mTable
->FwResourceCount
= 0;
446 mTable
->FwResourceCountMax
= GROWTH_STEP
;
447 mTable
->FwResourceVersion
= EFI_SYSTEM_RESOURCE_TABLE_FIRMWARE_RESOURCE_VERSION
;
450 // Register notify function for all FMP installed
452 mFmpInstallEvent
= EfiCreateProtocolNotifyEvent (
453 &gEfiFirmwareManagementProtocolGuid
,
455 FmpInstallProtocolNotify
,
457 &mFmpInstallEventRegistration
460 ASSERT (mFmpInstallEvent
!= NULL
);
462 if (mFmpInstallEvent
== NULL
) {
463 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to Create Protocol Notify Event for FMP.\n"));
467 // Register notify function to install ESRT on ReadyToBoot Event.
469 Status
= EfiCreateEventReadyToBootEx (
471 EsrtReadyToBootEventNotify
,
473 &mEsrtReadyToBootEvent
476 ASSERT_EFI_ERROR (Status
);
477 if (EFI_ERROR (Status
)) {
478 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to register for ready to boot\n"));