]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[block] Allow use of a non-default EFI SAN boot filename
authorMichael Brown <mcb30@ipxe.org>
Wed, 12 Apr 2017 14:03:25 +0000 (15:03 +0100)
committerMichael Brown <mcb30@ipxe.org>
Wed, 12 Apr 2017 14:58:05 +0000 (15:58 +0100)
Some older operating systems (e.g. RHEL6) use a non-default filename
on the root disk and rely on setting an EFI variable to point to the
bootloader.  This does not work when performing a SAN boot on a
machine where the EFI variable is not present.

Fix by allowing a non-default filename to be specified via the
"sanboot --filename" option or the "san-filename" setting.  For
example:

  sanboot --filename \efi\redhat\grub.efi \
          iscsi:192.168.0.1::::iqn.2010-04.org.ipxe.demo:rhel6

or

  option ipxe.san-filename code 188 = string;
  option ipxe.san-filename "\\efi\\redhat\\grub.efi";
  option root-path "iscsi:192.168.0.1::::iqn.2010-04.org.ipxe.demo:rhel6";

Originally-implemented-by: Vishvananda Ishaya Abrams <vish.ishaya@oracle.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
12 files changed:
src/arch/x86/interface/pcbios/int13.c
src/core/dummy_sanboot.c
src/core/null_sanboot.c
src/core/settings.c
src/hci/commands/sanboot_cmd.c
src/include/ipxe/dhcp.h
src/include/ipxe/sanboot.h
src/include/ipxe/settings.h
src/include/usr/autoboot.h
src/interface/efi/efi_block.c
src/usr/autoboot.c
src/usr/pxemenu.c

index b793d730cc826c927f3ac2e5ca63264127a784cc..8ac14e58c0135bcb58faaae57a8922299229444d 100644 (file)
@@ -1507,6 +1507,7 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
  * Attempt to boot from an INT 13 drive
  *
  * @v drive            Drive number
+ * @v filename         Filename (or NULL to use default)
  * @ret rc             Return status code
  *
  * This boots from the specified INT 13 drive by loading the Master
@@ -1516,7 +1517,7 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
  *
  * Note that this function can never return success, by definition.
  */
