david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[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>
This commit is contained in:
Michael Brown 2017-04-12 15:03:25 +01:00
parent a82f937485
commit 84d406ccf4
12 changed files with 97 additions and 21 deletions

View File

@ -1507,6 +1507,7 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
* Attempt to boot from an INT 13 drive * Attempt to boot from an INT 13 drive
* *
* @v drive Drive number * @v drive Drive number
* @v filename Filename (or NULL to use default)
* @ret rc Return status code * @ret rc Return status code
* *
* This boots from the specified INT 13 drive by loading the Master * 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. * 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 memory_map memmap;
struct segoff address; struct segoff address;
int rc; int rc;

View File

@ -95,8 +95,11 @@ static void dummy_san_unhook ( unsigned int drive ) {
* Boot from dummy SAN device * Boot from dummy SAN device
* *
* @v drive Drive number * @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; return -EOPNOTSUPP;
} }

View File

@ -37,7 +37,8 @@ static void null_san_unhook ( unsigned int drive __unused ) {
/* Do nothing */ /* 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; return -EOPNOTSUPP;
} }

View File

@ -2396,6 +2396,15 @@ const struct setting root_path_setting __setting ( SETTING_SANBOOT, root-path)={
.type = &setting_type_string, .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 */ /** Username setting */
const struct setting username_setting __setting ( SETTING_AUTH, username ) = { const struct setting username_setting __setting ( SETTING_AUTH, username ) = {
.name = "username", .name = "username",

View File

@ -47,12 +47,14 @@ struct sanboot_options {
int no_describe; int no_describe;
/** Keep SAN device */ /** Keep SAN device */
int keep; int keep;
/** Filename */
char *filename;
}; };
/** "sanboot" option list */ /** "sanboot" option list */
static union { static union {
/* "sanboot" takes all three options */ /* "sanboot" takes all four options */
struct option_descriptor sanboot[3]; struct option_descriptor sanboot[4];
/* "sanhook" takes only --drive and --no-describe */ /* "sanhook" takes only --drive and --no-describe */
struct option_descriptor sanhook[2]; struct option_descriptor sanhook[2];
/* "sanunhook" takes only --drive */ /* "sanunhook" takes only --drive */
@ -65,6 +67,8 @@ static union {
struct sanboot_options, no_describe, parse_flag ), struct sanboot_options, no_describe, parse_flag ),
OPTION_DESC ( "keep", 'k', no_argument, OPTION_DESC ( "keep", 'k', no_argument,
struct sanboot_options, keep, parse_flag ), 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; flags |= no_root_path_flags;
/* Boot from root path */ /* 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; goto err_uriboot;
err_uriboot: err_uriboot:

View File

@ -440,6 +440,12 @@ struct dhcp_netdev_desc {
*/ */
#define DHCP_EB_SAN_RETRY DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xbb ) #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 /** SAN drive number
* *
* This is the drive number for a SAN-hooked drive. For BIOS, 0x80 is * This is the drive number for a SAN-hooked drive. For BIOS, 0x80 is

View File

@ -155,9 +155,10 @@ void san_unhook ( unsigned int drive );
* Attempt to boot from a SAN device * Attempt to boot from a SAN device
* *
* @v drive Drive number * @v drive Drive number
* @v filename Filename (or NULL to use default)
* @ret rc Return status code * @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 * Describe SAN devices for SAN-booted operating system

View File

@ -452,6 +452,8 @@ filename_setting __setting ( SETTING_BOOT, filename );
extern const struct setting extern const struct setting
root_path_setting __setting ( SETTING_SANBOOT, root-path ); root_path_setting __setting ( SETTING_SANBOOT, root-path );
extern const struct setting extern const struct setting
san_filename_setting __setting ( SETTING_SANBOOT, san-filename );
extern const struct setting
username_setting __setting ( SETTING_AUTH, username ); username_setting __setting ( SETTING_AUTH, username );
extern const struct setting extern const struct setting
password_setting __setting ( SETTING_AUTH, password ); password_setting __setting ( SETTING_AUTH, password );

View 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, extern int uriboot ( struct uri *filename, struct uri **root_paths,
unsigned int root_path_count, int drive, unsigned int root_path_count, int drive,
unsigned int flags ); const char *san_filename, unsigned int flags );
extern struct uri * extern struct uri *
fetch_next_server_and_filename ( struct settings *settings ); fetch_next_server_and_filename ( struct settings *settings );
extern int netboot ( struct net_device *netdev ); extern int netboot ( struct net_device *netdev );

View File

@ -518,10 +518,12 @@ static int efi_block_describe ( void ) {
* *
* @v sandev SAN device * @v sandev SAN device
* @v handle EFI handle * @v handle EFI handle
* @v filename Filename (or NULL to use default)
* @v image Image handle to fill in
* @ret rc Return status code * @ret rc Return status code
*/ */
static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle, 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; EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
struct efi_block_data *block = sandev->priv; struct efi_block_data *block = sandev->priv;
union { union {
@ -563,7 +565,10 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle,
end = efi_devpath_end ( path.path ); end = efi_devpath_end ( path.path );
prefix_len = ( ( ( void * ) end ) - ( ( void * ) path.path ) ); prefix_len = ( ( ( void * ) end ) - ( ( void * ) path.path ) );
filepath_len = ( SIZE_OF_FILEPATH_DEVICE_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_len = ( prefix_len + filepath_len + sizeof ( *end ) );
boot_path = zalloc ( boot_path_len ); boot_path = zalloc ( boot_path_len );
if ( ! boot_path ) { 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.SubType = MEDIA_FILEPATH_DP;
filepath->Header.Length[0] = ( filepath_len & 0xff ); filepath->Header.Length[0] = ( filepath_len & 0xff );
filepath->Header.Length[1] = ( filepath_len >> 8 ); filepath->Header.Length[1] = ( filepath_len >> 8 );
memcpy ( filepath->PathName, efi_block_boot_filename, if ( filename ) {
sizeof ( efi_block_boot_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 = ( ( ( void * ) filepath ) + filepath_len );
end->Type = END_DEVICE_PATH_TYPE; end->Type = END_DEVICE_PATH_TYPE;
end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; 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 * Boot from EFI block device
* *
* @v drive Drive number * @v drive Drive number
* @v filename Filename (or NULL to use default)
* @ret rc Return status code * @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; EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
struct san_device *sandev; struct san_device *sandev;
EFI_HANDLE *handles; EFI_HANDLE *handles;
@ -649,7 +659,7 @@ static int efi_block_boot ( unsigned int drive ) {
*/ */
rc = -ENOENT; rc = -ENOENT;
for ( i = 0 ; i < count ; i++ ) { 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 ) &image ) ) != 0 )
continue; continue;
DBGC ( sandev, "EFIBLK %#02x found boot image\n", DBGC ( sandev, "EFIBLK %#02x found boot image\n",

View File

@ -112,6 +112,7 @@ const struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA,
* @v root_paths Root path(s) * @v root_paths Root path(s)
* @v root_path_count Number of root paths * @v root_path_count Number of root paths
* @v drive SAN drive (if applicable) * @v drive SAN drive (if applicable)
* @v san_filename SAN filename (or NULL to use default)
* @v flags Boot action flags * @v flags Boot action flags
* @ret rc Return status code * @ret rc Return status code
* *
@ -122,7 +123,8 @@ const struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA,
* "skip-san-boot" options. * "skip-san-boot" options.
*/ */
int uriboot ( struct uri *filename, struct uri **root_paths, 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; struct image *image;
int rc; int rc;
@ -177,8 +179,10 @@ int uriboot ( struct uri *filename, struct uri **root_paths,
/* Attempt SAN boot if applicable */ /* Attempt SAN boot if applicable */
if ( ! ( flags & URIBOOT_NO_SAN_BOOT ) ) { if ( ! ( flags & URIBOOT_NO_SAN_BOOT ) ) {
if ( fetch_intz_setting ( NULL, &skip_san_boot_setting) == 0 ) { if ( fetch_intz_setting ( NULL, &skip_san_boot_setting) == 0 ) {
printf ( "Booting from SAN device %#02x\n", drive ); printf ( "Booting%s%s from SAN device %#02x\n",
rc = san_boot ( drive ); ( san_filename ? " " : "" ),
( san_filename ? san_filename : "" ), drive );
rc = san_boot ( drive, san_filename );
printf ( "Boot from SAN device %#02x failed: %s\n", printf ( "Boot from SAN device %#02x failed: %s\n",
drive, strerror ( rc ) ); drive, strerror ( rc ) );
} else { } else {
@ -300,10 +304,10 @@ static struct uri * fetch_root_path ( struct settings *settings ) {
root_path = expand_settings ( raw_root_path ); root_path = expand_settings ( raw_root_path );
if ( ! root_path ) if ( ! root_path )
goto err_expand; goto err_expand;
/* Parse root path */
if ( root_path[0] ) if ( root_path[0] )
printf ( "Root path: %s\n", root_path ); printf ( "Root path: %s\n", root_path );
/* Parse root path */
uri = parse_uri ( root_path ); uri = parse_uri ( root_path );
if ( ! uri ) if ( ! uri )
goto err_parse; goto err_parse;
@ -316,6 +320,35 @@ static struct uri * fetch_root_path ( struct settings *settings ) {
return uri; 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 * 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 ) { int netboot ( struct net_device *netdev ) {
struct uri *filename; struct uri *filename;
struct uri *root_path; struct uri *root_path;
char *san_filename;
int rc; int rc;
/* Close all other network devices */ /* Close all other network devices */
@ -379,6 +413,9 @@ int netboot ( struct net_device *netdev ) {
/* Fetch root path (if any) */ /* Fetch root path (if any) */
root_path = fetch_root_path ( NULL ); 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 /* If we have both a filename and a root path, ignore an
* unsupported or missing URI scheme in the root path, since * unsupported or missing URI scheme in the root path, since
* it may represent an NFS root. * it may represent an NFS root.
@ -400,12 +437,13 @@ int netboot ( struct net_device *netdev ) {
/* Boot using next server, filename and root path */ /* Boot using next server, filename and root path */
if ( ( rc = uriboot ( filename, &root_path, ( root_path ? 1 : 0 ), 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 ) ( root_path ? 0 : URIBOOT_NO_SAN ) ) ) != 0 )
goto err_uriboot; goto err_uriboot;
err_uriboot: err_uriboot:
err_no_boot: err_no_boot:
free ( san_filename );
uri_put ( root_path ); uri_put ( root_path );
uri_put ( filename ); uri_put ( filename );
err_pxe_menu_boot: err_pxe_menu_boot:

View File

@ -378,7 +378,7 @@ int pxe_menu_boot ( struct net_device *netdev ) {
return -ENOMEM; return -ENOMEM;
/* Attempt boot */ /* Attempt boot */
rc = uriboot ( uri, NULL, 0, 0, URIBOOT_NO_SAN ); rc = uriboot ( uri, NULL, 0, 0, NULL, URIBOOT_NO_SAN );
uri_put ( uri ); uri_put ( uri );
return rc; return rc;
} }