WIP - shim
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 @@
 	int keep;
 	/** Download timeout */
 	unsigned long timeout;
+	/** Second stage alternative name */
+	char *altname;
 };
 
 /** "shim" option list */
@@ -49,6 +51,8 @@
 		      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 @@
 	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 @@
 	/* 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 @@
 /**
  * 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 @@
 		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 @@
 		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 @@
 	}
 
 	/* 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 @@
 	}
 
 	/* 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 @@
 		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 @@
 };
 
 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 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 @@
 		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 @@
 	.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 @@
  * 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 @@
 	}
 	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 @@
 
 	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 @@
 	/* 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 );