diff --git a/NEWS b/NEWS
index d7c1d23aed..9dec2cfe9c 100644
--- a/NEWS
+++ b/NEWS
@@ -98,7 +98,7 @@ New in 2.02:
* Prefer pmtimer for TSC calibration.
* New/improved platform support:
- * New `efifwsetup', `lsefi' and `connectefi` commands on EFI platforms.
+ * New `efifwsetup', `lsefi' 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.
diff --git a/docs/grub.texi b/docs/grub.texi
index 267705978e..df501e3689 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4009,6 +4009,7 @@ you forget a command, you can run the command @command{help}
* cmostest:: Test bit in CMOS
* cmp:: Compare two files
* configfile:: Load a configuration file
+* connectefi:: Connect EFI devices (on EFI platforms only)
* cpuid:: Check for CPU features
* crc:: Compute or check CRC32 checksums
* cryptomount:: Mount a crypto device
@@ -4233,6 +4234,11 @@ syntax}) to grab the first sector of the current partition with @samp{+1}.
If you specify the option @option{--force}, then load @var{file} forcibly,
whether it has a correct signature or not. This is required when you want to
load a defective boot loader, such as SCO UnixWare 7.1.
+
+On EFI platforms, when initially network booting, or booting from another disk,
+it may be required to connect the EFI devices using @command{connectefi}
+command (@pxref{connectefi}) prior to chainloading to the disk, otherwise no
+disk may show up or the EFI partition on the disk may not be readable.
@end deffn
@@ -4305,6 +4311,26 @@ after @command{configfile} returns.
@end deffn
+@node connectefi
+@subsection connectefi
+
+@deffn Command connectefi pciroot|disk|scsi|all
+When used with @samp{pciroot} parameter, all PCI devices are recursively
+connected, which may be a slow operation, depending on the hardware.
+
+When used with @samp{disk} or @samp{scsi} parameter (deprecated), only SCSI I/O
+and DISK I/O devices are connected; this is the recommended usage when
+chainloading to internal disk, unless some disks are not detected anyway, in
+such case @samp{all} may be used and a bug be reported to enhance the
+implementation.
+
+When used with @samp{all} parameter, all EFI devices are recursively connected,
+which may be an extremely slow operation, depending on the hardware.
+
+Note: This command is only available on EFI platforms.
+@end deffn
+
+
@node cpuid
@subsection cpuid
diff --git a/grub-core/commands/efi/connectefi.c b/grub-core/commands/efi/connectefi.c
index 3752ae17ed..7d4fddd6c4 100644
--- a/grub-core/commands/efi/connectefi.c
+++ b/grub-core/commands/efi/connectefi.c
@@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2022 Free Software Foundation, Inc.
+ * Copyright (C) 2025 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
@@ -15,123 +15,145 @@
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see .
*/
+
#include
#include
#include
#include
#include
#include
-#include
#include
#include
#include
GRUB_MOD_LICENSE ("GPLv3+");
-typedef struct handle_list
+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_handle_t handle;
- struct handle_list *next;
-} handle_list_t;
+ grub_efi_boot_services_t *b;
-static handle_list_t *already_handled = NULL;
+ b = grub_efi_system_table->boot_services;
+ return efi_call_4 (b->connect_controller, controller_handle,
+ driver_image_handle, remaining_device_path, recursive);
+}
-static grub_err_t
-add_handle (grub_efi_handle_t handle)
+struct grub_efi_handle_list
{
- 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;
-}
+ struct grub_efi_handle_list *next;
+ struct grub_efi_handle_list **prev;
+ grub_efi_handle_t handle;
+};
+
+typedef struct grub_efi_handle_list grub_efi_handle_list_t;
-static int
-is_in_list (grub_efi_handle_t handle)
+static bool
+is_in_list (grub_efi_handle_t handle, grub_efi_handle_list_t *handles)
{
- handle_list_t *e;
- for (e = already_handled; e != NULL; e = e->next)
+ grub_efi_handle_list_t *e;
+
+ FOR_LIST_ELEMENTS (e, handles)
if (e->handle == handle)
- return 1;
- return 0;
+ return true;
+
+ return false;
}
static void
-free_handle_list (void)
+free_handle_list (grub_efi_handle_list_t **handles_p)
{
- handle_list_t *e;
- while ((e = already_handled) != NULL)
+ grub_efi_handle_list_t *e;
+
+ while ((e = *handles_p) != NULL)
{
- already_handled = already_handled->next;
+ *handles_p = e->next;
grub_free (e);
}
}
-typedef enum searched_item_flag
+enum searched_item_flag
{
SEARCHED_ITEM_FLAG_LOOP = 1,
SEARCHED_ITEM_FLAG_RECURSIVE = 2
-} searched_item_flags;
+};
+
+typedef enum searched_item_flag searched_item_flag_t;
-typedef struct searched_item
+struct searched_item
{
grub_efi_guid_t guid;
const char *name;
- searched_item_flags flags;
-} searched_items;
+ searched_item_flag_t flags;
+};
+
+typedef struct searched_item searched_item_t;
static grub_err_t
grub_cmd_connectefi (grub_command_t cmd __attribute__ ((unused)),
int argc, char **args)
{
- unsigned s;
- searched_items pciroot_items[] =
+ int s;
+ searched_item_t pciroot_items[] =
{
{ GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", SEARCHED_ITEM_FLAG_RECURSIVE }
};
- searched_items scsi_items[] =
+ searched_item_t disk_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 }
+ { GRUB_EFI_SCSI_IO_PROTOCOL_GUID, "SCSI I/O", SEARCHED_ITEM_FLAG_RECURSIVE },
+ { GRUB_EFI_DISK_IO_PROTOCOL_GUID, "DISK I/O", SEARCHED_ITEM_FLAG_RECURSIVE }
};
- searched_items *items = NULL;
- unsigned nitems = 0;
+ searched_item_t *items = NULL;
+ int nitems = 0;
grub_err_t grub_err = GRUB_ERR_NONE;
- unsigned total_connected = 0;
+ bool connected_devices = false;
+ grub_efi_handle_list_t *already_handled = NULL;
if (argc != 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
- if (grub_strcmp(args[0], N_("pciroot")) == 0)
+ if (grub_strcmp (args[0], "pciroot") == 0)
{
items = pciroot_items;
nitems = ARRAY_SIZE (pciroot_items);
}
- else if (grub_strcmp(args[0], N_("scsi")) == 0)
+ else if ((grub_strcmp (args[0], "disk") == 0) ||
+ (grub_strcmp (args[0], "scsi") == 0))
+ {
+ items = disk_items;
+ nitems = ARRAY_SIZE (disk_items);
+ }
+ else if (grub_strcmp (args[0], "all") == 0)
{
- items = scsi_items;
- nitems = ARRAY_SIZE (scsi_items);
+ items = NULL;
+ nitems = 1;
}
else
return grub_error (GRUB_ERR_BAD_ARGUMENT,
- N_("unexpected argument `%s'"), args[0]);
+ 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;
+ int i, loop = 0;
+ bool connected = false;
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 (items != NULL)
+ {
+ 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);
+ }
+ else
+ handles = grub_efi_locate_handle (GRUB_EFI_ALL_HANDLES,
+ NULL, NULL, &num_handles);
if (!handles)
continue;
@@ -140,48 +162,52 @@ grub_cmd_connectefi (grub_command_t cmd __attribute__ ((unused)),
{
grub_efi_handle_t handle = handles[i];
grub_efi_status_t status;
- unsigned j;
+ int j;
/* Skip already handled handles */
- if (is_in_list (handle))
+ if (is_in_list (handle, already_handled))
{
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);
+ status = grub_efi_connect_controller (handle, NULL, NULL,
+ !items || items[s].flags & SEARCHED_ITEM_FLAG_RECURSIVE ? 1 : 0);
if (status == GRUB_EFI_SUCCESS)
{
- connected++;
- total_connected++;
+ connected = true;
+ connected_devices = true;
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);
+ grub_dprintf ("efi", " handle %p: failed to connect ("
+ PRIuGRUB_EFI_UINTN_T ")\n", handle, status);
- if ((grub_err = add_handle (handle)) != GRUB_ERR_NONE)
+ grub_efi_handle_list_t *item;
+ item = grub_malloc (sizeof (*item));
+ if (item == NULL)
break; /* fatal */
+ grub_list_push (GRUB_AS_LIST_P (&already_handled), GRUB_AS_LIST (item));
+ item->handle = handle;
}
grub_free (handles);
if (grub_err != GRUB_ERR_NONE)
break; /* fatal */
- if (items[s].flags & SEARCHED_ITEM_FLAG_LOOP && connected)
+ if (items && items[s].flags & SEARCHED_ITEM_FLAG_LOOP && connected)
{
- connected = 0;
+ connected = false;
goto loop;
}
- free_handle_list ();
+ free_handle_list (&already_handled);
}
- free_handle_list ();
+ free_handle_list (&already_handled);
- if (total_connected)
+ if (connected_devices)
grub_efidisk_reenumerate_disks ();
return grub_err;
@@ -192,12 +218,14 @@ static grub_command_t cmd;
GRUB_MOD_INIT(connectefi)
{
cmd = grub_register_command ("connectefi", grub_cmd_connectefi,
- N_("pciroot|scsi"),
+ "pciroot|disk|scsi|all",
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."));
+ " If 'disk' or 'scsi' is specified, connect"
+ " SCSI and DISK I/O EFI handles recursively."
+ " If 'all' is specified, connect all"
+ " EFI handles recursively."));
}
GRUB_MOD_FINI(connectefi)
diff --git a/grub-core/commands/efi/lsefi.c b/grub-core/commands/efi/lsefi.c
index f2d2430e66..ab49531379 100644
--- a/grub-core/commands/efi/lsefi.c
+++ b/grub-core/commands/efi/lsefi.c
@@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2012 Free Software Foundation, Inc.
+ * Copyright (C) 2025 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
@@ -15,6 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see .
*/
+
#include
#include
#include
@@ -36,7 +37,7 @@ struct known_protocol
const char *name;
} known_protocols[] =
{
- { GRUB_EFI_DISK_IO_GUID, "disk" },
+ { GRUB_EFI_DISK_IO_PROTOCOL_GUID, "disk" },
{ GRUB_EFI_BLOCK_IO_GUID, "block" },
{ GRUB_EFI_SERIAL_IO_GUID, "serial" },
{ GRUB_EFI_SIMPLE_NETWORK_GUID, "network" },
diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c
index 062143dfff..45ff05258d 100644
--- a/grub-core/disk/efi/efidisk.c
+++ b/grub-core/disk/efi/efidisk.c
@@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc.
+ * Copyright (C) 2025 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
@@ -402,9 +402,9 @@ 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;
+ fd_devices = NULL;
+ hd_devices = NULL;
+ cd_devices = NULL;
enumerate_disks ();
}
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
index 4ac2b2754e..3d2ff4f543 100644
--- a/grub-core/kern/efi/efi.c
+++ b/grub-core/kern/efi/efi.c
@@ -1,7 +1,7 @@
/* efi.c - generic EFI support */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc.
+ * Copyright (C) 2025 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
@@ -95,19 +95,6 @@ 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/api.h b/include/grub/efi/api.h
index f224037b52..5662805769 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -1,7 +1,7 @@
/* efi.h - declare EFI types and functions */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc.
+ * Copyright (C) 2025 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
@@ -79,7 +79,7 @@
{ 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
}
-#define GRUB_EFI_DISK_IO_GUID \
+#define GRUB_EFI_DISK_IO_PROTOCOL_GUID \
{ 0xce345171, 0xba0b, 0x11d2, \
{ 0x8e, 0x4f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
}
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 449e55269f..7fe8363b5f 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -1,7 +1,7 @@
/* efi.h - declare variables and functions for EFI support */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc.
+ * Copyright (C) 2025 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
@@ -41,11 +41,6 @@ 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);