From b2332d511807b87bd71cf73acaaf48e671d71c9d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 7 Mar 2011 22:02:07 +0000 Subject: [PATCH] [prefix] Allow iPXE's own command line to be executed as a script Some prefixes (e.g. .lkrn) allow a command line to be passed in to iPXE. At present, this command line is ignored. If a command line is provided, treat it as an embedded script (without an explicit "#!ipxe" magic marker). This allows for patterns of invocation such as title iPXE kernel /boot/ipxe.lkrn dhcp && \ sanboot iscsi:10.0.4.1::::iqn.2010-04.org.ipxe.dolphin:storage Here GRUB is instructed to load ipxe.lkrn with an embedded script equivalent to #!ipxe dhcp sanboot iscsi:10.0.4.1::::iqn.2010-04.org.ipxe.dolphin:storage This can be used to effectively vary the embedded script without having to rebuild ipxe.lkrn. Originally-implemented-by: Dave Hansen Signed-off-by: Michael Brown --- src/arch/i386/core/cmdline.c | 113 ++++++++++++++++++++++++++++++ src/arch/i386/prefix/lkrnprefix.S | 10 +++ src/image/embedded.c | 2 +- src/image/script.c | 1 + src/include/ipxe/init.h | 1 + src/include/ipxe/script.h | 16 +++++ 6 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 src/arch/i386/core/cmdline.c create mode 100644 src/include/ipxe/script.h diff --git a/src/arch/i386/core/cmdline.c b/src/arch/i386/core/cmdline.c new file mode 100644 index 00000000..fa5adb8c --- /dev/null +++ b/src/arch/i386/core/cmdline.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2011 Michael Brown . + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Command line passed to iPXE + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** Command line physical address + * + * This can be set by the prefix. + */ +uint32_t __bss16 ( cmdline_phys ); +#define cmdline_phys __use_data16 ( cmdline_phys ) + +/** 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, "CMDLINE 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 = "", + .type = &script_image_type, +}; + +/** + * Initialise command line + * + */ +static void cmdline_init ( void ) { + struct image *image = &cmdline_image; + userptr_t cmdline_user; + char *cmdline; + char *tmp; + size_t len; + + /* Do nothing if no command line was specified */ + if ( ! cmdline_phys ) { + DBGC ( image, "CMDLINE found no command line\n" ); + return; + } + cmdline_user = phys_to_user ( cmdline_phys ); + len = ( strlen_user ( cmdline_user, 0 ) + 1 /* NUL */ ); + + /* Allocate and copy command line */ + cmdline_copy = malloc ( len ); + if ( ! cmdline_copy ) { + DBGC ( image, "CMDLINE could not allocate %zd bytes\n", len ); + /* No way to indicate failure */ + return; + } + cmdline = cmdline_copy; + copy_from_user ( cmdline, cmdline_user, 0, len ); + DBGC ( image, "CMDLINE found \"%s\"\n", cmdline ); + + /* Check for unwanted cruft in the command line */ + while ( isspace ( *cmdline ) ) + cmdline++; + if ( ( tmp = strstr ( cmdline, "BOOT_IMAGE=" ) ) != NULL ) { + DBGC ( image, "CMDLINE stripping \"%s\"\n", tmp ); + *tmp = '\0'; + } + DBGC ( image, "CMDLINE using \"%s\"\n", cmdline ); + + /* Prepare and register image */ + cmdline_image.data = virt_to_user ( cmdline ); + cmdline_image.len = strlen ( cmdline ); + if ( cmdline_image.len ) + register_image ( &cmdline_image ); + + /* Drop our reference to the image */ + image_put ( &cmdline_image ); +} + +/** Command line initialisation function */ +struct init_fn cmdline_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = cmdline_init, +}; diff --git a/src/arch/i386/prefix/lkrnprefix.S b/src/arch/i386/prefix/lkrnprefix.S index 008c79ef..f87ef85a 100644 --- a/src/arch/i386/prefix/lkrnprefix.S +++ b/src/arch/i386/prefix/lkrnprefix.S @@ -193,6 +193,9 @@ run_ipxe: movw %ax, %ss movw $0x7c00, %sp + /* Retrieve command-line pointer */ + movl %es:cmd_line_ptr, %edx + /* Install iPXE */ call install @@ -206,6 +209,13 @@ run_ipxe: lret .section ".text16", "awx", @progbits 1: + /* Set up %ds for access to .data16 */ + movw %bx, %ds + + /* Store command-line pointer */ + movl %edx, cmdline_phys + + /* Run iPXE */ pushl $main pushw %cs call prot_call diff --git a/src/image/embedded.c b/src/image/embedded.c index 2ddccfed..6358378f 100644 --- a/src/image/embedded.c +++ b/src/image/embedded.c @@ -86,6 +86,6 @@ static void embedded_init ( void ) { } /** Embedded image initialisation function */ -struct init_fn embedded_init_fn __init_fn ( INIT_NORMAL ) = { +struct init_fn embedded_init_fn __init_fn ( INIT_LATE ) = { .initialise = embedded_init, }; diff --git a/src/image/script.c b/src/image/script.c index b819693d..572eac71 100644 --- a/src/image/script.c +++ b/src/image/script.c @@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include /** Currently running script * diff --git a/src/include/ipxe/init.h b/src/include/ipxe/init.h index 954cda45..19c5925b 100644 --- a/src/include/ipxe/init.h +++ b/src/include/ipxe/init.h @@ -29,6 +29,7 @@ struct init_fn { #define INIT_SERIAL 02 /**< Serial driver initialisation */ #define INIT_CONSOLE 03 /**< Console initialisation */ #define INIT_NORMAL 04 /**< Normal initialisation */ +#define INIT_LATE 05 /**< Late initialisation */ /** @} */ diff --git a/src/include/ipxe/script.h b/src/include/ipxe/script.h new file mode 100644 index 00000000..33420dae --- /dev/null +++ b/src/include/ipxe/script.h @@ -0,0 +1,16 @@ +#ifndef _IPXE_SCRIPT_H +#define _IPXE_SCRIPT_H + +/** @file + * + * iPXE scripts + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +extern struct image_type script_image_type __image_type ( PROBE_NORMAL ); + +#endif /* _IPXE_SCRIPT_H */