TianoCore EDK2 master
Loading...
Searching...
No Matches
EsrtFmp.c
Go to the documentation of this file.
1
12#include <Uefi.h>
13#include <Library/BaseLib.h>
17#include <Library/DebugLib.h>
18#include <Library/PcdLib.h>
19#include <Library/UefiLib.h>
21#include <Guid/EventGroup.h>
23
28typedef struct {
39
46VOID
47EFIAPI
50 );
51
63 )
64{
65 EFI_STATUS Status;
66
67 Status = EFI_SUCCESS;
68 if (Table->FwResourceCount == 0) {
69 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Can't install ESRT table because it has zero Entries. \n"));
70 Status = EFI_UNSUPPORTED;
71 } else {
72 //
73 // Install the pointer into config table
74 //
75 Status = gBS->InstallConfigurationTable (&gEfiSystemResourceTableGuid, Table);
76 if (EFI_ERROR (Status)) {
77 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Can't install ESRT table. Status: %r. \n", Status));
78 } else {
79 DEBUG ((DEBUG_INFO, "EsrtFmpDxe: Installed ESRT table. \n"));
80 }
81 }
82
83 return Status;
84}
85
94BOOLEAN
97 )
98{
99 GUID *Guid;
100 UINTN Count;
101 UINTN Index;
102
103 Guid = PcdGetPtr (PcdSystemFmpCapsuleImageTypeIdGuid);
104 Count = PcdGetSize (PcdSystemFmpCapsuleImageTypeIdGuid) / sizeof (GUID);
105
106 for (Index = 0; Index < Count; Index++, Guid++) {
107 if (CompareGuid (&FmpImageInfo->ImageTypeId, Guid)) {
108 return TRUE;
109 }
110 }
111
112 return FALSE;
113}
114
139 IN OUT GUID_HARDWAREINSTANCE_PAIR *HardwareInstances,
140 IN OUT UINT32 *NumberOfDescriptors,
141 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf,
142 IN UINT32 FmpVersion
143 )
144{
145 UINTN Index;
147 UINT64 FmpHardwareInstance;
148
149 FmpHardwareInstance = 0;
150 if (FmpVersion >= 3) {
151 FmpHardwareInstance = FmpImageInfoBuf->HardwareInstance;
152 }
153
154 //
155 // Check to see of FmpImageInfoBuf GUID/HardwareInstance is unique
156 // Skip if HardwareInstance is 0 as this is the case if FmpVersion < 3
157 // or the device can not create a unique ID per UEFI specification
158 //
159 if (FmpHardwareInstance != 0) {
160 for (Index = 0; Index < *NumberOfDescriptors; Index++) {
161 if (CompareGuid (&HardwareInstances[Index].ImageTypeGuid, &FmpImageInfoBuf->ImageTypeId)) {
162 if (HardwareInstances[Index].HardwareInstance == FmpHardwareInstance) {
163 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Duplicate firmware image descriptor with GUID %g HardwareInstance:0x%x\n", &FmpImageInfoBuf->ImageTypeId, FmpHardwareInstance));
164 ASSERT (
165 !CompareGuid (&HardwareInstances[Index].ImageTypeGuid, &FmpImageInfoBuf->ImageTypeId) ||
166 HardwareInstances[Index].HardwareInstance != FmpHardwareInstance
167 );
168 return EFI_UNSUPPORTED;
169 }
170 }
171 }
172 }
173
174 //
175 // Record new GUID/HardwareInstance pair
176 //
177 CopyGuid (&HardwareInstances[*NumberOfDescriptors].ImageTypeGuid, &FmpImageInfoBuf->ImageTypeId);
178 HardwareInstances[*NumberOfDescriptors].HardwareInstance = FmpHardwareInstance;
179 *NumberOfDescriptors = *NumberOfDescriptors + 1;
180
181 DEBUG ((DEBUG_INFO, "EsrtFmpDxe: Add new image descriptor with GUID %g HardwareInstance:0x%x\n", &FmpImageInfoBuf->ImageTypeId, FmpHardwareInstance));
182
183 //
184 // Check to see if GUID is already in the ESRT table
185 //
186 Entry = (EFI_SYSTEM_RESOURCE_ENTRY *)(Table + 1);
187 for (Index = 0; Index < Table->FwResourceCount; Index++, Entry++) {
188 if (!CompareGuid (&Entry->FwClass, &FmpImageInfoBuf->ImageTypeId)) {
189 continue;
190 }
191
192 DEBUG ((DEBUG_INFO, "EsrtFmpDxe: ESRT Entry already exists for FMP Instance with GUID %g\n", &Entry->FwClass));
193
194 //
195 // Set ESRT FwVersion to the smaller of the two values
196 //
197 Entry->FwVersion = MIN (FmpImageInfoBuf->Version, Entry->FwVersion);
198
199 //
200 // VERSION 2 has Lowest Supported
201 //
202 if (FmpVersion >= 2) {
203 //
204 // Set ESRT LowestSupportedFwVersion to the smaller of the two values
205 //
206 Entry->LowestSupportedFwVersion =
207 MIN (
208 FmpImageInfoBuf->LowestSupportedImageVersion,
209 Entry->LowestSupportedFwVersion
210 );
211 }
212
213 //
214 // VERSION 3 supports last attempt values
215 //
216 if (FmpVersion >= 3) {
217 //
218 // Update the ESRT entry with the last attempt status and last attempt
219 // version from the first FMP instance whose last attempt status is not
220 // SUCCESS. If all FMP instances are SUCCESS, then set version to the
221 // smallest value from all FMP instances.
222 //
223 if (Entry->LastAttemptStatus == LAST_ATTEMPT_STATUS_SUCCESS) {
224 if (FmpImageInfoBuf->LastAttemptStatus != LAST_ATTEMPT_STATUS_SUCCESS) {
225 Entry->LastAttemptStatus = FmpImageInfoBuf->LastAttemptStatus;
226 Entry->LastAttemptVersion = FmpImageInfoBuf->LastAttemptVersion;
227 } else {
228 Entry->LastAttemptVersion =
229 MIN (
230 FmpImageInfoBuf->LastAttemptVersion,
231 Entry->LastAttemptVersion
232 );
233 }
234 }
235 }
236
237 return EFI_SUCCESS;
238 }
239
240 //
241 // Add a new ESRT Table Entry
242 //
243 Entry = (EFI_SYSTEM_RESOURCE_ENTRY *)(Table + 1) + Table->FwResourceCount;
244
245 CopyGuid (&Entry->FwClass, &FmpImageInfoBuf->ImageTypeId);
246
247 if (IsSystemFmp (FmpImageInfoBuf)) {
248 DEBUG ((DEBUG_INFO, "EsrtFmpDxe: Found an ESRT entry for a System Device.\n"));
249 Entry->FwType = (UINT32)(ESRT_FW_TYPE_SYSTEMFIRMWARE);
250 } else {
251 Entry->FwType = (UINT32)(ESRT_FW_TYPE_DEVICEFIRMWARE);
252 }
253
254 Entry->FwVersion = FmpImageInfoBuf->Version;
255 Entry->LowestSupportedFwVersion = 0;
256 Entry->CapsuleFlags = 0;
257 Entry->LastAttemptVersion = 0;
258 Entry->LastAttemptStatus = 0;
259
260 //
261 // VERSION 2 has Lowest Supported
262 //
263 if (FmpVersion >= 2) {
264 Entry->LowestSupportedFwVersion = FmpImageInfoBuf->LowestSupportedImageVersion;
265 }
266
267 //
268 // VERSION 3 supports last attempt values
269 //
270 if (FmpVersion >= 3) {
271 Entry->LastAttemptVersion = FmpImageInfoBuf->LastAttemptVersion;
272 Entry->LastAttemptStatus = FmpImageInfoBuf->LastAttemptStatus;
273 }
274
275 //
276 // Increment the number of active ESRT Table Entries
277 //
278 Table->FwResourceCount++;
279
280 return EFI_SUCCESS;
281}
282
303 OUT UINT32 *FmpImageInfoDescriptorVer,
304 OUT UINT8 *FmpImageInfoCount,
305 OUT UINTN *DescriptorSize
306 )
307{
308 EFI_STATUS Status;
309 UINTN ImageInfoSize;
310 UINT32 PackageVersion;
311 CHAR16 *PackageVersionName;
312 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
313
314 ImageInfoSize = 0;
315 Status = Fmp->GetImageInfo (
316 Fmp, // FMP Pointer
317 &ImageInfoSize, // Buffer Size (in this case 0)
318 NULL, // NULL so we can get size
319 FmpImageInfoDescriptorVer, // DescriptorVersion
320 FmpImageInfoCount, // DescriptorCount
321 DescriptorSize, // DescriptorSize
322 &PackageVersion, // PackageVersion
323 &PackageVersionName // PackageVersionName
324 );
325 if (Status != EFI_BUFFER_TOO_SMALL) {
326 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Unexpected Failure in GetImageInfo. Status = %r\n", Status));
327 return NULL;
328 }
329
330 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
331 if (FmpImageInfoBuf == NULL) {
332 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to get memory for FMP descriptor.\n"));
333 return NULL;
334 }
335
336 PackageVersionName = NULL;
337 Status = Fmp->GetImageInfo (
338 Fmp, // FMP Pointer
339 &ImageInfoSize, // ImageInfoSize
340 FmpImageInfoBuf, // ImageInfo
341 FmpImageInfoDescriptorVer, // DescriptorVersion
342 FmpImageInfoCount, // DescriptorCount
343 DescriptorSize, // DescriptorSize
344 &PackageVersion, // PackageVersion
345 &PackageVersionName // PackageVersionName
346 );
347 if (PackageVersionName != NULL) {
348 FreePool (PackageVersionName);
349 }
350
351 if (EFI_ERROR (Status)) {
352 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failure in GetImageInfo. Status = %r\n", Status));
353 FreePool (FmpImageInfoBuf);
354 return NULL;
355 }
356
357 return FmpImageInfoBuf;
358}
359
370 VOID
371 )
372{
373 EFI_STATUS Status;
374 UINTN NoProtocols;
375 VOID **Buffer;
376 UINTN Index;
377 UINT32 FmpImageInfoDescriptorVer;
378 UINT8 FmpImageInfoCount;
379 UINTN DescriptorSize;
380 UINT32 NumberOfDescriptors;
381 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
382 EFI_FIRMWARE_IMAGE_DESCRIPTOR *OrgFmpImageInfoBuf;
384 GUID_HARDWAREINSTANCE_PAIR *HardwareInstances;
385
386 Status = EFI_SUCCESS;
387 NoProtocols = 0;
388 Buffer = NULL;
389 FmpImageInfoBuf = NULL;
390 OrgFmpImageInfoBuf = NULL;
391 Table = NULL;
392 HardwareInstances = NULL;
393
394 Status = EfiLocateProtocolBuffer (
395 &gEfiFirmwareManagementProtocolGuid,
396 &NoProtocols,
397 &Buffer
398 );
399 if (EFI_ERROR (Status) || (Buffer == NULL)) {
400 return NULL;
401 }
402
403 //
404 // Count the total number of EFI_FIRMWARE_IMAGE_DESCRIPTORs
405 //
406 for (Index = 0, NumberOfDescriptors = 0; Index < NoProtocols; Index++) {
407 FmpImageInfoBuf = FmpGetFirmwareImageDescriptor (
408 (EFI_FIRMWARE_MANAGEMENT_PROTOCOL *)Buffer[Index],
409 &FmpImageInfoDescriptorVer,
410 &FmpImageInfoCount,
411 &DescriptorSize
412 );
413 if (FmpImageInfoBuf != NULL) {
414 NumberOfDescriptors += FmpImageInfoCount;
415 FreePool (FmpImageInfoBuf);
416 }
417 }
418
419 //
420 // Allocate ESRT Table and GUID/HardwareInstance table
421 //
422 Table = AllocateZeroPool (
423 (NumberOfDescriptors * sizeof (EFI_SYSTEM_RESOURCE_ENTRY)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE)
424 );
425 if (Table == NULL) {
426 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to allocate memory for ESRT.\n"));
427 FreePool (Buffer);
428 return NULL;
429 }
430
431 HardwareInstances = AllocateZeroPool (NumberOfDescriptors * sizeof (GUID_HARDWAREINSTANCE_PAIR));
432 if (HardwareInstances == NULL) {
433 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to allocate memory for HW Instance Table.\n"));
434 FreePool (Table);
435 FreePool (Buffer);
436 return NULL;
437 }
438
439 //
440 // Initialize ESRT Table
441 //
442 Table->FwResourceCount = 0;
443 Table->FwResourceCountMax = NumberOfDescriptors;
445
446 NumberOfDescriptors = 0;
447 for (Index = 0; Index < NoProtocols; Index++) {
448 FmpImageInfoBuf = FmpGetFirmwareImageDescriptor (
449 (EFI_FIRMWARE_MANAGEMENT_PROTOCOL *)Buffer[Index],
450 &FmpImageInfoDescriptorVer,
451 &FmpImageInfoCount,
452 &DescriptorSize
453 );
454 if (FmpImageInfoBuf == NULL) {
455 continue;
456 }
457
458 //
459 // Check each descriptor and read from the one specified
460 //
461 OrgFmpImageInfoBuf = FmpImageInfoBuf;
462 while (FmpImageInfoCount > 0) {
463 //
464 // If the descriptor has the IN USE bit set, create ESRT entry otherwise ignore.
465 //
466 if ((FmpImageInfoBuf->AttributesSetting & FmpImageInfoBuf->AttributesSupported & IMAGE_ATTRIBUTE_IN_USE) == IMAGE_ATTRIBUTE_IN_USE) {
467 //
468 // Create ESRT entry
469 //
470 CreateEsrtEntry (Table, HardwareInstances, &NumberOfDescriptors, FmpImageInfoBuf, FmpImageInfoDescriptorVer);
471 }
472
473 FmpImageInfoCount--;
474 //
475 // Increment the buffer pointer ahead by the size of the descriptor
476 //
477 FmpImageInfoBuf = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)(((UINT8 *)FmpImageInfoBuf) + DescriptorSize);
478 }
479
480 FreePool (OrgFmpImageInfoBuf);
481 OrgFmpImageInfoBuf = NULL;
482 }
483
484 FreePool (Buffer);
485 FreePool (HardwareInstances);
486 return Table;
487}
488
497VOID
498EFIAPI
500 IN EFI_EVENT Event,
501 IN VOID *Context
502 )
503{
504 EFI_STATUS Status;
506
507 Table = CreateFmpBasedEsrt ();
508 if (Table != NULL) {
509 //
510 // Print table on debug builds
511 //
513 PrintTable (Table);
515
517 if (EFI_ERROR (Status)) {
518 FreePool (Table);
519 }
520 } else {
521 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Can't install ESRT table because it is NULL. \n"));
522 }
523
524 //
525 // Close the event to prevent it be signalled again.
526 //
527 gBS->CloseEvent (Event);
528}
529
541EFIAPI
543 IN EFI_HANDLE ImageHandle,
544 IN EFI_SYSTEM_TABLE *SystemTable
545 )
546{
547 EFI_STATUS Status;
548 EFI_EVENT EsrtReadyToBootEvent;
549
550 //
551 // Register notify function to install ESRT on ReadyToBoot Event.
552 //
554 TPL_CALLBACK,
556 NULL,
557 &EsrtReadyToBootEvent
558 );
559
560 ASSERT_EFI_ERROR (Status);
561 if (EFI_ERROR (Status)) {
562 DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to register for ready to boot\n"));
563 }
564
565 return Status;
566}
UINT64 UINTN
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
Definition: MemLibGuid.c:73
GUID *EFIAPI CopyGuid(OUT GUID *DestinationGuid, IN CONST GUID *SourceGuid)
Definition: MemLibGuid.c:39
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
EFI_STATUS EFIAPI EsrtFmpEntryPoint(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
Definition: EsrtFmp.c:542
EFI_STATUS InstallEfiSystemResourceTableInUefiConfigurationTable(IN EFI_SYSTEM_RESOURCE_TABLE *Table)
Definition: EsrtFmp.c:61
EFI_FIRMWARE_IMAGE_DESCRIPTOR * FmpGetFirmwareImageDescriptor(IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp, OUT UINT32 *FmpImageInfoDescriptorVer, OUT UINT8 *FmpImageInfoCount, OUT UINTN *DescriptorSize)
Definition: EsrtFmp.c:301
VOID EFIAPI EsrtReadyToBootEventNotify(IN EFI_EVENT Event, IN VOID *Context)
Definition: EsrtFmp.c:499
VOID EFIAPI PrintTable(IN EFI_SYSTEM_RESOURCE_TABLE *Table)
BOOLEAN IsSystemFmp(IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfo)
Definition: EsrtFmp.c:95
EFI_STATUS CreateEsrtEntry(IN OUT EFI_SYSTEM_RESOURCE_TABLE *Table, IN OUT GUID_HARDWAREINSTANCE_PAIR *HardwareInstances, IN OUT UINT32 *NumberOfDescriptors, IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf, IN UINT32 FmpVersion)
Definition: EsrtFmp.c:137
EFI_SYSTEM_RESOURCE_TABLE * CreateFmpBasedEsrt(VOID)
Definition: EsrtFmp.c:369
#define IMAGE_ATTRIBUTE_IN_USE
#define NULL
Definition: Base.h:319
#define MIN(a, b)
Definition: Base.h:1007
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG_CODE_BEGIN()
Definition: DebugLib.h:564
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define DEBUG_CODE_END()
Definition: DebugLib.h:578
#define PcdGetSize(TokenName)
Definition: PcdLib.h:440
#define PcdGetPtr(TokenName)
Definition: PcdLib.h:388
#define EFI_SYSTEM_RESOURCE_TABLE_FIRMWARE_RESOURCE_VERSION
#define LAST_ATTEMPT_STATUS_SUCCESS
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_STATUS EFIAPI EfiCreateEventReadyToBootEx(IN EFI_TPL NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL, IN VOID *NotifyContext OPTIONAL, OUT EFI_EVENT *ReadyToBootEvent)
Definition: UefiNotTiano.c:164
EFI_STATUS EFIAPI EfiLocateProtocolBuffer(IN EFI_GUID *Protocol, OUT UINTN *NoProtocols, OUT VOID ***Buffer)
Definition: UefiLib.c:1650
Definition: Base.h:213