mirror of https://github.com/ipxe/ipxe.git
[efi] Use device path to locate filesystem from which we were loaded
The file:/ URI syntax may be used to refer to local files on the filesystem from which the iPXE binary was loaded. This is currently implemented by directly using the DeviceHandle recorded in our EFI_LOADED_IMAGE_PROTOCOL. This mechanism will fail when a USB-enabled build of iPXE is loaded from USB storage and subsequently installs its own USB host controller drivers, since doing so will disconnect and reconnect the existing USB storage drivers and thereby invalidate the original storage device handle. Fix by recording the device path for the loaded image's DeviceHandle at initialisation time and later using the recorded device path to locate the appropriate device handle. Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/129/head
parent
fd47fa8fe1
commit
c63e61df75
|
@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
#include <ipxe/rotate.h>
|
#include <ipxe/rotate.h>
|
||||||
#include <ipxe/efi/efi.h>
|
#include <ipxe/efi/efi.h>
|
||||||
#include <ipxe/efi/efi_driver.h>
|
#include <ipxe/efi/efi_driver.h>
|
||||||
|
#include <ipxe/efi/efi_utils.h>
|
||||||
#include <ipxe/efi/Protocol/LoadedImage.h>
|
#include <ipxe/efi/Protocol/LoadedImage.h>
|
||||||
|
|
||||||
/** Image handle passed to entry point */
|
/** Image handle passed to entry point */
|
||||||
|
@ -34,6 +35,9 @@ EFI_HANDLE efi_image_handle;
|
||||||
/** Loaded image protocol for this image */
|
/** Loaded image protocol for this image */
|
||||||
EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image;
|
EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image;
|
||||||
|
|
||||||
|
/** Device path for the loaded image's device handle */
|
||||||
|
EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path;
|
||||||
|
|
||||||
/** System table passed to entry point
|
/** System table passed to entry point
|
||||||
*
|
*
|
||||||
* We construct the symbol name efi_systab via the PLATFORM macro.
|
* We construct the symbol name efi_systab via the PLATFORM macro.
|
||||||
|
@ -152,6 +156,9 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
|
||||||
struct efi_protocol *prot;
|
struct efi_protocol *prot;
|
||||||
struct efi_config_table *tab;
|
struct efi_config_table *tab;
|
||||||
void *loaded_image;
|
void *loaded_image;
|
||||||
|
void *device_path;
|
||||||
|
void *device_path_copy;
|
||||||
|
size_t device_path_len;
|
||||||
EFI_STATUS efirc;
|
EFI_STATUS efirc;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -230,6 +237,33 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
|
||||||
DBGC ( systab, "EFI image base address %p\n",
|
DBGC ( systab, "EFI image base address %p\n",
|
||||||
efi_loaded_image->ImageBase );
|
efi_loaded_image->ImageBase );
|
||||||
|
|
||||||
|
/* Get loaded image's device handle's device path */
|
||||||
|
if ( ( efirc = bs->OpenProtocol ( efi_loaded_image->DeviceHandle,
|
||||||
|
&efi_device_path_protocol_guid,
|
||||||
|
&device_path, image_handle, NULL,
|
||||||
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
|
||||||
|
rc = -EEFI ( efirc );
|
||||||
|
DBGC ( systab, "EFI could not get loaded image's device path: "
|
||||||
|
"%s", strerror ( rc ) );
|
||||||
|
goto err_no_device_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make a copy of the loaded image's device handle's device
|
||||||
|
* path, since the device handle itself may become invalidated
|
||||||
|
* when we load our own drivers.
|
||||||
|
*/
|
||||||
|
device_path_len = ( efi_devpath_len ( device_path ) +
|
||||||
|
sizeof ( EFI_DEVICE_PATH_PROTOCOL ) );
|
||||||
|
if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, device_path_len,
|
||||||
|
&device_path_copy ) ) != 0 ) {
|
||||||
|
rc = -EEFI ( efirc );
|
||||||
|
goto err_alloc_device_path;
|
||||||
|
}
|
||||||
|
memcpy ( device_path_copy, device_path, device_path_len );
|
||||||
|
efi_loaded_image_path = device_path_copy;
|
||||||
|
DBGC ( systab, "EFI image device path %s\n",
|
||||||
|
efi_devpath_text ( efi_loaded_image_path ) );
|
||||||
|
|
||||||
/* EFI is perfectly capable of gracefully shutting down any
|
/* EFI is perfectly capable of gracefully shutting down any
|
||||||
* loaded devices if it decides to fall back to a legacy boot.
|
* loaded devices if it decides to fall back to a legacy boot.
|
||||||
* For no particularly comprehensible reason, it doesn't
|
* For no particularly comprehensible reason, it doesn't
|
||||||
|
@ -261,6 +295,9 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
|
||||||
err_driver_install:
|
err_driver_install:
|
||||||
bs->CloseEvent ( efi_shutdown_event );
|
bs->CloseEvent ( efi_shutdown_event );
|
||||||
err_create_event:
|
err_create_event:
|
||||||
|
bs->FreePool ( efi_loaded_image_path );
|
||||||
|
err_alloc_device_path:
|
||||||
|
err_no_device_path:
|
||||||
err_no_loaded_image:
|
err_no_loaded_image:
|
||||||
err_missing_table:
|
err_missing_table:
|
||||||
err_missing_protocol:
|
err_missing_protocol:
|
||||||
|
@ -291,6 +328,9 @@ static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
|
||||||
/* Uninstall exit boot services event */
|
/* Uninstall exit boot services event */
|
||||||
bs->CloseEvent ( efi_shutdown_event );
|
bs->CloseEvent ( efi_shutdown_event );
|
||||||
|
|
||||||
|
/* Free copy of loaded image's device handle's device path */
|
||||||
|
bs->FreePool ( efi_loaded_image_path );
|
||||||
|
|
||||||
DBGC ( systab, "EFI image unloaded\n" );
|
DBGC ( systab, "EFI image unloaded\n" );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -307,6 +307,7 @@ static int efi_local_open_volume ( struct efi_local *local,
|
||||||
EFI_GUID *protocol = &efi_simple_file_system_protocol_guid;
|
EFI_GUID *protocol = &efi_simple_file_system_protocol_guid;
|
||||||
int ( * check ) ( struct efi_local *local, EFI_HANDLE device,
|
int ( * check ) ( struct efi_local *local, EFI_HANDLE device,
|
||||||
EFI_FILE_PROTOCOL *root, const char *volume );
|
EFI_FILE_PROTOCOL *root, const char *volume );
|
||||||
|
EFI_DEVICE_PATH_PROTOCOL *path;
|
||||||
EFI_FILE_PROTOCOL *root;
|
EFI_FILE_PROTOCOL *root;
|
||||||
EFI_HANDLE *handles;
|
EFI_HANDLE *handles;
|
||||||
EFI_HANDLE device;
|
EFI_HANDLE device;
|
||||||
|
@ -328,8 +329,18 @@ static int efi_local_open_volume ( struct efi_local *local,
|
||||||
}
|
}
|
||||||
check = efi_local_check_volume_name;
|
check = efi_local_check_volume_name;
|
||||||
} else {
|
} else {
|
||||||
/* Use our loaded image's device handle */
|
/* Locate filesystem from which we were loaded */
|
||||||
handles = &efi_loaded_image->DeviceHandle;
|
path = efi_loaded_image_path;
|
||||||
|
if ( ( efirc = bs->LocateDevicePath ( protocol, &path,
|
||||||
|
&device ) ) != 0 ) {
|
||||||
|
rc = -EEFI ( efirc );
|
||||||
|
DBGC ( local, "LOCAL %p could not locate file system "
|
||||||
|
"on %s: %s\n", local,
|
||||||
|
efi_devpath_text ( efi_loaded_image_path ),
|
||||||
|
strerror ( rc ) );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
handles = &device;
|
||||||
num_handles = 1;
|
num_handles = 1;
|
||||||
check = NULL;
|
check = NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue