Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / i386 / core / runtime.c
1 /*
2  * Copyright (C) 2011 Michael Brown <mbrown@fensystems.co.uk>.
3  *
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.
8  *
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.
13  *
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
17  * 02110-1301, USA.
18  */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 /** @file
23  *
24  * Command line and initrd passed to iPXE at runtime
25  *
26  */
27
28 #include <stddef.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <assert.h>
34 #include <ipxe/init.h>
35 #include <ipxe/image.h>
36 #include <ipxe/script.h>
37 #include <ipxe/umalloc.h>
38 #include <realmode.h>
39
40 /** Command line physical address
41  *
42  * This can be set by the prefix.
43  */
44 uint32_t __bss16 ( cmdline_phys );
45 #define cmdline_phys __use_data16 ( cmdline_phys )
46
47 /** initrd physical address
48  *
49  * This can be set by the prefix.
50  */
51 uint32_t __bss16 ( initrd_phys );
52 #define initrd_phys __use_data16 ( initrd_phys )
53
54 /** initrd length
55  *
56  * This can be set by the prefix.
57  */
58 uint32_t __bss16 ( initrd_len );
59 #define initrd_len __use_data16 ( initrd_len )
60
61 /** Internal copy of the command line */
62 static char *cmdline_copy;
63
64 /** Free command line image */
65 static void cmdline_image_free ( struct refcnt *refcnt ) {
66         struct image *image = container_of ( refcnt, struct image, refcnt );
67
68         DBGC ( image, "RUNTIME freeing command line\n" );
69         free ( cmdline_copy );
70 }
71
72 /** Embedded script representing the command line */
73 static struct image cmdline_image = {
74         .refcnt = REF_INIT ( cmdline_image_free ),
75         .name = "<CMDLINE>",
76         .type = &script_image_type,
77 };
78
79 /** Colour for debug messages */
80 #define colour &cmdline_image
81
82 /**
83  * Strip unwanted cruft from command line
84  *
85  * @v cmdline           Command line
86  * @v cruft             Initial substring of cruft to strip
87  */
88 static void cmdline_strip ( char *cmdline, const char *cruft ) {
89         char *strip;
90         char *strip_end;
91
92         /* Find unwanted cruft, if present */
93         if ( ! ( strip = strstr ( cmdline, cruft ) ) )
94                 return;
95
96         /* Strip unwanted cruft */
97         strip_end = strchr ( strip, ' ' );
98         if ( strip_end ) {
99                 *strip_end = '\0';
100                 DBGC ( colour, "RUNTIME stripping \"%s\"\n", strip );
101                 strcpy ( strip, ( strip_end + 1 ) );
102         } else {
103                 DBGC ( colour, "RUNTIME stripping \"%s\"\n", strip );
104                 *strip = '\0';
105         }
106 }
107
108 /**
109  * Initialise command line
110  *
111  * @ret rc              Return status code
112  */
113 static int cmdline_init ( void ) {
114         userptr_t cmdline_user;
115         char *cmdline;
116         size_t len;
117         int rc;
118
119         /* Do nothing if no command line was specified */
120         if ( ! cmdline_phys ) {
121                 DBGC ( colour, "RUNTIME found no command line\n" );
122                 return 0;
123         }
124         cmdline_user = phys_to_user ( cmdline_phys );
125         len = ( strlen_user ( cmdline_user, 0 ) + 1 /* NUL */ );
126
127         /* Allocate and copy command line */
128         cmdline_copy = malloc ( len );
129         if ( ! cmdline_copy ) {
130                 DBGC ( colour, "RUNTIME could not allocate %zd bytes for "
131                        "command line\n", len );
132                 rc = -ENOMEM;
133                 goto err_alloc_cmdline_copy;
134         }
135         cmdline = cmdline_copy;
136         copy_from_user ( cmdline, cmdline_user, 0, len );
137         DBGC ( colour, "RUNTIME found command line \"%s\" at %08x\n",
138                cmdline, cmdline_phys );
139
140         /* Mark command line as consumed */
141         cmdline_phys = 0;
142
143         /* Strip unwanted cruft from the command line */
144         cmdline_strip ( cmdline, "BOOT_IMAGE=" );
145         cmdline_strip ( cmdline, "initrd=" );
146         while ( isspace ( *cmdline ) )
147                 cmdline++;
148         DBGC ( colour, "RUNTIME using command line \"%s\"\n", cmdline );
149
150         /* Prepare and register image */
151         cmdline_image.data = virt_to_user ( cmdline );
152         cmdline_image.len = strlen ( cmdline );
153         if ( cmdline_image.len ) {
154                 if ( ( rc = register_image ( &cmdline_image ) ) != 0 ) {
155                         DBGC ( colour, "RUNTIME could not register command "
156                                "line: %s\n", strerror ( rc ) );
157                         goto err_register_image;
158                 }
159         }
160
161         /* Drop our reference to the image */
162         image_put ( &cmdline_image );
163
164         return 0;
165
166  err_register_image:
167         image_put ( &cmdline_image );
168  err_alloc_cmdline_copy:
169         return rc;
170 }
171
172 /**
173  * Initialise initrd
174  *
175  * @ret rc              Return status code
176  */
177 static int initrd_init ( void ) {
178         struct image *image;
179         int rc;
180
181         /* Do nothing if no initrd was specified */
182         if ( ! initrd_phys ) {
183                 DBGC ( colour, "RUNTIME found no initrd\n" );
184                 return 0;
185         }
186         if ( ! initrd_len ) {
187                 DBGC ( colour, "RUNTIME found empty initrd\n" );
188                 return 0;
189         }
190         DBGC ( colour, "RUNTIME found initrd at [%x,%x)\n",
191                initrd_phys, ( initrd_phys + initrd_len ) );
192
193         /* Allocate image */
194         image = alloc_image ( NULL );
195         if ( ! image ) {
196                 DBGC ( colour, "RUNTIME could not allocate image for "
197                        "initrd\n" );
198                 rc = -ENOMEM;
199                 goto err_alloc_image;
200         }
201         if ( ( rc = image_set_name ( image, "<INITRD>" ) ) != 0 ) {
202                 DBGC ( colour, "RUNTIME could not set image name: %s\n",
203                        strerror ( rc ) );
204                 goto err_set_name;
205         }
206
207         /* Allocate and copy initrd content */
208         image->data = umalloc ( initrd_len );
209         if ( ! image->data ) {
210                 DBGC ( colour, "RUNTIME could not allocate %d bytes for "
211                        "initrd\n", initrd_len );
212                 rc = -ENOMEM;
213                 goto err_umalloc;
214         }
215         image->len = initrd_len;
216         memcpy_user ( image->data, 0, phys_to_user ( initrd_phys ), 0,
217                       initrd_len );
218
219         /* Mark initrd as consumed */
220         initrd_phys = 0;
221
222         /* Register image */
223         if ( ( rc = register_image ( image ) ) != 0 ) {
224                 DBGC ( colour, "RUNTIME could not register initrd: %s\n",
225                        strerror ( rc ) );
226                 goto err_register_image;
227         }
228
229         /* Drop our reference to the image */
230         image_put ( image );
231
232         return 0;
233
234  err_register_image:
235  err_umalloc:
236  err_set_name:
237         image_put ( image );
238  err_alloc_image:
239         return rc;
240 }
241
242 /**
243  * Initialise command line and initrd
244  *
245  */
246 static void runtime_init ( void ) {
247         int rc;
248
249         /* Initialise command line */
250         if ( ( rc = cmdline_init() ) != 0 ) {
251                 /* No way to report failure */
252                 return;
253         }
254
255         /* Initialise initrd */
256         if ( ( rc = initrd_init() ) != 0 ) {
257                 /* No way to report failure */
258                 return;
259         }
260 }
261
262 /** Command line and initrd initialisation function */
263 struct startup_fn runtime_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
264         .startup = runtime_init,
265 };