diff options
author | Michael Brown | 2017-04-12 16:03:25 +0200 |
---|---|---|
committer | Michael Brown | 2017-04-12 16:58:05 +0200 |
commit | 84d406ccf48c8808b0bb30d526b758e4b58cacc8 (patch) | |
tree | e0d262d87136fcaf8f202ab7d6e51760a387fe78 /src | |
parent | [efi] Add efi_sprintf() and efi_vsprintf() (diff) | |
download | ipxe-84d406ccf48c8808b0bb30d526b758e4b58cacc8.tar.gz ipxe-84d406ccf48c8808b0bb30d526b758e4b58cacc8.tar.xz ipxe-84d406ccf48c8808b0bb30d526b758e4b58cacc8.zip |
[block] Allow use of a non-default EFI SAN boot filename
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>
Diffstat (limited to 'src')
-rw-r--r-- | src/arch/x86/interface/pcbios/int13.c | 3 | ||||
-rw-r--r-- | src/core/dummy_sanboot.c | 5 | ||||
-rw-r--r-- | src/core/null_sanboot.c | 3 | ||||
-rw-r--r-- | src/core/settings.c | 9 | ||||
-rw-r--r-- | src/hci/commands/sanboot_cmd.c | 11 | ||||
-rw-r--r-- | src/include/ipxe/dhcp.h | 6 | ||||
-rw-r--r-- | src/include/ipxe/sanboot.h | 3 | ||||
-rw-r--r-- | src/include/ipxe/settings.h | 2 | ||||
-rw-r--r-- | src/include/usr/autoboot.h | 2 | ||||
-rw-r--r-- | src/interface/efi/efi_block.c | 22 | ||||
-rw-r--r-- | src/usr/autoboot.c | 50 | ||||
-rw-r--r-- | src/usr/pxemenu.c | 2 |
12 files changed, 97 insertions, 21 deletions
diff --git a/src/arch/x86/interface/pcbios/int13.c b/src/arch/x86/interface/pcbios/int13.c index b793d730..8ac14e58 100644 --- a/src/arch/x86/interface/pcbios/int13.c +++ b/src/arch/x86/interface/pcbios/int13.c @@ -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; diff --git a/src/core/dummy_sanboot.c b/src/core/dummy_sanboot.c index 08180852..e6293099 100644 --- a/src/core/dummy_sanboot.c +++ b/src/core/dummy_sanboot.c @@ -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; } diff --git a/src/core/null_sanboot.c b/src/core/null_sanboot.c index b09562e2..7c0680f5 100644 --- a/src/core/null_sanboot.c +++ b/src/core/null_sanboot.c @@ -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; } diff --git a/src/core/settings.c b/src/core/settings.c index f5be5c4e..87905722 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -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", diff --git a/src/hci/commands/sanboot_cmd.c b/src/hci/commands/sanboot_cmd.c index 9965ec15..3907276a 100644 --- a/src/hci/commands/sanboot_cmd.c +++ b/src/hci/commands/sanboot_cmd.c @@ -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: diff --git a/src/include/ipxe/dhcp.h b/src/include/ipxe/dhcp.h index 0f662d63..b7a5f004 100644 --- a/src/include/ipxe/dhcp.h +++ b/src/include/ipxe/dhcp.h @@ -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 diff --git a/src/include/ipxe/sanboot.h b/src/include/ipxe/sanboot.h index 8737bbc0..8b3e2b28 100644 --- a/src/include/ipxe/sanboot.h +++ b/src/include/ipxe/sanboot.h @@ -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 diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h index 521efa99..36b4c241 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -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 ); diff --git a/src/include/usr/autoboot.h b/src/include/usr/autoboot.h index c62d06c6..f88b8494 100644 --- a/src/include/usr/autoboot.h +++ b/src/include/usr/autoboot.h @@ -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 ); diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index fa2271b3..70a87dcf 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -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", diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c index 10ccdc1d..106e0f87 100644 --- a/src/usr/autoboot.c +++ b/src/usr/autoboot.c @@ -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; @@ -317,6 +321,35 @@ static struct uri * fetch_root_path ( struct settings *settings ) { } /** + * 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 * * @ret have_menu A usable PXE menu is present @@ -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: diff --git a/src/usr/pxemenu.c b/src/usr/pxemenu.c index 391d698a..5e497f99 100644 --- a/src/usr/pxemenu.c +++ b/src/usr/pxemenu.c @@ -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; } |