2 * Copyright (C) 2011 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
28 * Command line and initrd passed to iPXE at runtime
38 #include <ipxe/init.h>
39 #include <ipxe/image.h>
40 #include <ipxe/script.h>
41 #include <ipxe/umalloc.h>
45 /** Command line physical address
47 * This can be set by the prefix.
49 uint32_t __bss16 ( cmdline_phys
);
50 #define cmdline_phys __use_data16 ( cmdline_phys )
52 /** initrd physical address
54 * This can be set by the prefix.
56 uint32_t __bss16 ( initrd_phys
);
57 #define initrd_phys __use_data16 ( initrd_phys )
61 * This can be set by the prefix.
63 uint32_t __bss16 ( initrd_len
);
64 #define initrd_len __use_data16 ( initrd_len )
66 /** Internal copy of the command line */
67 static char *cmdline_copy
;
69 /** Free command line image */
70 static void cmdline_image_free ( struct refcnt
*refcnt
) {
71 struct image
*image
= container_of ( refcnt
, struct image
, refcnt
);
73 DBGC ( image
, "RUNTIME freeing command line\n" );
74 free ( cmdline_copy
);
77 /** Embedded script representing the command line */
78 static struct image cmdline_image
= {
79 .refcnt
= REF_INIT ( cmdline_image_free
),
81 .type
= &script_image_type
,
84 /** Colour for debug messages */
85 #define colour &cmdline_image
88 * Strip unwanted cruft from command line
90 * @v cmdline Command line
91 * @v cruft Initial substring of cruft to strip
93 static void cmdline_strip ( char *cmdline
, const char *cruft
) {
97 /* Find unwanted cruft, if present */
98 if ( ! ( strip
= strstr ( cmdline
, cruft
) ) )
101 /* Strip unwanted cruft */
102 strip_end
= strchr ( strip
, ' ' );
105 DBGC ( colour
, "RUNTIME stripping \"%s\"\n", strip
);
106 strcpy ( strip
, ( strip_end
+ 1 ) );
108 DBGC ( colour
, "RUNTIME stripping \"%s\"\n", strip
);
114 * Initialise command line
116 * @ret rc Return status code
118 static int cmdline_init ( void ) {
119 userptr_t cmdline_user
;
128 /* Do nothing if no command line was specified */
129 if ( ! cmdline_phys
) {
130 DBGC ( colour
, "RUNTIME found no command line\n" );
133 cmdline_user
= phys_to_user ( cmdline_phys
);
134 len
= ( strlen_user ( cmdline_user
, 0 ) + 1 /* NUL */ );
136 pos1
= strstr((char *)cmdline_user
, "mem:");
139 pos2
= strstr(pos1
, ":size:");
143 chainaddr
= phys_to_user(strtoul(pos1
+ 4 + 2, NULL
, 16)); // skip 0x prefix in hex number
144 chainlen
= (int)strtoul(pos2
+ 6, NULL
, 10);
147 g_initrd_addr
= (void *)umalloc(chainlen
);
148 g_initrd_len
= chainlen
;
149 memcpy_user((userptr_t
)g_initrd_addr
, 0, chainaddr
, 0, chainlen
);
153 /* Allocate and copy command line */
154 cmdline_copy
= malloc ( len
);
155 if ( ! cmdline_copy
) {
156 DBGC ( colour
, "RUNTIME could not allocate %zd bytes for "
157 "command line\n", len
);
159 goto err_alloc_cmdline_copy
;
162 g_cmdline_copy
= cmdline_copy
;
164 cmdline
= cmdline_copy
;
165 copy_from_user ( cmdline
, cmdline_user
, 0, len
);
166 DBGC ( colour
, "RUNTIME found command line \"%s\" at %08x\n",
167 cmdline
, cmdline_phys
);
169 /* Mark command line as consumed */
172 /* Strip unwanted cruft from the command line */
173 cmdline_strip ( cmdline
, "BOOT_IMAGE=" );
174 cmdline_strip ( cmdline
, "initrd=" );
175 while ( isspace ( *cmdline
) )
177 DBGC ( colour
, "RUNTIME using command line \"%s\"\n", cmdline
);
179 /* Prepare and register image */
180 cmdline_image
.data
= virt_to_user ( cmdline
);
181 cmdline_image
.len
= strlen ( cmdline
);
182 if ( cmdline_image
.len
) {
183 if ( ( rc
= register_image ( &cmdline_image
) ) != 0 ) {
184 DBGC ( colour
, "RUNTIME could not register command "
185 "line: %s\n", strerror ( rc
) );
186 goto err_register_image
;
190 /* Drop our reference to the image */
191 image_put ( &cmdline_image
);
196 image_put ( &cmdline_image
);
197 err_alloc_cmdline_copy
:
204 * @ret rc Return status code
206 static int initrd_init ( void ) {
210 /* Do nothing if no initrd was specified */
211 if ( ! initrd_phys
) {
212 DBGC ( colour
, "RUNTIME found no initrd\n" );
215 if ( ! initrd_len
) {
216 DBGC ( colour
, "RUNTIME found empty initrd\n" );
219 DBGC ( colour
, "RUNTIME found initrd at [%x,%x)\n",
220 initrd_phys
, ( initrd_phys
+ initrd_len
) );
223 image
= alloc_image ( NULL
);
225 DBGC ( colour
, "RUNTIME could not allocate image for "
228 goto err_alloc_image
;
230 if ( ( rc
= image_set_name ( image
, "<INITRD>" ) ) != 0 ) {
231 DBGC ( colour
, "RUNTIME could not set image name: %s\n",
236 /* Allocate and copy initrd content */
237 image
->data
= umalloc ( initrd_len
);
238 if ( ! image
->data
) {
239 DBGC ( colour
, "RUNTIME could not allocate %d bytes for "
240 "initrd\n", initrd_len
);
244 image
->len
= initrd_len
;
245 memcpy_user ( image
->data
, 0, phys_to_user ( initrd_phys
), 0,
248 /* Mark initrd as consumed */
252 if ( ( rc
= register_image ( image
) ) != 0 ) {
253 DBGC ( colour
, "RUNTIME could not register initrd: %s\n",
255 goto err_register_image
;
258 /* Drop our reference to the image */
272 * Initialise command line and initrd
275 static void runtime_init ( void ) {
278 /* Initialise command line */
279 if ( ( rc
= cmdline_init() ) != 0 ) {
280 /* No way to report failure */
284 /* Initialise initrd */
285 if ( ( rc
= initrd_init() ) != 0 ) {
286 /* No way to report failure */
291 /** Command line and initrd initialisation function */
292 struct startup_fn runtime_startup_fn
__startup_fn ( STARTUP_NORMAL
) = {
294 .startup
= runtime_init
,