1 /* ----------------------------------------------------------------------- *
3 * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009-2012 Intel Corporation; author: H. Peter Anvin
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following
15 * The above copyright notice and this permission notice shall
16 * be included in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
27 * ----------------------------------------------------------------------- */
32 * Sample module to load Linux kernels. This module can also create
33 * a file out of the DHCP return data if running under PXELINUX.
35 * If -dhcpinfo is specified, the DHCP info is written into the file
36 * /dhcpinfo.dat in the initramfs.
38 * Usage: linux.c32 [-dhcpinfo] kernel arguments...
47 #include <syslinux/loadfile.h>
48 #include <syslinux/linux.h>
49 #include <syslinux/pxe.h>
57 typedef int f_ldinitramfs(struct initramfs
*, char *);
59 const char *progname
= "linux.c32";
61 /* Find the last instance of a particular command line argument
62 (which should include the final =; do not use for boolean arguments) */
63 static char *find_argument(char **argv
, const char *argument
)
65 int la
= strlen(argument
);
69 for (arg
= argv
; *arg
; arg
++) {
70 if (!strncmp(*arg
, argument
, la
))
77 /* Find the next instance of a particular command line argument */
78 static char **find_arguments(char **argv
, char **ptr
,
81 int la
= strlen(argument
);
84 for (arg
= argv
; *arg
; arg
++) {
85 if (!strncmp(*arg
, argument
, la
)) {
91 /* Exhausted all arguments */
98 /* Search for a boolean argument; return its position, or 0 if not present */
99 static int find_boolean(char **argv
, const char *argument
)
103 for (arg
= argv
; *arg
; arg
++) {
104 if (!strcmp(*arg
, argument
))
105 return (arg
- argv
) + 1;
111 /* Stitch together the command line from a set of argv's */
112 static char *make_cmdline(char **argv
)
118 bytes
= 1; /* Just in case we have a zero-entry cmdline */
119 for (arg
= argv
; *arg
; arg
++) {
120 bytes
+= strlen(*arg
) + 1;
123 p
= cmdline
= malloc(bytes
);
127 for (arg
= argv
; *arg
; arg
++) {
128 int len
= strlen(*arg
);
129 memcpy(p
, *arg
, len
);
135 p
--; /* Remove the last space */
141 static f_ldinitramfs ldinitramfs_raw
;
142 static int ldinitramfs_raw(struct initramfs
*initramfs
, char *fname
)
144 return initramfs_load_archive(initramfs
, fname
);
147 static f_ldinitramfs ldinitramfs_cpio
;
148 static int ldinitramfs_cpio(struct initramfs
*initramfs
, char *fname
)
150 char *target_fname
, *p
;
151 int do_mkdir
, unmangle
, rc
;
153 /* Choose target_fname based on presence of "@" syntax */
154 target_fname
= strchr(fname
, '@');
156 /* Temporarily mangle */
158 *target_fname
++ = '\0';
160 /* Make parent directories? */
161 do_mkdir
= !!strchr(target_fname
, '/');
165 /* Forget the source path */
166 target_fname
= fname
;
167 while ((p
= strchr(target_fname
, '/')))
168 target_fname
= p
+ 1;
170 /* The user didn't specify a desired path */
175 * Load the file, encapsulate it with the desired path, make the
176 * parent directories if the desired path contains them, add to initramfs
178 rc
= initramfs_load_file(initramfs
, fname
, target_fname
, do_mkdir
, 0755);
180 /* Unmangle, if needed*/
182 *--target_fname
= '@';
187 /* It only makes sense to call this function from main */
188 static int process_initramfs_args(char *arg
, struct initramfs
*initramfs
,
189 const char *kernel_name
, enum ldmode mode
,
192 const char *mode_msg
;
193 f_ldinitramfs
*ldinitramfs
;
198 mode_msg
= "Loading";
199 ldinitramfs
= ldinitramfs_raw
;
202 mode_msg
= "Encapsulating";
203 ldinitramfs
= ldinitramfs_cpio
;
211 p
= strchr(arg
, ',');
216 printf("%s %s... ", mode_msg
, arg
);
218 if (ldinitramfs(initramfs
, arg
)) {
220 printf("Loading %s ", kernel_name
);
234 static int setup_data_file(struct setup_data
*setup_data
,
235 uint32_t type
, const char *filename
,
239 printf("Loading %s... ", filename
);
241 if (setup_data_load(setup_data
, type
, filename
)) {
243 printf("Loading %s ", filename
);
254 int main(int argc
, char *argv
[])
256 const char *kernel_name
;
257 struct initramfs
*initramfs
;
258 struct setup_data
*setup_data
;
263 bool opt_dhcpinfo
= false;
264 bool opt_quiet
= false;
267 char **argp
, **argl
, *arg
;
272 while ((arg
= *argp
) && arg
[0] == '-') {
273 if (!strcmp("-dhcpinfo", arg
)) {
276 fprintf(stderr
, "%s: unknown option: %s\n", progname
, arg
);
283 fprintf(stderr
, "%s: missing kernel name\n", progname
);
290 boot_image
= malloc(strlen(kernel_name
) + 12);
292 fprintf(stderr
, "Error allocating BOOT_IMAGE string: ");
295 strcpy(boot_image
, "BOOT_IMAGE=");
296 strcpy(boot_image
+ 11, kernel_name
);
297 /* argp now points to the kernel name, and the command line follows.
298 Overwrite the kernel name with the BOOT_IMAGE= argument, and thus
299 we have the final argument. */
302 if (find_boolean(argp
, "quiet"))
306 printf("Loading %s... ", kernel_name
);
308 if (loadfile(kernel_name
, &kernel_data
, &kernel_len
)) {
310 printf("Loading %s ", kernel_name
);
318 cmdline
= make_cmdline(argp
);
320 fprintf(stderr
, "make_cmdline() failed: ");
324 /* Initialize the initramfs chain */
326 initramfs
= initramfs_init();
328 fprintf(stderr
, "initramfs_init() failed: ");
332 /* Process initramfs arguments */
333 if ((arg
= find_argument(argp
, "initrd="))) {
334 if (process_initramfs_args(arg
, initramfs
, kernel_name
, ldmode_raw
,
340 while ((argl
= find_arguments(argl
, &arg
, "initrd+="))) {
342 if (process_initramfs_args(arg
, initramfs
, kernel_name
, ldmode_raw
,
348 while ((argl
= find_arguments(argl
, &arg
, "initrdfile="))) {
350 if (process_initramfs_args(arg
, initramfs
, kernel_name
, ldmode_cpio
,
355 /* Append the DHCP info */
357 !pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK
, &dhcpdata
, &dhcplen
)) {
359 if (initramfs_add_file(initramfs
, dhcpdata
, dhcplen
, dhcplen
,
360 "/dhcpinfo.dat", 0, 0755)) {
361 fprintf(stderr
, "Unable to add DHCP info: ");
366 /* Handle dtb and eventually other setup data */
367 setup_data
= setup_data_init();
372 while ((argl
= find_arguments(argl
, &arg
, "dtb="))) {
374 if (setup_data_file(setup_data
, SETUP_DTB
, arg
, opt_quiet
))
379 while ((argl
= find_arguments(argl
, &arg
, "blob."))) {
384 type
= strtoul(arg
, &ep
, 10);
385 if (ep
[0] != '=' || !ep
[1])
391 if (setup_data_file(setup_data
, type
, ep
+1, opt_quiet
))
395 /* This should not return... */
397 syslinux_boot_linux(kernel_data
, kernel_len
, initramfs
,
398 setup_data
, cmdline
);
399 fprintf(stderr
, "syslinux_boot_linux() failed: ");
404 fprintf(stderr
, "File not found\n");
407 fprintf(stderr
, "Out of memory\n");
410 fprintf(stderr
, "Error %d\n", errno
);
413 fprintf(stderr
, "%s: Boot aborted!\n", progname
);