aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/ipxe/efi/efi_autoexec.h3
-rw-r--r--src/interface/efi/efi_autoexec.c85
-rw-r--r--src/interface/efi/efiprefix.c9
3 files changed, 75 insertions, 22 deletions
diff --git a/src/include/ipxe/efi/efi_autoexec.h b/src/include/ipxe/efi/efi_autoexec.h
index 1f93b41..08ddf58 100644
--- a/src/include/ipxe/efi/efi_autoexec.h
+++ b/src/include/ipxe/efi/efi_autoexec.h
@@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi.h>
-extern int efi_autoexec_load ( EFI_HANDLE device );
+extern int efi_autoexec_load ( EFI_HANDLE device,
+ EFI_DEVICE_PATH_PROTOCOL *path );
#endif /* _IPXE_EFI_AUTOEXEC_H */
diff --git a/src/interface/efi/efi_autoexec.c b/src/interface/efi/efi_autoexec.c
index 79d4a4c..fb12cef 100644
--- a/src/interface/efi/efi_autoexec.c
+++ b/src/interface/efi/efi_autoexec.c
@@ -54,12 +54,14 @@ static void *efi_autoexec;
static size_t efi_autoexec_len;
/**
- * Load autoexec script from filesystem
+ * Load autoexec script from path within filesystem
*
* @v device Device handle
+ * @v path Relative path to image, or NULL to load from root
* @ret rc Return status code
*/
-static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
+static int efi_autoexec_filesystem ( EFI_HANDLE device,
+ EFI_DEVICE_PATH_PROTOCOL *path ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
union {
void *interface;
@@ -70,13 +72,58 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
CHAR16 name[ sizeof ( efi_autoexec_wname ) /
sizeof ( efi_autoexec_wname[0] ) ];
} info;
+ FILEPATH_DEVICE_PATH *filepath;
EFI_FILE_PROTOCOL *root;
EFI_FILE_PROTOCOL *file;
UINTN size;
VOID *data;
+ unsigned int dirlen;
+ size_t len;
+ CHAR16 *wname;
EFI_STATUS efirc;
int rc;
+ /* Identify directory */
+ if ( path ) {
+
+ /* Check relative device path is a file path */
+ if ( ! ( ( path->Type == MEDIA_DEVICE_PATH ) &&
+ ( path->SubType == MEDIA_FILEPATH_DP ) ) ) {
+ DBGC ( device, "EFI %s image path ",
+ efi_handle_name ( device ) );
+ DBGC ( device, " \"%s\" is not a file path\n",
+ efi_devpath_text ( path ) );
+ rc = -ENOTTY;
+ goto err_not_filepath;
+ }
+ filepath = container_of ( path, FILEPATH_DEVICE_PATH, Header );
+
+ /* Find length of containing directory */
+ dirlen = ( ( ( ( path->Length[1] << 8 ) | path->Length[0] )
+ - offsetof ( typeof ( *filepath ), PathName ) )
+ / sizeof ( filepath->PathName[0] ) );
+ for ( ; dirlen ; dirlen-- ) {
+ if ( filepath->PathName[ dirlen - 1 ] == L'\\' )
+ break;
+ }
+
+ } else {
+
+ /* Use root directory */
+ filepath = NULL;
+ dirlen = 0;
+ }
+
+ /* Allocate filename */
+ len = ( ( dirlen * sizeof ( wname[0] ) ) + sizeof ( efi_autoexec_wname ) );
+ wname = malloc ( len );
+ if ( ! wname ) {
+ rc = -ENOMEM;
+ goto err_wname;
+ }
+ memcpy ( wname, filepath->PathName, ( dirlen * sizeof ( wname[0] ) ) );
+ memcpy ( &wname[dirlen], efi_autoexec_wname, sizeof ( efi_autoexec_wname ) );
+
/* Open simple file system protocol */
if ( ( efirc = bs->OpenProtocol ( device,
&efi_simple_file_system_protocol_guid,
@@ -98,12 +145,11 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
}
/* Open autoexec script */
- if ( ( efirc = root->Open ( root, &file, efi_autoexec_wname,
+ if ( ( efirc = root->Open ( root, &file, wname,
EFI_FILE_MODE_READ, 0 ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s has no %ls: %s\n",
- efi_handle_name ( device ), efi_autoexec_wname,
- strerror ( rc ) );
+ efi_handle_name ( device ), wname, strerror ( rc ) );
goto err_open;
}
@@ -113,8 +159,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
&info ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not get %ls info: %s\n",
- efi_handle_name ( device ), efi_autoexec_wname,
- strerror ( rc ) );
+ efi_handle_name ( device ), wname, strerror ( rc ) );
goto err_getinfo;
}
size = info.info.FileSize;
@@ -123,7 +168,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
if ( ! size ) {
rc = -EINVAL;
DBGC ( device, "EFI %s has zero-length %ls\n",
- efi_handle_name ( device ), efi_autoexec_wname );
+ efi_handle_name ( device ), wname );
goto err_empty;
}
@@ -132,8 +177,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
&data ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not allocate %ls: %s\n",
- efi_handle_name ( device ), efi_autoexec_wname,
- strerror ( rc ) );
+ efi_handle_name ( device ), wname, strerror ( rc ) );
goto err_alloc;
}
@@ -141,8 +185,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
if ( ( efirc = file->Read ( file, &size, data ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not read %ls: %s\n",
- efi_handle_name ( device ), efi_autoexec_wname,
- strerror ( rc ) );
+ efi_handle_name ( device ), wname, strerror ( rc ) );
goto err_read;
}
@@ -150,8 +193,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
efi_autoexec = data;
efi_autoexec_len = size;
data = NULL;
- DBGC ( device, "EFI %s found %ls\n",
- efi_handle_name ( device ), efi_autoexec_wname );
+ DBGC ( device, "EFI %s found %ls\n", efi_handle_name ( device ), wname );
/* Success */
rc = 0;
@@ -169,6 +211,9 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
bs->CloseProtocol ( device, &efi_simple_file_system_protocol_guid,
efi_image_handle, device );
err_filesystem:
+ free ( wname );
+ err_wname:
+ err_not_filepath:
return rc;
}
@@ -345,17 +390,23 @@ static int efi_autoexec_tftp ( EFI_HANDLE device ) {
* Load autoexec script
*
* @v device Device handle
+ * @v path Image path within device handle
* @ret rc Return status code
*/
-int efi_autoexec_load ( EFI_HANDLE device ) {
+int efi_autoexec_load ( EFI_HANDLE device,
+ EFI_DEVICE_PATH_PROTOCOL *path ) {
int rc;
/* Sanity check */
assert ( efi_autoexec == NULL );
assert ( efi_autoexec_len == 0 );
- /* Try loading from file system, if supported */
- if ( ( rc = efi_autoexec_filesystem ( device ) ) == 0 )
+ /* Try loading from file system loaded image directory, if supported */
+ if ( ( rc = efi_autoexec_filesystem ( device, path ) ) == 0 )
+ return 0;
+
+ /* Try loading from file system root directory, if supported */
+ if ( ( rc = efi_autoexec_filesystem ( device, NULL ) ) == 0 )
return 0;
/* Try loading via TFTP, if supported */
diff --git a/src/interface/efi/efiprefix.c b/src/interface/efi/efiprefix.c
index bdc36d9..2611606 100644
--- a/src/interface/efi/efiprefix.c
+++ b/src/interface/efi/efiprefix.c
@@ -78,16 +78,17 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
*/
static void efi_init_application ( void ) {
EFI_HANDLE device = efi_loaded_image->DeviceHandle;
- EFI_DEVICE_PATH_PROTOCOL *path = efi_loaded_image_path;
+ EFI_DEVICE_PATH_PROTOCOL *devpath = efi_loaded_image_path;
+ EFI_DEVICE_PATH_PROTOCOL *filepath = efi_loaded_image->FilePath;
/* Identify autoboot device, if any */
- efi_set_autoboot_ll_addr ( device, path );
+ efi_set_autoboot_ll_addr ( device, devpath );
/* Store cached DHCP packet, if any */
- efi_cachedhcp_record ( device, path );
+ efi_cachedhcp_record ( device, devpath );
/* Load autoexec script, if any */
- efi_autoexec_load ( device );
+ efi_autoexec_load ( device, filepath );
}
/** EFI application initialisation function */