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.
44 @param[in] Table Pointer to the ESRT table.
50 IN EFI_SYSTEM_RESOURCE_TABLE
*Table
54 // Number of ESRT entries to grow by each time we run out of room
56 #define GROWTH_STEP 10
59 Install EFI System Resource Table into the UEFI Configuration Table
61 @param[in] Table Pointer to the ESRT.
67 InstallEfiSystemResourceTableInUefiConfigurationTable (
68 IN EFI_SYSTEM_RESOURCE_TABLE
*Table
74 if (Table
->FwResourceCount
== 0) {
75 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Can't install ESRT table because it has zero Entries. \n"));
76 Status
= EFI_UNSUPPORTED
;
79 // Install the pointer into config table
81 Status
= gBS
->InstallConfigurationTable (&gEfiSystemResourceTableGuid
, Table
);
82 if (EFI_ERROR (Status
)) {
83 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Can't install ESRT table. Status: %r. \n", Status
));
85 DEBUG ((DEBUG_INFO
, "EsrtFmpDxe: Installed ESRT table. \n"));
92 Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.
94 @param[in] FmpImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR
96 @return TRUE It is a system FMP.
97 @return FALSE It is a device FMP.
101 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR
*FmpImageInfo
108 Guid
= PcdGetPtr (PcdSystemFmpCapsuleImageTypeIdGuid
);
109 Count
= PcdGetSize (PcdSystemFmpCapsuleImageTypeIdGuid
) / sizeof(GUID
);
111 for (Index
= 0; Index
< Count
; Index
++, Guid
++) {
112 if (CompareGuid (&FmpImageInfo
->ImageTypeId
, Guid
)) {
121 Function to create a single ESRT Entry and add it to the ESRT
122 given a FMP descriptor. If the guid is already in the ESRT it
123 will be ignored. The ESRT will grow if it does not have enough room.
125 @param[in, out] Table On input, pointer to the pointer to the ESRT.
126 On output, same as input or pointer to the pointer
127 to new enlarged ESRT.
128 @param[in] FmpImageInfoBuf Pointer to the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
129 @param[in] FmpVersion FMP Version.
136 IN OUT EFI_SYSTEM_RESOURCE_TABLE
**Table
,
137 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR
*FmpImageInfoBuf
,
142 EFI_SYSTEM_RESOURCE_ENTRY
*Entry
;
144 EFI_SYSTEM_RESOURCE_TABLE
*NewTable
;
149 Entry
= (EFI_SYSTEM_RESOURCE_ENTRY
*)((*Table
) + 1);
151 // Make sure Guid isn't already in the list
153 for (Index
= 0; Index
< (*Table
)->FwResourceCount
; Index
++) {
154 if (CompareGuid (&Entry
->FwClass
, &FmpImageInfoBuf
->ImageTypeId
)) {
155 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: ESRT Entry already exists for FMP Instance with GUID %g\n", &Entry
->FwClass
));
156 return EFI_INVALID_PARAMETER
;
162 // Grow table if needed
164 if ((*Table
)->FwResourceCount
>= (*Table
)->FwResourceCountMax
) {
165 NewSize
= (((*Table
)->FwResourceCountMax
+ GROWTH_STEP
) * sizeof (EFI_SYSTEM_RESOURCE_ENTRY
)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE
);
166 NewTable
= AllocateZeroPool (NewSize
);
167 if (NewTable
== NULL
) {
168 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to allocate memory larger table for ESRT. \n"));
169 return EFI_OUT_OF_RESOURCES
;
172 // Copy the whole old table into new table buffer
177 (((*Table
)->FwResourceCountMax
) * sizeof (EFI_SYSTEM_RESOURCE_ENTRY
)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE
)
182 NewTable
->FwResourceCountMax
= NewTable
->FwResourceCountMax
+ GROWTH_STEP
;
188 // Reassign pointer to new table.
194 // ESRT table has enough room for the new entry so add new entry
196 Entry
= (EFI_SYSTEM_RESOURCE_ENTRY
*)(((UINT8
*)(*Table
)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE
));
198 // Move to the location of new entry
200 Entry
= Entry
+ (*Table
)->FwResourceCount
;
202 // Increment resource count
204 (*Table
)->FwResourceCount
++;
206 CopyGuid (&Entry
->FwClass
, &FmpImageInfoBuf
->ImageTypeId
);
208 if (IsSystemFmp (FmpImageInfoBuf
)) {
209 DEBUG ((DEBUG_INFO
, "EsrtFmpDxe: Found an ESRT entry for a System Device.\n"));
210 Entry
->FwType
= (UINT32
)(ESRT_FW_TYPE_SYSTEMFIRMWARE
);
212 Entry
->FwType
= (UINT32
)(ESRT_FW_TYPE_DEVICEFIRMWARE
);
215 Entry
->FwVersion
= FmpImageInfoBuf
->Version
;
216 Entry
->LowestSupportedFwVersion
= 0;
217 Entry
->CapsuleFlags
= 0;
218 Entry
->LastAttemptVersion
= 0;
219 Entry
->LastAttemptStatus
= 0;
222 // VERSION 2 has Lowest Supported
224 if (FmpVersion
>= 2) {
225 Entry
->LowestSupportedFwVersion
= FmpImageInfoBuf
->LowestSupportedImageVersion
;
229 // VERSION 3 supports last attempt values
231 if (FmpVersion
>= 3) {
232 Entry
->LastAttemptVersion
= FmpImageInfoBuf
->LastAttemptVersion
;
233 Entry
->LastAttemptStatus
= FmpImageInfoBuf
->LastAttemptStatus
;
240 Function to create ESRT based on FMP Instances.
241 Create ESRT table, get the descriptors from FMP Instance and
242 create ESRT entries (ESRE).
244 @return Pointer to the ESRT created.
247 EFI_SYSTEM_RESOURCE_TABLE
*
253 EFI_SYSTEM_RESOURCE_TABLE
*Table
;
257 EFI_FIRMWARE_MANAGEMENT_PROTOCOL
*Fmp
;
258 UINTN DescriptorSize
;
259 EFI_FIRMWARE_IMAGE_DESCRIPTOR
*FmpImageInfoBuf
;
260 EFI_FIRMWARE_IMAGE_DESCRIPTOR
*FmpImageInfoBufOrg
;
261 UINT8 FmpImageInfoCount
;
262 UINT32 FmpImageInfoDescriptorVer
;
264 UINT32 PackageVersion
;
265 CHAR16
*PackageVersionName
;
267 Status
= EFI_SUCCESS
;
271 PackageVersionName
= NULL
;
272 FmpImageInfoBuf
= NULL
;
273 FmpImageInfoBufOrg
= NULL
;
276 Status
= EfiLocateProtocolBuffer (
277 &gEfiFirmwareManagementProtocolGuid
,
281 if (EFI_ERROR(Status
) || (Buffer
== NULL
)) {
286 // Allocate Memory for table
288 Table
= AllocateZeroPool (
289 (GROWTH_STEP
* sizeof (EFI_SYSTEM_RESOURCE_ENTRY
)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE
)
292 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to allocate memory for ESRT.\n"));
293 gBS
->FreePool (Buffer
);
297 Table
->FwResourceCount
= 0;
298 Table
->FwResourceCountMax
= GROWTH_STEP
;
299 Table
->FwResourceVersion
= EFI_SYSTEM_RESOURCE_TABLE_FIRMWARE_RESOURCE_VERSION
;
301 for (Index
= 0; Index
< NoProtocols
; Index
++) {
302 Fmp
= (EFI_FIRMWARE_MANAGEMENT_PROTOCOL
*) Buffer
[Index
];
305 Status
= Fmp
->GetImageInfo (
307 &ImageInfoSize
, // Buffer Size (in this case 0)
308 NULL
, // NULL so we can get size
309 &FmpImageInfoDescriptorVer
, // DescriptorVersion
310 &FmpImageInfoCount
, // DescriptorCount
311 &DescriptorSize
, // DescriptorSize
312 &PackageVersion
, // PackageVersion
313 &PackageVersionName
// PackageVersionName
316 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
317 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Unexpected Failure in GetImageInfo. Status = %r\n", Status
));
321 FmpImageInfoBuf
= AllocateZeroPool (ImageInfoSize
);
322 if (FmpImageInfoBuf
== NULL
) {
323 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to get memory for descriptors.\n"));
327 FmpImageInfoBufOrg
= FmpImageInfoBuf
;
328 PackageVersionName
= NULL
;
329 Status
= Fmp
->GetImageInfo (
331 &ImageInfoSize
, // ImageInfoSize
332 FmpImageInfoBuf
, // ImageInfo
333 &FmpImageInfoDescriptorVer
, // DescriptorVersion
334 &FmpImageInfoCount
, // DescriptorCount
335 &DescriptorSize
, // DescriptorSize
336 &PackageVersion
, // PackageVersion
337 &PackageVersionName
// PackageVersionName
339 if (EFI_ERROR (Status
)) {
340 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failure in GetImageInfo. Status = %r\n", Status
));
341 FreePool (FmpImageInfoBufOrg
);
342 FmpImageInfoBufOrg
= NULL
;
347 // Check each descriptor and read from the one specified
349 while (FmpImageInfoCount
> 0) {
351 // If the descriptor has the IN USE bit set, create ESRT entry otherwise ignore.
353 if ((FmpImageInfoBuf
->AttributesSetting
& FmpImageInfoBuf
->AttributesSupported
& IMAGE_ATTRIBUTE_IN_USE
) == IMAGE_ATTRIBUTE_IN_USE
) {
357 CreateEsrtEntry (&Table
, FmpImageInfoBuf
, FmpImageInfoDescriptorVer
);
361 // Increment the buffer pointer ahead by the size of the descriptor
363 FmpImageInfoBuf
= (EFI_FIRMWARE_IMAGE_DESCRIPTOR
*)(((UINT8
*)FmpImageInfoBuf
) + DescriptorSize
);
366 if (PackageVersionName
!= NULL
) {
367 FreePool (PackageVersionName
);
368 PackageVersionName
= NULL
;
370 FreePool (FmpImageInfoBufOrg
);
371 FmpImageInfoBufOrg
= NULL
;
374 gBS
->FreePool (Buffer
);
379 Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
380 install the Efi System Resource Table.
382 @param[in] Event The Event that is being processed.
383 @param[in] Context The Event Context.
388 EsrtReadyToBootEventNotify (
394 EFI_SYSTEM_RESOURCE_TABLE
*Table
;
396 Table
= CreateFmpBasedEsrt ();
399 // Print table on debug builds
405 Status
= InstallEfiSystemResourceTableInUefiConfigurationTable (Table
);
406 if (EFI_ERROR (Status
)) {
410 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Can't install ESRT table because it is NULL. \n"));
414 // Close the event to prevent it be signalled again.
416 gBS
->CloseEvent (Event
);
420 The module Entry Point of the Efi System Resource Table DXE driver.
422 @param[in] ImageHandle The firmware allocated handle for the EFI image.
423 @param[in] SystemTable A pointer to the EFI System Table.
425 @retval EFI_SUCCESS The entry point is executed successfully.
426 @retval Other Some error occurs when executing this entry point.
432 IN EFI_HANDLE ImageHandle
,
433 IN EFI_SYSTEM_TABLE
*SystemTable
437 EFI_EVENT EsrtReadyToBootEvent
;
440 // Register notify function to install ESRT on ReadyToBoot Event.
442 Status
= EfiCreateEventReadyToBootEx (
444 EsrtReadyToBootEventNotify
,
446 &EsrtReadyToBootEvent
449 ASSERT_EFI_ERROR (Status
);
450 if (EFI_ERROR (Status
)) {
451 DEBUG ((DEBUG_ERROR
, "EsrtFmpDxe: Failed to register for ready to boot\n"));