summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2023-02-02 00:54:19 +0100
committerMichael Brown2023-02-02 00:54:19 +0100
commit6f250be279311d461f78bb17eb8b5b70ad90dd0a (patch)
tree07c07d85835367e6844965aba420ccc6811a5ac3
parent[realtek] Explicitly disable VLAN offload (diff)
downloadipxe-6f250be279311d461f78bb17eb8b5b70ad90dd0a.tar.gz
ipxe-6f250be279311d461f78bb17eb8b5b70ad90dd0a.tar.xz
ipxe-6f250be279311d461f78bb17eb8b5b70ad90dd0a.zip
[efi] Allow autoexec script to be located alongside iPXE binary
Try loading the autoexec.ipxe script first from the directory containing the iPXE binary (based on the relative file path provided to us via EFI_LOADED_IMAGE_PROTOCOL), then fall back to trying the root directory. Signed-off-by: Michael Brown <mcb30@ipxe.org>
-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 1f93b41c..08ddf583 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 79d4a4ca..fb12cef0 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 bdc36d9b..26116068 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 */