[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>
This commit is contained in:
Michael Brown
2023-02-01 23:54:19 +00:00
parent b6304f2984
commit 6f250be279
3 changed files with 75 additions and 22 deletions

View File

@@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi.h> #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 */ #endif /* _IPXE_EFI_AUTOEXEC_H */

View File

@@ -54,12 +54,14 @@ static void *efi_autoexec;
static size_t efi_autoexec_len; static size_t efi_autoexec_len;
/** /**
* Load autoexec script from filesystem * Load autoexec script from path within filesystem
* *
* @v device Device handle * @v device Device handle
* @v path Relative path to image, or NULL to load from root
* @ret rc Return status code * @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; EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
union { union {
void *interface; void *interface;
@@ -70,13 +72,58 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
CHAR16 name[ sizeof ( efi_autoexec_wname ) / CHAR16 name[ sizeof ( efi_autoexec_wname ) /
sizeof ( efi_autoexec_wname[0] ) ]; sizeof ( efi_autoexec_wname[0] ) ];
} info; } info;
FILEPATH_DEVICE_PATH *filepath;
EFI_FILE_PROTOCOL *root; EFI_FILE_PROTOCOL *root;
EFI_FILE_PROTOCOL *file; EFI_FILE_PROTOCOL *file;
UINTN size; UINTN size;
VOID *data; VOID *data;
unsigned int dirlen;
size_t len;
CHAR16 *wname;
EFI_STATUS efirc; EFI_STATUS efirc;
int rc; 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 */ /* Open simple file system protocol */
if ( ( efirc = bs->OpenProtocol ( device, if ( ( efirc = bs->OpenProtocol ( device,
&efi_simple_file_system_protocol_guid, &efi_simple_file_system_protocol_guid,
@@ -98,12 +145,11 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
} }
/* Open autoexec script */ /* 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 ) { EFI_FILE_MODE_READ, 0 ) ) != 0 ) {
rc = -EEFI ( efirc ); rc = -EEFI ( efirc );
DBGC ( device, "EFI %s has no %ls: %s\n", DBGC ( device, "EFI %s has no %ls: %s\n",
efi_handle_name ( device ), efi_autoexec_wname, efi_handle_name ( device ), wname, strerror ( rc ) );
strerror ( rc ) );
goto err_open; goto err_open;
} }
@@ -113,8 +159,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
&info ) ) != 0 ) { &info ) ) != 0 ) {
rc = -EEFI ( efirc ); rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not get %ls info: %s\n", DBGC ( device, "EFI %s could not get %ls info: %s\n",
efi_handle_name ( device ), efi_autoexec_wname, efi_handle_name ( device ), wname, strerror ( rc ) );
strerror ( rc ) );
goto err_getinfo; goto err_getinfo;
} }
size = info.info.FileSize; size = info.info.FileSize;
@@ -123,7 +168,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
if ( ! size ) { if ( ! size ) {
rc = -EINVAL; rc = -EINVAL;
DBGC ( device, "EFI %s has zero-length %ls\n", DBGC ( device, "EFI %s has zero-length %ls\n",
efi_handle_name ( device ), efi_autoexec_wname ); efi_handle_name ( device ), wname );
goto err_empty; goto err_empty;
} }
@@ -132,8 +177,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
&data ) ) != 0 ) { &data ) ) != 0 ) {
rc = -EEFI ( efirc ); rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not allocate %ls: %s\n", DBGC ( device, "EFI %s could not allocate %ls: %s\n",
efi_handle_name ( device ), efi_autoexec_wname, efi_handle_name ( device ), wname, strerror ( rc ) );
strerror ( rc ) );
goto err_alloc; goto err_alloc;
} }
@@ -141,8 +185,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
if ( ( efirc = file->Read ( file, &size, data ) ) != 0 ) { if ( ( efirc = file->Read ( file, &size, data ) ) != 0 ) {
rc = -EEFI ( efirc ); rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not read %ls: %s\n", DBGC ( device, "EFI %s could not read %ls: %s\n",
efi_handle_name ( device ), efi_autoexec_wname, efi_handle_name ( device ), wname, strerror ( rc ) );
strerror ( rc ) );
goto err_read; goto err_read;
} }
@@ -150,8 +193,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
efi_autoexec = data; efi_autoexec = data;
efi_autoexec_len = size; efi_autoexec_len = size;
data = NULL; data = NULL;
DBGC ( device, "EFI %s found %ls\n", DBGC ( device, "EFI %s found %ls\n", efi_handle_name ( device ), wname );
efi_handle_name ( device ), efi_autoexec_wname );
/* Success */ /* Success */
rc = 0; rc = 0;
@@ -169,6 +211,9 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
bs->CloseProtocol ( device, &efi_simple_file_system_protocol_guid, bs->CloseProtocol ( device, &efi_simple_file_system_protocol_guid,
efi_image_handle, device ); efi_image_handle, device );
err_filesystem: err_filesystem:
free ( wname );
err_wname:
err_not_filepath:
return rc; return rc;
} }
@@ -345,17 +390,23 @@ static int efi_autoexec_tftp ( EFI_HANDLE device ) {
* Load autoexec script * Load autoexec script
* *
* @v device Device handle * @v device Device handle
* @v path Image path within device handle
* @ret rc Return status code * @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; int rc;
/* Sanity check */ /* Sanity check */
assert ( efi_autoexec == NULL ); assert ( efi_autoexec == NULL );
assert ( efi_autoexec_len == 0 ); assert ( efi_autoexec_len == 0 );
/* Try loading from file system, if supported */ /* Try loading from file system loaded image directory, if supported */
if ( ( rc = efi_autoexec_filesystem ( device ) ) == 0 ) 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; return 0;
/* Try loading via TFTP, if supported */ /* Try loading via TFTP, if supported */

View File

@@ -78,16 +78,17 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
*/ */
static void efi_init_application ( void ) { static void efi_init_application ( void ) {
EFI_HANDLE device = efi_loaded_image->DeviceHandle; 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 */ /* 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 */ /* Store cached DHCP packet, if any */
efi_cachedhcp_record ( device, path ); efi_cachedhcp_record ( device, devpath );
/* Load autoexec script, if any */ /* Load autoexec script, if any */
efi_autoexec_load ( device ); efi_autoexec_load ( device, filepath );
} }
/** EFI application initialisation function */ /** EFI application initialisation function */