[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 <mcb30@ipxe.org>
This commit is contained in:
Michael Brown 2026-03-05 11:29:41 +00:00
parent 3df8f9c379
commit 910d9c5a98

View File

@ -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;
}