2 Esrt management module.
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
15 ESRT_PRIVATE_DATA mPrivate
;
17 ESRT_MANAGEMENT_PROTOCOL mEsrtManagementProtocolTemplate
= {
19 EsrtDxeUpdateEsrtEntry
,
20 EsrtDxeRegisterEsrtEntry
,
21 EsrtDxeUnRegisterEsrtEntry
,
23 EsrtDxeLockEsrtRepository
27 Get ESRT entry from ESRT Cache by FwClass Guid
29 @param[in] FwClass FwClass of Esrt entry to get
30 @param[in, out] Entry Esrt entry returned
32 @retval EFI_SUCCESS The variable saving this Esrt Entry exists.
33 @retval EF_NOT_FOUND No correct variable found.
34 @retval EFI_WRITE_PROTECTED ESRT Cache repository is locked
41 IN OUT EFI_SYSTEM_RESOURCE_ENTRY
*Entry
46 if (FwClass
== NULL
|| Entry
== NULL
) {
47 return EFI_INVALID_PARAMETER
;
50 Status
= EfiAcquireLockOrFail (&mPrivate
.NonFmpLock
);
51 if (EFI_ERROR (Status
)) {
56 // Find in Non-FMP Cached Esrt Repository
58 Status
= GetEsrtEntry(
64 EfiReleaseLock(&mPrivate
.NonFmpLock
);
66 if (EFI_ERROR(Status
)) {
67 Status
= EfiAcquireLockOrFail (&mPrivate
.FmpLock
);
68 if (EFI_ERROR (Status
)) {
73 // Find in FMP Cached Esrt NV Variable
75 Status
= GetEsrtEntry(
81 EfiReleaseLock(&mPrivate
.FmpLock
);
88 Update one ESRT entry in ESRT Cache.
90 @param[in] Entry Esrt entry to be updated
92 @retval EFI_SUCCESS Successfully update an ESRT entry in cache.
93 @retval EFI_INVALID_PARAMETER Entry does't exist in ESRT Cache
94 @retval EFI_WRITE_PROTECTED ESRT Cache repositoy is locked
99 EsrtDxeUpdateEsrtEntry(
100 IN EFI_SYSTEM_RESOURCE_ENTRY
*Entry
106 return EFI_INVALID_PARAMETER
;
109 Status
= EfiAcquireLockOrFail (&mPrivate
.FmpLock
);
110 if (EFI_ERROR (Status
)) {
114 Status
= UpdateEsrtEntry(Entry
, ESRT_FROM_FMP
);
116 if (!EFI_ERROR(Status
)) {
117 EfiReleaseLock(&mPrivate
.FmpLock
);
120 EfiReleaseLock(&mPrivate
.FmpLock
);
123 Status
= EfiAcquireLockOrFail (&mPrivate
.NonFmpLock
);
124 if (EFI_ERROR (Status
)) {
128 Status
= UpdateEsrtEntry(Entry
, ESRT_FROM_NONFMP
);
130 EfiReleaseLock(&mPrivate
.NonFmpLock
);
136 Non-FMP instance to unregister Esrt Entry from ESRT Cache.
138 @param[in] FwClass FwClass of Esrt entry to Unregister
140 @retval EFI_SUCCESS Insert all entries Successfully
141 @retval EFI_NOT_FOUND Entry of FwClass does not exsit
146 EsrtDxeUnRegisterEsrtEntry(
152 if (FwClass
== NULL
) {
153 return EFI_INVALID_PARAMETER
;
156 Status
= EfiAcquireLockOrFail (&mPrivate
.NonFmpLock
);
157 if (EFI_ERROR (Status
)) {
161 Status
= DeleteEsrtEntry(FwClass
, ESRT_FROM_NONFMP
);
163 EfiReleaseLock(&mPrivate
.NonFmpLock
);
169 Non-FMP instance to register one ESRT entry into ESRT Cache.
171 @param[in] Entry Esrt entry to be set
173 @retval EFI_SUCCESS Successfully set a variable.
174 @retval EFI_INVALID_PARAMETER ESRT Entry is already exist
175 @retval EFI_OUT_OF_RESOURCES Non-FMP ESRT repository is full
180 EsrtDxeRegisterEsrtEntry(
181 IN EFI_SYSTEM_RESOURCE_ENTRY
*Entry
185 EFI_SYSTEM_RESOURCE_ENTRY EsrtEntryTmp
;
188 return EFI_INVALID_PARAMETER
;
191 Status
= EfiAcquireLockOrFail (&mPrivate
.NonFmpLock
);
192 if (EFI_ERROR (Status
)) {
196 Status
= GetEsrtEntry(
202 if (Status
== EFI_NOT_FOUND
) {
203 Status
= InsertEsrtEntry(Entry
, ESRT_FROM_NONFMP
);
206 EfiReleaseLock(&mPrivate
.NonFmpLock
);
212 This function syn up Cached ESRT with data from FMP instances
213 Function should be called after Connect All in order to locate all FMP protocols
216 @retval EFI_SUCCESS Successfully sync cache repository from FMP instances
217 @retval EFI_NOT_FOUND No FMP Instance are found
218 @retval EFI_OUT_OF_RESOURCES Resource allocaton fail
231 EFI_HANDLE
*HandleBuffer
;
232 EFI_FIRMWARE_MANAGEMENT_PROTOCOL
**FmpBuf
;
233 UINTN NumberOfHandles
;
234 UINTN
*DescriptorSizeBuf
;
235 EFI_FIRMWARE_IMAGE_DESCRIPTOR
**FmpImageInfoBuf
;
236 EFI_FIRMWARE_IMAGE_DESCRIPTOR
*TempFmpImageInfo
;
237 UINT8
*FmpImageInfoCountBuf
;
238 UINT32
*FmpImageInfoDescriptorVerBuf
;
240 UINT32 PackageVersion
;
241 CHAR16
*PackageVersionName
;
242 EFI_SYSTEM_RESOURCE_ENTRY
*EsrtRepositoryNew
;
249 FmpImageInfoBuf
= NULL
;
250 FmpImageInfoCountBuf
= NULL
;
251 PackageVersionName
= NULL
;
252 DescriptorSizeBuf
= NULL
;
253 FmpImageInfoDescriptorVerBuf
= NULL
;
254 EsrtRepositoryNew
= NULL
;
257 // Get image information from all FMP protocol
259 Status
= gBS
->LocateHandleBuffer (
261 &gEfiFirmwareManagementProtocolGuid
,
268 if (Status
== EFI_NOT_FOUND
) {
270 goto UPDATE_REPOSITORY
;
271 } else if (EFI_ERROR(Status
)){
276 // Allocate buffer to hold new FMP ESRT Cache repository
278 EsrtRepositoryNew
= AllocateZeroPool(PcdGet32(PcdMaxFmpEsrtCacheNum
) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY
));
279 if (EsrtRepositoryNew
== NULL
) {
280 Status
= EFI_OUT_OF_RESOURCES
;
284 FmpBuf
= AllocatePool(sizeof(EFI_FIRMWARE_MANAGEMENT_PROTOCOL
*) * NumberOfHandles
);
285 if (FmpBuf
== NULL
) {
286 Status
= EFI_OUT_OF_RESOURCES
;
290 FmpImageInfoBuf
= AllocateZeroPool(sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR
*) * NumberOfHandles
);
291 if (FmpImageInfoBuf
== NULL
) {
292 Status
= EFI_OUT_OF_RESOURCES
;
296 FmpImageInfoCountBuf
= AllocateZeroPool(sizeof(UINT8
) * NumberOfHandles
);
297 if (FmpImageInfoCountBuf
== NULL
) {
298 Status
= EFI_OUT_OF_RESOURCES
;
302 DescriptorSizeBuf
= AllocateZeroPool(sizeof(UINTN
) * NumberOfHandles
);
303 if (DescriptorSizeBuf
== NULL
) {
304 Status
= EFI_OUT_OF_RESOURCES
;
308 FmpImageInfoDescriptorVerBuf
= AllocateZeroPool(sizeof(UINT32
) * NumberOfHandles
);
309 if (FmpImageInfoDescriptorVerBuf
== NULL
) {
310 Status
= EFI_OUT_OF_RESOURCES
;
315 // Get all FmpImageInfo Descriptor into FmpImageInfoBuf
317 for (Index1
= 0; Index1
< NumberOfHandles
; Index1
++){
318 Status
= gBS
->HandleProtocol(
319 HandleBuffer
[Index1
],
320 &gEfiFirmwareManagementProtocolGuid
,
321 (VOID
**)&FmpBuf
[Index1
]
324 if (EFI_ERROR(Status
)) {
329 Status
= FmpBuf
[Index1
]->GetImageInfo (
340 if (Status
== EFI_BUFFER_TOO_SMALL
) {
341 FmpImageInfoBuf
[Index1
] = AllocateZeroPool(ImageInfoSize
);
342 if (FmpImageInfoBuf
[Index1
] == NULL
) {
343 Status
= EFI_OUT_OF_RESOURCES
;
350 PackageVersionName
= NULL
;
351 Status
= FmpBuf
[Index1
]->GetImageInfo (
354 FmpImageInfoBuf
[Index1
],
355 &FmpImageInfoDescriptorVerBuf
[Index1
],
356 &FmpImageInfoCountBuf
[Index1
],
357 &DescriptorSizeBuf
[Index1
],
363 // If FMP GetInformation interface failed, skip this resource
365 if (EFI_ERROR(Status
)){
366 FmpImageInfoCountBuf
[Index1
] = 0;
370 if (PackageVersionName
!= NULL
) {
371 FreePool(PackageVersionName
);
376 // Create new FMP cache repository based on FmpImageInfoBuf
378 for (Index2
= 0; Index2
< NumberOfHandles
; Index2
++){
379 TempFmpImageInfo
= FmpImageInfoBuf
[Index2
];
380 for (Index3
= 0; Index3
< FmpImageInfoCountBuf
[Index2
]; Index3
++){
381 if ((TempFmpImageInfo
->AttributesSupported
& IMAGE_ATTRIBUTE_IN_USE
) != 0
382 && (TempFmpImageInfo
->AttributesSetting
& IMAGE_ATTRIBUTE_IN_USE
) != 0){
384 // Always put the first smallest version of Image info into ESRT cache
386 for(Index1
= 0; Index1
< EntryNumNew
; Index1
++) {
387 if (CompareGuid(&EsrtRepositoryNew
[Index1
].FwClass
, &TempFmpImageInfo
->ImageTypeId
)) {
388 if(EsrtRepositoryNew
[Index1
].FwVersion
> TempFmpImageInfo
->Version
) {
389 SetEsrtEntryFromFmpInfo(&EsrtRepositoryNew
[Index1
], TempFmpImageInfo
, FmpImageInfoDescriptorVerBuf
[Index2
]);
395 // New ImageTypeId can't be found in EsrtRepositoryNew. Create a new one
397 if (Index1
== EntryNumNew
){
398 SetEsrtEntryFromFmpInfo(&EsrtRepositoryNew
[EntryNumNew
], TempFmpImageInfo
, FmpImageInfoDescriptorVerBuf
[Index2
]);
400 if (EntryNumNew
>= PcdGet32(PcdMaxFmpEsrtCacheNum
)) {
407 // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
409 TempFmpImageInfo
= (EFI_FIRMWARE_IMAGE_DESCRIPTOR
*)((UINT8
*)TempFmpImageInfo
+ DescriptorSizeBuf
[Index2
]);
415 Status
= EfiAcquireLockOrFail (&mPrivate
.FmpLock
);
416 if (EFI_ERROR (Status
)) {
420 Status
= gRT
->SetVariable(
421 EFI_ESRT_FMP_VARIABLE_NAME
,
423 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
424 EntryNumNew
* sizeof(EFI_SYSTEM_RESOURCE_ENTRY
),
428 EfiReleaseLock(&mPrivate
.FmpLock
);
431 if (EsrtRepositoryNew
!= NULL
) {
432 FreePool(EsrtRepositoryNew
);
435 if (HandleBuffer
!= NULL
) {
436 FreePool(HandleBuffer
);
439 if (FmpBuf
!= NULL
) {
443 if (FmpImageInfoCountBuf
!= NULL
) {
444 FreePool(FmpImageInfoCountBuf
);
447 if (DescriptorSizeBuf
!= NULL
) {
448 FreePool(DescriptorSizeBuf
);
451 if (FmpImageInfoDescriptorVerBuf
!= NULL
) {
452 FreePool(FmpImageInfoDescriptorVerBuf
);
455 if (FmpImageInfoBuf
!= NULL
) {
456 for (Index1
= 0; Index1
< NumberOfHandles
; Index1
++){
457 if (FmpImageInfoBuf
[Index1
] != NULL
) {
458 FreePool(FmpImageInfoBuf
[Index1
]);
461 FreePool(FmpImageInfoBuf
);
468 This function locks up Esrt repository to be readonly. It should be called
469 before gEfiEndOfDxeEventGroupGuid event signaled
471 @retval EFI_SUCCESS Locks up FMP Non-FMP repository successfully
476 EsrtDxeLockEsrtRepository(
481 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
483 // Mark ACPI_GLOBAL_VARIABLE variable to read-only if the Variable Lock protocol exists
485 Status
= gBS
->LocateProtocol (&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**) &VariableLock
);
486 if (!EFI_ERROR (Status
)) {
487 Status
= VariableLock
->RequestToLock (VariableLock
, EFI_ESRT_FMP_VARIABLE_NAME
, &gEfiCallerIdGuid
);
488 DEBUG((EFI_D_INFO
, "EsrtDxe Lock EsrtFmp Variable Status 0x%x", Status
));
490 Status
= VariableLock
->RequestToLock (VariableLock
, EFI_ESRT_NONFMP_VARIABLE_NAME
, &gEfiCallerIdGuid
);
491 DEBUG((EFI_D_INFO
, "EsrtDxe Lock EsrtNonFmp Variable Status 0x%x", Status
));
498 Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
499 install the Esrt Table into system configuration table
501 @param[in] Event The Event that is being processed.
502 @param[in] Context The Event Context.
507 EsrtReadyToBootEventNotify (
513 EFI_SYSTEM_RESOURCE_TABLE
*EsrtTable
;
514 EFI_SYSTEM_RESOURCE_ENTRY
*FmpEsrtRepository
;
515 EFI_SYSTEM_RESOURCE_ENTRY
*NonFmpEsrtRepository
;
516 UINTN FmpRepositorySize
;
517 UINTN NonFmpRepositorySize
;
520 FmpEsrtRepository
= NULL
;
521 NonFmpEsrtRepository
= NULL
;
522 FmpRepositorySize
= 0;
523 NonFmpRepositorySize
= 0;
525 Status
= EfiAcquireLockOrFail (&mPrivate
.NonFmpLock
);
526 if (EFI_ERROR (Status
)) {
530 Status
= GetVariable2 (
531 EFI_ESRT_NONFMP_VARIABLE_NAME
,
533 (VOID
**) &NonFmpEsrtRepository
,
534 &NonFmpRepositorySize
537 if (EFI_ERROR(Status
)) {
538 NonFmpRepositorySize
= 0;
541 if (NonFmpRepositorySize
% sizeof(EFI_SYSTEM_RESOURCE_ENTRY
) != 0) {
542 DEBUG((EFI_D_ERROR
, "NonFmp Repository Corrupt. Need to rebuild NonFmp Repository.\n"));
543 NonFmpRepositorySize
= 0;
546 EfiReleaseLock(&mPrivate
.NonFmpLock
);
548 Status
= EfiAcquireLockOrFail (&mPrivate
.FmpLock
);
549 Status
= GetVariable2 (
550 EFI_ESRT_FMP_VARIABLE_NAME
,
552 (VOID
**) &FmpEsrtRepository
,
556 if (EFI_ERROR(Status
)) {
557 FmpRepositorySize
= 0;
560 if (FmpRepositorySize
% sizeof(EFI_SYSTEM_RESOURCE_ENTRY
) != 0) {
561 DEBUG((EFI_D_ERROR
, "Fmp Repository Corrupt. Need to rebuild Fmp Repository.\n"));
562 FmpRepositorySize
= 0;
565 EfiReleaseLock(&mPrivate
.FmpLock
);
568 // Skip ESRT table publish if no ESRT entry exists
570 if (NonFmpRepositorySize
+ FmpRepositorySize
== 0) {
574 EsrtTable
= AllocatePool(sizeof(EFI_SYSTEM_RESOURCE_TABLE
) + NonFmpRepositorySize
+ FmpRepositorySize
);
575 if (EsrtTable
== NULL
) {
576 DEBUG ((EFI_D_ERROR
, "Esrt table memory allocation failure\n"));
580 EsrtTable
->FwResourceVersion
= EFI_SYSTEM_RESOURCE_TABLE_FIRMWARE_RESOURCE_VERSION
;
581 EsrtTable
->FwResourceCount
= (UINT32
)((NonFmpRepositorySize
+ FmpRepositorySize
) / sizeof(EFI_SYSTEM_RESOURCE_ENTRY
));
582 EsrtTable
->FwResourceCountMax
= PcdGet32(PcdMaxNonFmpEsrtCacheNum
) + PcdGet32(PcdMaxFmpEsrtCacheNum
);
584 if (NonFmpRepositorySize
!= 0 && NonFmpEsrtRepository
!= NULL
) {
585 CopyMem(EsrtTable
+ 1, NonFmpEsrtRepository
, NonFmpRepositorySize
);
588 if (FmpRepositorySize
!= 0 && FmpEsrtRepository
!= NULL
) {
589 CopyMem((UINT8
*)(EsrtTable
+ 1) + NonFmpRepositorySize
, FmpEsrtRepository
, FmpRepositorySize
);
593 // Publish Esrt to system config table
595 Status
= gBS
->InstallConfigurationTable (&gEfiSystemResourceTableGuid
, EsrtTable
);
598 // Only one successful install
600 gBS
->CloseEvent(Event
);
604 if (FmpEsrtRepository
!= NULL
) {
605 FreePool(FmpEsrtRepository
);
608 if (NonFmpEsrtRepository
!= NULL
) {
609 FreePool(NonFmpEsrtRepository
);
614 The module Entry Point of the Esrt DXE driver that manages cached ESRT repository
615 & publishes ESRT table
617 @param[in] ImageHandle The firmware allocated handle for the EFI image.
618 @param[in] SystemTable A pointer to the EFI System Table.
620 @retval EFI_SUCCESS The entry point is executed successfully.
621 @retval Other Some error occurs when executing this entry point.
627 IN EFI_HANDLE ImageHandle
,
628 IN EFI_SYSTEM_TABLE
*SystemTable
633 EfiInitializeLock (&mPrivate
.FmpLock
, TPL_CALLBACK
);
634 EfiInitializeLock (&mPrivate
.NonFmpLock
, TPL_CALLBACK
);
637 // Install Esrt management Protocol
639 Status
= gBS
->InstallMultipleProtocolInterfaces (
641 &gEsrtManagementProtocolGuid
,
642 &mEsrtManagementProtocolTemplate
,
645 ASSERT_EFI_ERROR (Status
);
648 // Register notify function to install Esrt Table on ReadyToBoot Event.
650 Status
= gBS
->CreateEventEx (
653 EsrtReadyToBootEventNotify
,
655 &gEfiEventReadyToBootGuid
,
658 ASSERT_EFI_ERROR (Status
);