2 Esrt management module.
4 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 ESRT_PRIVATE_DATA mPrivate
;
23 ESRT_MANAGEMENT_PROTOCOL mEsrtManagementProtocolTemplate
= {
25 EsrtDxeUpdateEsrtEntry
,
26 EsrtDxeRegisterEsrtEntry
,
27 EsrtDxeUnRegisterEsrtEntry
,
29 EsrtDxeLockEsrtRepository
33 Get ESRT entry from ESRT Cache by FwClass Guid
35 @param[in] FwClass FwClass of Esrt entry to get
36 @param[in, out] Entry Esrt entry returned
38 @retval EFI_SUCCESS The variable saving this Esrt Entry exists.
39 @retval EF_NOT_FOUND No correct variable found.
40 @retval EFI_WRITE_PROTECTED ESRT Cache repository is locked
47 IN OUT EFI_SYSTEM_RESOURCE_ENTRY
*Entry
52 if (FwClass
== NULL
|| Entry
== NULL
) {
53 return EFI_INVALID_PARAMETER
;
56 Status
= EfiAcquireLockOrFail (&mPrivate
.NonFmpLock
);
57 if (EFI_ERROR (Status
)) {
62 // Find in Non-FMP Cached Esrt Repository
64 Status
= GetEsrtEntry(
70 EfiReleaseLock(&mPrivate
.NonFmpLock
);
72 if (EFI_ERROR(Status
)) {
73 Status
= EfiAcquireLockOrFail (&mPrivate
.FmpLock
);
74 if (EFI_ERROR (Status
)) {
79 // Find in FMP Cached Esrt NV Variable
81 Status
= GetEsrtEntry(
87 EfiReleaseLock(&mPrivate
.FmpLock
);
94 Update one ESRT entry in ESRT Cache.
96 @param[in] Entry Esrt entry to be updated
98 @retval EFI_SUCCESS Successfully update an ESRT entry in cache.
99 @retval EFI_INVALID_PARAMETER Entry does't exist in ESRT Cache
100 @retval EFI_WRITE_PROTECTED ESRT Cache repositoy is locked
105 EsrtDxeUpdateEsrtEntry(
106 IN EFI_SYSTEM_RESOURCE_ENTRY
*Entry
112 return EFI_INVALID_PARAMETER
;
115 Status
= EfiAcquireLockOrFail (&mPrivate
.FmpLock
);
116 if (EFI_ERROR (Status
)) {
120 Status
= UpdateEsrtEntry(Entry
, ESRT_FROM_FMP
);
122 if (!EFI_ERROR(Status
)) {
123 EfiReleaseLock(&mPrivate
.FmpLock
);
126 EfiReleaseLock(&mPrivate
.FmpLock
);
129 Status
= EfiAcquireLockOrFail (&mPrivate
.NonFmpLock
);
130 if (EFI_ERROR (Status
)) {
134 Status
= UpdateEsrtEntry(Entry
, ESRT_FROM_NONFMP
);
136 EfiReleaseLock(&mPrivate
.NonFmpLock
);
142 Non-FMP instance to unregister Esrt Entry from ESRT Cache.
144 @param[in] FwClass FwClass of Esrt entry to Unregister
146 @retval EFI_SUCCESS Insert all entries Successfully
147 @retval EFI_NOT_FOUND Entry of FwClass does not exsit
152 EsrtDxeUnRegisterEsrtEntry(
158 if (FwClass
== NULL
) {
159 return EFI_INVALID_PARAMETER
;
162 Status
= EfiAcquireLockOrFail (&mPrivate
.NonFmpLock
);
163 if (EFI_ERROR (Status
)) {
167 Status
= DeleteEsrtEntry(FwClass
, ESRT_FROM_NONFMP
);
169 EfiReleaseLock(&mPrivate
.NonFmpLock
);
175 Non-FMP instance to register one ESRT entry into ESRT Cache.
177 @param[in] Entry Esrt entry to be set
179 @retval EFI_SUCCESS Successfully set a variable.
180 @retval EFI_INVALID_PARAMETER ESRT Entry is already exist
181 @retval EFI_OUT_OF_RESOURCES Non-FMP ESRT repository is full
186 EsrtDxeRegisterEsrtEntry(
187 IN EFI_SYSTEM_RESOURCE_ENTRY
*Entry
191 EFI_SYSTEM_RESOURCE_ENTRY EsrtEntryTmp
;
194 return EFI_INVALID_PARAMETER
;
197 Status
= EfiAcquireLockOrFail (&mPrivate
.NonFmpLock
);
198 if (EFI_ERROR (Status
)) {
202 Status
= GetEsrtEntry(
208 if (Status
== EFI_NOT_FOUND
) {
209 Status
= InsertEsrtEntry(Entry
, ESRT_FROM_NONFMP
);
212 EfiReleaseLock(&mPrivate
.NonFmpLock
);
218 This function syn up Cached ESRT with data from FMP instances
219 Function should be called after Connect All in order to locate all FMP protocols
222 @retval EFI_SUCCESS Successfully sync cache repository from FMP instances
223 @retval EFI_NOT_FOUND No FMP Instance are found
224 @retval EFI_OUT_OF_RESOURCES Resource allocaton fail
237 EFI_HANDLE
*HandleBuffer
;
238 EFI_FIRMWARE_MANAGEMENT_PROTOCOL
**FmpBuf
;
239 UINTN NumberOfHandles
;
240 UINTN
*DescriptorSizeBuf
;
241 EFI_FIRMWARE_IMAGE_DESCRIPTOR
**FmpImageInfoBuf
;
242 EFI_FIRMWARE_IMAGE_DESCRIPTOR
*TempFmpImageInfo
;
243 UINT8
*FmpImageInfoCountBuf
;
244 UINT32
*FmpImageInfoDescriptorVerBuf
;
246 UINT32 PackageVersion
;
247 CHAR16
*PackageVersionName
;
248 EFI_SYSTEM_RESOURCE_ENTRY
*EsrtRepositoryNew
;
255 FmpImageInfoBuf
= NULL
;
256 FmpImageInfoCountBuf
= NULL
;
257 PackageVersionName
= NULL
;
258 DescriptorSizeBuf
= NULL
;
259 FmpImageInfoDescriptorVerBuf
= NULL
;
260 EsrtRepositoryNew
= NULL
;
263 // Get image information from all FMP protocol
265 Status
= gBS
->LocateHandleBuffer (
267 &gEfiFirmwareManagementProtocolGuid
,
274 if (Status
== EFI_NOT_FOUND
) {
276 goto UPDATE_REPOSITORY
;
277 } else if (EFI_ERROR(Status
)){
282 // Allocate buffer to hold new FMP ESRT Cache repository
284 EsrtRepositoryNew
= AllocateZeroPool(PcdGet32(PcdMaxFmpEsrtCacheNum
) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY
));
285 if (EsrtRepositoryNew
== NULL
) {
286 Status
= EFI_OUT_OF_RESOURCES
;
290 FmpBuf
= AllocatePool(sizeof(EFI_FIRMWARE_MANAGEMENT_PROTOCOL
*) * NumberOfHandles
);
291 if (FmpBuf
== NULL
) {
292 Status
= EFI_OUT_OF_RESOURCES
;
296 FmpImageInfoBuf
= AllocateZeroPool(sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR
*) * NumberOfHandles
);
297 if (FmpImageInfoBuf
== NULL
) {
298 Status
= EFI_OUT_OF_RESOURCES
;
302 FmpImageInfoCountBuf
= AllocateZeroPool(sizeof(UINT8
) * NumberOfHandles
);
303 if (FmpImageInfoCountBuf
== NULL
) {
304 Status
= EFI_OUT_OF_RESOURCES
;
308 DescriptorSizeBuf
= AllocateZeroPool(sizeof(UINTN
) * NumberOfHandles
);
309 if (DescriptorSizeBuf
== NULL
) {
310 Status
= EFI_OUT_OF_RESOURCES
;
314 FmpImageInfoDescriptorVerBuf
= AllocateZeroPool(sizeof(UINT32
) * NumberOfHandles
);
315 if (FmpImageInfoDescriptorVerBuf
== NULL
) {
316 Status
= EFI_OUT_OF_RESOURCES
;
321 // Get all FmpImageInfo Descriptor into FmpImageInfoBuf
323 for (Index1
= 0; Index1
< NumberOfHandles
; Index1
++){
324 Status
= gBS
->HandleProtocol(
325 HandleBuffer
[Index1
],
326 &gEfiFirmwareManagementProtocolGuid
,
327 (VOID
**)&FmpBuf
[Index1
]
330 if (EFI_ERROR(Status
)) {
335 Status
= FmpBuf
[Index1
]->GetImageInfo (
346 if (Status
== EFI_BUFFER_TOO_SMALL
) {
347 FmpImageInfoBuf
[Index1
] = AllocateZeroPool(ImageInfoSize
);
348 if (FmpImageInfoBuf
[Index1
] == NULL
) {
349 Status
= EFI_OUT_OF_RESOURCES
;
356 PackageVersionName
= NULL
;
357 Status
= FmpBuf
[Index1
]->GetImageInfo (
360 FmpImageInfoBuf
[Index1
],
361 &FmpImageInfoDescriptorVerBuf
[Index1
],
362 &FmpImageInfoCountBuf
[Index1
],
363 &DescriptorSizeBuf
[Index1
],
369 // If FMP GetInformation interface failed, skip this resource
371 if (EFI_ERROR(Status
)){
372 FmpImageInfoCountBuf
[Index1
] = 0;
376 if (PackageVersionName
!= NULL
) {
377 FreePool(PackageVersionName
);
382 // Create new FMP cache repository based on FmpImageInfoBuf
384 for (Index2
= 0; Index2
< NumberOfHandles
; Index2
++){
385 TempFmpImageInfo
= FmpImageInfoBuf
[Index2
];
386 for (Index3
= 0; Index3
< FmpImageInfoCountBuf
[Index2
]; Index3
++){
387 if ((TempFmpImageInfo
->AttributesSupported
& IMAGE_ATTRIBUTE_IN_USE
) != 0
388 && (TempFmpImageInfo
->AttributesSetting
& IMAGE_ATTRIBUTE_IN_USE
) != 0){
390 // Always put the first smallest version of Image info into ESRT cache
392 for(Index1
= 0; Index1
< EntryNumNew
; Index1
++) {
393 if (CompareGuid(&EsrtRepositoryNew
[Index1
].FwClass
, &TempFmpImageInfo
->ImageTypeId
)) {
394 if(EsrtRepositoryNew
[Index1
].FwVersion
> TempFmpImageInfo
->Version
) {
395 SetEsrtEntryFromFmpInfo(&EsrtRepositoryNew
[Index1
], TempFmpImageInfo
, FmpImageInfoDescriptorVerBuf
[Index2
]);
401 // New ImageTypeId can't be found in EsrtRepositoryNew. Create a new one
403 if (Index1
== EntryNumNew
){
404 SetEsrtEntryFromFmpInfo(&EsrtRepositoryNew
[EntryNumNew
], TempFmpImageInfo
, FmpImageInfoDescriptorVerBuf
[Index2
]);
406 if (EntryNumNew
>= PcdGet32(PcdMaxFmpEsrtCacheNum
)) {
413 // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
415 TempFmpImageInfo
= (EFI_FIRMWARE_IMAGE_DESCRIPTOR
*)((UINT8
*)TempFmpImageInfo
+ DescriptorSizeBuf
[Index2
]);
421 Status
= EfiAcquireLockOrFail (&mPrivate
.FmpLock
);
422 if (EFI_ERROR (Status
)) {
426 Status
= gRT
->SetVariable(
427 EFI_ESRT_FMP_VARIABLE_NAME
,
429 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
430 EntryNumNew
* sizeof(EFI_SYSTEM_RESOURCE_ENTRY
),
434 EfiReleaseLock(&mPrivate
.FmpLock
);
437 if (EsrtRepositoryNew
!= NULL
) {
438 FreePool(EsrtRepositoryNew
);
441 if (HandleBuffer
!= NULL
) {
442 FreePool(HandleBuffer
);
445 if (FmpBuf
!= NULL
) {
449 if (FmpImageInfoCountBuf
!= NULL
) {
450 FreePool(FmpImageInfoCountBuf
);
453 if (DescriptorSizeBuf
!= NULL
) {
454 FreePool(DescriptorSizeBuf
);
457 if (FmpImageInfoDescriptorVerBuf
!= NULL
) {
458 FreePool(FmpImageInfoDescriptorVerBuf
);
461 if (FmpImageInfoBuf
!= NULL
) {
462 for (Index1
= 0; Index1
< NumberOfHandles
; Index1
++){
463 if (FmpImageInfoBuf
[Index1
] != NULL
) {
464 FreePool(FmpImageInfoBuf
[Index1
]);
467 FreePool(FmpImageInfoBuf
);
474 This function locks up Esrt repository to be readonly. It should be called
475 before gEfiEndOfDxeEventGroupGuid event signaled
477 @retval EFI_SUCCESS Locks up FMP Non-FMP repository successfully
482 EsrtDxeLockEsrtRepository(
487 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
489 // Mark ACPI_GLOBAL_VARIABLE variable to read-only if the Variable Lock protocol exists
491 Status
= gBS
->LocateProtocol (&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**) &VariableLock
);
492 if (!EFI_ERROR (Status
)) {
493 Status
= VariableLock
->RequestToLock (VariableLock
, EFI_ESRT_FMP_VARIABLE_NAME
, &gEfiCallerIdGuid
);
494 DEBUG((EFI_D_INFO
, "EsrtDxe Lock EsrtFmp Variable Status 0x%x", Status
));
496 Status
= VariableLock
->RequestToLock (VariableLock
, EFI_ESRT_NONFMP_VARIABLE_NAME
, &gEfiCallerIdGuid
);
497 DEBUG((EFI_D_INFO
, "EsrtDxe Lock EsrtNonFmp Variable Status 0x%x", Status
));
504 Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
505 install the Esrt Table into system configuration table
507 @param[in] Event The Event that is being processed.
508 @param[in] Context The Event Context.
513 EsrtReadyToBootEventNotify (
519 EFI_SYSTEM_RESOURCE_TABLE
*EsrtTable
;
520 EFI_SYSTEM_RESOURCE_ENTRY
*FmpEsrtRepository
;
521 EFI_SYSTEM_RESOURCE_ENTRY
*NonFmpEsrtRepository
;
522 UINTN FmpRepositorySize
;
523 UINTN NonFmpRepositorySize
;
526 FmpEsrtRepository
= NULL
;
527 NonFmpEsrtRepository
= NULL
;
528 FmpRepositorySize
= 0;
529 NonFmpRepositorySize
= 0;
531 Status
= EfiAcquireLockOrFail (&mPrivate
.NonFmpLock
);
532 if (EFI_ERROR (Status
)) {
536 Status
= GetVariable2 (
537 EFI_ESRT_NONFMP_VARIABLE_NAME
,
539 (VOID
**) &NonFmpEsrtRepository
,
540 &NonFmpRepositorySize
543 if (EFI_ERROR(Status
)) {
544 NonFmpRepositorySize
= 0;
547 if (NonFmpRepositorySize
% sizeof(EFI_SYSTEM_RESOURCE_ENTRY
) != 0) {
548 DEBUG((EFI_D_ERROR
, "NonFmp Repository Corrupt. Need to rebuild NonFmp Repository.\n"));
549 NonFmpRepositorySize
= 0;
552 EfiReleaseLock(&mPrivate
.NonFmpLock
);
554 Status
= EfiAcquireLockOrFail (&mPrivate
.FmpLock
);
555 Status
= GetVariable2 (
556 EFI_ESRT_FMP_VARIABLE_NAME
,
558 (VOID
**) &FmpEsrtRepository
,
562 if (EFI_ERROR(Status
)) {
563 FmpRepositorySize
= 0;
566 if (FmpRepositorySize
% sizeof(EFI_SYSTEM_RESOURCE_ENTRY
) != 0) {
567 DEBUG((EFI_D_ERROR
, "Fmp Repository Corrupt. Need to rebuild Fmp Repository.\n"));
568 FmpRepositorySize
= 0;
571 EfiReleaseLock(&mPrivate
.FmpLock
);
574 // Skip ESRT table publish if no ESRT entry exists
576 if (NonFmpRepositorySize
+ FmpRepositorySize
== 0) {
580 EsrtTable
= AllocatePool(sizeof(EFI_SYSTEM_RESOURCE_TABLE
) + NonFmpRepositorySize
+ FmpRepositorySize
);
581 if (EsrtTable
== NULL
) {
582 DEBUG ((EFI_D_ERROR
, "Esrt table memory allocation failure\n"));
586 EsrtTable
->FwResourceVersion
= EFI_SYSTEM_RESOURCE_TABLE_FIRMWARE_RESOURCE_VERSION
;
587 EsrtTable
->FwResourceCount
= (UINT32
)((NonFmpRepositorySize
+ FmpRepositorySize
) / sizeof(EFI_SYSTEM_RESOURCE_ENTRY
));
588 EsrtTable
->FwResourceCountMax
= PcdGet32(PcdMaxNonFmpEsrtCacheNum
) + PcdGet32(PcdMaxFmpEsrtCacheNum
);
590 if (NonFmpRepositorySize
!= 0 && NonFmpEsrtRepository
!= NULL
) {
591 CopyMem(EsrtTable
+ 1, NonFmpEsrtRepository
, NonFmpRepositorySize
);
594 if (FmpRepositorySize
!= 0 && FmpEsrtRepository
!= NULL
) {
595 CopyMem((UINT8
*)(EsrtTable
+ 1) + NonFmpRepositorySize
, FmpEsrtRepository
, FmpRepositorySize
);
599 // Publish Esrt to system config table
601 Status
= gBS
->InstallConfigurationTable (&gEfiSystemResourceTableGuid
, EsrtTable
);
604 // Only one successful install
606 gBS
->CloseEvent(Event
);
610 if (FmpEsrtRepository
!= NULL
) {
611 FreePool(FmpEsrtRepository
);
614 if (NonFmpEsrtRepository
!= NULL
) {
615 FreePool(NonFmpEsrtRepository
);
620 The module Entry Point of the Esrt DXE driver that manages cached ESRT repository
621 & publishes ESRT table
623 @param[in] ImageHandle The firmware allocated handle for the EFI image.
624 @param[in] SystemTable A pointer to the EFI System Table.
626 @retval EFI_SUCCESS The entry point is executed successfully.
627 @retval Other Some error occurs when executing this entry point.
633 IN EFI_HANDLE ImageHandle
,
634 IN EFI_SYSTEM_TABLE
*SystemTable
639 EfiInitializeLock (&mPrivate
.FmpLock
, TPL_CALLBACK
);
640 EfiInitializeLock (&mPrivate
.NonFmpLock
, TPL_CALLBACK
);
643 // Install Esrt management Protocol
645 Status
= gBS
->InstallMultipleProtocolInterfaces (
647 &gEsrtManagementProtocolGuid
,
648 &mEsrtManagementProtocolTemplate
,
651 ASSERT_EFI_ERROR (Status
);
654 // Register notify function to install Esrt Table on ReadyToBoot Event.
656 Status
= gBS
->CreateEventEx (
659 EsrtReadyToBootEventNotify
,
661 &gEfiEventReadyToBootGuid
,
664 ASSERT_EFI_ERROR (Status
);