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);