From 27fdb9557266eaaadfb39a2eddfb06d2aade9661 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 12 Nov 2011 00:34:55 +0000 Subject: [PATCH] [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 --- src/arch/i386/core/cmdline.c | 123 ------------- src/arch/i386/core/runtime.c | 249 +++++++++++++++++++++++++++ src/arch/i386/include/bits/errfile.h | 1 + src/arch/i386/prefix/lkrnprefix.S | 13 +- 4 files changed, 262 insertions(+), 124 deletions(-) delete mode 100644 src/arch/i386/core/cmdline.c create mode 100644 src/arch/i386/core/runtime.c diff --git a/src/arch/i386/core/cmdline.c b/src/arch/i386/core/cmdline.c deleted file mode 100644 index 595fdada..00000000 --- a/src/arch/i386/core/cmdline.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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 *boot_image; - char *boot_image_end; - 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 ( ( boot_image = strstr ( cmdline, "BOOT_IMAGE=" ) ) != NULL ) { - boot_image_end = strchr ( boot_image, ' ' ); - if ( boot_image_end ) { - *boot_image_end = '\0'; - DBGC ( image, "CMDLINE stripping \"%s\"\n", - boot_image ); - strcpy ( boot_image, ( boot_image_end + 1 ) ); - } else { - DBGC ( image, "CMDLINE stripping \"%s\"\n", - boot_image ); - *boot_image = '\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/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 . + * + * 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 +#include +#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 ) + +/** 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 = "", + .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, "" ); + + /* 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, +}; diff --git a/src/arch/i386/include/bits/errfile.h b/src/arch/i386/include/bits/errfile.h index 32b8a085..93f34f8d 100644 --- a/src/arch/i386/include/bits/errfile.h +++ b/src/arch/i386/include/bits/errfile.h @@ -15,6 +15,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_biosint ( ERRFILE_ARCH | ERRFILE_CORE | 0x00040000 ) #define ERRFILE_int13 ( ERRFILE_ARCH | ERRFILE_CORE | 0x00050000 ) #define ERRFILE_pxeparent ( ERRFILE_ARCH | ERRFILE_CORE | 0x00060000 ) +#define ERRFILE_runtime ( ERRFILE_ARCH | ERRFILE_CORE | 0x00070000 ) #define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 ) diff --git a/src/arch/i386/prefix/lkrnprefix.S b/src/arch/i386/prefix/lkrnprefix.S index 338ffa3d..bc1f8bfb 100644 --- a/src/arch/i386/prefix/lkrnprefix.S +++ b/src/arch/i386/prefix/lkrnprefix.S @@ -196,8 +196,15 @@ run_ipxe: /* Retrieve command-line pointer */ movl %es:cmd_line_ptr, %edx + /* Retrieve initrd pointer and size */ + movl %es:ramdisk_image, %ebp + movl %es:ramdisk_size, %ecx + /* Install iPXE */ - call install + call alloc_basemem + xorl %esi, %esi + xorl %edi, %edi + call install_prealloc /* Set up real-mode stack */ movw %bx, %ss @@ -215,6 +222,10 @@ run_ipxe: /* Store command-line pointer */ movl %edx, cmdline_phys + /* Store initrd pointer and size */ + movl %ebp, initrd_phys + movl %ecx, initrd_len + /* Run iPXE */ pushl $main pushw %cs