On 13 July 2016 at 22:17, Laszlo Ersek <[email protected]> wrote:
> 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".
>

OK, thanks for clarifying.

>>
>>> +    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 :)
>

I don't care too deeply, tbh, it is just something that stands out
when looking at the patch.

So leave it, or change it, as you prefer.

Reviewed-by: Ard Biesheuvel <[email protected]>
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to