On 07/13/16 22:03, Ard Biesheuvel wrote:
> On 13 July 2016 at 18:44, Laszlo Ersek <[email protected]> wrote:
>> (This patch ports OvmfPkg commit 2eb358986052 to ArmVirtPkg. That
>> functionality was not added to QemuBootOrderLib, because it was (and is)
>> independent from QEMU and fw_cfg.)
>>
>> Remove any boot options that point to binaries built into the firmware and
>> have become stale due to any of the following:
>> - FvMain's base address or size changed (historical -- see commit
>> e191a3114f4c),
>> - FvMain's FvNameGuid changed,
>> - the FILE_GUID of the pointed-to binary changed,
>> - the referenced binary is no longer built into the firmware.
>>
>> For example, multiple such "EFI Internal Shell" boot options can coexist.
>> They technically differ from each other, but may not describe any built-in
>> shell binary exactly. Such options can accumulate in a varstore over time,
>> and while they remain generally bootable (thanks to the efforts of
>> BmGetFileBufferByFvFilePath()), they look bad.
>>
>> Filter out any stale options.
>>
>> Cc: Ard Biesheuvel <[email protected]>
>> Fixes: https://github.com/tianocore/edk2/issues/107
>> Contributed-under: TianoCore Contribution Agreement 1.0
>> Signed-off-by: Laszlo Ersek <[email protected]>
>> ---
>> ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf | 1 +
>> ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c | 132
>> ++++++++++++++++++++
>> 2 files changed, 133 insertions(+)
>>
>> diff --git
>> a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
>> b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
>> index 9c95b69cc974..bec7fabb479c 100644
>> --- a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
>> +++ b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
>> @@ -78,6 +78,7 @@ [Guids]
>>
>> [Protocols]
>> gEfiDevicePathProtocolGuid
>> + gEfiFirmwareVolume2ProtocolGuid
>> gEfiGraphicsOutputProtocolGuid
>> gEfiLoadedImageProtocolGuid
>> gEfiPciRootBridgeIoProtocolGuid
>> diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
>> b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
>> index eaafe7ff57ea..c11196a8a59c 100644
>> --- a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
>> +++ b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
>> @@ -22,6 +22,7 @@
>> #include <Library/QemuBootOrderLib.h>
>> #include <Library/UefiBootManagerLib.h>
>> #include <Protocol/DevicePath.h>
>> +#include <Protocol/FirmwareVolume2.h>
>> #include <Protocol/GraphicsOutput.h>
>> #include <Protocol/LoadedImage.h>
>> #include <Protocol/PciIo.h>
>> @@ -387,6 +388,136 @@ PlatformRegisterFvBootOption (
>> }
>>
>>
>> +/**
>> + 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:
>> + - FvMain's base address or size changed (historical),
>> + - FvMain'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.
>> +**/
>> +STATIC
>> +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, *SearchNode;
>> + EFI_STATUS Status;
>> + EFI_HANDLE FvHandle;
>> +
>> + //
>> + // 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;
>> + }
>> +
>> + //
>> + // 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 = Node1;
>> + Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid,
>> + &SearchNode, &FvHandle);
>> +
>> + if (!EFI_ERROR (Status)) {
>> + //
>> + // The firmware volume was found; now let's see if it contains the
>> FvFile
>> + // identified by GUID.
>> + //
>> + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
>> + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
>> + UINTN BufferSize;
>> + EFI_FV_FILETYPE FoundType;
>> + EFI_FV_FILE_ATTRIBUTES FileAttributes;
>> + UINT32 AuthenticationStatus;
>> +
>> + Status = gBS->HandleProtocol (FvHandle,
>> &gEfiFirmwareVolume2ProtocolGuid,
>> + (VOID **)&FvProtocol);
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
>> + //
>> + // Buffer==NULL means we request metadata only: BufferSize, FoundType,
>> + // FileAttributes.
>> + //
>> + Status = FvProtocol->ReadFile (
>> + FvProtocol,
>> + &FvFileNode->FvFileName, // NameGuid
>> + NULL, // Buffer
>> + &BufferSize,
>> + &FoundType,
>> + &FileAttributes,
>> + &AuthenticationStatus
>> + );
>> + if (!EFI_ERROR (Status)) {
>> + //
>> + // The FvFile was found. Keep the boot option.
>> + //
>> + continue;
>> + }
>> + }
>> +
>> + //
>> + // Delete the boot option.
>> + //
>> + Status = EfiBootManagerDeleteLoadOptionVariable (
>> + BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
>
> So I suppose deleting by index does not reshuffle the list?
That's right. The OptionNumber field is the "Boot####" variable's
number, and EfiBootManagerDeleteLoadOptionVariable() works on the
"BootOrder" and "Boot####" variables themselves.
The BootOptions array that we have in memory at this time is
independent. The "BootOrder" variable is shrunken, but the next call
will again supply a "Boot####" variable number, which is looked up from
scratch in "BootOrder".
>
>> + DEBUG_CODE (
>> + CHAR16 *DevicePathString;
>> +
>> + DevicePathString =
>> ConvertDevicePathToText(BootOptions[Index].FilePath,
>> + FALSE, FALSE);
>> + DEBUG ((
>> + EFI_ERROR (Status) ? EFI_D_WARN : EFI_D_VERBOSE,
>> + "%a: removing stale Boot#%04x %s: %r\n",
>> + __FUNCTION__,
>> + (UINT32)BootOptions[Index].OptionNumber,
>> + DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
>> + Status
>> + ));
>> + if (DevicePathString != NULL) {
>> + FreePool (DevicePathString);
>> + }
>> + );
>
> Indentation?
This was intentional on my part; the canonical edk2 style requires
BlahBlah (
Foo,
Bar,
Quux
);
Are you suggesting we shouldn't follow it in this case, with DEBUG_CODE?
If so I hope you'd be okay with me fixing up that one trailing ")"
before pushing the patch :)
Thanks!
Laszlo
>
>> + }
>> +
>> + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
>> +}
>> +
>> +
>> STATIC
>> VOID
>> PlatformRegisterOptionsAndKeys (
>> @@ -560,6 +691,7 @@ PlatformBootManagerAfterConsole (
>> PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE
>> );
>>
>> + RemoveStaleFvFileOptions ();
>> SetBootOrderFromQemu ();
>> }
>>
>> --
>> 1.8.3.1
>>
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel