From 910d9c5a98a0263ecd7677079cac4c308ebb52ea Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 5 Mar 2026 11:29:41 +0000 Subject: [PATCH] [efi] Allow executing images even with no open network devices We need a device handle from which to nominally load an EFI image. We currently rely on using the most recently opened network device's SNP device handle, in the same way that we use the most recently opened network device when loading a BIOS PXE NBP image. If there is no most recently opened network device, then we cannot execute an EFI image. We use three aspects of the SNP device handle: the handle itself (giving us something on which to install protocols), the associated device path (giving us a base path from which to construct the new image's file path), and the associated network device (giving us an interface for the PXE base code protocol installation). Make the network device optional by simply choosing not to install the PXE base code protocols when no network device is defined. This allows us to fall back to using our own loaded image's device handle and device path for the other two purposes. Signed-off-by: Michael Brown --- src/image/efi_image.c | 45 +++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/image/efi_image.c b/src/image/efi_image.c index 2631530e7..79890001d 100644 --- a/src/image/efi_image.c +++ b/src/image/efi_image.c @@ -153,7 +153,9 @@ __weak int efi_fdt_uninstall ( void ) { static int efi_image_exec ( struct image *image ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_snp_device *snpdev; - EFI_DEVICE_PATH_PROTOCOL *path; + struct net_device *netdev; + EFI_DEVICE_PATH_PROTOCOL *devpath; + EFI_DEVICE_PATH_PROTOCOL *imgpath; EFI_LOADED_IMAGE_PROTOCOL *loaded; struct image *shim; struct image *exec; @@ -167,13 +169,23 @@ static int efi_image_exec ( struct image *image ) { /* Find an appropriate device handle to use */ snpdev = last_opened_snpdev(); - if ( ! snpdev ) { - DBGC ( image, "EFIIMAGE %s could not identify SNP device\n", - image->name ); - rc = -ENODEV; - goto err_no_snpdev; + if ( snpdev ) { + /* We have a netX: use this as the base device */ + device = snpdev->handle; + devpath = snpdev->path; + netdev = netdev_get ( snpdev->netdev ); + DBGC ( image, "EFIIMAGE %s using %s %s\n", image->name, + netdev->name, efi_devpath_text ( devpath ) ); + } else { + /* We have no netX: fall back to using our own loaded + * image's device. + */ + device = efi_loaded_image->DeviceHandle; + devpath = efi_loaded_image_path; + netdev = NULL; + DBGC ( image, "EFIIMAGE %s using %s\n", + image->name, efi_devpath_text ( devpath ) ); } - device = snpdev->handle; /* Use shim instead of directly executing image if applicable */ shim = ( efi_can_load ( image ) ? @@ -198,7 +210,8 @@ static int efi_image_exec ( struct image *image ) { } /* Install PXE base code protocol */ - if ( ( rc = efi_pxe_install ( device, snpdev->netdev ) ) != 0 ){ + if ( ( netdev != NULL ) && + ( rc = efi_pxe_install ( device, netdev ) ) != 0 ) { DBGC ( image, "EFIIMAGE %s could not install PXE protocol: " "%s\n", image->name, strerror ( rc ) ); goto err_pxe_install; @@ -219,8 +232,8 @@ static int efi_image_exec ( struct image *image ) { } /* Create device path for image */ - path = efi_image_path ( exec, snpdev->path ); - if ( ! path ) { + imgpath = efi_image_path ( exec, devpath ); + if ( ! imgpath ) { DBGC ( image, "EFIIMAGE %s could not create device path\n", image->name ); rc = -ENOMEM; @@ -251,7 +264,7 @@ static int efi_image_exec ( struct image *image ) { * therefore use the .rwdata field rather than .data. */ handle = NULL; - if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, path, + if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, imgpath, exec->rwdata, exec->len, &handle ) ) != 0 ) { /* Not an EFI image */ @@ -302,9 +315,6 @@ static int efi_image_exec ( struct image *image ) { /* Reset console since image will probably use it */ console_reset(); - /* Assume that image may cause SNP device to be removed */ - snpdev = NULL; - /* Start the image */ if ( ( efirc = bs->StartImage ( handle, NULL, NULL ) ) != 0 ) { rc = -EEFI_START ( efirc ); @@ -349,20 +359,21 @@ static int efi_image_exec ( struct image *image ) { err_shim_install: free ( cmdline ); err_cmdline: - free ( path ); + free ( imgpath ); err_image_path: efi_fdt_uninstall(); err_fdt_install: efi_download_uninstall ( device ); err_download_install: - efi_pxe_uninstall ( device ); + if ( netdev ) + efi_pxe_uninstall ( device ); err_pxe_install: efi_file_uninstall ( device ); err_file_install: unregister_image ( image ); err_register_image: image->flags ^= toggle; - err_no_snpdev: + netdev_put ( netdev ); return rc; }