diff options
-rw-r--r-- | src/hci/commands/shim_cmd.c | 13 | ||||
-rw-r--r-- | src/image/efi_image.c | 6 | ||||
-rw-r--r-- | src/include/ipxe/efi/efi_shim.h | 16 | ||||
-rw-r--r-- | src/include/usr/shimmgmt.h | 16 | ||||
-rw-r--r-- | src/interface/efi/efi_file.c | 63 | ||||
-rw-r--r-- | src/usr/shimmgmt.c | 85 |
6 files changed, 145 insertions, 54 deletions
diff --git a/src/hci/commands/shim_cmd.c b/src/hci/commands/shim_cmd.c index 4252fc7..1f29f4d 100644 --- a/src/hci/commands/shim_cmd.c +++ b/src/hci/commands/shim_cmd.c @@ -28,6 +28,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/parseopt.h> #include <ipxe/efi/efi_shim.h> #include <usr/imgmgmt.h> +#include <usr/shimmgmt.h> /** @file * @@ -85,20 +86,14 @@ static int shim_exec ( int argc, char **argv ) { goto err_acquire; } - /* Record second stage alternative name, if any */ - if ( image && ( rc = image_set_cmdline ( image, opts.altname ) ) != 0 ) - goto err_cmdline; - /* (Un)register as shim */ - efi_set_shim ( image ); - - /* Success */ - rc = 0; + if ( ( rc = shim ( image, opts.altname ) ) != 0 ) + goto err_shim; /* Unregister original image unless --keep was specified */ if ( image && ( ! opts.keep ) ) unregister_image ( image ); - err_cmdline: + err_shim: err_acquire: err_parse: return rc; diff --git a/src/image/efi_image.c b/src/image/efi_image.c index e1f4507..58de63d 100644 --- a/src/image/efi_image.c +++ b/src/image/efi_image.c @@ -172,10 +172,8 @@ static int efi_image_exec ( struct image *image ) { 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 ); + DBGC ( image, "EFIIMAGE %s (aka %s) executing via %s\n", + image->name, altname, shim->name ); } else { exec = image; prefix = NULL; diff --git a/src/include/ipxe/efi/efi_shim.h b/src/include/ipxe/efi/efi_shim.h index ef65599..d7abf5e 100644 --- a/src/include/ipxe/efi/efi_shim.h +++ b/src/include/ipxe/efi/efi_shim.h @@ -9,22 +9,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); -#include <ipxe/image.h> +struct image; extern struct image *efi_shim; -/** - * Set shim image - * - * @v image Shim image, or NULL to clear shim - */ -static inline void efi_set_shim ( struct image *image ) { - - /* Clear any existing shim */ - image_put ( efi_shim ); - - /* Record as shim */ - efi_shim = image_get ( image ); -} - #endif /* _IPXE_EFI_SHIM_H */ diff --git a/src/include/usr/shimmgmt.h b/src/include/usr/shimmgmt.h new file mode 100644 index 0000000..19f13e7 --- /dev/null +++ b/src/include/usr/shimmgmt.h @@ -0,0 +1,16 @@ +#ifndef _USR_SHIMMGMT_H +#define _USR_SHIMMGMT_H + +/** @file + * + * EFI shim management + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <ipxe/image.h> + +extern int shim ( struct image *image, const char *altname ); + +#endif /* _USR_SHIMMGMT_H */ diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c index 6fcc61e..b6bb842 100644 --- a/src/interface/efi/efi_file.c +++ b/src/interface/efi/efi_file.c @@ -322,6 +322,33 @@ static void efi_file_image ( struct efi_file *file, struct image *image ) { } /** + * Open dynamically allocated file + * + * @v image Image + * @v new New EFI file + * @ret efirc EFI status code + */ +static EFI_STATUS efi_file_open_dynamic ( 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 ) ); + *new = &file->file; + DBGC ( file, "EFIFILE %s opened\n", efi_file_name ( file ) ); + + return 0; +} + +/** * Open file * * @v this EFI file @@ -336,7 +363,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; @@ -368,6 +394,14 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, return EFI_WRITE_PROTECTED; } + /* Allow magic initrd to be opened */ + if ( strcasecmp ( name, efi_file_initrd.name ) == 0 ) + return efi_file_open_fixed ( &efi_file_initrd, name, new ); + + /* Allow registered images to be opened */ + if ( ( image = efi_file_find ( name ) ) != NULL ) + return efi_file_open_dynamic ( image, new ); + /* Allow magic second stage to be opened */ if ( ( efi_file_second.image != NULL ) && ( ( strcasecmp ( name, efi_file_second.image->name ) == 0 ) || @@ -376,31 +410,8 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, return efi_file_open_fixed ( &efi_file_second, name, new ); } - /* Allow magic initrd to be opened */ - if ( strcasecmp ( name, efi_file_initrd.name ) == 0 ) - return efi_file_open_fixed ( &efi_file_initrd, name, 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; } /** diff --git a/src/usr/shimmgmt.c b/src/usr/shimmgmt.c new file mode 100644 index 0000000..7c064bd --- /dev/null +++ b/src/usr/shimmgmt.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2023 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <string.h> +#include <strings.h> +#include <stdio.h> +#include <assert.h> +#include <ipxe/image.h> +#include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_shim.h> +#include <usr/shimmgmt.h> + +/** @file + * + * EFI shim management + * + */ + +/** + * Set shim image + * + * @v image Shim image, or NULL to clear shim + * @v altname Second stage alternative name, or NULL to use default + * @ret rc Return status code + */ +int shim ( struct image *image, const char *altname ) { + static wchar_t wbootpath[] = EFI_REMOVABLE_MEDIA_FILE_NAME; + char bootpath[ sizeof ( wbootpath ) / sizeof ( wbootpath[0] ) ]; + char *bootname; + char *sep; + int rc; + + /* Clear any existing shim */ + image_put ( efi_shim ); + efi_shim = NULL; + + /* Do nothing more unless a shim is specified */ + if ( ! image ) + return 0; + + /* Construct default second stage alternative name */ + snprintf ( bootpath, sizeof ( bootpath ), "%ls", wbootpath ); + sep = strrchr ( bootpath, '\\' ); + assert ( sep != NULL ); + bootname = ( sep + 1 ); + assert ( strncasecmp ( bootname, "BOOT", 4 ) == 0 ); + memcpy ( bootname, "GRUB", 4 ); + + /* Use default second stage alternative name, if not specified */ + if ( ! altname ) + altname = bootname; + + /* Record second stage alternative name, if any */ + if ( ( rc = image_set_cmdline ( image, altname ) ) != 0 ) + return rc; + + /* Record as shim */ + efi_shim = image_get ( image ); + + DBGC ( image, "SHIM %s installed (altname %s)\n", + image->name, image->cmdline ); + return 0; +} |