* 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
*
* 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;
* 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;
}
/* 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;
}
.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",
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 */
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 ),
},
};
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:
*/
#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
* 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
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 );
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 );
*
* @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 {
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 ) {
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;
* 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;
*/
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",
* @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
*
* "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;
/* 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 {
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;
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
*
int netboot ( struct net_device *netdev ) {
struct uri *filename;
struct uri *root_path;
+ char *san_filename;
int rc;
/* Close all other network devices */
/* 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.
/* 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:
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;
}