Add efidisk/connectefi patches

Resolves: #2049219
Resolves: #2049220
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
This commit is contained in:
Robbie Harwood 2022-02-24 22:24:21 +00:00
parent d08fc02f2d
commit 82f85447d7
5 changed files with 601 additions and 1 deletions

View File

@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
Date: Tue, 8 Feb 2022 08:39:10 +0100
Subject: [PATCH] search: fixed bug stopping iteration when --no-floppy is used
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When using --no-floppy and a floppy was encountered, iterate_device()
was returning 1, causing the iteration to stop instead of continuing.
Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
(cherry picked from commit e784b4b3367341b0468dd2a83b265d49383f48ae)
---
grub-core/commands/search.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c
index ed090b3af8b..51656e361cc 100644
--- a/grub-core/commands/search.c
+++ b/grub-core/commands/search.c
@@ -64,7 +64,7 @@ iterate_device (const char *name, void *data)
/* Skip floppy drives when requested. */
if (ctx->no_floppy &&
name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9')
- return 1;
+ return 0;
#ifdef DO_SEARCH_FS_UUID
#define compare_fn grub_strcasecmp

View File

@ -0,0 +1,167 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
Date: Tue, 8 Feb 2022 08:39:11 +0100
Subject: [PATCH] search: new --efidisk-only option on EFI systems
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When using 'search' on EFI systems, we sometimes want to exclude devices
that are not EFI disks (e.g. md, lvm).
This is typically used when wanting to chainload when having a software
raid (md) for EFI partition:
with no option, 'search --file /EFI/redhat/shimx64.efi' sets root envvar
to 'md/boot_efi' which cannot be used for chainloading since there is no
effective EFI device behind.
This commit also refactors handling of --no-floppy option.
Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
(cherry picked from commit aedb45f32106dd2a64f906b0db6a76ee09f1b930)
---
grub-core/commands/search.c | 27 +++++++++++++++++++++++----
grub-core/commands/search_wrap.c | 18 ++++++++++++------
include/grub/search.h | 15 ++++++++++++---
3 files changed, 47 insertions(+), 13 deletions(-)
diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c
index 51656e361cc..57d26ced8a8 100644
--- a/grub-core/commands/search.c
+++ b/grub-core/commands/search.c
@@ -47,7 +47,7 @@ struct search_ctx
{
const char *key;
const char *var;
- int no_floppy;
+ enum search_flags flags;
char **hints;
unsigned nhints;
int count;
@@ -62,10 +62,29 @@ iterate_device (const char *name, void *data)
int found = 0;
/* Skip floppy drives when requested. */
- if (ctx->no_floppy &&
+ if (ctx->flags & SEARCH_FLAGS_NO_FLOPPY &&
name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9')
return 0;
+ /* Limit to EFI disks when requested. */
+ if (ctx->flags & SEARCH_FLAGS_EFIDISK_ONLY)
+ {
+ grub_device_t dev;
+ dev = grub_device_open (name);
+ if (! dev)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return 0;
+ }
+ if (! dev->disk || dev->disk->dev->id != GRUB_DISK_DEVICE_EFIDISK_ID)
+ {
+ grub_device_close (dev);
+ grub_errno = GRUB_ERR_NONE;
+ return 0;
+ }
+ grub_device_close (dev);
+ }
+
#ifdef DO_SEARCH_FS_UUID
#define compare_fn grub_strcasecmp
#else
@@ -261,13 +280,13 @@ try (struct search_ctx *ctx)
}
void
-FUNC_NAME (const char *key, const char *var, int no_floppy,
+FUNC_NAME (const char *key, const char *var, enum search_flags flags,
char **hints, unsigned nhints)
{
struct search_ctx ctx = {
.key = key,
.var = var,
- .no_floppy = no_floppy,
+ .flags = flags,
.hints = hints,
.nhints = nhints,
.count = 0,
diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c
index 47fc8eb9966..464e6ebb1c8 100644
--- a/grub-core/commands/search_wrap.c
+++ b/grub-core/commands/search_wrap.c
@@ -40,6 +40,7 @@ static const struct grub_arg_option options[] =
N_("Set a variable to the first device found."), N_("VARNAME"),
ARG_TYPE_STRING},
{"no-floppy", 'n', 0, N_("Do not probe any floppy drive."), 0, 0},
+ {"efidisk-only", 0, 0, N_("Only probe EFI disks."), 0, 0},
{"hint", 'h', GRUB_ARG_OPTION_REPEATABLE,
N_("First try the device HINT. If HINT ends in comma, "
"also try subpartitions"), N_("HINT"), ARG_TYPE_STRING},
@@ -73,6 +74,7 @@ enum options
SEARCH_FS_UUID,
SEARCH_SET,
SEARCH_NO_FLOPPY,
+ SEARCH_EFIDISK_ONLY,
SEARCH_HINT,
SEARCH_HINT_IEEE1275,
SEARCH_HINT_BIOS,
@@ -89,6 +91,7 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
const char *id = 0;
int i = 0, j = 0, nhints = 0;
char **hints = NULL;
+ enum search_flags flags;
if (state[SEARCH_HINT].set)
for (i = 0; state[SEARCH_HINT].args[i]; i++)
@@ -180,15 +183,18 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
goto out;
}
+ if (state[SEARCH_NO_FLOPPY].set)
+ flags |= SEARCH_FLAGS_NO_FLOPPY;
+
+ if (state[SEARCH_EFIDISK_ONLY].set)
+ flags |= SEARCH_FLAGS_EFIDISK_ONLY;
+
if (state[SEARCH_LABEL].set)
- grub_search_label (id, var, state[SEARCH_NO_FLOPPY].set,
- hints, nhints);
+ grub_search_label (id, var, flags, hints, nhints);
else if (state[SEARCH_FS_UUID].set)
- grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
- hints, nhints);
+ grub_search_fs_uuid (id, var, flags, hints, nhints);
else if (state[SEARCH_FILE].set)
- grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set,
- hints, nhints);
+ grub_search_fs_file (id, var, flags, hints, nhints);
else
grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type");
diff --git a/include/grub/search.h b/include/grub/search.h
index d80347df34b..4190aeb2cbf 100644
--- a/include/grub/search.h
+++ b/include/grub/search.h
@@ -19,11 +19,20 @@
#ifndef GRUB_SEARCH_HEADER
#define GRUB_SEARCH_HEADER 1
-void grub_search_fs_file (const char *key, const char *var, int no_floppy,
+enum search_flags
+ {
+ SEARCH_FLAGS_NO_FLOPPY = 1,
+ SEARCH_FLAGS_EFIDISK_ONLY = 2
+ };
+
+void grub_search_fs_file (const char *key, const char *var,
+ enum search_flags flags,
char **hints, unsigned nhints);
-void grub_search_fs_uuid (const char *key, const char *var, int no_floppy,
+void grub_search_fs_uuid (const char *key, const char *var,
+ enum search_flags flags,
char **hints, unsigned nhints);
-void grub_search_label (const char *key, const char *var, int no_floppy,
+void grub_search_label (const char *key, const char *var,
+ enum search_flags flags,
char **hints, unsigned nhints);
#endif

View File

@ -0,0 +1,395 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
Date: Tue, 15 Feb 2022 14:05:22 +0100
Subject: [PATCH] efi: new 'connectefi' command
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When efi.quickboot is enabled on VMWare (which is the default for
hardware release 16 and later), it may happen that not all EFI devices
are connected. Due to this, browsing the devices in make_devices() just
fails to find devices, in particular disks or partitions for a given
disk.
This typically happens when network booting, then trying to chainload to
local disk (this is used in deployment tools such as Red Hat Satellite),
which is done through using the following grub.cfg snippet:
-------- 8< ---------------- 8< ---------------- 8< --------
unset prefix
search --file --set=prefix /EFI/redhat/grubx64.efi
if [ -n "$prefix" ]; then
chainloader ($prefix)/EFI/redhat/grubx64/efi
...
-------- 8< ---------------- 8< ---------------- 8< --------
With efi.quickboot, none of the devices are connected, causing "search"
to fail. Sometimes devices are connected but not the partition of the
disk matching $prefix, causing partition to not be found by
"chainloader".
This patch introduces a new "connectefi pciroot|scsi" command which
recursively connects all EFI devices starting from a given controller
type:
- if 'pciroot' is specified, recursion is performed for all PCI root
handles
- if 'scsi' is specified, recursion is performed for all SCSI I/O
handles (recommended usage to avoid connecting unwanted handles which
may impact Grub performances)
Typical grub.cfg snippet would then be:
-------- 8< ---------------- 8< ---------------- 8< --------
connectefi scsi
unset prefix
search --file --set=prefix /EFI/redhat/grubx64.efi
if [ -n "$prefix" ]; then
chainloader ($prefix)/EFI/redhat/grubx64/efi
...
-------- 8< ---------------- 8< ---------------- 8< --------
The code is easily extensible to handle other arguments in the future if
needed.
Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
(cherry picked from commit 73e183ce1e42bd97ae91a9254f8d4acd4d0b1cbc)
---
grub-core/Makefile.core.def | 6 ++
grub-core/commands/efi/connectefi.c | 205 ++++++++++++++++++++++++++++++++++++
grub-core/commands/efi/lsefi.c | 1 +
grub-core/disk/efi/efidisk.c | 13 +++
grub-core/kern/efi/efi.c | 13 +++
include/grub/efi/disk.h | 2 +
include/grub/efi/efi.h | 5 +
NEWS | 2 +-
8 files changed, 246 insertions(+), 1 deletion(-)
create mode 100644 grub-core/commands/efi/connectefi.c
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 6b00eb55575..97abc01f064 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -833,6 +833,12 @@ module = {
enable = efi;
};
+module = {
+ name = connectefi;
+ common = commands/efi/connectefi.c;
+ enable = efi;
+};
+
module = {
name = blocklist;
common = commands/blocklist.c;
diff --git a/grub-core/commands/efi/connectefi.c b/grub-core/commands/efi/connectefi.c
new file mode 100644
index 00000000000..8ab75bd51be
--- /dev/null
+++ b/grub-core/commands/efi/connectefi.c
@@ -0,0 +1,205 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/efi/api.h>
+#include <grub/efi/pci.h>
+#include <grub/efi/efi.h>
+#include <grub/command.h>
+#include <grub/err.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+typedef struct handle_list
+{
+ grub_efi_handle_t handle;
+ struct handle_list *next;
+} handle_list_t;
+
+static handle_list_t *already_handled = NULL;
+
+static grub_err_t
+add_handle (grub_efi_handle_t handle)
+{
+ handle_list_t *e;
+ e = grub_malloc (sizeof (*e));
+ if (! e)
+ return grub_errno;
+ e->handle = handle;
+ e->next = already_handled;
+ already_handled = e;
+ return GRUB_ERR_NONE;
+}
+
+static int
+is_in_list (grub_efi_handle_t handle)
+{
+ handle_list_t *e;
+ for (e = already_handled; e != NULL; e = e->next)
+ if (e->handle == handle)
+ return 1;
+ return 0;
+}
+
+static void
+free_handle_list (void)
+{
+ handle_list_t *e;
+ while ((e = already_handled) != NULL)
+ {
+ already_handled = already_handled->next;
+ grub_free (e);
+ }
+}
+
+typedef enum searched_item_flag
+{
+ SEARCHED_ITEM_FLAG_LOOP = 1,
+ SEARCHED_ITEM_FLAG_RECURSIVE = 2
+} searched_item_flags;
+
+typedef struct searched_item
+{
+ grub_efi_guid_t guid;
+ const char *name;
+ searched_item_flags flags;
+} searched_items;
+
+static grub_err_t
+grub_cmd_connectefi (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ unsigned s;
+ searched_items pciroot_items[] =
+ {
+ { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", SEARCHED_ITEM_FLAG_RECURSIVE }
+ };
+ searched_items scsi_items[] =
+ {
+ { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", 0 },
+ { GRUB_EFI_PCI_IO_GUID, "PCI", SEARCHED_ITEM_FLAG_LOOP },
+ { GRUB_EFI_SCSI_IO_PROTOCOL_GUID, "SCSI I/O", SEARCHED_ITEM_FLAG_RECURSIVE }
+ };
+ searched_items *items = NULL;
+ unsigned nitems = 0;
+ grub_err_t grub_err = GRUB_ERR_NONE;
+ unsigned total_connected = 0;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+ if (grub_strcmp(args[0], N_("pciroot")) == 0)
+ {
+ items = pciroot_items;
+ nitems = ARRAY_SIZE (pciroot_items);
+ }
+ else if (grub_strcmp(args[0], N_("scsi")) == 0)
+ {
+ items = scsi_items;
+ nitems = ARRAY_SIZE (scsi_items);
+ }
+ else
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("unexpected argument `%s'"), args[0]);
+
+ for (s = 0; s < nitems; s++)
+ {
+ grub_efi_handle_t *handles;
+ grub_efi_uintn_t num_handles;
+ unsigned i, connected = 0, loop = 0;
+
+loop:
+ loop++;
+ grub_dprintf ("efi", "step '%s' loop %d:\n", items[s].name, loop);
+
+ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL,
+ &items[s].guid, 0, &num_handles);
+
+ if (!handles)
+ continue;
+
+ for (i = 0; i < num_handles; i++)
+ {
+ grub_efi_handle_t handle = handles[i];
+ grub_efi_status_t status;
+ unsigned j;
+
+ /* Skip already handled handles */
+ if (is_in_list (handle))
+ {
+ grub_dprintf ("efi", " handle %p: already processed\n",
+ handle);
+ continue;
+ }
+
+ status = grub_efi_connect_controller(handle, NULL, NULL,
+ items[s].flags & SEARCHED_ITEM_FLAG_RECURSIVE ? 1 : 0);
+ if (status == GRUB_EFI_SUCCESS)
+ {
+ connected++;
+ total_connected++;
+ grub_dprintf ("efi", " handle %p: connected\n", handle);
+ }
+ else
+ grub_dprintf ("efi", " handle %p: failed to connect (%d)\n",
+ handle, (grub_efi_int8_t) status);
+
+ if ((grub_err = add_handle (handle)) != GRUB_ERR_NONE)
+ break; /* fatal */
+ }
+
+ grub_free (handles);
+ if (grub_err != GRUB_ERR_NONE)
+ break; /* fatal */
+
+ if (items[s].flags & SEARCHED_ITEM_FLAG_LOOP && connected)
+ {
+ connected = 0;
+ goto loop;
+ }
+
+ free_handle_list ();
+ }
+
+ free_handle_list ();
+
+ if (total_connected)
+ grub_efidisk_reenumerate_disks ();
+
+ return grub_err;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(connectefi)
+{
+ cmd = grub_register_command ("connectefi", grub_cmd_connectefi,
+ N_("pciroot|scsi"),
+ N_("Connect EFI handles."
+ " If 'pciroot' is specified, connect PCI"
+ " root EFI handles recursively."
+ " If 'scsi' is specified, connect SCSI"
+ " I/O EFI handles recursively."));
+}
+
+GRUB_MOD_FINI(connectefi)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/efi/lsefi.c b/grub-core/commands/efi/lsefi.c
index d1ce99af438..f2d2430e666 100644
--- a/grub-core/commands/efi/lsefi.c
+++ b/grub-core/commands/efi/lsefi.c
@@ -19,6 +19,7 @@
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/efi/api.h>
+#include <grub/efi/disk.h>
#include <grub/efi/edid.h>
#include <grub/efi/pci.h>
#include <grub/efi/efi.h>
diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c
index fe8ba6e6c93..062143dfffd 100644
--- a/grub-core/disk/efi/efidisk.c
+++ b/grub-core/disk/efi/efidisk.c
@@ -396,6 +396,19 @@ enumerate_disks (void)
free_devices (devices);
}
+void
+grub_efidisk_reenumerate_disks (void)
+{
+ free_devices (fd_devices);
+ free_devices (hd_devices);
+ free_devices (cd_devices);
+ fd_devices = 0;
+ hd_devices = 0;
+ cd_devices = 0;
+
+ enumerate_disks ();
+}
+
static int
grub_efidisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
grub_disk_pull_t pull)
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
index 14bc10eb564..7fcca69c17b 100644
--- a/grub-core/kern/efi/efi.c
+++ b/grub-core/kern/efi/efi.c
@@ -95,6 +95,19 @@ grub_efi_locate_handle (grub_efi_locate_search_type_t search_type,
return buffer;
}
+grub_efi_status_t
+grub_efi_connect_controller (grub_efi_handle_t controller_handle,
+ grub_efi_handle_t *driver_image_handle,
+ grub_efi_device_path_protocol_t *remaining_device_path,
+ grub_efi_boolean_t recursive)
+{
+ grub_efi_boot_services_t *b;
+
+ b = grub_efi_system_table->boot_services;
+ return efi_call_4 (b->connect_controller, controller_handle,
+ driver_image_handle, remaining_device_path, recursive);
+}
+
void *
grub_efi_open_protocol (grub_efi_handle_t handle,
grub_efi_guid_t *protocol,
diff --git a/include/grub/efi/disk.h b/include/grub/efi/disk.h
index 254475c8428..6845c2f1fd8 100644
--- a/include/grub/efi/disk.h
+++ b/include/grub/efi/disk.h
@@ -27,6 +27,8 @@ grub_efi_handle_t
EXPORT_FUNC(grub_efidisk_get_device_handle) (grub_disk_t disk);
char *EXPORT_FUNC(grub_efidisk_get_device_name) (grub_efi_handle_t *handle);
+void EXPORT_FUNC(grub_efidisk_reenumerate_disks) (void);
+
void grub_efidisk_init (void);
void grub_efidisk_fini (void);
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 8dfc89a33b9..ec52083c49f 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -41,6 +41,11 @@ EXPORT_FUNC(grub_efi_locate_handle) (grub_efi_locate_search_type_t search_type,
grub_efi_guid_t *protocol,
void *search_key,
grub_efi_uintn_t *num_handles);
+grub_efi_status_t
+EXPORT_FUNC(grub_efi_connect_controller) (grub_efi_handle_t controller_handle,
+ grub_efi_handle_t *driver_image_handle,
+ grub_efi_device_path_protocol_t *remaining_device_path,
+ grub_efi_boolean_t recursive);
void *EXPORT_FUNC(grub_efi_open_protocol) (grub_efi_handle_t handle,
grub_efi_guid_t *protocol,
grub_efi_uint32_t attributes);
diff --git a/NEWS b/NEWS
index 73b8492bc42..d7c1d23aed7 100644
--- a/NEWS
+++ b/NEWS
@@ -98,7 +98,7 @@ New in 2.02:
* Prefer pmtimer for TSC calibration.
* New/improved platform support:
- * New `efifwsetup' and `lsefi' commands on EFI platforms.
+ * New `efifwsetup', `lsefi' and `connectefi` commands on EFI platforms.
* New `cmosdump' and `cmosset' commands on platforms with CMOS support.
* New command `pcidump' for PCI platforms.
* Improve opcode parsing in ACPI halt implementation.

View File

@ -222,3 +222,6 @@ Patch0221: 0221-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch
Patch0222: 0222-Print-module-name-on-license-check-failure.patch
Patch0223: 0223-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch
Patch0224: 0224-grub-mkconfig-restore-umask-for-grub.cfg.patch
Patch0225: 0225-search-fixed-bug-stopping-iteration-when-no-floppy-i.patch
Patch0226: 0226-search-new-efidisk-only-option-on-EFI-systems.patch
Patch0227: 0227-efi-new-connectefi-command.patch

View File

@ -14,7 +14,7 @@
Name: grub2
Epoch: 1
Version: 2.06
Release: 23%{?dist}
Release: 24%{?dist}
Summary: Bootloader with support for Linux, Multiboot and more
License: GPLv3+
URL: http://www.gnu.org/software/grub/
@ -530,6 +530,11 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg
%endif
%changelog
* Thu Feb 24 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-24
- Add efidisk/connectefi patches
- Resolves: #2049219
- Resolves: #2049220
* Fri Feb 18 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-23
- Re-arm GRUB_ENABLE_BLSCFG=false
- Resolves: #2018331