[ipxe-devel] [PATCH] [efi] Use EFI command line as script

Ladi Prosek lprosek at redhat.com
Fri Sep 8 13:00:29 BST 2017


Analogous to passing a script to ipxe.lkrn via kernel parameters, this
patch enables the same on EFI using the EFI command line, available in
the LoadOptions field of EFI_LOADED_IMAGE_PROTOCOL.

Signed-off-by: Ladi Prosek <lprosek at redhat.com>
---
 src/interface/efi/efi_init.c | 92 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/src/interface/efi/efi_init.c b/src/interface/efi/efi_init.c
index ed9707f..fb90816 100644
--- a/src/interface/efi/efi_init.c
+++ b/src/interface/efi/efi_init.c
@@ -21,7 +21,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <string.h>
 #include <errno.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <ctype.h>
 #include <ipxe/init.h>
+#include <ipxe/image.h>
+#include <ipxe/script.h>
 #include <ipxe/efi/efi.h>
 #include <ipxe/efi/efi_driver.h>
 #include <ipxe/efi/Protocol/LoadedImage.h>
@@ -240,3 +245,90 @@ static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
 
 	return 0;
 }
+
+/** Internal copy of the command line */
+static char *cmdline_copy;
+
+/** Free command line image */
+static void cmdline_image_free ( struct refcnt *refcnt ) {
+	struct image *image = container_of ( refcnt, struct image, refcnt );
+
+	DBGC ( image, "EFI freeing command line\n" );
+	free ( cmdline_copy );
+}
+
+/** Embedded script representing the command line */
+static struct image cmdline_image = {
+	.refcnt = REF_INIT ( cmdline_image_free ),
+	.name = "<CMDLINE>",
+	.type = &script_image_type,
+};
+
+static int efi_cmdline_init ( EFI_LOADED_IMAGE_PROTOCOL *image ) {
+	wchar_t *load_options;
+	char *cmdline;
+	unsigned i;
+	int rc;
+
+	/* Get command line */
+	if ( image->LoadOptionsSize ) {
+		load_options = ( wchar_t * ) image->LoadOptions;
+		cmdline_copy = malloc ( image->LoadOptionsSize + 1 );
+		if ( ! cmdline_copy ) {
+			DBGC ( image, "EFI could not allocate command line\n" );
+			rc = -ENOMEM;
+			goto err_alloc_cmdline_copy;
+		}
+
+		for ( i = 0 ; i < efi_loaded_image->LoadOptionsSize ; i++ ) {
+			wcrtomb ( cmdline_copy + i, load_options [ i ], NULL );
+		}
+		cmdline_copy[i] = 0;
+		cmdline = cmdline_copy;
+
+		/* Skip the first parameter (image name) */
+		while ( isspace ( *cmdline ) )
+			cmdline++;
+		while ( *cmdline && ! isspace ( *cmdline ) )
+			cmdline++;
+		while ( isspace ( *cmdline ) )
+			cmdline++;
+
+		cmdline_image.len = strlen ( cmdline );
+		cmdline_image.data = virt_to_user ( cmdline );
+
+		if ( cmdline_image.len ) {
+			DBGC ( image, "EFI got cmdline of length %zd\n",
+			       cmdline_image.len );
+
+			if ( ( rc = register_image ( &cmdline_image ) ) != 0 ) {
+				DBGC ( image, "EFI could not register command "
+				       "line: %s\n", strerror ( rc ) );
+				goto err_register_image;
+			}
+		}
+		/* Drop our reference to the image */
+		image_put ( &cmdline_image );
+	}
+
+	return 0;
+
+ err_register_image:
+	image_put ( &cmdline_image );
+ err_alloc_cmdline_copy:
+	return rc;
+}
+
+/**
+ * EFI initialization that cannot be done in efi_init (e.g. because it allocates).
+ */
+static void efi_startup ( void ) {
+	if ( efi_cmdline_init ( efi_loaded_image ) != 0 ) {
+		/* No way to report failure */
+		return;
+	}
+}
+
+struct startup_fn efi_runtime_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
+	.startup = efi_startup,
+};
-- 
2.9.3



More information about the ipxe-devel mailing list