On 13 July 2016 at 18:44, Laszlo Ersek <ler...@redhat.com> 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 <ard.biesheu...@linaro.org>
> Fixes: https://github.com/tianocore/edk2/issues/107
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Laszlo Ersek <ler...@redhat.com>
> ---
>  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?

> +    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?

> +  }
> +
> +  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
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to