From 22cc65535a331f05863f3c4b48910b0d50ff5dd7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 4 May 2023 15:29:23 +0100 Subject: [efi] Allow downloaded images to take precedence over constructed files Try searching for a matching registered image before checking for fixed filenames (such as "initrd.magic" for the dynamically generated magic initrd file). This minimises surprise by ensuring that an explicitly downloaded image will always be used verbatim. Signed-off-by: Michael Brown --- src/interface/efi/efi_file.c | 55 ++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 22 deletions(-) (limited to 'src/interface/efi/efi_file.c') diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c index b232591dc..2ac6e2b20 100644 --- a/src/interface/efi/efi_file.c +++ b/src/interface/efi/efi_file.c @@ -320,6 +320,33 @@ static void efi_file_image ( struct efi_file *file, struct image *image ) { file->read = efi_file_read_image; } +/** + * Open image-backed file + * + * @v image Image + * @v new New EFI file + * @ret efirc EFI status code + */ +static EFI_STATUS efi_file_open_image ( struct image *image, + EFI_FILE_PROTOCOL **new ) { + struct efi_file *file; + + /* Allocate and initialise file */ + file = zalloc ( sizeof ( *file ) ); + if ( ! file ) + return EFI_OUT_OF_RESOURCES; + ref_init ( &file->refcnt, efi_file_free ); + memcpy ( &file->file, &efi_file_root.file, sizeof ( file->file ) ); + memcpy ( &file->load, &efi_file_root.load, sizeof ( file->load ) ); + efi_file_image ( file, image_get ( image ) ); + + /* Return opened file */ + *new = &file->file; + + DBGC ( file, "EFIFILE %s opened\n", efi_file_name ( file ) ); + return 0; +} + /** * Open file * @@ -335,7 +362,6 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, CHAR16 *wname, UINT64 mode, UINT64 attributes __unused ) { struct efi_file *file = container_of ( this, struct efi_file, file ); char buf[ wcslen ( wname ) + 1 /* NUL */ ]; - struct efi_file *new_file; struct image *image; char *name; @@ -367,31 +393,16 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, return EFI_WRITE_PROTECTED; } + /* Allow registered images to be opened */ + if ( ( image = efi_file_find ( name ) ) != NULL ) + return efi_file_open_image ( image, new ); + /* Allow magic initrd to be opened */ if ( strcasecmp ( name, efi_file_initrd.file.name ) == 0 ) return efi_file_open_fixed ( &efi_file_initrd.file, new ); - /* Identify image */ - image = efi_file_find ( name ); - if ( ! image ) { - DBGC ( file, "EFIFILE %s does not exist\n", name ); - return EFI_NOT_FOUND; - } - - /* Allocate and initialise file */ - new_file = zalloc ( sizeof ( *new_file ) ); - if ( ! new_file ) - return EFI_OUT_OF_RESOURCES; - ref_init ( &file->refcnt, efi_file_free ); - memcpy ( &new_file->file, &efi_file_root.file, - sizeof ( new_file->file ) ); - memcpy ( &new_file->load, &efi_file_root.load, - sizeof ( new_file->load ) ); - efi_file_image ( new_file, image_get ( image ) ); - *new = &new_file->file; - DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) ); - - return 0; + DBGC ( file, "EFIFILE %s does not exist\n", name ); + return EFI_NOT_FOUND; } /** -- cgit v1.2.3-55-g7522 From f93e6b712ff2beb7ea4e169a681b8144785f3e49 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 5 May 2023 12:46:54 +0100 Subject: [efi] Show original filenames in debug messages Show the original filename as used by the consumer when calling our EFI_SIMPLE_FILE_SYSTEM_PROTOCOL's Open() method. Signed-off-by: Michael Brown --- src/interface/efi/efi_file.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'src/interface/efi/efi_file.c') diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c index 2ac6e2b20..fd0bcc6ce 100644 --- a/src/interface/efi/efi_file.c +++ b/src/interface/efi/efi_file.c @@ -291,10 +291,12 @@ static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) { * Open fixed file * * @v file EFI file + * @v wname Filename * @v new New EFI file * @ret efirc EFI status code */ static EFI_STATUS efi_file_open_fixed ( struct efi_file *file, + const wchar_t *wname, EFI_FILE_PROTOCOL **new ) { /* Increment reference count */ @@ -303,7 +305,8 @@ static EFI_STATUS efi_file_open_fixed ( struct efi_file *file, /* Return opened file */ *new = &file->file; - DBGC ( file, "EFIFILE %s opened\n", efi_file_name ( file ) ); + DBGC ( file, "EFIFILE %s opened via %ls\n", + efi_file_name ( file ), wname ); return 0; } @@ -324,10 +327,12 @@ static void efi_file_image ( struct efi_file *file, struct image *image ) { * Open image-backed file * * @v image Image + * @v wname Filename * @v new New EFI file * @ret efirc EFI status code */ static EFI_STATUS efi_file_open_image ( struct image *image, + const wchar_t *wname, EFI_FILE_PROTOCOL **new ) { struct efi_file *file; @@ -343,7 +348,8 @@ static EFI_STATUS efi_file_open_image ( struct image *image, /* Return opened file */ *new = &file->file; - DBGC ( file, "EFIFILE %s opened\n", efi_file_name ( file ) ); + DBGC ( file, "EFIFILE %s opened via %ls\n", + efi_file_name ( file ), wname ); return 0; } @@ -377,7 +383,7 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, /* Allow root directory itself to be opened */ if ( ( name[0] == '\0' ) || ( name[0] == '.' ) ) - return efi_file_open_fixed ( &efi_file_root, new ); + return efi_file_open_fixed ( &efi_file_root, wname, new ); /* Fail unless opening from the root */ if ( file != &efi_file_root ) { @@ -395,13 +401,15 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, /* Allow registered images to be opened */ if ( ( image = efi_file_find ( name ) ) != NULL ) - return efi_file_open_image ( image, new ); + return efi_file_open_image ( image, wname, new ); /* Allow magic initrd to be opened */ - if ( strcasecmp ( name, efi_file_initrd.file.name ) == 0 ) - return efi_file_open_fixed ( &efi_file_initrd.file, new ); + if ( strcasecmp ( name, efi_file_initrd.file.name ) == 0 ) { + return efi_file_open_fixed ( &efi_file_initrd.file, wname, + new ); + } - DBGC ( file, "EFIFILE %s does not exist\n", name ); + DBGC ( file, "EFIFILE %ls does not exist\n", wname ); return EFI_NOT_FOUND; } @@ -832,7 +840,7 @@ efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused, EFI_FILE_PROTOCOL **file ) { DBGC ( &efi_file_root, "EFIFILE open volume\n" ); - return efi_file_open_fixed ( &efi_file_root, file ); + return efi_file_open_fixed ( &efi_file_root, L"", file ); } /** EFI simple file system protocol */ -- cgit v1.2.3-55-g7522 From f9beb20e99abbfcbea7cf222ba692aa3cbf10df7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 4 May 2023 14:21:42 +0100 Subject: [image] Allow for images to be hidden from lists of all images When invoking a kernel via the UEFI shim, the kernel (and potentially also a helper binary such as GRUB) must be accessible via the virtual filesystem exposed via EFI_SIMPLE_FILE_SYSTEM_PROTOCOL but must not be present in the magic initrd constructed from all registered images. Allow for images to be flagged as hidden, which will cause them to be excluded from API-level lists of all images such as the virtual filesystem directory contents, the magic initrd, or the Multiboot module list. Hidden images remain visible to iPXE commands including "imgstat", which will show a "[HIDDEN]" flag for such images. Signed-off-by: Michael Brown --- src/arch/x86/image/bzimage.c | 4 ++++ src/arch/x86/image/multiboot.c | 4 ++++ src/include/ipxe/image.h | 12 +++--------- src/interface/efi/efi_file.c | 36 ++++++++++++++++++++++++++---------- src/usr/imgmgmt.c | 2 ++ 5 files changed, 39 insertions(+), 19 deletions(-) (limited to 'src/interface/efi/efi_file.c') diff --git a/src/arch/x86/image/bzimage.c b/src/arch/x86/image/bzimage.c index b15bd5563..2c776147d 100644 --- a/src/arch/x86/image/bzimage.c +++ b/src/arch/x86/image/bzimage.c @@ -355,6 +355,10 @@ static size_t bzimage_load_initrd ( struct image *image, size_t offset; size_t pad_len; + /* Skip hidden images */ + if ( initrd->flags & IMAGE_HIDDEN ) + return 0; + /* Create cpio header for non-prebuilt images */ offset = cpio_header ( initrd, &cpio ); diff --git a/src/arch/x86/image/multiboot.c b/src/arch/x86/image/multiboot.c index c1c63bc97..cada021ab 100644 --- a/src/arch/x86/image/multiboot.c +++ b/src/arch/x86/image/multiboot.c @@ -204,6 +204,10 @@ static int multiboot_add_modules ( struct image *image, physaddr_t start, break; } + /* Skip hidden images */ + if ( module_image->flags & IMAGE_HIDDEN ) + continue; + /* Page-align the module */ start = ( ( start + 0xfff ) & ~0xfff ); diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index 9e0c0f22a..e00af82ef 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -72,6 +72,9 @@ struct image { /** Image will be automatically unregistered after execution */ #define IMAGE_AUTO_UNREGISTER 0x0008 +/** Image will be hidden from enumeration */ +#define IMAGE_HIDDEN 0x0010 + /** An executable image type */ struct image_type { /** Name of this image type */ @@ -161,15 +164,6 @@ extern struct image *current_image; #define for_each_image_safe( image, tmp ) \ list_for_each_entry_safe ( (image), (tmp), &images, list ) -/** - * Test for existence of images - * - * @ret existence Some images exist - */ -static inline int have_images ( void ) { - return ( ! list_empty ( &images ) ); -} - /** * Retrieve first image * diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c index fd0bcc6ce..673f902d5 100644 --- a/src/interface/efi/efi_file.c +++ b/src/interface/efi/efi_file.c @@ -250,6 +250,10 @@ static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) { len = 0; for_each_image ( image ) { + /* Skip hidden images */ + if ( image->flags & IMAGE_HIDDEN ) + continue; + /* Pad to alignment boundary */ pad_len = ( ( -reader->pos ) & ( INITRD_ALIGN - 1 ) ); if ( pad_len ) { @@ -524,13 +528,21 @@ static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len, /* Construct directory entries for image-backed files */ index = file->pos; for_each_image ( image ) { - if ( index-- == 0 ) { - efi_file_image ( &entry, image ); - efirc = efi_file_info ( &entry, len, data ); - if ( efirc == 0 ) - file->pos++; - return efirc; - } + + /* Skip hidden images */ + if ( image->flags & IMAGE_HIDDEN ) + continue; + + /* Skip preceding images */ + if ( index-- ) + continue; + + /* Construct directory entry */ + efi_file_image ( &entry, image ); + efirc = efi_file_info ( &entry, len, data ); + if ( efirc == 0 ) + file->pos++; + return efirc; } /* No more entries */ @@ -1093,6 +1105,7 @@ int efi_file_install ( EFI_HANDLE handle ) { EFI_DISK_IO_PROTOCOL *diskio; void *interface; } diskio; + struct image *image; EFI_STATUS efirc; int rc; @@ -1156,9 +1169,12 @@ int efi_file_install ( EFI_HANDLE handle ) { goto err_initrd_claim; /* Install Linux initrd fixed device path file if non-empty */ - if ( have_images() && - ( ( rc = efi_file_path_install ( &efi_file_initrd ) ) != 0 ) ) { - goto err_initrd_install; + for_each_image ( image ) { + if ( image->flags & IMAGE_HIDDEN ) + continue; + if ( ( rc = efi_file_path_install ( &efi_file_initrd ) ) != 0 ) + goto err_initrd_install; + break; } return 0; diff --git a/src/usr/imgmgmt.c b/src/usr/imgmgmt.c index b7fc8293d..94f3d2ce0 100644 --- a/src/usr/imgmgmt.c +++ b/src/usr/imgmgmt.c @@ -165,6 +165,8 @@ void imgstat ( struct image *image ) { printf ( " [SELECTED]" ); if ( image->flags & IMAGE_AUTO_UNREGISTER ) printf ( " [AUTOFREE]" ); + if ( image->flags & IMAGE_HIDDEN ) + printf ( " [HIDDEN]" ); if ( image->cmdline ) printf ( " \"%s\"", image->cmdline ); printf ( "\n" ); -- cgit v1.2.3-55-g7522 From 03eea19c19b52851002654c2818b765d4aa42894 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 5 May 2023 12:51:09 +0100 Subject: [efi] Allow currently selected image to be opened as "grub*.efi" Versions 15.4 and earlier of the UEFI shim are incapable of correctly parsing the command line in order to extract the second stage loader filename, and will always attempt to load "grubx64.efi" or equivalent. Versions 15.3 and later of the UEFI shim are currently incapable of loading a Linux kernel directly anyway, since the kernel does not include SBAT metadata. These versions will require a genuine shim-signed GRUB binary to be used as a crutch to assist shim in loading a Linux kernel. This leaves versions 15.2 and earlier of the UEFI shim (as currently used in e.g. RHEL7) as being capable of directly loading a Linux kernel, but incorrectly attempting to load it using the filename "grubx64.efi" or equivalent. To support the bugs in these older versions of the UEFI shim, allow the currently selected image to be opened via any filename of the form "grub*.efi". Signed-off-by: Michael Brown --- src/interface/efi/efi_file.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/interface/efi/efi_file.c') diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c index 673f902d5..266de4a6c 100644 --- a/src/interface/efi/efi_file.c +++ b/src/interface/efi/efi_file.c @@ -374,6 +374,7 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, char buf[ wcslen ( wname ) + 1 /* NUL */ ]; struct image *image; char *name; + char *sep; /* Convert name to ASCII */ snprintf ( buf, sizeof ( buf ), "%ls", wname ); @@ -413,6 +414,16 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, new ); } + /* Allow currently selected image to be opened as "grub*.efi", + * to work around buggy versions of the UEFI shim. + */ + if ( ( strncasecmp ( name, "grub", 4 ) == 0 ) && + ( ( sep = strrchr ( name, '.' ) ) != NULL ) && + ( strcasecmp ( sep, ".efi" ) == 0 ) && + ( ( image = image_find_selected() ) != NULL ) ) { + return efi_file_open_image ( image, wname, new ); + } + DBGC ( file, "EFIFILE %ls does not exist\n", wname ); return EFI_NOT_FOUND; } -- cgit v1.2.3-55-g7522 From c4a8d90387437425faec91bdee42a254944bab76 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 13 May 2023 20:27:58 +0100 Subject: [image] Generalise concept of selected image Most image flags are independent values: any combination of flags may be set for any image, and the flags for one image are independent of the flags for any other image. The "selected" flag does not follow this pattern: at most one image may be marked as selected at any time. When invoking a kernel via the UEFI shim, there will be multiple "special" images: the selected kernel itself, the shim image, and potentially a shim-signed GRUB binary to be used as a crutch to assist shim in loading the kernel (since current versions of the UEFI shim are not capable of directly loading a Linux kernel). Remove the "selected" image flag and replace it with a general concept of an image tag with the same semantics: a given tag may be assigned to at most one image, an image may be found by its tag only while the image is currently registered, and a tag will survive unregistration and reregistration of an image (if it has not already been assigned to a new image). For visual consistency, also replace the current image pointer with a current image tag. The image pointer stored within the image tag holds only a weak reference to the image, since the selection of an image should not prevent that image from being freed. (The strong reference to the currently executing image is held locally within the execution scope of image_exec(), and is logically separate from the current image pointer.) Signed-off-by: Michael Brown --- src/core/image.c | 69 +++++++++++++++++++++++--------------------- src/hci/commands/image_cmd.c | 2 +- src/image/script.c | 7 +++-- src/include/ipxe/image.h | 47 +++++++++++++++++++++++------- src/interface/efi/efi_file.c | 2 +- src/usr/imgmgmt.c | 8 +++-- 6 files changed, 85 insertions(+), 50 deletions(-) (limited to 'src/interface/efi/efi_file.c') diff --git a/src/core/image.c b/src/core/image.c index b280eb4d3..3e65b5edf 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -56,8 +56,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** List of registered images */ struct list_head images = LIST_HEAD_INIT ( images ); +/** Image selected for execution */ +struct image_tag selected_image __image_tag = { + .name = "SELECTED", +}; + /** Currently-executing image */ -struct image *current_image; +struct image_tag current_image __image_tag = { + .name = "CURRENT", +}; /** Current image trust requirement */ static int require_trusted_images = 0; @@ -72,8 +79,13 @@ static int require_trusted_images_permanent = 0; */ static void free_image ( struct refcnt *refcnt ) { struct image *image = container_of ( refcnt, struct image, refcnt ); + struct image_tag *tag; DBGC ( image, "IMAGE %s freed\n", image->name ); + for_each_table_entry ( tag, IMAGE_TAGS ) { + if ( tag->image == image ) + tag->image = NULL; + } free ( image->name ); free ( image->cmdline ); uri_put ( image->uri ); @@ -261,12 +273,6 @@ int register_image ( struct image *image ) { return rc; } - /* Avoid ending up with multiple "selected" images on - * re-registration - */ - if ( image_find_selected() ) - image->flags &= ~IMAGE_SELECTED; - /* Add to image list */ image_get ( image ); image->flags |= IMAGE_REGISTERED; @@ -320,6 +326,23 @@ struct image * find_image ( const char *name ) { return NULL; } +/** + * Find image by tag + * + * @v tag Image tag + * @ret image Executable image, or NULL + */ +struct image * find_image_tag ( struct image_tag *tag ) { + struct image *image; + + for_each_image ( image ) { + if ( tag->image == image ) + return image; + } + + return NULL; +} + /** * Execute image * @@ -346,13 +369,13 @@ int image_exec ( struct image *image ) { if ( image->uri ) churi ( image->uri ); - /* Preserve record of any currently-running image */ - saved_current_image = current_image; + /* Set as currently running image */ + saved_current_image = image_tag ( image, ¤t_image ); /* Take out a temporary reference to the image, so that it * does not get freed when temporarily unregistered. */ - current_image = image_get ( image ); + image_get ( image ); /* Check that this image can be executed */ if ( ! ( image->type && image->type->exec ) ) { @@ -419,7 +442,7 @@ int image_exec ( struct image *image ) { image_put ( image ); /* Restore previous currently-running image */ - current_image = saved_current_image; + image_tag ( saved_current_image, ¤t_image ); /* Reset current working directory */ churi ( old_cwuri ); @@ -442,7 +465,7 @@ int image_exec ( struct image *image ) { * registered until the currently-executing image returns. */ int image_replace ( struct image *replacement ) { - struct image *image = current_image; + struct image *image = current_image.image; int rc; /* Sanity check */ @@ -478,37 +501,17 @@ int image_replace ( struct image *replacement ) { * @ret rc Return status code */ int image_select ( struct image *image ) { - struct image *tmp; - - /* Unselect all other images */ - for_each_image ( tmp ) - tmp->flags &= ~IMAGE_SELECTED; /* Check that this image can be executed */ if ( ! ( image->type && image->type->exec ) ) return -ENOEXEC; /* Mark image as selected */ - image->flags |= IMAGE_SELECTED; + image_tag ( image, &selected_image ); return 0; } -/** - * Find selected image - * - * @ret image Executable image, or NULL - */ -struct image * image_find_selected ( void ) { - struct image *image; - - for_each_image ( image ) { - if ( image->flags & IMAGE_SELECTED ) - return image; - } - return NULL; -} - /** * Change image trust requirement * diff --git a/src/hci/commands/image_cmd.c b/src/hci/commands/image_cmd.c index 4a7c500a4..bf97b4deb 100644 --- a/src/hci/commands/image_cmd.c +++ b/src/hci/commands/image_cmd.c @@ -129,7 +129,7 @@ static int imgsingle_exec ( int argc, char **argv, &image ) ) != 0 ) goto err_acquire; } else { - image = image_find_selected(); + image = find_image_tag ( &selected_image ); if ( ! image ) { printf ( "No image selected\n" ); goto err_acquire; diff --git a/src/image/script.c b/src/image/script.c index b34df1e21..49b356403 100644 --- a/src/image/script.c +++ b/src/image/script.c @@ -311,6 +311,7 @@ static int terminate_on_label_found ( int rc ) { * @ret rc Return status code */ static int goto_exec ( int argc, char **argv ) { + struct image *image = current_image.image; struct goto_options opts; size_t saved_offset; int rc; @@ -320,7 +321,7 @@ static int goto_exec ( int argc, char **argv ) { return rc; /* Sanity check */ - if ( ! current_image ) { + if ( ! image ) { rc = -ENOTTY; printf ( "Not in a script: %s\n", strerror ( rc ) ); return rc; @@ -331,10 +332,10 @@ static int goto_exec ( int argc, char **argv ) { /* Find label */ saved_offset = script_offset; - if ( ( rc = process_script ( current_image, goto_find_label, + if ( ( rc = process_script ( image, goto_find_label, terminate_on_label_found ) ) != 0 ) { script_offset = saved_offset; - DBGC ( current_image, "[%04zx] No such label :%s\n", + DBGC ( image, "[%04zx] No such label :%s\n", script_offset, goto_label ); return rc; } diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index e00af82ef..cd51188d3 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -61,19 +61,16 @@ struct image { }; /** Image is registered */ -#define IMAGE_REGISTERED 0x00001 - -/** Image is selected for execution */ -#define IMAGE_SELECTED 0x0002 +#define IMAGE_REGISTERED 0x0001 /** Image is trusted */ -#define IMAGE_TRUSTED 0x0004 +#define IMAGE_TRUSTED 0x0002 /** Image will be automatically unregistered after execution */ -#define IMAGE_AUTO_UNREGISTER 0x0008 +#define IMAGE_AUTO_UNREGISTER 0x0004 /** Image will be hidden from enumeration */ -#define IMAGE_HIDDEN 0x0010 +#define IMAGE_HIDDEN 0x0008 /** An executable image type */ struct image_type { @@ -153,8 +150,23 @@ struct image_type { /** An executable image type */ #define __image_type( probe_order ) __table_entry ( IMAGE_TYPES, probe_order ) +/** An image tag */ +struct image_tag { + /** Name */ + const char *name; + /** Image (weak reference, nullified when image is freed) */ + struct image *image; +}; + +/** Image tag table */ +#define IMAGE_TAGS __table ( struct image_tag, "image_tags" ) + +/** An image tag */ +#define __image_tag __table_entry ( IMAGE_TAGS, 01 ) + extern struct list_head images; -extern struct image *current_image; +extern struct image_tag current_image; +extern struct image_tag selected_image; /** Iterate over all registered images */ #define for_each_image( image ) \ @@ -181,11 +193,11 @@ extern int image_set_len ( struct image *image, size_t len ); extern int image_set_data ( struct image *image, userptr_t data, size_t len ); extern int register_image ( struct image *image ); extern void unregister_image ( struct image *image ); -struct image * find_image ( const char *name ); +extern struct image * find_image ( const char *name ); +extern struct image * find_image_tag ( struct image_tag *tag ); extern int image_exec ( struct image *image ); extern int image_replace ( struct image *replacement ); extern int image_select ( struct image *image ); -extern struct image * image_find_selected ( void ); extern int image_set_trust ( int require_trusted, int permanent ); extern struct image * image_memory ( const char *name, userptr_t data, size_t len ); @@ -244,4 +256,19 @@ static inline void image_untrust ( struct image *image ) { image->flags &= ~IMAGE_TRUSTED; } +/** + * Tag image + * + * @v image Image + * @v tag Image tag + * @ret prev Previous tagged image (if any) + */ +static inline struct image * image_tag ( struct image *image, + struct image_tag *tag ) { + struct image *prev = tag->image; + + tag->image = image; + return prev; +} + #endif /* _IPXE_IMAGE_H */ diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c index 266de4a6c..2ae3a0cb4 100644 --- a/src/interface/efi/efi_file.c +++ b/src/interface/efi/efi_file.c @@ -420,7 +420,7 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, if ( ( strncasecmp ( name, "grub", 4 ) == 0 ) && ( ( sep = strrchr ( name, '.' ) ) != NULL ) && ( strcasecmp ( sep, ".efi" ) == 0 ) && - ( ( image = image_find_selected() ) != NULL ) ) { + ( ( image = find_image_tag ( &selected_image ) ) != NULL ) ) { return efi_file_open_image ( image, wname, new ); } diff --git a/src/usr/imgmgmt.c b/src/usr/imgmgmt.c index 94f3d2ce0..92bf236f9 100644 --- a/src/usr/imgmgmt.c +++ b/src/usr/imgmgmt.c @@ -156,13 +156,17 @@ int imgacquire ( const char *name_uri, unsigned long timeout, * @v image Executable/loadable image */ void imgstat ( struct image *image ) { + struct image_tag *tag; + printf ( "%s : %zd bytes", image->name, image->len ); if ( image->type ) printf ( " [%s]", image->type->name ); + for_each_table_entry ( tag, IMAGE_TAGS ) { + if ( tag->image == image ) + printf ( " [%s]", tag->name ); + } if ( image->flags & IMAGE_TRUSTED ) printf ( " [TRUSTED]" ); - if ( image->flags & IMAGE_SELECTED ) - printf ( " [SELECTED]" ); if ( image->flags & IMAGE_AUTO_UNREGISTER ) printf ( " [AUTOFREE]" ); if ( image->flags & IMAGE_HIDDEN ) -- cgit v1.2.3-55-g7522