diff options
author | Michael Brown | 2011-11-12 01:34:55 +0100 |
---|---|---|
committer | Michael Brown | 2011-11-12 01:34:55 +0100 |
commit | 27fdb9557266eaaadfb39a2eddfb06d2aade9661 (patch) | |
tree | cd90e9c4d37f79bea7728c4c0c57f425eb3ef2c3 /src/arch/i386/core/runtime.c | |
parent | [prefix] Allow prefix to specify an arbitrary maximum address for relocation (diff) | |
download | ipxe-27fdb9557266eaaadfb39a2eddfb06d2aade9661.tar.gz ipxe-27fdb9557266eaaadfb39a2eddfb06d2aade9661.tar.xz ipxe-27fdb9557266eaaadfb39a2eddfb06d2aade9661.zip |
[prefix] Allow an initrd to be passed to iPXE
Allow an initrd (such as an embedded script) to be passed to iPXE when
loaded as a .lkrn (or .iso) image. This allows an embedded script to
be varied without recompiling iPXE.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/arch/i386/core/runtime.c')
-rw-r--r-- | src/arch/i386/core/runtime.c | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/src/arch/i386/core/runtime.c b/src/arch/i386/core/runtime.c new file mode 100644 index 00000000..09ba6256 --- /dev/null +++ b/src/arch/i386/core/runtime.c @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2011 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Command line and initrd passed to iPXE at runtime + * + */ + +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <errno.h> +#include <assert.h> +#include <ipxe/init.h> +#include <ipxe/image.h> +#include <ipxe/script.h> +#include <ipxe/umalloc.h> +#include <realmode.h> + +/** Command line physical address + * + * This can be set by the prefix. + */ +uint32_t __bss16 ( cmdline_phys ); +#define cmdline_phys __use_data16 ( cmdline_phys ) + +/** initrd physical address + * + * This can be set by the prefix. + */ +uint32_t __bss16 ( initrd_phys ); +#define initrd_phys __use_data16 ( initrd_phys ) + +/** initrd length + * + * This can be set by the prefix. + */ +uint32_t __bss16 ( initrd_len ); +#define initrd_len __use_data16 ( initrd_len ) + +/** 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, "RUNTIME 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, +}; + +/** Colour for debug messages */ +#define colour &cmdline_image + +/** + * Strip unwanted cruft from command line + * + * @v cmdline Command line + * @v cruft Initial substring of cruft to strip + */ +static void cmdline_strip ( char *cmdline, const char *cruft ) { + char *strip; + char *strip_end; + + /* Find unwanted cruft, if present */ + if ( ! ( strip = strstr ( cmdline, cruft ) ) ) + return; + + /* Strip unwanted cruft */ + strip_end = strchr ( strip, ' ' ); + if ( strip_end ) { + *strip_end = '\0'; + DBGC ( colour, "RUNTIME stripping \"%s\"\n", strip ); + strcpy ( strip, ( strip_end + 1 ) ); + } else { + DBGC ( colour, "RUNTIME stripping \"%s\"\n", strip ); + *strip = '\0'; + } +} + +/** + * Initialise command line + * + * @ret rc Return status code + */ +static int cmdline_init ( void ) { + userptr_t cmdline_user; + char *cmdline; + size_t len; + int rc; + + /* Do nothing if no command line was specified */ + if ( ! cmdline_phys ) { + DBGC ( colour, "RUNTIME found no command line\n" ); + return 0; + } + 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 ( colour, "RUNTIME could not allocate %zd bytes for " + "command line\n", len ); + rc = -ENOMEM; + goto err_alloc_cmdline_copy; + } + cmdline = cmdline_copy; + copy_from_user ( cmdline, cmdline_user, 0, len ); + DBGC ( colour, "RUNTIME found command line \"%s\"\n", cmdline ); + + /* Strip unwanted cruft from the command line */ + cmdline_strip ( cmdline, "BOOT_IMAGE=" ); + cmdline_strip ( cmdline, "initrd=" ); + while ( isspace ( *cmdline ) ) + cmdline++; + DBGC ( colour, "RUNTIME using command line \"%s\"\n", cmdline ); + + /* Prepare and register image */ + cmdline_image.data = virt_to_user ( cmdline ); + cmdline_image.len = strlen ( cmdline ); + if ( cmdline_image.len ) { + if ( ( rc = register_image ( &cmdline_image ) ) != 0 ) { + DBGC ( colour, "RUNTIME 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; +} + +/** + * Initialise initrd + * + * @ret rc Return status code + */ +static int initrd_init ( void ) { + struct image *image; + int rc; + + /* Do nothing if no initrd was specified */ + if ( ! initrd_phys ) { + DBGC ( colour, "RUNTIME found no initrd\n" ); + return 0; + } + if ( ! initrd_len ) { + DBGC ( colour, "RUNTIME found empty initrd\n" ); + return 0; + } + DBGC ( colour, "RUNTIME found initrd at [%x,%x)\n", + initrd_phys, ( initrd_phys + initrd_len ) ); + + /* Allocate image */ + image = alloc_image(); + if ( ! image ) { + DBGC ( colour, "RUNTIME could not allocate image for " + "initrd\n" ); + goto err_alloc_image; + } + image_set_name ( image, "<INITRD>" ); + + /* Allocate and copy initrd content */ + image->data = umalloc ( initrd_len ); + if ( ! image->data ) { + DBGC ( colour, "RUNTIME could not allocate %zd bytes for " + "initrd\n", initrd_len ); + goto err_umalloc; + } + image->len = initrd_len; + memcpy_user ( image->data, 0, phys_to_user ( initrd_phys ), 0, + initrd_len ); + + /* Register image */ + if ( ( rc = register_image ( image ) ) != 0 ) { + DBGC ( colour, "RUNTIME could not register initrd: %s\n", + strerror ( rc ) ); + goto err_register_image; + } + + /* Drop our reference to the image */ + image_put ( image ); + + return 0; + + err_register_image: + err_umalloc: + image_put ( image ); + err_alloc_image: + return rc; +} + +/** + * Initialise command line and initrd + * + */ +static void runtime_init ( void ) { + int rc; + + /* Initialise command line */ + if ( ( rc = cmdline_init() ) != 0 ) { + /* No way to report failure */ + return; + } + + /* Initialise initrd */ + if ( ( rc = initrd_init() ) != 0 ) { + /* No way to report failure */ + return; + } +} + +/** Command line and initrd initialisation function */ +struct init_fn runtime_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = runtime_init, +}; |