]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Allow autoexec script to be located alongside iPXE binary
authorMichael Brown <mcb30@ipxe.org>
Wed, 1 Feb 2023 23:54:19 +0000 (23:54 +0000)
committerMichael Brown <mcb30@ipxe.org>
Wed, 1 Feb 2023 23:54:19 +0000 (23:54 +0000)
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>
src/include/ipxe/efi/efi_autoexec.h
src/interface/efi/efi_autoexec.c
src/interface/efi/efiprefix.c

index 1f93b41cd261649b7b7cd024ef938daaea0d4503..08ddf58367abb70b1fb5b33e76126719e8ac7896 100644 (file)
@@ -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 */
index 79d4a4cafca4cadc353a5c4a3d3f8ca2d701a9ca..fb12cef0803adc5cac7e80ed0081d1fd4e0685e5 100644 (file)
@@ -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 */
index bdc36d9bd7e84a9898e0ec2a29a5d8305624f931..2611606818d3df633c271fdb7e7ec5a3bfce2d31 100644 (file)
@@ -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 */