-static int int13_boot ( unsigned int drive ) {
+static int int13_boot ( unsigned int drive, const char *filename __unused ) {
        struct memory_map memmap;
        struct segoff address;
        int rc;
index 08180852c62715f2b21f97ca813f9bd945cb9564..e6293099a4b3eecd33bffd9da6f65bf8f7db47a7 100644 (file)
@@ -95,8 +95,11 @@ static void dummy_san_unhook ( unsigned int drive ) {
  * Boot from dummy SAN device
  *
  * @v drive            Drive number
+ * @v filename         Filename (or NULL to use default)
+ * @ret rc             Return status code
  */
-static int dummy_san_boot ( unsigned int drive __unused ) {
+static int dummy_san_boot ( unsigned int drive __unused,
+                           const char *filename __unused ) {
 
        return -EOPNOTSUPP;
 }
index b09562e28bc413777ebd45ac76fbf027f23ad9b1..7c0680f584459af2142e7458fe2d9e9e36cf81ff 100644 (file)
@@ -37,7 +37,8 @@ static void null_san_unhook ( unsigned int drive __unused ) {
        /* Do nothing */
 }
 
-static int null_san_boot ( unsigned int drive __unused ) {
+static int null_san_boot ( unsigned int drive __unused,
+                          const char *filename __unused ) {
        return -EOPNOTSUPP;
 }
 
index f5be5c4eb281f28e02373e589f4c0c1382020644..879057224e93cdd6eb78b0f88f1bc45cd9917160 100644 (file)
@@ -2396,6 +2396,15 @@ const struct setting root_path_setting __setting ( SETTING_SANBOOT, root-path)={
        .type = &setting_type_string,
 };
 
+/** SAN filename setting */
+const struct setting san_filename_setting __setting ( SETTING_SANBOOT,
+                                                     san-filename ) = {
+       .name = "san-filename",
+       .description = "SAN filename",
+       .tag = DHCP_EB_SAN_FILENAME,
+       .type = &setting_type_string,
+};
+
 /** Username setting */
 const struct setting username_setting __setting ( SETTING_AUTH, username ) = {
        .name = "username",
index 9965ec15111d1c00e723cfee4406cd3f5d8293af..3907276a0a1f419e9fdd88ac14edc3671b486685 100644 (file)
@@ -47,12 +47,14 @@ struct sanboot_options {
        int no_describe;
        /** Keep SAN device */
        int keep;
+       /** Filename */
+       char *filename;
 };
 
 /** "sanboot" option list */
 static union {
-       /* "sanboot" takes all three options */
-       struct option_descriptor sanboot[3];
+       /* "sanboot" takes all four options */
+       struct option_descriptor sanboot[4];
        /* "sanhook" takes only --drive and --no-describe */
        struct option_descriptor sanhook[2];
        /* "sanunhook" takes only --drive */
@@ -65,6 +67,8 @@ static union {
                              struct sanboot_options, no_describe, parse_flag ),
                OPTION_DESC ( "keep", 'k', no_argument,
                              struct sanboot_options, keep, parse_flag ),
+               OPTION_DESC ( "filename", 'f', required_argument,
+                             struct sanboot_options, filename, parse_string ),
        },
 };
 
@@ -130,7 +134,8 @@ static int sanboot_core_exec ( int argc, char **argv,
                flags |= no_root_path_flags;
 
        /* Boot from root path */
-       if ( ( rc = uriboot ( NULL, uris, count, opts.drive, flags ) ) != 0 )
+       if ( ( rc = uriboot ( NULL, uris, count, opts.drive, opts.filename,
+                             flags ) ) != 0 )
                goto err_uriboot;
 
  err_uriboot:
index 0f662d633a11142a66447906ce3e4e0066a8c604..b7a5f004bdad051da2b24ba23f1d6ed6c0289087 100644 (file)
@@ -440,6 +440,12 @@ struct dhcp_netdev_desc {
  */
 #define DHCP_EB_SAN_RETRY DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xbb )
 
+/** SAN filename
+ *
+ * This is the path of the bootloader within the SAN device.
+ */
+#define DHCP_EB_SAN_FILENAME DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xbc )
+
 /** SAN drive number
  *
  * This is the drive number for a SAN-hooked drive.  For BIOS, 0x80 is
index 8737bbc0b4508804ff38f6b336ef73e1ac6c58ae..8b3e2b28251e33dae60898c27f515ecb197a1448 100644 (file)
@@ -155,9 +155,10 @@ void san_unhook ( unsigned int drive );
  * Attempt to boot from a SAN device
  *
  * @v drive            Drive number
+ * @v filename         Filename (or NULL to use default)
  * @ret rc             Return status code
  */
-int san_boot ( unsigned int drive );
+int san_boot ( unsigned int drive, const char *filename );
 
 /**
  * Describe SAN devices for SAN-booted operating system
index 521efa99d81d86a94dd080ad7fc4dae60d1a3ef6..36b4c2410db4824093076097218048835c523e6a 100644 (file)
@@ -452,6 +452,8 @@ filename_setting __setting ( SETTING_BOOT, filename );
 extern const struct setting
 root_path_setting __setting ( SETTING_SANBOOT, root-path );
 extern const struct setting
+san_filename_setting __setting ( SETTING_SANBOOT, san-filename );
+extern const struct setting
 username_setting __setting ( SETTING_AUTH, username );
 extern const struct setting
 password_setting __setting ( SETTING_AUTH, password );
index c62d06c6ff4dea9318ad4f89d37f60015ab2bd56..f88b8494f9c62b38662af201eadbade929a43baf 100644 (file)
@@ -32,7 +32,7 @@ extern void set_autoboot_ll_addr ( const void *ll_addr, size_t len );
 
 extern int uriboot ( struct uri *filename, struct uri **root_paths,
                     unsigned int root_path_count, int drive,
-                    unsigned int flags );
+                    const char *san_filename, unsigned int flags );
 extern struct uri *
 fetch_next_server_and_filename ( struct settings *settings );
 extern int netboot ( struct net_device *netdev );
index fa2271b3137f6008dc2794e722dbed6a83b70a1a..70a87dcf1fed3d842a2b74285227d0f3f8d4304a 100644 (file)
@@ -518,10 +518,12 @@ static int efi_block_describe ( void ) {
  *
  * @v sandev           SAN device
  * @v handle           EFI handle
+ * @v filename         Filename (or NULL to use default)
+ * @v image            Image handle to fill in
  * @ret rc             Return status code
  */
 static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle,
-                                 EFI_HANDLE *image ) {
+                                 const char *filename, EFI_HANDLE *image ) {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct efi_block_data *block = sandev->priv;
        union {
@@ -563,7 +565,10 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle,
        end = efi_devpath_end ( path.path );
        prefix_len = ( ( ( void * ) end ) - ( ( void * ) path.path ) );
        filepath_len = ( SIZE_OF_FILEPATH_DEVICE_PATH +
-                        sizeof ( efi_block_boot_filename ) );
+                        ( filename ?
+                          ( ( strlen ( filename ) + 1 /* NUL */ ) *
+                            sizeof ( filepath->PathName[0] ) ) :
+                          sizeof ( efi_block_boot_filename ) ) );
        boot_path_len = ( prefix_len + filepath_len + sizeof ( *end ) );
        boot_path = zalloc ( boot_path_len );
        if ( ! boot_path ) {
@@ -576,8 +581,12 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle,
        filepath->Header.SubType = MEDIA_FILEPATH_DP;
        filepath->Header.Length[0] = ( filepath_len & 0xff );
        filepath->Header.Length[1] = ( filepath_len >> 8 );
-       memcpy ( filepath->PathName, efi_block_boot_filename,
-                sizeof ( efi_block_boot_filename ) );
+       if ( filename ) {
+               efi_sprintf ( filepath->PathName, "%s", filename );
+       } else {
+               memcpy ( filepath->PathName, efi_block_boot_filename,
+                        sizeof ( efi_block_boot_filename ) );
+       }
        end = ( ( ( void * ) filepath ) + filepath_len );
        end->Type = END_DEVICE_PATH_TYPE;
        end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
@@ -609,9 +618,10 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle,
  * Boot from EFI block device
  *
  * @v drive            Drive number
+ * @v filename         Filename (or NULL to use default)
  * @ret rc             Return status code
  */
-static int efi_block_boot ( unsigned int drive ) {
+static int efi_block_boot ( unsigned int drive, const char *filename ) {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct san_device *sandev;
        EFI_HANDLE *handles;
@@ -649,7 +659,7 @@ static int efi_block_boot ( unsigned int drive ) {
         */
        rc = -ENOENT;
        for ( i = 0 ; i < count ; i++ ) {
-               if ( ( rc = efi_block_boot_image ( sandev, handles[i],
+               if ( ( rc = efi_block_boot_image ( sandev, handles[i], filename,
                                                   &image ) ) != 0 )
                        continue;
                DBGC ( sandev, "EFIBLK %#02x found boot image\n",
index 10ccdc1d642c47e70f718b514140fc373a275c14..106e0f87992ff920ff0290dd4c908fbdbedf9674 100644 (file)
@@ -112,6 +112,7 @@ const struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA,
  * @v root_paths       Root path(s)
  * @v root_path_count  Number of root paths
  * @v drive            SAN drive (if applicable)
+ * @v san_filename     SAN filename (or NULL to use default)
  * @v flags            Boot action flags
  * @ret rc             Return status code
  *
@@ -122,7 +123,8 @@ const struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA,
  * "skip-san-boot" options.
  */
 int uriboot ( struct uri *filename, struct uri **root_paths,
-             unsigned int root_path_count, int drive, unsigned int flags ) {
+             unsigned int root_path_count, int drive,
+             const char *san_filename, unsigned int flags ) {
        struct image *image;
        int rc;
 
@@ -177,8 +179,10 @@ int uriboot ( struct uri *filename, struct uri **root_paths,
        /* Attempt SAN boot if applicable */
        if ( ! ( flags & URIBOOT_NO_SAN_BOOT ) ) {
                if ( fetch_intz_setting ( NULL, &skip_san_boot_setting) == 0 ) {
-                       printf ( "Booting from SAN device %#02x\n", drive );
-                       rc = san_boot ( drive );
+                       printf ( "Booting%s%s from SAN device %#02x\n",
+                                ( san_filename ? " " : "" ),
+                                ( san_filename ? san_filename : "" ), drive );
+                       rc = san_boot ( drive, san_filename );
                        printf ( "Boot from SAN device %#02x failed: %s\n",
                                 drive, strerror ( rc ) );
                } else {
@@ -300,10 +304,10 @@ static struct uri * fetch_root_path ( struct settings *settings ) {
        root_path = expand_settings ( raw_root_path );
        if ( ! root_path )
                goto err_expand;
-
-       /* Parse root path */
        if ( root_path[0] )
                printf ( "Root path: %s\n", root_path );
+
+       /* Parse root path */
        uri = parse_uri ( root_path );
        if ( ! uri )
                goto err_parse;
@@ -316,6 +320,35 @@ static struct uri * fetch_root_path ( struct settings *settings ) {
        return uri;
 }
 
+/**
+ * Fetch san-filename setting
+ *
+ * @v settings         Settings block
+ * @ret san_filename   SAN filename, or NULL on failure
+ */
+static char * fetch_san_filename ( struct settings *settings ) {
+       char *raw_san_filename;
+       char *san_filename = NULL;
+
+       /* Fetch san-filename setting */
+       fetch_string_setting_copy ( settings, &san_filename_setting,
+                                   &raw_san_filename );
+       if ( ! raw_san_filename )
+               goto err_fetch;
+
+       /* Expand san-filename setting */
+       san_filename = expand_settings ( raw_san_filename );
+       if ( ! san_filename )
+               goto err_expand;
+       if ( san_filename[0] )
+               printf ( "SAN filename: %s\n", san_filename );
+
+ err_expand:
+       free ( raw_san_filename );
+ err_fetch:
+       return san_filename;
+}
+
 /**
  * Check whether or not we have a usable PXE menu
  *
@@ -351,6 +384,7 @@ static int have_pxe_menu ( void ) {
 int netboot ( struct net_device *netdev ) {
        struct uri *filename;
        struct uri *root_path;
+       char *san_filename;
        int rc;
 
        /* Close all other network devices */
@@ -379,6 +413,9 @@ int netboot ( struct net_device *netdev ) {
        /* Fetch root path (if any) */
        root_path = fetch_root_path ( NULL );
 
+       /* Fetch SAN filename (if any) */
+       san_filename = fetch_san_filename ( NULL );
+
        /* If we have both a filename and a root path, ignore an
         * unsupported or missing URI scheme in the root path, since
         * it may represent an NFS root.
@@ -400,12 +437,13 @@ int netboot ( struct net_device *netdev ) {
 
        /* Boot using next server, filename and root path */
        if ( ( rc = uriboot ( filename, &root_path, ( root_path ? 1 : 0 ),
-                             san_default_drive(),
+                             san_default_drive(), san_filename,
                              ( root_path ? 0 : URIBOOT_NO_SAN ) ) ) != 0 )
                goto err_uriboot;
 
  err_uriboot:
  err_no_boot:
+       free ( san_filename );
        uri_put ( root_path );
        uri_put ( filename );
  err_pxe_menu_boot:
index 391d698a96cc163f7d79bdc52869eaccec2f8fd2..5e497f990118a0253b29847858a14fcf3d89a04e 100644 (file)
@@ -378,7 +378,7 @@ int pxe_menu_boot ( struct net_device *netdev ) {
                return -ENOMEM;
 
        /* Attempt boot */
-       rc = uriboot ( uri, NULL, 0, 0, URIBOOT_NO_SAN );
+       rc = uriboot ( uri, NULL, 0, 0, NULL, URIBOOT_NO_SAN );
        uri_put ( uri );
        return rc;
 }