mirror of
https://gitlab.com/qemu-project/ipxe.git
synced 2025-10-30 07:56:50 +08:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4b7ad95261 | |||
| 99aad39037 | |||
| b123d32870 | |||
| 2aef08b7a5 |
@ -290,6 +290,9 @@ REQUIRE_OBJECT ( cert_cmd );
|
||||
#ifdef IMAGE_MEM_CMD
|
||||
REQUIRE_OBJECT ( image_mem_cmd );
|
||||
#endif
|
||||
#ifdef SHIM_CMD
|
||||
REQUIRE_OBJECT ( shim_cmd );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Drag in miscellaneous objects
|
||||
|
||||
@ -47,6 +47,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define USB_BLOCK /* USB block devices */
|
||||
|
||||
#define REBOOT_CMD /* Reboot command */
|
||||
#define SHIM_CMD /* EFI shim command */
|
||||
|
||||
#if defined ( __i386__ ) || defined ( __x86_64__ )
|
||||
#define IOAPI_X86
|
||||
|
||||
@ -160,6 +160,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
//#define CERT_CMD /* Certificate management commands */
|
||||
//#define IMAGE_MEM_CMD /* Read memory command */
|
||||
#define IMAGE_ARCHIVE_CMD /* Archive image management commands */
|
||||
//#define SHIM_CMD /* EFI shim command */
|
||||
|
||||
/*
|
||||
* ROM-specific options
|
||||
|
||||
108
src/hci/commands/shim_cmd.c
Normal file
108
src/hci/commands/shim_cmd.c
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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 <getopt.h>
|
||||
#include <ipxe/command.h>
|
||||
#include <ipxe/parseopt.h>
|
||||
#include <ipxe/efi/efi_shim.h>
|
||||
#include <usr/imgmgmt.h>
|
||||
#include <usr/shimmgmt.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* EFI shim command
|
||||
*
|
||||
*/
|
||||
|
||||
/** "shim" options */
|
||||
struct shim_options {
|
||||
/** Keep original image */
|
||||
int keep;
|
||||
/** Download timeout */
|
||||
unsigned long timeout;
|
||||
/** Second stage alternative name */
|
||||
char *altname;
|
||||
};
|
||||
|
||||
/** "shim" option list */
|
||||
static struct option_descriptor shim_opts[] = {
|
||||
OPTION_DESC ( "keep", 'k', no_argument,
|
||||
struct shim_options, keep, parse_flag ),
|
||||
OPTION_DESC ( "timeout", 't', required_argument,
|
||||
struct shim_options, timeout, parse_timeout ),
|
||||
OPTION_DESC ( "altname", 'a', required_argument,
|
||||
struct shim_options, altname, parse_string ),
|
||||
};
|
||||
|
||||
/** "shim" command descriptor */
|
||||
static struct command_descriptor shim_cmd =
|
||||
COMMAND_DESC ( struct shim_options, shim_opts, 0, 1, NULL );
|
||||
|
||||
/**
|
||||
* The "shim" command
|
||||
*
|
||||
* @v argc Argument count
|
||||
* @v argv Argument list
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int shim_exec ( int argc, char **argv ) {
|
||||
struct shim_options opts;
|
||||
struct image *image = NULL;
|
||||
char *name_uri = NULL;
|
||||
int rc;
|
||||
|
||||
/* Parse options */
|
||||
if ( ( rc = parse_options ( argc, argv, &shim_cmd, &opts ) ) != 0 )
|
||||
goto err_parse;
|
||||
|
||||
/* Parse name/URI string */
|
||||
name_uri = argv[optind];
|
||||
|
||||
/* Acquire image, if applicable */
|
||||
if ( name_uri &&
|
||||
( rc = imgacquire ( name_uri, opts.timeout, &image ) ) != 0 ) {
|
||||
goto err_acquire;
|
||||
}
|
||||
|
||||
/* (Un)register as shim */
|
||||
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_shim:
|
||||
err_acquire:
|
||||
err_parse:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** Shim commands */
|
||||
struct command shim_commands[] __command = {
|
||||
{
|
||||
.name = "shim",
|
||||
.exec = shim_exec,
|
||||
},
|
||||
};
|
||||
@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <ipxe/efi/efi_wrap.h>
|
||||
#include <ipxe/efi/efi_pxe.h>
|
||||
#include <ipxe/efi/efi_driver.h>
|
||||
#include <ipxe/efi/efi_shim.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/features.h>
|
||||
@ -55,6 +56,9 @@ FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
|
||||
"Could not start image" )
|
||||
#define EEFI_START( efirc ) EPLATFORM ( EINFO_EEFI_START, efirc )
|
||||
|
||||
/** Registered shim, if any */
|
||||
struct image *efi_shim;
|
||||
|
||||
/**
|
||||
* Create device path for image
|
||||
*
|
||||
@ -104,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 : "" ) );
|
||||
@ -132,12 +142,16 @@ static wchar_t * efi_image_cmdline ( struct image *image ) {
|
||||
*/
|
||||
static int efi_image_exec ( struct image *image ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
struct image *shim = efi_shim;
|
||||
struct efi_snp_device *snpdev;
|
||||
EFI_DEVICE_PATH_PROTOCOL *path;
|
||||
union {
|
||||
EFI_LOADED_IMAGE_PROTOCOL *image;
|
||||
void *interface;
|
||||
} loaded;
|
||||
struct image *exec;
|
||||
const char *prefix;
|
||||
const char *altname;
|
||||
EFI_HANDLE handle;
|
||||
EFI_MEMORY_TYPE type;
|
||||
wchar_t *cmdline;
|
||||
@ -153,15 +167,29 @@ 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 (aka %s) executing via %s\n",
|
||||
image->name, 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;
|
||||
}
|
||||
|
||||
/* Install PXE base code protocol */
|
||||
if ( ( rc = efi_pxe_install ( snpdev->handle, snpdev->netdev ) ) != 0 ){
|
||||
/* Install PXE base code protocol (unless using a shim) */
|
||||
if ( ( ! shim ) &&
|
||||
( rc = efi_pxe_install ( snpdev->handle, snpdev->netdev ) ) != 0 ){
|
||||
DBGC ( image, "EFIIMAGE %s could not install PXE protocol: "
|
||||
"%s\n", image->name, strerror ( rc ) );
|
||||
goto err_pxe_install;
|
||||
@ -175,7 +203,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 );
|
||||
@ -184,7 +212,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 );
|
||||
@ -195,8 +223,8 @@ static int efi_image_exec ( struct image *image ) {
|
||||
/* Attempt loading image */
|
||||
handle = NULL;
|
||||
if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, path,
|
||||
user_to_virt ( image->data, 0 ),
|
||||
image->len, &handle ) ) != 0 ) {
|
||||
user_to_virt ( exec->data, 0 ),
|
||||
exec->len, &handle ) ) != 0 ) {
|
||||
/* Not an EFI image */
|
||||
rc = -EEFI_LOAD ( efirc );
|
||||
DBGC ( image, "EFIIMAGE %s could not load: %s\n",
|
||||
@ -292,7 +320,8 @@ static int efi_image_exec ( struct image *image ) {
|
||||
err_image_path:
|
||||
efi_download_uninstall ( snpdev->handle );
|
||||
err_download_install:
|
||||
efi_pxe_uninstall ( snpdev->handle );
|
||||
if ( ! shim )
|
||||
efi_pxe_uninstall ( snpdev->handle );
|
||||
err_pxe_install:
|
||||
efi_file_uninstall ( snpdev->handle );
|
||||
err_file_install:
|
||||
|
||||
@ -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 */
|
||||
|
||||
16
src/include/ipxe/efi/efi_shim.h
Normal file
16
src/include/ipxe/efi/efi_shim.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef _IPXE_EFI_SHIM_H
|
||||
#define _IPXE_EFI_SHIM_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* EFI shim
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
struct image;
|
||||
|
||||
extern struct image *efi_shim;
|
||||
|
||||
#endif /* _IPXE_EFI_SHIM_H */
|
||||
16
src/include/usr/shimmgmt.h
Normal file
16
src/include/usr/shimmgmt.h
Normal file
@ -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 */
|
||||
@ -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->image != NULL ) {
|
||||
return file->image->name;
|
||||
} else if ( file->name != NULL ) {
|
||||
return file->name;
|
||||
} else {
|
||||
return "<UNKNOWN>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -281,10 +290,11 @@ 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,
|
||||
static EFI_STATUS efi_file_open_fixed ( struct efi_file *file, const char *name,
|
||||
EFI_FILE_PROTOCOL **new ) {
|
||||
|
||||
/* Increment reference count */
|
||||
@ -293,7 +303,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 %s\n",
|
||||
efi_file_name ( file ), name );
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -310,6 +321,33 @@ static void efi_file_image ( struct efi_file *file, struct image *image ) {
|
||||
file->read = efi_file_read_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
|
||||
*
|
||||
@ -325,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;
|
||||
|
||||
@ -341,7 +378,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, name, new );
|
||||
|
||||
/* Fail unless opening from the root */
|
||||
if ( file != &efi_file_root ) {
|
||||
@ -359,29 +396,22 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
|
||||
|
||||
/* Allow magic initrd to be opened */
|
||||
if ( strcasecmp ( name, efi_file_initrd.name ) == 0 )
|
||||
return efi_file_open_fixed ( &efi_file_initrd, new );
|
||||
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;
|
||||
/* 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 ) ||
|
||||
( ( efi_file_second.name != NULL ) &&
|
||||
( strcasecmp ( name, efi_file_second.name ) == 0 ) ) ) ) {
|
||||
return efi_file_open_fixed ( &efi_file_second, name, new );
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -752,6 +782,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 ),
|
||||
@ -808,7 +862,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, "volume", file );
|
||||
}
|
||||
|
||||
/** EFI simple file system protocol */
|
||||
@ -1012,9 +1066,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 +1136,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 +1160,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 +1191,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 );
|
||||
|
||||
85
src/usr/shimmgmt.c
Normal file
85
src/usr/shimmgmt.c
Normal file
@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user