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 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include <Library/BaseLib.h>
14 #include <Library/BaseMemoryLib.h>
15 #include <Library/MemoryAllocationLib.h>
16 #include <Library/UefiBootServicesTableLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/PcdLib.h>
19 #include <Library/UefiLib.h>
20 #include <Protocol/FirmwareManagement.h>
21 #include <Guid/EventGroup.h>
22 #include <Guid/SystemResourceTable.h>
25 Print ESRT to debug console.
27 @param[in] Table Pointer to the ESRT table.
33 IN EFI_SYSTEM_RESOURCE_TABLE
*Table
37 // Number of ESRT entries to grow by each time we run out of room
39 #define GROWTH_STEP 10
42 Install EFI System Resource Table into the UEFI Configuration Table
44 @param[in] Table Pointer to the ESRT.
50 InstallEfiSystemResourceTableInUefiConfigurationTable (
51 IN EFI_SYSTEM_RESOURCE_TABLE
*Table
57 if (Table
->FwResourceCount
== 0) {
58 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Can't install ESRT table because it has zero Entries. \n"));
59 Status
= EFI_UNSUPPORTED
;
62 // Install the pointer into config table
64 Status
= gBS
->InstallConfigurationTable (&gEfiSystemResourceTableGuid
, Table
);
65 if (EFI_ERROR (Status
)) {
66 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Can't install ESRT table. Status: %r. \n", Status
));
68 DEBUG ((DEBUG_INFO
, "EsrtFmpDxe: Installed ESRT table. \n"));
75 Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.
77 @param[in] FmpImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR
79 @return TRUE It is a system FMP.
80 @return FALSE It is a device FMP.
84 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR
*FmpImageInfo
91 Guid
= PcdGetPtr (PcdSystemFmpCapsuleImageTypeIdGuid
);
92 Count
= PcdGetSize (PcdSystemFmpCapsuleImageTypeIdGuid
) / sizeof(GUID
);
94 for (Index
= 0; Index
< Count
; Index
++, Guid
++) {
95 if (CompareGuid (&FmpImageInfo
->ImageTypeId
, Guid
)) {
104 Function to create a single ESRT Entry and add it to the ESRT
105 given a FMP descriptor. If the guid is already in the ESRT it
106 will be ignored. The ESRT will grow if it does not have enough room.
108 @param[in, out] Table On input, pointer to the pointer to the ESRT.
109 On output, same as input or pointer to the pointer
110 to new enlarged ESRT.
111 @param[in] FmpImageInfoBuf Pointer to the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
112 @param[in] FmpVersion FMP Version.
119 IN OUT EFI_SYSTEM_RESOURCE_TABLE
**Table
,
120 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR
*FmpImageInfoBuf
,
125 EFI_SYSTEM_RESOURCE_ENTRY
*Entry
;
127 EFI_SYSTEM_RESOURCE_TABLE
*NewTable
;
132 Entry
= (EFI_SYSTEM_RESOURCE_ENTRY
*)((*Table
) + 1);
134 // Make sure Guid isn't already in the list
136 for (Index
= 0; Index
< (*Table
)->FwResourceCount
; Index
++) {
137 if (CompareGuid (&Entry
->FwClass
, &FmpImageInfoBuf
->ImageTypeId
)) {
138 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: ESRT Entry already exists for FMP Instance with GUID %g\n", &Entry
->FwClass
));
139 return EFI_INVALID_PARAMETER
;
145 // Grow table if needed
147 if ((*Table
)->FwResourceCount
>= (*Table
)->FwResourceCountMax
) {
148 NewSize
= (((*Table
)->FwResourceCountMax
+ GROWTH_STEP
) * sizeof (EFI_SYSTEM_RESOURCE_ENTRY
)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE
);
149 NewTable
= AllocateZeroPool (NewSize
);
150 if (NewTable
== NULL
) {
151 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to allocate memory larger table for ESRT. \n"));
152 return EFI_OUT_OF_RESOURCES
;
155 // Copy the whole old table into new table buffer
160 (((*Table
)->FwResourceCountMax
) * sizeof (EFI_SYSTEM_RESOURCE_ENTRY
)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE
)
165 NewTable
->FwResourceCountMax
= NewTable
->FwResourceCountMax
+ GROWTH_STEP
;
171 // Reassign pointer to new table.
177 // ESRT table has enough room for the new entry so add new entry
179 Entry
= (EFI_SYSTEM_RESOURCE_ENTRY
*)(((UINT8
*)(*Table
)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE
));
181 // Move to the location of new entry
183 Entry
= Entry
+ (*Table
)->FwResourceCount
;
185 // Increment resource count
187 (*Table
)->FwResourceCount
++;
189 CopyGuid (&Entry
->FwClass
, &FmpImageInfoBuf
->ImageTypeId
);
191 if (IsSystemFmp (FmpImageInfoBuf
)) {
192 DEBUG ((DEBUG_INFO
, "EsrtFmpDxe: Found an ESRT entry for a System Device.\n"));
193 Entry
->FwType
= (UINT32
)(ESRT_FW_TYPE_SYSTEMFIRMWARE
);
195 Entry
->FwType
= (UINT32
)(ESRT_FW_TYPE_DEVICEFIRMWARE
);
198 Entry
->FwVersion
= FmpImageInfoBuf
->Version
;
199 Entry
->LowestSupportedFwVersion
= 0;
200 Entry
->CapsuleFlags
= 0;
201 Entry
->LastAttemptVersion
= 0;
202 Entry
->LastAttemptStatus
= 0;
205 // VERSION 2 has Lowest Supported
207 if (FmpVersion
>= 2) {
208 Entry
->LowestSupportedFwVersion
= FmpImageInfoBuf
->LowestSupportedImageVersion
;
212 // VERSION 3 supports last attempt values
214 if (FmpVersion
>= 3) {
215 Entry
->LastAttemptVersion
= FmpImageInfoBuf
->LastAttemptVersion
;
216 Entry
->LastAttemptStatus
= FmpImageInfoBuf
->LastAttemptStatus
;
223 Function to create ESRT based on FMP Instances.
224 Create ESRT table, get the descriptors from FMP Instance and
225 create ESRT entries (ESRE).
227 @return Pointer to the ESRT created.
230 EFI_SYSTEM_RESOURCE_TABLE
*
236 EFI_SYSTEM_RESOURCE_TABLE
*Table
;
240 EFI_FIRMWARE_MANAGEMENT_PROTOCOL
*Fmp
;
241 UINTN DescriptorSize
;
242 EFI_FIRMWARE_IMAGE_DESCRIPTOR
*FmpImageInfoBuf
;
243 EFI_FIRMWARE_IMAGE_DESCRIPTOR
*FmpImageInfoBufOrg
;
244 UINT8 FmpImageInfoCount
;
245 UINT32 FmpImageInfoDescriptorVer
;
247 UINT32 PackageVersion
;
248 CHAR16
*PackageVersionName
;
250 Status
= EFI_SUCCESS
;
254 PackageVersionName
= NULL
;
255 FmpImageInfoBuf
= NULL
;
256 FmpImageInfoBufOrg
= NULL
;
259 Status
= EfiLocateProtocolBuffer (
260 &gEfiFirmwareManagementProtocolGuid
,
264 if (EFI_ERROR(Status
) || (Buffer
== NULL
)) {
269 // Allocate Memory for table
271 Table
= AllocateZeroPool (
272 (GROWTH_STEP
* sizeof (EFI_SYSTEM_RESOURCE_ENTRY
)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE
)
275 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to allocate memory for ESRT.\n"));
276 gBS
->FreePool (Buffer
);
280 Table
->FwResourceCount
= 0;
281 Table
->FwResourceCountMax
= GROWTH_STEP
;
282 Table
->FwResourceVersion
= EFI_SYSTEM_RESOURCE_TABLE_FIRMWARE_RESOURCE_VERSION
;
284 for (Index
= 0; Index
< NoProtocols
; Index
++) {
285 Fmp
= (EFI_FIRMWARE_MANAGEMENT_PROTOCOL
*) Buffer
[Index
];
288 Status
= Fmp
->GetImageInfo (
290 &ImageInfoSize
, // Buffer Size (in this case 0)
291 NULL
, // NULL so we can get size
292 &FmpImageInfoDescriptorVer
, // DescriptorVersion
293 &FmpImageInfoCount
, // DescriptorCount
294 &DescriptorSize
, // DescriptorSize
295 &PackageVersion
, // PackageVersion
296 &PackageVersionName
// PackageVersionName
299 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
300 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Unexpected Failure in GetImageInfo. Status = %r\n", Status
));
304 FmpImageInfoBuf
= AllocateZeroPool (ImageInfoSize
);
305 if (FmpImageInfoBuf
== NULL
) {
306 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to get memory for descriptors.\n"));
310 FmpImageInfoBufOrg
= FmpImageInfoBuf
;
311 PackageVersionName
= NULL
;
312 Status
= Fmp
->GetImageInfo (
314 &ImageInfoSize
, // ImageInfoSize
315 FmpImageInfoBuf
, // ImageInfo
316 &FmpImageInfoDescriptorVer
, // DescriptorVersion
317 &FmpImageInfoCount
, // DescriptorCount
318 &DescriptorSize
, // DescriptorSize
319 &PackageVersion
, // PackageVersion
320 &PackageVersionName
// PackageVersionName
322 if (EFI_ERROR (Status
)) {
323 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failure in GetImageInfo. Status = %r\n", Status
));
324 FreePool (FmpImageInfoBufOrg
);
325 FmpImageInfoBufOrg
= NULL
;
330 // Check each descriptor and read from the one specified
332 while (FmpImageInfoCount
> 0) {
334 // If the descriptor has the IN USE bit set, create ESRT entry otherwise ignore.
336 if ((FmpImageInfoBuf
->AttributesSetting
& FmpImageInfoBuf
->AttributesSupported
& IMAGE_ATTRIBUTE_IN_USE
) == IMAGE_ATTRIBUTE_IN_USE
) {
340 CreateEsrtEntry (&Table
, FmpImageInfoBuf
, FmpImageInfoDescriptorVer
);
344 // Increment the buffer pointer ahead by the size of the descriptor
346 FmpImageInfoBuf
= (EFI_FIRMWARE_IMAGE_DESCRIPTOR
*)(((UINT8
*)FmpImageInfoBuf
) + DescriptorSize
);
349 if (PackageVersionName
!= NULL
) {
350 FreePool (PackageVersionName
);
351 PackageVersionName
= NULL
;
353 FreePool (FmpImageInfoBufOrg
);
354 FmpImageInfoBufOrg
= NULL
;
357 gBS
->FreePool (Buffer
);
362 Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
363 install the Efi System Resource Table.
365 @param[in] Event The Event that is being processed.
366 @param[in] Context The Event Context.
371 EsrtReadyToBootEventNotify (
377 EFI_SYSTEM_RESOURCE_TABLE
*Table
;
379 Table
= CreateFmpBasedEsrt ();
382 // Print table on debug builds
388 Status
= InstallEfiSystemResourceTableInUefiConfigurationTable (Table
);
389 if (EFI_ERROR (Status
)) {
393 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Can't install ESRT table because it is NULL. \n"));
397 // Close the event to prevent it be signalled again.
399 gBS
->CloseEvent (Event
);
403 The module Entry Point of the Efi System Resource Table DXE driver.
405 @param[in] ImageHandle The firmware allocated handle for the EFI image.
406 @param[in] SystemTable A pointer to the EFI System Table.
408 @retval EFI_SUCCESS The entry point is executed successfully.
409 @retval Other Some error occurs when executing this entry point.
415 IN EFI_HANDLE ImageHandle
,
416 IN EFI_SYSTEM_TABLE
*SystemTable
420 EFI_EVENT EsrtReadyToBootEvent
;
423 // Register notify function to install ESRT on ReadyToBoot Event.
425 Status
= EfiCreateEventReadyToBootEx (
427 EsrtReadyToBootEventNotify
,
429 &EsrtReadyToBootEvent
432 ASSERT_EFI_ERROR (Status
);
433 if (EFI_ERROR (Status
)) {
434 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to register for ready to boot\n"));