iPXE
runtime.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2011 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 /** @file
00027  *
00028  * Command line and initrd passed to iPXE at runtime
00029  *
00030  */
00031 
00032 #include <stddef.h>
00033 #include <stdint.h>
00034 #include <stdlib.h>
00035 #include <ctype.h>
00036 #include <errno.h>
00037 #include <assert.h>
00038 #include <ipxe/init.h>
00039 #include <ipxe/image.h>
00040 #include <ipxe/script.h>
00041 #include <ipxe/umalloc.h>
00042 #include <realmode.h>
00043 
00044 /** Command line physical address
00045  *
00046  * This can be set by the prefix.
00047  */
00048 uint32_t __bss16 ( cmdline_phys );
00049 #define cmdline_phys __use_data16 ( cmdline_phys )
00050 
00051 /** initrd physical address
00052  *
00053  * This can be set by the prefix.
00054  */
00055 uint32_t __bss16 ( initrd_phys );
00056 #define initrd_phys __use_data16 ( initrd_phys )
00057 
00058 /** initrd length
00059  *
00060  * This can be set by the prefix.
00061  */
00062 uint32_t __bss16 ( initrd_len );
00063 #define initrd_len __use_data16 ( initrd_len )
00064 
00065 /** Internal copy of the command line */
00066 static char *cmdline_copy;
00067 
00068 /** Free command line image */
00069 static void cmdline_image_free ( struct refcnt *refcnt ) {
00070         struct image *image = container_of ( refcnt, struct image, refcnt );
00071 
00072         DBGC ( image, "RUNTIME freeing command line\n" );
00073         free ( cmdline_copy );
00074 }
00075 
00076 /** Embedded script representing the command line */
00077 static struct image cmdline_image = {
00078         .refcnt = REF_INIT ( cmdline_image_free ),
00079         .name = "<CMDLINE>",
00080         .type = &script_image_type,
00081 };
00082 
00083 /** Colour for debug messages */
00084 #define colour &cmdline_image
00085 
00086 /**
00087  * Strip unwanted cruft from command line
00088  *
00089  * @v cmdline           Command line
00090  * @v cruft             Initial substring of cruft to strip
00091  */
00092 static void cmdline_strip ( char *cmdline, const char *cruft ) {
00093         char *strip;
00094         char *strip_end;
00095 
00096         /* Find unwanted cruft, if present */
00097         if ( ! ( strip = strstr ( cmdline, cruft ) ) )
00098                 return;
00099 
00100         /* Strip unwanted cruft */
00101         strip_end = strchr ( strip, ' ' );
00102         if ( strip_end ) {
00103                 *strip_end = '\0';
00104                 DBGC ( colour, "RUNTIME stripping \"%s\"\n", strip );
00105                 strcpy ( strip, ( strip_end + 1 ) );
00106         } else {
00107                 DBGC ( colour, "RUNTIME stripping \"%s\"\n", strip );
00108                 *strip = '\0';
00109         }
00110 }
00111 
00112 /**
00113  * Initialise command line
00114  *
00115  * @ret rc              Return status code
00116  */
00117 static int cmdline_init ( void ) {
00118         userptr_t cmdline_user;
00119         char *cmdline;
00120         size_t len;
00121         int rc;
00122 
00123         /* Do nothing if no command line was specified */
00124         if ( ! cmdline_phys ) {
00125                 DBGC ( colour, "RUNTIME found no command line\n" );
00126                 return 0;
00127         }
00128         cmdline_user = phys_to_user ( cmdline_phys );
00129         len = ( strlen_user ( cmdline_user, 0 ) + 1 /* NUL */ );
00130 
00131         /* Allocate and copy command line */
00132         cmdline_copy = malloc ( len );
00133         if ( ! cmdline_copy ) {
00134                 DBGC ( colour, "RUNTIME could not allocate %zd bytes for "
00135                        "command line\n", len );
00136                 rc = -ENOMEM;
00137                 goto err_alloc_cmdline_copy;
00138         }
00139         cmdline = cmdline_copy;
00140         copy_from_user ( cmdline, cmdline_user, 0, len );
00141         DBGC ( colour, "RUNTIME found command line \"%s\" at %08x\n",
00142                cmdline, cmdline_phys );
00143 
00144         /* Mark command line as consumed */
00145         cmdline_phys = 0;
00146 
00147         /* Strip unwanted cruft from the command line */
00148         cmdline_strip ( cmdline, "BOOT_IMAGE=" );
00149         cmdline_strip ( cmdline, "initrd=" );
00150         while ( isspace ( *cmdline ) )
00151                 cmdline++;
00152         DBGC ( colour, "RUNTIME using command line \"%s\"\n", cmdline );
00153 
00154         /* Prepare and register image */
00155         cmdline_image.data = virt_to_user ( cmdline );
00156         cmdline_image.len = strlen ( cmdline );
00157         if ( cmdline_image.len ) {
00158                 if ( ( rc = register_image ( &cmdline_image ) ) != 0 ) {
00159                         DBGC ( colour, "RUNTIME could not register command "
00160                                "line: %s\n", strerror ( rc ) );
00161                         goto err_register_image;
00162                 }
00163         }
00164 
00165         /* Drop our reference to the image */
00166         image_put ( &cmdline_image );
00167 
00168         return 0;
00169 
00170  err_register_image:
00171         image_put ( &cmdline_image );
00172  err_alloc_cmdline_copy:
00173         return rc;
00174 }
00175 
00176 /**
00177  * Initialise initrd
00178  *
00179  * @ret rc              Return status code
00180  */
00181 static int initrd_init ( void ) {
00182         struct image *image;
00183         int rc;
00184 
00185         /* Do nothing if no initrd was specified */
00186         if ( ! initrd_phys ) {
00187                 DBGC ( colour, "RUNTIME found no initrd\n" );
00188                 return 0;
00189         }
00190         if ( ! initrd_len ) {
00191                 DBGC ( colour, "RUNTIME found empty initrd\n" );
00192                 return 0;
00193         }
00194         DBGC ( colour, "RUNTIME found initrd at [%x,%x)\n",
00195                initrd_phys, ( initrd_phys + initrd_len ) );
00196 
00197         /* Allocate image */
00198         image = alloc_image ( NULL );
00199         if ( ! image ) {
00200                 DBGC ( colour, "RUNTIME could not allocate image for "
00201                        "initrd\n" );
00202                 rc = -ENOMEM;
00203                 goto err_alloc_image;
00204         }
00205         if ( ( rc = image_set_name ( image, "<INITRD>" ) ) != 0 ) {
00206                 DBGC ( colour, "RUNTIME could not set image name: %s\n",
00207                        strerror ( rc ) );
00208                 goto err_set_name;
00209         }
00210 
00211         /* Allocate and copy initrd content */
00212         image->data = umalloc ( initrd_len );
00213         if ( ! image->data ) {
00214                 DBGC ( colour, "RUNTIME could not allocate %d bytes for "
00215                        "initrd\n", initrd_len );
00216                 rc = -ENOMEM;
00217                 goto err_umalloc;
00218         }
00219         image->len = initrd_len;
00220         memcpy_user ( image->data, 0, phys_to_user ( initrd_phys ), 0,
00221                       initrd_len );
00222 
00223         /* Mark initrd as consumed */
00224         initrd_phys = 0;
00225 
00226         /* Register image */
00227         if ( ( rc = register_image ( image ) ) != 0 ) {
00228                 DBGC ( colour, "RUNTIME could not register initrd: %s\n",
00229                        strerror ( rc ) );
00230                 goto err_register_image;
00231         }
00232 
00233         /* Drop our reference to the image */
00234         image_put ( image );
00235 
00236         return 0;
00237 
00238  err_register_image:
00239  err_umalloc:
00240  err_set_name:
00241         image_put ( image );
00242  err_alloc_image:
00243         return rc;
00244 }
00245 
00246 /**
00247  * Initialise command line and initrd
00248  *
00249  */
00250 static void runtime_init ( void ) {
00251         int rc;
00252 
00253         /* Initialise command line */
00254         if ( ( rc = cmdline_init() ) != 0 ) {
00255                 /* No way to report failure */
00256                 return;
00257         }
00258 
00259         /* Initialise initrd */
00260         if ( ( rc = initrd_init() ) != 0 ) {
00261                 /* No way to report failure */
00262                 return;
00263         }
00264 }
00265 
00266 /** Command line and initrd initialisation function */
00267 struct startup_fn runtime_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
00268         .startup = runtime_init,
00269 };