OvmfPkg: Introduce PlatformBootManagerCommonLib

Many function present in PlatformBootManagerLib and
PlatformBootManagerLibLight have the same implementation. The idea of
this new Library is to collect them to enable code reuse.

Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
This commit is contained in:
Luigi Leonardi
2025-02-13 12:51:11 +01:00
committed by mergify[bot]
parent 566aece5b8
commit a255b52fbc
3 changed files with 357 additions and 0 deletions

View File

@ -0,0 +1,28 @@
/** @file
Common code PlatformBootManager and PlatformBootManagerLight.
Copyright (C) 2025, Red Hat, Inc.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __PLATFORMBOOTMANAGERCOMMON_LIB_H__
#define __PLATFORMBOOTMANAGERCOMMON_LIB_H__
#include <Uefi/UefiBaseType.h>
#include <Base.h>
VOID
PlatformRegisterFvBootOption (
EFI_GUID *FileGuid,
CHAR16 *Description,
UINT32 Attributes,
BOOLEAN Enabled
);
VOID
RemoveStaleFvFileOptions (
VOID
);
#endif

View File

@ -0,0 +1,282 @@
/** @file
Common code PlatformBootManager and PlatformBootManagerLight.
Copyright (C) 2025, Red Hat, Inc.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/QemuFwCfgLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootManagerLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/BaseLib.h>
#include <Library/PrintLib.h>
#include <Library/DevicePathLib.h>
#include <Library/PlatformBootManagerCommonLib.h>
#include <Library/BaseMemoryLib.h>
#include <Guid/GlobalVariable.h>
#include <Protocol/LoadedImage.h>
#include <Library/UefiLib.h>
#include <Protocol/FirmwareVolume2.h>
/**
This function checks whether a File exists within the firmware volume.
@param[in] FilePath Path of the file.
@return TRUE if the file exists within the volume, false
otherwise.
**/
BOOLEAN
static
FileIsInFv (
EFI_DEVICE_PATH_PROTOCOL *FilePath
)
{
UINT32 AuthenticationStatus;
EFI_FV_FILE_ATTRIBUTES FileAttributes;
EFI_DEVICE_PATH_PROTOCOL *SearchNode;
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
UINTN BufferSize;
EFI_FV_FILETYPE FoundType;
EFI_HANDLE FvHandle;
EFI_STATUS Status;
//
// Locate the Firmware Volume2 protocol instance that is denoted by the
// boot option. If this lookup fails (i.e., the boot option references a
// firmware volume that doesn't exist), then we'll proceed to delete the
// boot option.
//
SearchNode = FilePath;
Status = gBS->LocateDevicePath (
&gEfiFirmwareVolume2ProtocolGuid,
&SearchNode,
&FvHandle
);
//
// File not Found
//
if (EFI_ERROR (Status)) {
return FALSE;
}
//
// The firmware volume was found; now let's see if it contains the FvFile
// identified by GUID.
//
Status = gBS->HandleProtocol (
FvHandle,
&gEfiFirmwareVolume2ProtocolGuid,
(VOID **)&FvProtocol
);
ASSERT_EFI_ERROR (Status);
FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)NextDevicePathNode (FilePath);
//
// Buffer==NULL means we request metadata only: BufferSize, FoundType,
// FileAttributes.
//
Status = FvProtocol->ReadFile (
FvProtocol,
&FvFileNode->FvFileName, // NameGuid
NULL, // Buffer
&BufferSize,
&FoundType,
&FileAttributes,
&AuthenticationStatus
);
//
// File not Found
//
if (EFI_ERROR (Status)) {
return FALSE;
}
//
// The FvFile was found.
//
return TRUE;
}
VOID
PlatformRegisterFvBootOption (
EFI_GUID *FileGuid,
CHAR16 *Description,
UINT32 Attributes,
BOOLEAN Enabled
)
{
EFI_STATUS Status;
INTN OptionIndex;
EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
UINTN BootOptionCount;
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
Status = gBS->HandleProtocol (
gImageHandle,
&gEfiLoadedImageProtocolGuid,
(VOID **)&LoadedImage
);
ASSERT_EFI_ERROR (Status);
EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
ASSERT (DevicePath != NULL);
DevicePath = AppendDevicePathNode (
DevicePath,
(EFI_DEVICE_PATH_PROTOCOL *)&FileNode
);
ASSERT (DevicePath != NULL);
//
// File is not in firmware, so it is going to be deleted anyway by
// RemoveStaleFvFileOptions, let's not add it.
//
if (!FileIsInFv (DevicePath)) {
FreePool (DevicePath);
return;
}
Status = EfiBootManagerInitializeLoadOption (
&NewOption,
LoadOptionNumberUnassigned,
LoadOptionTypeBoot,
Attributes,
Description,
DevicePath,
NULL,
0
);
ASSERT_EFI_ERROR (Status);
FreePool (DevicePath);
BootOptions = EfiBootManagerGetLoadOptions (
&BootOptionCount,
LoadOptionTypeBoot
);
OptionIndex = EfiBootManagerFindLoadOption (
&NewOption,
BootOptions,
BootOptionCount
);
if ((OptionIndex == -1) && Enabled) {
Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
ASSERT_EFI_ERROR (Status);
} else if ((OptionIndex != -1) && !Enabled) {
Status = EfiBootManagerDeleteLoadOptionVariable (
BootOptions[OptionIndex].OptionNumber,
LoadOptionTypeBoot
);
ASSERT_EFI_ERROR (Status);
}
EfiBootManagerFreeLoadOption (&NewOption);
EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
}
/**
Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
whose device paths do not resolve exactly to an FvFile in the system.
This removes any boot options that point to binaries built into the firmware
and have become stale due to any of the following:
- DXEFV's base address or size changed (historical),
- DXEFV's FvNameGuid changed,
- the FILE_GUID of the pointed-to binary changed,
- the referenced binary is no longer built into the firmware.
EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
avoids exact duplicates.
**/
VOID
RemoveStaleFvFileOptions (
VOID
)
{
EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
UINTN BootOptionCount;
UINTN Index;
BootOptions = EfiBootManagerGetLoadOptions (
&BootOptionCount,
LoadOptionTypeBoot
);
for (Index = 0; Index < BootOptionCount; ++Index) {
EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2;
EFI_STATUS Status;
//
// If the device path starts with neither MemoryMapped(...) nor Fv(...),
// then keep the boot option.
//
Node1 = BootOptions[Index].FilePath;
if (!((DevicePathType (Node1) == HARDWARE_DEVICE_PATH) &&
(DevicePathSubType (Node1) == HW_MEMMAP_DP)) &&
!((DevicePathType (Node1) == MEDIA_DEVICE_PATH) &&
(DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)))
{
continue;
}
//
// If the second device path node is not FvFile(...), then keep the boot
// option.
//
Node2 = NextDevicePathNode (Node1);
if ((DevicePathType (Node2) != MEDIA_DEVICE_PATH) ||
(DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP))
{
continue;
}
// If file is in firmware then keep the entry
if (FileIsInFv (BootOptions[Index].FilePath)) {
continue;
}
//
// Delete the boot option.
//
Status = EfiBootManagerDeleteLoadOptionVariable (
BootOptions[Index].OptionNumber,
LoadOptionTypeBoot
);
DEBUG_CODE_BEGIN ();
CHAR16 *DevicePathString;
DevicePathString = ConvertDevicePathToText (
BootOptions[Index].FilePath,
FALSE,
FALSE
);
DEBUG ((
EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE,
"%a: removing stale Boot#%04x %s: %r\n",
__func__,
(UINT32)BootOptions[Index].OptionNumber,
DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
Status
));
if (DevicePathString != NULL) {
FreePool (DevicePathString);
}
DEBUG_CODE_END ();
}
EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
}

View File

@ -0,0 +1,47 @@
## @file
# Common code PlatformBootManager and PlatformBootManagerLight.
#
# Copyright (C) 2025, Red Hat, Inc.
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = PlatformBootManagerCommonLib
FILE_GUID = B6169BD3-EB70-4E00-B4CB-4C24C2C5235E
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = PlatformBootManagerCommonLib|DXE_DRIVER
[Sources]
PlatformBootManagerCommonLib.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
OvmfPkg/OvmfPkg.dec
[LibraryClasses]
QemuFwCfgLib
DebugLib
MemoryAllocationLib
UefiBootManagerLib
UefiBootServicesTableLib
UefiLib
UefiRuntimeServicesTableLib
BaseLib
PrintLib
DevicePathLib
BaseMemoryLib
OrderedCollectionLib
[Guids]
gEfiGlobalVariableGuid
gVirtioMmioTransportGuid
gVMMBootOrderGuid
[Protocols]
gEfiDevicePathProtocolGuid ## CONSUMES
gEfiPciRootBridgeIoProtocolGuid ## CONSUMES