From patchwork Tue Jul 12 17:04:34 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laszlo Ersek X-Patchwork-Id: 71875 Delivered-To: patch@linaro.org Received: by 10.140.29.52 with SMTP id a49csp578123qga; Tue, 12 Jul 2016 10:04:46 -0700 (PDT) X-Received: by 10.98.78.138 with SMTP id c132mr21834538pfb.67.1468343086079; Tue, 12 Jul 2016 10:04:46 -0700 (PDT) Return-Path: Received: from ml01.01.org (ml01.01.org. [198.145.21.10]) by mx.google.com with ESMTPS id sj8si4858912pab.245.2016.07.12.10.04.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 12 Jul 2016 10:04:46 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) client-ip=198.145.21.10; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 8B9491A1EEC; Tue, 12 Jul 2016 10:05:29 -0700 (PDT) X-Original-To: edk2-devel@ml01.01.org Delivered-To: edk2-devel@ml01.01.org Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id F35C91A1EE7 for ; Tue, 12 Jul 2016 10:05:28 -0700 (PDT) Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 86275C05FBB4; Tue, 12 Jul 2016 17:04:43 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-96.phx2.redhat.com [10.3.116.96]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u6CH4cxw021880; Tue, 12 Jul 2016 13:04:42 -0400 From: Laszlo Ersek To: edk2-devel-01 Date: Tue, 12 Jul 2016 19:04:34 +0200 Message-Id: <1468343074-29596-3-git-send-email-lersek@redhat.com> In-Reply-To: <1468343074-29596-1-git-send-email-lersek@redhat.com> References: <1468343074-29596-1-git-send-email-lersek@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Tue, 12 Jul 2016 17:04:43 +0000 (UTC) Subject: [edk2] [PATCH v2 2/2] OvmfPkg/PlatformBootManagerLib: remove stale FvFile boot options X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Ruiyu Ni , Jordan Justen , Gary Lin , Ard Biesheuvel MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" 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. 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. This functionality is not added to QemuBootOrderLib, because it is independent from QEMU and fw_cfg. Cc: Ard Biesheuvel Cc: Gary Lin Cc: Jordan Justen Cc: Ruiyu Ni Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek --- Notes: v2: - Consider Fv(...) -- i.e., MEDIA_DEVICE_PATH / MEDIA_PIWG_FW_VOL_DP -- first nodes as well. Do that for the sake of ArmVirtPkg too, which has just moved to Fv(...) as well. Rewrite / add some comments accordingly; update the commit message. [Ray] v1: - Once this patch converges, I'll port it to ArmVirtPkg. OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf | 1 + OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c | 130 ++++++++++++++++++++ 2 files changed, 131 insertions(+) -- 1.8.3.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel diff --git a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf index ffa1288e4d1a..f3303b9f2cf3 100644 --- a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf +++ b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf @@ -72,6 +72,7 @@ [Protocols] gEfiS3SaveStateProtocolGuid # PROTOCOL SOMETIMES_CONSUMED gEfiDxeSmmReadyToLockProtocolGuid # PROTOCOL SOMETIMES_PRODUCED gEfiLoadedImageProtocolGuid # PROTOCOL SOMETIMES_PRODUCED + gEfiFirmwareVolume2ProtocolGuid # PROTOCOL SOMETIMES_CONSUMED [Guids] gEfiXenInfoGuid diff --git a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c index 912c5ed1ece4..351fbc1e86c7 100644 --- a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c +++ b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c @@ -15,6 +15,7 @@ #include "BdsPlatform.h" #include #include +#include // @@ -149,6 +150,134 @@ PlatformRegisterFvBootOption ( 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, *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); + 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"" : DevicePathString, + Status + )); + if (DevicePathString != NULL) { + FreePool (DevicePathString); + } + ); + } + + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); +} + VOID PlatformRegisterOptionsAndKeys ( VOID @@ -1343,6 +1472,7 @@ Routine Description: PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE ); + RemoveStaleFvFileOptions (); SetBootOrderFromQemu (); }