aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2023-03-10 15:36:08 +0000
committerMichael Brown <mcb30@ipxe.org>2023-03-10 15:36:08 +0000
commitb123d3287009df4b50fd38c266072fefe677a0bf (patch)
treed399cfba060667a6c18cf8d5e45b4f8e2d25a176
parent2aef08b7a5fa98e5b309d47d933b5cd32a6feec0 (diff)
downloadipxe-b123d3287009df4b50fd38c266072fefe677a0bf.zip
ipxe-b123d3287009df4b50fd38c266072fefe677a0bf.tar.gz
ipxe-b123d3287009df4b50fd38c266072fefe677a0bf.tar.bz2
WIP - shim
-rw-r--r--src/hci/commands/shim_cmd.c9
-rw-r--r--src/image/efi_image.c44
-rw-r--r--src/include/ipxe/efi/efi_file.h5
-rw-r--r--src/interface/efi/efi_file.c62
4 files changed, 103 insertions, 17 deletions
diff --git a/src/hci/commands/shim_cmd.c b/src/hci/commands/shim_cmd.c
index f8a841a..efefb5b 100644
--- a/src/hci/commands/shim_cmd.c
+++ b/src/hci/commands/shim_cmd.c
@@ -41,6 +41,8 @@ struct shim_options {
int keep;
/** Download timeout */
unsigned long timeout;
+ /** Second stage alternative name */
+ char *altname;
};
/** "shim" option list */
@@ -49,6 +51,8 @@ static struct option_descriptor shim_opts[] = {
struct shim_options, keep, parse_flag ),
OPTION_DESC ( "timeout", 't', required_argument,
struct shim_options, timeout, parse_timeout ),
+ OPTION_DESC ( "second", 's', required_argument,
+ struct shim_options, altname, parse_string ),
};
/** "shim" command descriptor */
@@ -75,6 +79,10 @@ static int shim_exec ( int argc, char **argv ) {
if ( ( rc = imgacquire ( argv[optind], opts.timeout, &image ) ) != 0 )
goto err_acquire;
+ /* Record second stage, if any */
+ if ( ( rc = image_set_cmdline ( image, opts.altname ) ) != 0 )
+ goto err_cmdline;
+
/* Register as shim */
efi_set_shim ( image );
@@ -84,6 +92,7 @@ static int shim_exec ( int argc, char **argv ) {
/* Discard original image unless --keep was specified */
if ( ! opts.keep )
unregister_image ( image );
+ err_cmdline:
err_acquire:
err_parse:
return rc;
diff --git a/src/image/efi_image.c b/src/image/efi_image.c
index 6235ea0..e1f4507 100644
--- a/src/image/efi_image.c
+++ b/src/image/efi_image.c
@@ -108,20 +108,26 @@ efi_image_path ( struct image *image, EFI_DEVICE_PATH_PROTOCOL *parent ) {
/**
* Create command line for image
*
- * @v image EFI image
+ * @v image EFI image
+ * @v prefix Command line prefix, or NULL
* @ret cmdline Command line, or NULL on failure
*/
-static wchar_t * efi_image_cmdline ( struct image *image ) {
+static wchar_t * efi_image_cmdline ( struct image *image,
+ const char *prefix ) {
wchar_t *cmdline;
size_t len;
- len = ( strlen ( image->name ) +
+ len = ( ( prefix ?
+ ( strlen ( prefix ) + 1 /* NUL */ + 1 /* " " */ ) : 0 ) +
+ strlen ( image->name ) +
( image->cmdline ?
( 1 /* " " */ + strlen ( image->cmdline ) ) : 0 ) );
cmdline = zalloc ( ( len + 1 /* NUL */ ) * sizeof ( wchar_t ) );
if ( ! cmdline )
return NULL;
- efi_snprintf ( cmdline, ( len + 1 /* NUL */ ), "%s%s%s",
+ efi_snprintf ( cmdline, ( len + 1 /* NUL */ ), "%s%s%s%s%s",
+ ( prefix ? prefix : "" ),
+ ( prefix ? " " : "" ),
image->name,
( image->cmdline ? " " : "" ),
( image->cmdline ? image->cmdline : "" ) );
@@ -144,6 +150,8 @@ static int efi_image_exec ( struct image *image ) {
void *interface;
} loaded;
struct image *exec;
+ const char *prefix;
+ const char *altname;
EFI_HANDLE handle;
EFI_MEMORY_TYPE type;
wchar_t *cmdline;
@@ -159,8 +167,23 @@ static int efi_image_exec ( struct image *image ) {
goto err_no_snpdev;
}
+ /* Choose to execute image via shim if applicable */
+ if ( shim ) {
+ exec = shim;
+ prefix = shim->name;
+ altname = shim->cmdline;
+ DBGC ( image, "EFIIMAGE %s%s%s%s executing via %s\n",
+ image->name, ( altname ? " (aka " : "" ),
+ ( altname ? altname : "" ), ( altname ? ")" : "" ),
+ shim->name );
+ } else {
+ exec = image;
+ prefix = NULL;
+ altname = NULL;
+ }
+
/* Install file I/O protocols */
- if ( ( rc = efi_file_install ( snpdev->handle ) ) != 0 ) {
+ if ( ( rc = efi_file_install ( snpdev->handle, image, altname ) ) != 0){
DBGC ( image, "EFIIMAGE %s could not install file protocol: "
"%s\n", image->name, strerror ( rc ) );
goto err_file_install;
@@ -182,7 +205,7 @@ static int efi_image_exec ( struct image *image ) {
}
/* Create device path for image */
- path = efi_image_path ( image, snpdev->path );
+ path = efi_image_path ( exec, snpdev->path );
if ( ! path ) {
DBGC ( image, "EFIIMAGE %s could not create device path\n",
image->name );
@@ -191,7 +214,7 @@ static int efi_image_exec ( struct image *image ) {
}
/* Create command line for image */
- cmdline = efi_image_cmdline ( image );
+ cmdline = efi_image_cmdline ( image, prefix );
if ( ! cmdline ) {
DBGC ( image, "EFIIMAGE %s could not create command line\n",
image->name );
@@ -199,13 +222,6 @@ static int efi_image_exec ( struct image *image ) {
goto err_cmdline;
}
- /* Execute image or shim as applicable */
- exec = ( shim ? shim : image );
- if ( shim ) {
- DBGC ( image, "EFIIMAGE %s executing via %s\n",
- image->name, shim->name );
- }
-
/* Attempt loading image */
handle = NULL;
if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, path,
diff --git a/src/include/ipxe/efi/efi_file.h b/src/include/ipxe/efi/efi_file.h
index 79c073c..ff90f53 100644
--- a/src/include/ipxe/efi/efi_file.h
+++ b/src/include/ipxe/efi/efi_file.h
@@ -9,7 +9,10 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-extern int efi_file_install ( EFI_HANDLE handle );
+struct image;
+
+extern int efi_file_install ( EFI_HANDLE handle, struct image *second,
+ const char *altname );
extern void efi_file_uninstall ( EFI_HANDLE handle );
#endif /* _IPXE_EFI_FILE_H */
diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c
index a0bba16..5afdf68 100644
--- a/src/interface/efi/efi_file.c
+++ b/src/interface/efi/efi_file.c
@@ -94,6 +94,7 @@ struct efi_file {
};
static struct efi_file efi_file_root;
+static struct efi_file efi_file_second;
static struct efi_file efi_file_initrd;
/**
@@ -117,7 +118,15 @@ static void efi_file_free ( struct refcnt *refcnt ) {
*/
static const char * efi_file_name ( struct efi_file *file ) {
- return ( file == &efi_file_root ? "<root>" : file->name );
+ if ( file == &efi_file_root ) {
+ return "<root>";
+ } else if ( file->name != NULL ) {
+ return file->name;
+ } else if ( file->image != NULL ) {
+ return file->image->name;
+ } else {
+ return "<UNKNOWN>";
+ }
}
/**
@@ -357,6 +366,14 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
return EFI_WRITE_PROTECTED;
}
+ /* Allow magic second stage to be opened */
+ if ( ( efi_file_second.image != NULL ) &&
+ ( ( strcasecmp ( name, efi_file_second.image->name ) == 0 ) ||
+ ( ( efi_file_second.name != NULL ) &&
+ ( strcasecmp ( name, efi_file_second.name ) == 0 ) ) ) ) {
+ return efi_file_open_fixed ( &efi_file_second, new );
+ }
+
/* Allow magic initrd to be opened */
if ( strcasecmp ( name, efi_file_initrd.name ) == 0 )
return efi_file_open_fixed ( &efi_file_initrd, new );
@@ -752,6 +769,30 @@ static struct efi_file efi_file_root = {
.name = "",
};
+/** Magic second stage file */
+static struct efi_file efi_file_second = {
+ .refcnt = REF_INIT ( ref_no_free ),
+ .file = {
+ .Revision = EFI_FILE_PROTOCOL_REVISION,
+ .Open = efi_file_open,
+ .Close = efi_file_close,
+ .Delete = efi_file_delete,
+ .Read = efi_file_read,
+ .Write = efi_file_write,
+ .GetPosition = efi_file_get_position,
+ .SetPosition = efi_file_set_position,
+ .GetInfo = efi_file_get_info,
+ .SetInfo = efi_file_set_info,
+ .Flush = efi_file_flush,
+ },
+ .load = {
+ .LoadFile = efi_file_load,
+ },
+ .image = NULL,
+ .name = NULL,
+ .read = efi_file_read_image,
+};
+
/** Magic initrd file */
static struct efi_file efi_file_initrd = {
.refcnt = REF_INIT ( ref_no_free ),
@@ -1012,9 +1053,12 @@ static int efi_file_path_install ( EFI_DEVICE_PATH_PROTOCOL *path,
* Install EFI simple file system protocol
*
* @v handle EFI handle
+ * @v second Second stage image, or NULL
+ * @v altname Second stage alternative filename, or NULL
* @ret rc Return status code
*/
-int efi_file_install ( EFI_HANDLE handle ) {
+int efi_file_install ( EFI_HANDLE handle, struct image *second,
+ const char *altname ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_LOAD_FILE2_PROTOCOL *load;
union {
@@ -1079,6 +1123,12 @@ int efi_file_install ( EFI_HANDLE handle ) {
}
assert ( diskio.diskio == &efi_disk_io_protocol );
+ /* Initialise magic second stage file, if any */
+ if ( second ) {
+ efi_file_second.image = image_get ( second );
+ efi_file_second.name = altname;
+ }
+
/* Install Linux initrd fixed device path file
*
* Install the device path handle unconditionally, since we
@@ -1097,6 +1147,9 @@ int efi_file_install ( EFI_HANDLE handle ) {
efi_file_path_install ( &efi_file_initrd_path.vendor.Header, NULL );
err_initrd:
+ image_put ( efi_file_second.image );
+ efi_file_second.image = NULL;
+ efi_file_second.name = NULL;
bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid,
efi_image_handle, handle );
err_open:
@@ -1125,6 +1178,11 @@ void efi_file_uninstall ( EFI_HANDLE handle ) {
/* Uninstall Linux initrd fixed device path file */
efi_file_path_install ( &efi_file_initrd_path.vendor.Header, NULL );
+ /* Clear magic second stage, if any */
+ image_put ( efi_file_second.image );
+ efi_file_second.image = NULL;
+ efi_file_second.name = NULL;
+
/* Close our own disk I/O protocol */
bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid,
efi_image_handle, handle );