aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/interface/efi/efi_init.c40
-rw-r--r--src/interface/efi/efi_local.c15
2 files changed, 53 insertions, 2 deletions
diff --git a/src/interface/efi/efi_init.c b/src/interface/efi/efi_init.c
index e1041a5..70212b1 100644
--- a/src/interface/efi/efi_init.c
+++ b/src/interface/efi/efi_init.c
@@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/rotate.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_driver.h>
+#include <ipxe/efi/efi_utils.h>
#include <ipxe/efi/Protocol/LoadedImage.h>
/** Image handle passed to entry point */
@@ -34,6 +35,9 @@ EFI_HANDLE efi_image_handle;
/** Loaded image protocol for this 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
*
* 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_config_table *tab;
void *loaded_image;
+ void *device_path;
+ void *device_path_copy;
+ size_t device_path_len;
EFI_STATUS efirc;
int rc;
@@ -230,6 +237,33 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
DBGC ( systab, "EFI image base address %p\n",
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
* loaded devices if it decides to fall back to a legacy boot.
* For no particularly comprehensible reason, it doesn't
@@ -261,6 +295,9 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
err_driver_install:
bs->CloseEvent ( efi_shutdown_event );
err_create_event:
+ bs->FreePool ( efi_loaded_image_path );
+ err_alloc_device_path:
+ err_no_device_path:
err_no_loaded_image:
err_missing_table:
err_missing_protocol:
@@ -291,6 +328,9 @@ static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
/* Uninstall exit boot services 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" );
return 0;
diff --git a/src/interface/efi/efi_local.c b/src/interface/efi/efi_local.c
index bd010ad..79ea822 100644
--- a/src/interface/efi/efi_local.c
+++ b/src/interface/efi/efi_local.c
@@ -307,6 +307,7 @@ static int efi_local_open_volume ( struct efi_local *local,
EFI_GUID *protocol = &efi_simple_file_system_protocol_guid;
int ( * check ) ( struct efi_local *local, EFI_HANDLE device,
EFI_FILE_PROTOCOL *root, const char *volume );
+ EFI_DEVICE_PATH_PROTOCOL *path;
EFI_FILE_PROTOCOL *root;
EFI_HANDLE *handles;
EFI_HANDLE device;
@@ -328,8 +329,18 @@ static int efi_local_open_volume ( struct efi_local *local,
}
check = efi_local_check_volume_name;
} else {
- /* Use our loaded image's device handle */
- handles = &efi_loaded_image->DeviceHandle;
+ /* Locate filesystem from which we were loaded */
+ 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;
check = NULL;
}