diff options
author | Michael Brown <mcb30@ipxe.org> | 2023-01-29 18:48:08 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2023-01-29 18:56:11 +0000 |
commit | 4bb521a8c4b324902651714915dfe6fd4a5c36af (patch) | |
tree | e27012b95f0c8a88648942a8e8f2c6fbc7a9b4a1 /src | |
parent | b9be454010ad261cebc336ce6a1a2e8ba418a686 (diff) | |
download | ipxe-4bb521a8c4b324902651714915dfe6fd4a5c36af.zip ipxe-4bb521a8c4b324902651714915dfe6fd4a5c36af.tar.gz ipxe-4bb521a8c4b324902651714915dfe6fd4a5c36af.tar.bz2 |
[efi] Accept a command line passed to an iPXE image via LoadOptionseficmdline
Treat a command line passed to iPXE via UEFI LoadOptions as an image
to be registered at startup, as is already done for the .lkrn, .pxe,
and .exe BIOS images.
Originally-implemented-by: Ladi Prosek <lprosek@redhat.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/include/ipxe/efi/efi_cmdline.h | 18 | ||||
-rw-r--r-- | src/include/ipxe/errfile.h | 1 | ||||
-rw-r--r-- | src/interface/efi/efi_cmdline.c | 151 | ||||
-rw-r--r-- | src/interface/efi/efi_init.c | 5 |
4 files changed, 175 insertions, 0 deletions
diff --git a/src/include/ipxe/efi/efi_cmdline.h b/src/include/ipxe/efi/efi_cmdline.h new file mode 100644 index 0000000..45abd54 --- /dev/null +++ b/src/include/ipxe/efi/efi_cmdline.h @@ -0,0 +1,18 @@ +#ifndef _IPXE_EFI_CMDLINE_H +#define _IPXE_EFI_CMDLINE_H + +/** @file + * + * EFI command line + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <stdint.h> +#include <wchar.h> + +extern const wchar_t *efi_cmdline; +extern size_t efi_cmdline_len; + +#endif /* _IPXE_EFI_CMDLINE_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index c3541e8..7c3b0c4 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -401,6 +401,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_dynkeymap ( ERRFILE_OTHER | 0x00580000 ) #define ERRFILE_pci_cmd ( ERRFILE_OTHER | 0x00590000 ) #define ERRFILE_dhe ( ERRFILE_OTHER | 0x005a0000 ) +#define ERRFILE_efi_cmdline ( ERRFILE_OTHER | 0x005b0000 ) /** @} */ diff --git a/src/interface/efi/efi_cmdline.c b/src/interface/efi/efi_cmdline.c new file mode 100644 index 0000000..b33bebd --- /dev/null +++ b/src/interface/efi/efi_cmdline.c @@ -0,0 +1,151 @@ +/* + * 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 ); + +/** @file + * + * EFI command line + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <ipxe/init.h> +#include <ipxe/image.h> +#include <ipxe/script.h> +#include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_cmdline.h> + +/** EFI command line (may not be wNUL-terminated */ +const wchar_t *efi_cmdline; + +/** Length of EFI command line (in bytes) */ +size_t efi_cmdline_len; + +/** Internal copy of the command line */ +static char *efi_cmdline_copy; + +/** + * Free command line image + * + * @v refcnt Reference count + */ +static void efi_cmdline_free ( struct refcnt *refcnt ) { + struct image *image = container_of ( refcnt, struct image, refcnt ); + + DBGC ( image, "CMDLINE freeing command line\n" ); + free ( efi_cmdline_copy ); +} + +/** Embedded script representing the command line */ +static struct image efi_cmdline_image = { + .refcnt = REF_INIT ( efi_cmdline_free ), + .name = "<CMDLINE>", + .type = &script_image_type, +}; + +/** Colour for debug messages */ +#define colour &efi_cmdline_image + +/** + * Initialise EFI command line + * + * @ret rc Return status code + */ +static int efi_cmdline_init ( void ) { + char *cmdline; + size_t len; + int rc; + + /* Do nothing if no command line was specified */ + if ( ! efi_cmdline_len ) { + DBGC ( colour, "CMDLINE found no command line\n" ); + return 0; + } + + /* Allocate ASCII copy of command line */ + len = ( ( efi_cmdline_len / sizeof ( efi_cmdline[0] ) ) + 1 /* NUL */ ); + efi_cmdline_copy = malloc ( len ); + if ( ! efi_cmdline_copy ) { + rc = -ENOMEM; + goto err_alloc; + } + cmdline = efi_cmdline_copy; + snprintf ( cmdline, len, "%ls", efi_cmdline ); + DBGC ( colour, "CMDLINE found command line \"%s\"\n", cmdline ); + + /* Mark command line as consumed */ + efi_cmdline_len = 0; + + /* Strip image name and surrounding whitespace */ + while ( isspace ( *cmdline ) ) + cmdline++; + while ( *cmdline && ( ! isspace ( *cmdline ) ) ) + cmdline++; + while ( isspace ( *cmdline ) ) + cmdline++; + DBGC ( colour, "CMDLINE using command line \"%s\"\n", cmdline ); + + /* Prepare and register image */ + efi_cmdline_image.data = virt_to_user ( cmdline ); + efi_cmdline_image.len = strlen ( cmdline ); + if ( efi_cmdline_image.len && + ( ( rc = register_image ( &efi_cmdline_image ) ) != 0 ) ) { + DBGC ( colour, "CMDLINE could not register command line: %s\n", + strerror ( rc ) ); + goto err_register_image; + } + + /* Drop our reference to the image */ + image_put ( &efi_cmdline_image ); + + return 0; + + err_register_image: + image_put ( &efi_cmdline_image ); + err_alloc: + return rc; +} + +/** + * EFI command line startup function + * + */ +static void efi_cmdline_startup ( void ) { + int rc; + + /* Initialise command line */ + if ( ( rc = efi_cmdline_init() ) != 0 ) { + /* No way to report failure */ + return; + } +} + +/** Command line and initrd initialisation function */ +struct startup_fn efi_cmdline_startup_fn __startup_fn ( STARTUP_NORMAL ) = { + .name = "efi_cmdline", + .startup = efi_cmdline_startup, +}; diff --git a/src/interface/efi/efi_init.c b/src/interface/efi/efi_init.c index 5d98f9f..d3c5042 100644 --- a/src/interface/efi/efi_init.c +++ b/src/interface/efi/efi_init.c @@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/efi/efi.h> #include <ipxe/efi/efi_driver.h> #include <ipxe/efi/efi_path.h> +#include <ipxe/efi/efi_cmdline.h> #include <ipxe/efi/Protocol/LoadedImage.h> /** Image handle passed to entry point */ @@ -254,6 +255,10 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, DBGC ( systab, "EFI image base address %p\n", efi_loaded_image->ImageBase ); + /* Record command line */ + efi_cmdline = efi_loaded_image->LoadOptions; + efi_cmdline_len = efi_loaded_image->LoadOptionsSize; + /* Get loaded image's device handle's device path */ if ( ( efirc = bs->OpenProtocol ( efi_loaded_image->DeviceHandle, &efi_device_path_protocol_guid, |