blob: 59483a75c8fd7960b7dcb300a03ef5e3bebf37bf [file] [log] [blame]
Jason Hobbs06283a62011-08-31 10:37:30 -05001/*
2 * Copyright 2010-2011 Calxeda, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#include <common.h>
18#include <command.h>
19#include <malloc.h>
20#include <linux/string.h>
21#include <linux/ctype.h>
22#include <errno.h>
23#include <linux/list.h>
24
25#include "menu.h"
26
27#define MAX_TFTP_PATH_LEN 127
28
Rob Herring39f98552012-12-02 21:00:28 -060029const char *pxe_default_paths[] = {
30 "default-" CONFIG_SYS_ARCH "-" CONFIG_SYS_SOC,
31 "default-" CONFIG_SYS_ARCH,
32 "default",
33 NULL
34};
35
Jason Hobbs06283a62011-08-31 10:37:30 -050036/*
37 * Like getenv, but prints an error if envvar isn't defined in the
38 * environment. It always returns what getenv does, so it can be used in
39 * place of getenv without changing error handling otherwise.
40 */
Rob Herring23b71942012-12-02 21:00:21 -060041static char *from_env(const char *envvar)
Jason Hobbs06283a62011-08-31 10:37:30 -050042{
43 char *ret;
44
45 ret = getenv(envvar);
46
47 if (!ret)
48 printf("missing environment variable: %s\n", envvar);
49
50 return ret;
51}
52
53/*
54 * Convert an ethaddr from the environment to the format used by pxelinux
55 * filenames based on mac addresses. Convert's ':' to '-', and adds "01-" to
56 * the beginning of the ethernet address to indicate a hardware type of
57 * Ethernet. Also converts uppercase hex characters into lowercase, to match
58 * pxelinux's behavior.
59 *
60 * Returns 1 for success, -ENOENT if 'ethaddr' is undefined in the
61 * environment, or some other value < 0 on error.
62 */
63static int format_mac_pxe(char *outbuf, size_t outbuf_len)
64{
Rob Herringef034c92012-12-02 21:00:20 -060065 uchar ethaddr[6];
Jason Hobbs06283a62011-08-31 10:37:30 -050066
Rob Herringef034c92012-12-02 21:00:20 -060067 if (outbuf_len < 21) {
68 printf("outbuf is too small (%d < 21)\n", outbuf_len);
Jason Hobbs06283a62011-08-31 10:37:30 -050069
70 return -EINVAL;
71 }
72
Rob Herringef034c92012-12-02 21:00:20 -060073 if (!eth_getenv_enetaddr_by_index("eth", eth_get_dev_index(),
74 ethaddr))
75 return -ENOENT;
Jason Hobbs06283a62011-08-31 10:37:30 -050076
Rob Herringef034c92012-12-02 21:00:20 -060077 sprintf(outbuf, "01-%02x-%02x-%02x-%02x-%02x-%02x",
78 ethaddr[0], ethaddr[1], ethaddr[2],
79 ethaddr[3], ethaddr[4], ethaddr[5]);
Jason Hobbs06283a62011-08-31 10:37:30 -050080
81 return 1;
82}
83
84/*
85 * Returns the directory the file specified in the bootfile env variable is
86 * in. If bootfile isn't defined in the environment, return NULL, which should
87 * be interpreted as "don't prepend anything to paths".
88 */
Rob Herring90ba7d72012-03-28 05:51:36 +000089static int get_bootfile_path(const char *file_path, char *bootfile_path,
90 size_t bootfile_path_size)
Jason Hobbs06283a62011-08-31 10:37:30 -050091{
92 char *bootfile, *last_slash;
Rob Herring90ba7d72012-03-28 05:51:36 +000093 size_t path_len = 0;
94
95 if (file_path[0] == '/')
96 goto ret;
Jason Hobbs06283a62011-08-31 10:37:30 -050097
98 bootfile = from_env("bootfile");
99
Rob Herring90ba7d72012-03-28 05:51:36 +0000100 if (!bootfile)
101 goto ret;
Jason Hobbs06283a62011-08-31 10:37:30 -0500102
103 last_slash = strrchr(bootfile, '/');
104
Rob Herring90ba7d72012-03-28 05:51:36 +0000105 if (last_slash == NULL)
106 goto ret;
Jason Hobbs06283a62011-08-31 10:37:30 -0500107
108 path_len = (last_slash - bootfile) + 1;
109
110 if (bootfile_path_size < path_len) {
111 printf("bootfile_path too small. (%d < %d)\n",
112 bootfile_path_size, path_len);
113
114 return -1;
115 }
116
117 strncpy(bootfile_path, bootfile, path_len);
118
Rob Herring90ba7d72012-03-28 05:51:36 +0000119 ret:
Jason Hobbs06283a62011-08-31 10:37:30 -0500120 bootfile_path[path_len] = '\0';
121
122 return 1;
123}
124
Rob Herring23b71942012-12-02 21:00:21 -0600125static int (*do_getfile)(const char *file_path, char *file_addr);
Rob Herring669df7e2012-05-25 10:47:39 +0000126
Rob Herring23b71942012-12-02 21:00:21 -0600127static int do_get_tftp(const char *file_path, char *file_addr)
Rob Herring669df7e2012-05-25 10:47:39 +0000128{
129 char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
130
131 tftp_argv[1] = file_addr;
Rob Herring23b71942012-12-02 21:00:21 -0600132 tftp_argv[2] = (void *)file_path;
Rob Herring669df7e2012-05-25 10:47:39 +0000133
134 if (do_tftpb(NULL, 0, 3, tftp_argv))
135 return -ENOENT;
136
137 return 1;
138}
139
140static char *fs_argv[5];
141
Rob Herring23b71942012-12-02 21:00:21 -0600142static int do_get_ext2(const char *file_path, char *file_addr)
Rob Herring669df7e2012-05-25 10:47:39 +0000143{
144#ifdef CONFIG_CMD_EXT2
145 fs_argv[0] = "ext2load";
146 fs_argv[3] = file_addr;
Rob Herring23b71942012-12-02 21:00:21 -0600147 fs_argv[4] = (void *)file_path;
Rob Herring669df7e2012-05-25 10:47:39 +0000148
149 if (!do_ext2load(NULL, 0, 5, fs_argv))
150 return 1;
151#endif
152 return -ENOENT;
153}
154
Rob Herring23b71942012-12-02 21:00:21 -0600155static int do_get_fat(const char *file_path, char *file_addr)
Rob Herring669df7e2012-05-25 10:47:39 +0000156{
157#ifdef CONFIG_CMD_FAT
158 fs_argv[0] = "fatload";
159 fs_argv[3] = file_addr;
Rob Herring23b71942012-12-02 21:00:21 -0600160 fs_argv[4] = (void *)file_path;
Rob Herring669df7e2012-05-25 10:47:39 +0000161
162 if (!do_fat_fsload(NULL, 0, 5, fs_argv))
163 return 1;
164#endif
165 return -ENOENT;
166}
167
Jason Hobbs06283a62011-08-31 10:37:30 -0500168/*
169 * As in pxelinux, paths to files referenced from files we retrieve are
170 * relative to the location of bootfile. get_relfile takes such a path and
171 * joins it with the bootfile path to get the full path to the target file. If
172 * the bootfile path is NULL, we use file_path as is.
173 *
174 * Returns 1 for success, or < 0 on error.
175 */
Rob Herring23b71942012-12-02 21:00:21 -0600176static int get_relfile(const char *file_path, void *file_addr)
Jason Hobbs06283a62011-08-31 10:37:30 -0500177{
178 size_t path_len;
179 char relfile[MAX_TFTP_PATH_LEN+1];
180 char addr_buf[10];
Jason Hobbs06283a62011-08-31 10:37:30 -0500181 int err;
182
Rob Herring90ba7d72012-03-28 05:51:36 +0000183 err = get_bootfile_path(file_path, relfile, sizeof(relfile));
Jason Hobbs06283a62011-08-31 10:37:30 -0500184
185 if (err < 0)
186 return err;
187
188 path_len = strlen(file_path);
189 path_len += strlen(relfile);
190
191 if (path_len > MAX_TFTP_PATH_LEN) {
192 printf("Base path too long (%s%s)\n",
193 relfile,
194 file_path);
195
196 return -ENAMETOOLONG;
197 }
198
199 strcat(relfile, file_path);
200
201 printf("Retrieving file: %s\n", relfile);
202
203 sprintf(addr_buf, "%p", file_addr);
204
Rob Herring669df7e2012-05-25 10:47:39 +0000205 return do_getfile(relfile, addr_buf);
Jason Hobbs06283a62011-08-31 10:37:30 -0500206}
207
208/*
209 * Retrieve the file at 'file_path' to the locate given by 'file_addr'. If
210 * 'bootfile' was specified in the environment, the path to bootfile will be
211 * prepended to 'file_path' and the resulting path will be used.
212 *
213 * Returns 1 on success, or < 0 for error.
214 */
Rob Herring23b71942012-12-02 21:00:21 -0600215static int get_pxe_file(const char *file_path, void *file_addr)
Jason Hobbs06283a62011-08-31 10:37:30 -0500216{
217 unsigned long config_file_size;
218 char *tftp_filesize;
219 int err;
220
221 err = get_relfile(file_path, file_addr);
222
223 if (err < 0)
224 return err;
225
226 /*
227 * the file comes without a NUL byte at the end, so find out its size
228 * and add the NUL byte.
229 */
230 tftp_filesize = from_env("filesize");
231
232 if (!tftp_filesize)
233 return -ENOENT;
234
235 if (strict_strtoul(tftp_filesize, 16, &config_file_size) < 0)
236 return -EINVAL;
237
238 *(char *)(file_addr + config_file_size) = '\0';
239
240 return 1;
241}
242
243#define PXELINUX_DIR "pxelinux.cfg/"
244
245/*
246 * Retrieves a file in the 'pxelinux.cfg' folder. Since this uses get_pxe_file
247 * to do the hard work, the location of the 'pxelinux.cfg' folder is generated
248 * from the bootfile path, as described above.
249 *
250 * Returns 1 on success or < 0 on error.
251 */
Rob Herring23b71942012-12-02 21:00:21 -0600252static int get_pxelinux_path(const char *file, void *pxefile_addr_r)
Jason Hobbs06283a62011-08-31 10:37:30 -0500253{
254 size_t base_len = strlen(PXELINUX_DIR);
255 char path[MAX_TFTP_PATH_LEN+1];
256
257 if (base_len + strlen(file) > MAX_TFTP_PATH_LEN) {
258 printf("path (%s%s) too long, skipping\n",
259 PXELINUX_DIR, file);
260 return -ENAMETOOLONG;
261 }
262
263 sprintf(path, PXELINUX_DIR "%s", file);
264
265 return get_pxe_file(path, pxefile_addr_r);
266}
267
268/*
269 * Looks for a pxe file with a name based on the pxeuuid environment variable.
270 *
271 * Returns 1 on success or < 0 on error.
272 */
273static int pxe_uuid_path(void *pxefile_addr_r)
274{
275 char *uuid_str;
276
277 uuid_str = from_env("pxeuuid");
278
279 if (!uuid_str)
280 return -ENOENT;
281
282 return get_pxelinux_path(uuid_str, pxefile_addr_r);
283}
284
285/*
286 * Looks for a pxe file with a name based on the 'ethaddr' environment
287 * variable.
288 *
289 * Returns 1 on success or < 0 on error.
290 */
291static int pxe_mac_path(void *pxefile_addr_r)
292{
293 char mac_str[21];
294 int err;
295
296 err = format_mac_pxe(mac_str, sizeof(mac_str));
297
298 if (err < 0)
299 return err;
300
301 return get_pxelinux_path(mac_str, pxefile_addr_r);
302}
303
304/*
305 * Looks for pxe files with names based on our IP address. See pxelinux
306 * documentation for details on what these file names look like. We match
307 * that exactly.
308 *
309 * Returns 1 on success or < 0 on error.
310 */
311static int pxe_ipaddr_paths(void *pxefile_addr_r)
312{
313 char ip_addr[9];
314 int mask_pos, err;
315
316 sprintf(ip_addr, "%08X", ntohl(NetOurIP));
317
318 for (mask_pos = 7; mask_pos >= 0; mask_pos--) {
319 err = get_pxelinux_path(ip_addr, pxefile_addr_r);
320
321 if (err > 0)
322 return err;
323
324 ip_addr[mask_pos] = '\0';
325 }
326
327 return -ENOENT;
328}
329
330/*
331 * Entry point for the 'pxe get' command.
332 * This Follows pxelinux's rules to download a config file from a tftp server.
333 * The file is stored at the location given by the pxefile_addr_r environment
334 * variable, which must be set.
335 *
336 * UUID comes from pxeuuid env variable, if defined
337 * MAC addr comes from ethaddr env variable, if defined
338 * IP
339 *
340 * see http://syslinux.zytor.com/wiki/index.php/PXELINUX
341 *
342 * Returns 0 on success or 1 on error.
343 */
344static int
345do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
346{
347 char *pxefile_addr_str;
Jason Hobbs834c9382012-03-05 08:12:28 +0000348 unsigned long pxefile_addr_r;
Rob Herring39f98552012-12-02 21:00:28 -0600349 int err, i = 0;
Jason Hobbs06283a62011-08-31 10:37:30 -0500350
Rob Herring669df7e2012-05-25 10:47:39 +0000351 do_getfile = do_get_tftp;
352
Jason Hobbs06283a62011-08-31 10:37:30 -0500353 if (argc != 1)
Simon Glass4c12eeb2011-12-10 08:44:01 +0000354 return CMD_RET_USAGE;
Jason Hobbs06283a62011-08-31 10:37:30 -0500355
Jason Hobbs06283a62011-08-31 10:37:30 -0500356 pxefile_addr_str = from_env("pxefile_addr_r");
357
358 if (!pxefile_addr_str)
359 return 1;
360
361 err = strict_strtoul(pxefile_addr_str, 16,
362 (unsigned long *)&pxefile_addr_r);
363 if (err < 0)
364 return 1;
365
366 /*
367 * Keep trying paths until we successfully get a file we're looking
368 * for.
369 */
Rob Herring39f98552012-12-02 21:00:28 -0600370 if (pxe_uuid_path((void *)pxefile_addr_r) > 0 ||
371 pxe_mac_path((void *)pxefile_addr_r) > 0 ||
372 pxe_ipaddr_paths((void *)pxefile_addr_r) > 0) {
Jason Hobbs06283a62011-08-31 10:37:30 -0500373 printf("Config file found\n");
374
375 return 0;
376 }
377
Rob Herring39f98552012-12-02 21:00:28 -0600378 while (pxe_default_paths[i]) {
379 if (get_pxelinux_path(pxe_default_paths[i],
380 (void *)pxefile_addr_r) > 0) {
381 printf("Config file found\n");
382 return 0;
383 }
384 i++;
385 }
386
Jason Hobbs06283a62011-08-31 10:37:30 -0500387 printf("Config file not found\n");
388
389 return 1;
390}
391
392/*
393 * Wrapper to make it easier to store the file at file_path in the location
394 * specified by envaddr_name. file_path will be joined to the bootfile path,
395 * if any is specified.
396 *
397 * Returns 1 on success or < 0 on error.
398 */
Rob Herring23b71942012-12-02 21:00:21 -0600399static int get_relfile_envaddr(const char *file_path, const char *envaddr_name)
Jason Hobbs06283a62011-08-31 10:37:30 -0500400{
Jason Hobbs834c9382012-03-05 08:12:28 +0000401 unsigned long file_addr;
Jason Hobbs06283a62011-08-31 10:37:30 -0500402 char *envaddr;
403
404 envaddr = from_env(envaddr_name);
405
406 if (!envaddr)
407 return -ENOENT;
408
Jason Hobbs834c9382012-03-05 08:12:28 +0000409 if (strict_strtoul(envaddr, 16, &file_addr) < 0)
Jason Hobbs06283a62011-08-31 10:37:30 -0500410 return -EINVAL;
411
Jason Hobbs834c9382012-03-05 08:12:28 +0000412 return get_relfile(file_path, (void *)file_addr);
Jason Hobbs06283a62011-08-31 10:37:30 -0500413}
414
415/*
416 * A note on the pxe file parser.
417 *
418 * We're parsing files that use syslinux grammar, which has a few quirks.
419 * String literals must be recognized based on context - there is no
420 * quoting or escaping support. There's also nothing to explicitly indicate
421 * when a label section completes. We deal with that by ending a label
422 * section whenever we see a line that doesn't include.
423 *
424 * As with the syslinux family, this same file format could be reused in the
425 * future for non pxe purposes. The only action it takes during parsing that
426 * would throw this off is handling of include files. It assumes we're using
427 * pxe, and does a tftp download of a file listed as an include file in the
428 * middle of the parsing operation. That could be handled by refactoring it to
429 * take a 'include file getter' function.
430 */
431
432/*
433 * Describes a single label given in a pxe file.
434 *
435 * Create these with the 'label_create' function given below.
436 *
437 * name - the name of the menu as given on the 'menu label' line.
438 * kernel - the path to the kernel file to use for this label.
439 * append - kernel command line to use when booting this label
440 * initrd - path to the initrd to use for this label.
441 * attempted - 0 if we haven't tried to boot this label, 1 if we have.
442 * localboot - 1 if this label specified 'localboot', 0 otherwise.
443 * list - lets these form a list, which a pxe_menu struct will hold.
444 */
445struct pxe_label {
Rob Herring32d2ffe2012-12-02 21:00:26 -0600446 char num[4];
Jason Hobbs06283a62011-08-31 10:37:30 -0500447 char *name;
Rob Herring7815c4e2012-03-28 05:51:34 +0000448 char *menu;
Jason Hobbs06283a62011-08-31 10:37:30 -0500449 char *kernel;
450 char *append;
451 char *initrd;
Chander Kashyapa6559382012-09-06 19:36:31 +0000452 char *fdt;
Jason Hobbs06283a62011-08-31 10:37:30 -0500453 int attempted;
454 int localboot;
Rob Herring500f3042012-12-02 21:00:22 -0600455 int localboot_val;
Jason Hobbs06283a62011-08-31 10:37:30 -0500456 struct list_head list;
457};
458
459/*
460 * Describes a pxe menu as given via pxe files.
461 *
462 * title - the name of the menu as given by a 'menu title' line.
463 * default_label - the name of the default label, if any.
464 * timeout - time in tenths of a second to wait for a user key-press before
465 * booting the default label.
466 * prompt - if 0, don't prompt for a choice unless the timeout period is
467 * interrupted. If 1, always prompt for a choice regardless of
468 * timeout.
469 * labels - a list of labels defined for the menu.
470 */
471struct pxe_menu {
472 char *title;
473 char *default_label;
474 int timeout;
475 int prompt;
476 struct list_head labels;
477};
478
479/*
480 * Allocates memory for and initializes a pxe_label. This uses malloc, so the
481 * result must be free()'d to reclaim the memory.
482 *
483 * Returns NULL if malloc fails.
484 */
485static struct pxe_label *label_create(void)
486{
487 struct pxe_label *label;
488
489 label = malloc(sizeof(struct pxe_label));
490
491 if (!label)
492 return NULL;
493
494 memset(label, 0, sizeof(struct pxe_label));
495
496 return label;
497}
498
499/*
500 * Free the memory used by a pxe_label, including that used by its name,
501 * kernel, append and initrd members, if they're non NULL.
502 *
503 * So - be sure to only use dynamically allocated memory for the members of
504 * the pxe_label struct, unless you want to clean it up first. These are
505 * currently only created by the pxe file parsing code.
506 */
507static void label_destroy(struct pxe_label *label)
508{
509 if (label->name)
510 free(label->name);
511
512 if (label->kernel)
513 free(label->kernel);
514
515 if (label->append)
516 free(label->append);
517
518 if (label->initrd)
519 free(label->initrd);
520
Chander Kashyapa6559382012-09-06 19:36:31 +0000521 if (label->fdt)
522 free(label->fdt);
523
Jason Hobbs06283a62011-08-31 10:37:30 -0500524 free(label);
525}
526
527/*
528 * Print a label and its string members if they're defined.
529 *
530 * This is passed as a callback to the menu code for displaying each
531 * menu entry.
532 */
533static void label_print(void *data)
534{
535 struct pxe_label *label = data;
Rob Herring32d2ffe2012-12-02 21:00:26 -0600536 const char *c = label->menu ? label->menu : label->name;
Jason Hobbs06283a62011-08-31 10:37:30 -0500537
Rob Herring32d2ffe2012-12-02 21:00:26 -0600538 printf("%s:\t%s\n", label->num, c);
Jason Hobbs06283a62011-08-31 10:37:30 -0500539}
540
541/*
542 * Boot a label that specified 'localboot'. This requires that the 'localcmd'
543 * environment variable is defined. Its contents will be executed as U-boot
544 * command. If the label specified an 'append' line, its contents will be
545 * used to overwrite the contents of the 'bootargs' environment variable prior
546 * to running 'localcmd'.
547 *
548 * Returns 1 on success or < 0 on error.
549 */
550static int label_localboot(struct pxe_label *label)
551{
Simon Glassd51004a2012-03-30 21:30:55 +0000552 char *localcmd;
Jason Hobbs06283a62011-08-31 10:37:30 -0500553
554 localcmd = from_env("localcmd");
555
556 if (!localcmd)
557 return -ENOENT;
558
Jason Hobbs06283a62011-08-31 10:37:30 -0500559 if (label->append)
560 setenv("bootargs", label->append);
561
Simon Glassd51004a2012-03-30 21:30:55 +0000562 debug("running: %s\n", localcmd);
Jason Hobbs06283a62011-08-31 10:37:30 -0500563
Simon Glassd51004a2012-03-30 21:30:55 +0000564 return run_command_list(localcmd, strlen(localcmd), 0);
Jason Hobbs06283a62011-08-31 10:37:30 -0500565}
566
567/*
568 * Boot according to the contents of a pxe_label.
569 *
570 * If we can't boot for any reason, we return. A successful boot never
571 * returns.
572 *
573 * The kernel will be stored in the location given by the 'kernel_addr_r'
574 * environment variable.
575 *
576 * If the label specifies an initrd file, it will be stored in the location
577 * given by the 'ramdisk_addr_r' environment variable.
578 *
579 * If the label specifies an 'append' line, its contents will overwrite that
580 * of the 'bootargs' environment variable.
581 */
Rob Herring500f3042012-12-02 21:00:22 -0600582static int label_boot(struct pxe_label *label)
Jason Hobbs06283a62011-08-31 10:37:30 -0500583{
584 char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
Rob Herringe6b6ccf2012-12-03 13:17:21 -0600585 char initrd_str[22];
Jason Hobbs06283a62011-08-31 10:37:30 -0500586 int bootm_argc = 3;
587
588 label_print(label);
589
590 label->attempted = 1;
591
592 if (label->localboot) {
Rob Herring500f3042012-12-02 21:00:22 -0600593 if (label->localboot_val >= 0)
594 label_localboot(label);
595 return 0;
Jason Hobbs06283a62011-08-31 10:37:30 -0500596 }
597
598 if (label->kernel == NULL) {
599 printf("No kernel given, skipping %s\n",
600 label->name);
Rob Herring500f3042012-12-02 21:00:22 -0600601 return 1;
Jason Hobbs06283a62011-08-31 10:37:30 -0500602 }
603
604 if (label->initrd) {
605 if (get_relfile_envaddr(label->initrd, "ramdisk_addr_r") < 0) {
606 printf("Skipping %s for failure retrieving initrd\n",
607 label->name);
Rob Herring500f3042012-12-02 21:00:22 -0600608 return 1;
Jason Hobbs06283a62011-08-31 10:37:30 -0500609 }
610
Rob Herringe6b6ccf2012-12-03 13:17:21 -0600611 bootm_argv[2] = initrd_str;
612 strcpy(bootm_argv[2], getenv("ramdisk_addr_r"));
613 strcat(bootm_argv[2], ":");
614 strcat(bootm_argv[2], getenv("filesize"));
Jason Hobbs06283a62011-08-31 10:37:30 -0500615 } else {
616 bootm_argv[2] = "-";
617 }
618
619 if (get_relfile_envaddr(label->kernel, "kernel_addr_r") < 0) {
620 printf("Skipping %s for failure retrieving kernel\n",
621 label->name);
Rob Herring500f3042012-12-02 21:00:22 -0600622 return 1;
Jason Hobbs06283a62011-08-31 10:37:30 -0500623 }
624
Rob Herring32d2ffe2012-12-02 21:00:26 -0600625 if (label->append) {
Jason Hobbs06283a62011-08-31 10:37:30 -0500626 setenv("bootargs", label->append);
Rob Herring32d2ffe2012-12-02 21:00:26 -0600627 printf("append: %s\n", label->append);
628 }
Jason Hobbs06283a62011-08-31 10:37:30 -0500629
630 bootm_argv[1] = getenv("kernel_addr_r");
631
632 /*
Chander Kashyapa6559382012-09-06 19:36:31 +0000633 * fdt usage is optional:
634 * It handles the following scenarios. All scenarios are exclusive
635 *
636 * Scenario 1: If fdt_addr_r specified and "fdt" label is defined in
637 * pxe file, retrieve fdt blob from server. Pass fdt_addr_r to bootm,
638 * and adjust argc appropriately.
639 *
640 * Scenario 2: If there is an fdt_addr specified, pass it along to
641 * bootm, and adjust argc appropriately.
642 *
643 * Scenario 3: fdt blob is not available.
Jason Hobbs06283a62011-08-31 10:37:30 -0500644 */
Chander Kashyapa6559382012-09-06 19:36:31 +0000645 bootm_argv[3] = getenv("fdt_addr_r");
646
647 /* if fdt label is defined then get fdt from server */
648 if (bootm_argv[3] && label->fdt) {
649 if (get_relfile_envaddr(label->fdt, "fdt_addr_r") < 0) {
650 printf("Skipping %s for failure retrieving fdt\n",
651 label->name);
Rob Herring500f3042012-12-02 21:00:22 -0600652 return 1;
Chander Kashyapa6559382012-09-06 19:36:31 +0000653 }
654 } else
655 bootm_argv[3] = getenv("fdt_addr");
Jason Hobbs06283a62011-08-31 10:37:30 -0500656
657 if (bootm_argv[3])
658 bootm_argc = 4;
659
660 do_bootm(NULL, 0, bootm_argc, bootm_argv);
Rob Herringe6b6ccf2012-12-03 13:17:21 -0600661
662#ifdef CONFIG_CMD_BOOTZ
663 /* Try booting a zImage if do_bootm returns */
664 do_bootz(NULL, 0, bootm_argc, bootm_argv);
665#endif
Rob Herring500f3042012-12-02 21:00:22 -0600666 return 1;
Jason Hobbs06283a62011-08-31 10:37:30 -0500667}
668
669/*
670 * Tokens for the pxe file parser.
671 */
672enum token_type {
673 T_EOL,
674 T_STRING,
675 T_EOF,
676 T_MENU,
677 T_TITLE,
678 T_TIMEOUT,
679 T_LABEL,
680 T_KERNEL,
Rob Herringbeb9f6c2012-03-28 05:51:35 +0000681 T_LINUX,
Jason Hobbs06283a62011-08-31 10:37:30 -0500682 T_APPEND,
683 T_INITRD,
684 T_LOCALBOOT,
685 T_DEFAULT,
686 T_PROMPT,
687 T_INCLUDE,
Chander Kashyapa6559382012-09-06 19:36:31 +0000688 T_FDT,
Rob Herring8577fec2012-12-02 21:00:27 -0600689 T_ONTIMEOUT,
Jason Hobbs06283a62011-08-31 10:37:30 -0500690 T_INVALID
691};
692
693/*
694 * A token - given by a value and a type.
695 */
696struct token {
697 char *val;
698 enum token_type type;
699};
700
701/*
702 * Keywords recognized.
703 */
704static const struct token keywords[] = {
705 {"menu", T_MENU},
706 {"title", T_TITLE},
707 {"timeout", T_TIMEOUT},
708 {"default", T_DEFAULT},
709 {"prompt", T_PROMPT},
710 {"label", T_LABEL},
711 {"kernel", T_KERNEL},
Rob Herringbeb9f6c2012-03-28 05:51:35 +0000712 {"linux", T_LINUX},
Jason Hobbs06283a62011-08-31 10:37:30 -0500713 {"localboot", T_LOCALBOOT},
714 {"append", T_APPEND},
715 {"initrd", T_INITRD},
716 {"include", T_INCLUDE},
Chander Kashyapa6559382012-09-06 19:36:31 +0000717 {"fdt", T_FDT},
Rob Herring8577fec2012-12-02 21:00:27 -0600718 {"ontimeout", T_ONTIMEOUT,},
Jason Hobbs06283a62011-08-31 10:37:30 -0500719 {NULL, T_INVALID}
720};
721
722/*
723 * Since pxe(linux) files don't have a token to identify the start of a
724 * literal, we have to keep track of when we're in a state where a literal is
725 * expected vs when we're in a state a keyword is expected.
726 */
727enum lex_state {
728 L_NORMAL = 0,
729 L_KEYWORD,
730 L_SLITERAL
731};
732
733/*
734 * get_string retrieves a string from *p and stores it as a token in
735 * *t.
736 *
737 * get_string used for scanning both string literals and keywords.
738 *
739 * Characters from *p are copied into t-val until a character equal to
740 * delim is found, or a NUL byte is reached. If delim has the special value of
741 * ' ', any whitespace character will be used as a delimiter.
742 *
743 * If lower is unequal to 0, uppercase characters will be converted to
744 * lowercase in the result. This is useful to make keywords case
745 * insensitive.
746 *
747 * The location of *p is updated to point to the first character after the end
748 * of the token - the ending delimiter.
749 *
750 * On success, the new value of t->val is returned. Memory for t->val is
751 * allocated using malloc and must be free()'d to reclaim it. If insufficient
752 * memory is available, NULL is returned.
753 */
754static char *get_string(char **p, struct token *t, char delim, int lower)
755{
756 char *b, *e;
757 size_t len, i;
758
759 /*
760 * b and e both start at the beginning of the input stream.
761 *
762 * e is incremented until we find the ending delimiter, or a NUL byte
763 * is reached. Then, we take e - b to find the length of the token.
764 */
765 b = e = *p;
766
767 while (*e) {
768 if ((delim == ' ' && isspace(*e)) || delim == *e)
769 break;
770 e++;
771 }
772
773 len = e - b;
774
775 /*
776 * Allocate memory to hold the string, and copy it in, converting
777 * characters to lowercase if lower is != 0.
778 */
779 t->val = malloc(len + 1);
780 if (!t->val)
781 return NULL;
782
783 for (i = 0; i < len; i++, b++) {
784 if (lower)
785 t->val[i] = tolower(*b);
786 else
787 t->val[i] = *b;
788 }
789
790 t->val[len] = '\0';
791
792 /*
793 * Update *p so the caller knows where to continue scanning.
794 */
795 *p = e;
796
797 t->type = T_STRING;
798
799 return t->val;
800}
801
802/*
803 * Populate a keyword token with a type and value.
804 */
805static void get_keyword(struct token *t)
806{
807 int i;
808
809 for (i = 0; keywords[i].val; i++) {
810 if (!strcmp(t->val, keywords[i].val)) {
811 t->type = keywords[i].type;
812 break;
813 }
814 }
815}
816
817/*
818 * Get the next token. We have to keep track of which state we're in to know
819 * if we're looking to get a string literal or a keyword.
820 *
821 * *p is updated to point at the first character after the current token.
822 */
823static void get_token(char **p, struct token *t, enum lex_state state)
824{
825 char *c = *p;
826
827 t->type = T_INVALID;
828
829 /* eat non EOL whitespace */
830 while (isblank(*c))
831 c++;
832
833 /*
834 * eat comments. note that string literals can't begin with #, but
835 * can contain a # after their first character.
836 */
837 if (*c == '#') {
838 while (*c && *c != '\n')
839 c++;
840 }
841
842 if (*c == '\n') {
843 t->type = T_EOL;
844 c++;
845 } else if (*c == '\0') {
846 t->type = T_EOF;
847 c++;
848 } else if (state == L_SLITERAL) {
849 get_string(&c, t, '\n', 0);
850 } else if (state == L_KEYWORD) {
851 /*
852 * when we expect a keyword, we first get the next string
853 * token delimited by whitespace, and then check if it
854 * matches a keyword in our keyword list. if it does, it's
855 * converted to a keyword token of the appropriate type, and
856 * if not, it remains a string token.
857 */
858 get_string(&c, t, ' ', 1);
859 get_keyword(t);
860 }
861
862 *p = c;
863}
864
865/*
866 * Increment *c until we get to the end of the current line, or EOF.
867 */
868static void eol_or_eof(char **c)
869{
870 while (**c && **c != '\n')
871 (*c)++;
872}
873
874/*
875 * All of these parse_* functions share some common behavior.
876 *
877 * They finish with *c pointing after the token they parse, and return 1 on
878 * success, or < 0 on error.
879 */
880
881/*
882 * Parse a string literal and store a pointer it at *dst. String literals
883 * terminate at the end of the line.
884 */
885static int parse_sliteral(char **c, char **dst)
886{
887 struct token t;
888 char *s = *c;
889
890 get_token(c, &t, L_SLITERAL);
891
892 if (t.type != T_STRING) {
893 printf("Expected string literal: %.*s\n", (int)(*c - s), s);
894 return -EINVAL;
895 }
896
897 *dst = t.val;
898
899 return 1;
900}
901
902/*
903 * Parse a base 10 (unsigned) integer and store it at *dst.
904 */
905static int parse_integer(char **c, int *dst)
906{
907 struct token t;
908 char *s = *c;
Jason Hobbs06283a62011-08-31 10:37:30 -0500909
910 get_token(c, &t, L_SLITERAL);
911
912 if (t.type != T_STRING) {
913 printf("Expected string: %.*s\n", (int)(*c - s), s);
914 return -EINVAL;
915 }
916
Rob Herring500f3042012-12-02 21:00:22 -0600917 *dst = simple_strtol(t.val, NULL, 10);
Jason Hobbs06283a62011-08-31 10:37:30 -0500918
919 free(t.val);
920
921 return 1;
922}
923
924static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level);
925
926/*
927 * Parse an include statement, and retrieve and parse the file it mentions.
928 *
929 * base should point to a location where it's safe to store the file, and
930 * nest_level should indicate how many nested includes have occurred. For this
931 * include, nest_level has already been incremented and doesn't need to be
932 * incremented here.
933 */
934static int handle_include(char **c, char *base,
935 struct pxe_menu *cfg, int nest_level)
936{
937 char *include_path;
938 char *s = *c;
939 int err;
940
941 err = parse_sliteral(c, &include_path);
942
943 if (err < 0) {
944 printf("Expected include path: %.*s\n",
945 (int)(*c - s), s);
946 return err;
947 }
948
949 err = get_pxe_file(include_path, base);
950
951 if (err < 0) {
952 printf("Couldn't retrieve %s\n", include_path);
953 return err;
954 }
955
956 return parse_pxefile_top(base, cfg, nest_level);
957}
958
959/*
960 * Parse lines that begin with 'menu'.
961 *
962 * b and nest are provided to handle the 'menu include' case.
963 *
964 * b should be the address where the file currently being parsed is stored.
965 *
966 * nest_level should be 1 when parsing the top level pxe file, 2 when parsing
967 * a file it includes, 3 when parsing a file included by that file, and so on.
968 */
969static int parse_menu(char **c, struct pxe_menu *cfg, char *b, int nest_level)
970{
971 struct token t;
972 char *s = *c;
Heiko Schocher43d4a5e2011-12-12 20:37:17 +0000973 int err = 0;
Jason Hobbs06283a62011-08-31 10:37:30 -0500974
975 get_token(c, &t, L_KEYWORD);
976
977 switch (t.type) {
978 case T_TITLE:
979 err = parse_sliteral(c, &cfg->title);
980
981 break;
982
983 case T_INCLUDE:
984 err = handle_include(c, b + strlen(b) + 1, cfg,
985 nest_level + 1);
986 break;
987
988 default:
989 printf("Ignoring malformed menu command: %.*s\n",
990 (int)(*c - s), s);
991 }
992
993 if (err < 0)
994 return err;
995
996 eol_or_eof(c);
997
998 return 1;
999}
1000
1001/*
1002 * Handles parsing a 'menu line' when we're parsing a label.
1003 */
1004static int parse_label_menu(char **c, struct pxe_menu *cfg,
1005 struct pxe_label *label)
1006{
1007 struct token t;
1008 char *s;
1009
1010 s = *c;
1011
1012 get_token(c, &t, L_KEYWORD);
1013
1014 switch (t.type) {
1015 case T_DEFAULT:
Rob Herring8577fec2012-12-02 21:00:27 -06001016 if (!cfg->default_label)
1017 cfg->default_label = strdup(label->name);
Jason Hobbs06283a62011-08-31 10:37:30 -05001018
1019 if (!cfg->default_label)
1020 return -ENOMEM;
1021
1022 break;
Rob Herring7815c4e2012-03-28 05:51:34 +00001023 case T_LABEL:
1024 parse_sliteral(c, &label->menu);
1025 break;
Jason Hobbs06283a62011-08-31 10:37:30 -05001026 default:
1027 printf("Ignoring malformed menu command: %.*s\n",
1028 (int)(*c - s), s);
1029 }
1030
1031 eol_or_eof(c);
1032
1033 return 0;
1034}
1035
1036/*
1037 * Parses a label and adds it to the list of labels for a menu.
1038 *
1039 * A label ends when we either get to the end of a file, or
1040 * get some input we otherwise don't have a handler defined
1041 * for.
1042 *
1043 */
1044static int parse_label(char **c, struct pxe_menu *cfg)
1045{
1046 struct token t;
Rob Herring34bd23e2012-03-28 05:51:37 +00001047 int len;
Jason Hobbs06283a62011-08-31 10:37:30 -05001048 char *s = *c;
1049 struct pxe_label *label;
1050 int err;
1051
1052 label = label_create();
1053 if (!label)
1054 return -ENOMEM;
1055
1056 err = parse_sliteral(c, &label->name);
1057 if (err < 0) {
1058 printf("Expected label name: %.*s\n", (int)(*c - s), s);
1059 label_destroy(label);
1060 return -EINVAL;
1061 }
1062
1063 list_add_tail(&label->list, &cfg->labels);
1064
1065 while (1) {
1066 s = *c;
1067 get_token(c, &t, L_KEYWORD);
1068
1069 err = 0;
1070 switch (t.type) {
1071 case T_MENU:
1072 err = parse_label_menu(c, cfg, label);
1073 break;
1074
1075 case T_KERNEL:
Rob Herringbeb9f6c2012-03-28 05:51:35 +00001076 case T_LINUX:
Jason Hobbs06283a62011-08-31 10:37:30 -05001077 err = parse_sliteral(c, &label->kernel);
1078 break;
1079
1080 case T_APPEND:
1081 err = parse_sliteral(c, &label->append);
Rob Herring34bd23e2012-03-28 05:51:37 +00001082 if (label->initrd)
1083 break;
1084 s = strstr(label->append, "initrd=");
1085 if (!s)
1086 break;
1087 s += 7;
1088 len = (int)(strchr(s, ' ') - s);
1089 label->initrd = malloc(len + 1);
1090 strncpy(label->initrd, s, len);
1091 label->initrd[len] = '\0';
1092
Jason Hobbs06283a62011-08-31 10:37:30 -05001093 break;
1094
1095 case T_INITRD:
Rob Herring34bd23e2012-03-28 05:51:37 +00001096 if (!label->initrd)
1097 err = parse_sliteral(c, &label->initrd);
Jason Hobbs06283a62011-08-31 10:37:30 -05001098 break;
1099
Chander Kashyapa6559382012-09-06 19:36:31 +00001100 case T_FDT:
1101 if (!label->fdt)
1102 err = parse_sliteral(c, &label->fdt);
1103 break;
1104
Jason Hobbs06283a62011-08-31 10:37:30 -05001105 case T_LOCALBOOT:
Rob Herring500f3042012-12-02 21:00:22 -06001106 label->localboot = 1;
1107 err = parse_integer(c, &label->localboot_val);
Jason Hobbs06283a62011-08-31 10:37:30 -05001108 break;
1109
1110 case T_EOL:
1111 break;
1112
1113 default:
1114 /*
1115 * put the token back! we don't want it - it's the end
1116 * of a label and whatever token this is, it's
1117 * something for the menu level context to handle.
1118 */
1119 *c = s;
1120 return 1;
1121 }
1122
1123 if (err < 0)
1124 return err;
1125 }
1126}
1127
1128/*
1129 * This 16 comes from the limit pxelinux imposes on nested includes.
1130 *
1131 * There is no reason at all we couldn't do more, but some limit helps prevent
1132 * infinite (until crash occurs) recursion if a file tries to include itself.
1133 */
1134#define MAX_NEST_LEVEL 16
1135
1136/*
1137 * Entry point for parsing a menu file. nest_level indicates how many times
1138 * we've nested in includes. It will be 1 for the top level menu file.
1139 *
1140 * Returns 1 on success, < 0 on error.
1141 */
1142static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level)
1143{
1144 struct token t;
1145 char *s, *b, *label_name;
1146 int err;
1147
1148 b = p;
1149
1150 if (nest_level > MAX_NEST_LEVEL) {
1151 printf("Maximum nesting (%d) exceeded\n", MAX_NEST_LEVEL);
1152 return -EMLINK;
1153 }
1154
1155 while (1) {
1156 s = p;
1157
1158 get_token(&p, &t, L_KEYWORD);
1159
1160 err = 0;
1161 switch (t.type) {
1162 case T_MENU:
Rob Herringe82eeb52012-12-02 21:00:25 -06001163 cfg->prompt = 1;
Jason Hobbs06283a62011-08-31 10:37:30 -05001164 err = parse_menu(&p, cfg, b, nest_level);
1165 break;
1166
1167 case T_TIMEOUT:
1168 err = parse_integer(&p, &cfg->timeout);
1169 break;
1170
1171 case T_LABEL:
1172 err = parse_label(&p, cfg);
1173 break;
1174
1175 case T_DEFAULT:
Rob Herring8577fec2012-12-02 21:00:27 -06001176 case T_ONTIMEOUT:
Jason Hobbs06283a62011-08-31 10:37:30 -05001177 err = parse_sliteral(&p, &label_name);
1178
1179 if (label_name) {
1180 if (cfg->default_label)
1181 free(cfg->default_label);
1182
1183 cfg->default_label = label_name;
1184 }
1185
1186 break;
1187
Rob Herring1e085222012-05-25 10:43:16 +00001188 case T_INCLUDE:
1189 err = handle_include(&p, b + ALIGN(strlen(b), 4), cfg,
1190 nest_level + 1);
1191 break;
1192
Jason Hobbs06283a62011-08-31 10:37:30 -05001193 case T_PROMPT:
Rob Herringe82eeb52012-12-02 21:00:25 -06001194 eol_or_eof(&p);
Jason Hobbs06283a62011-08-31 10:37:30 -05001195 break;
1196
1197 case T_EOL:
1198 break;
1199
1200 case T_EOF:
1201 return 1;
1202
1203 default:
1204 printf("Ignoring unknown command: %.*s\n",
1205 (int)(p - s), s);
1206 eol_or_eof(&p);
1207 }
1208
1209 if (err < 0)
1210 return err;
1211 }
1212}
1213
1214/*
1215 * Free the memory used by a pxe_menu and its labels.
1216 */
1217static void destroy_pxe_menu(struct pxe_menu *cfg)
1218{
1219 struct list_head *pos, *n;
1220 struct pxe_label *label;
1221
1222 if (cfg->title)
1223 free(cfg->title);
1224
1225 if (cfg->default_label)
1226 free(cfg->default_label);
1227
1228 list_for_each_safe(pos, n, &cfg->labels) {
1229 label = list_entry(pos, struct pxe_label, list);
1230
1231 label_destroy(label);
1232 }
1233
1234 free(cfg);
1235}
1236
1237/*
1238 * Entry point for parsing a pxe file. This is only used for the top level
1239 * file.
1240 *
1241 * Returns NULL if there is an error, otherwise, returns a pointer to a
1242 * pxe_menu struct populated with the results of parsing the pxe file (and any
1243 * files it includes). The resulting pxe_menu struct can be free()'d by using
1244 * the destroy_pxe_menu() function.
1245 */
1246static struct pxe_menu *parse_pxefile(char *menucfg)
1247{
1248 struct pxe_menu *cfg;
1249
1250 cfg = malloc(sizeof(struct pxe_menu));
1251
1252 if (!cfg)
1253 return NULL;
1254
1255 memset(cfg, 0, sizeof(struct pxe_menu));
1256
1257 INIT_LIST_HEAD(&cfg->labels);
1258
1259 if (parse_pxefile_top(menucfg, cfg, 1) < 0) {
1260 destroy_pxe_menu(cfg);
1261 return NULL;
1262 }
1263
1264 return cfg;
1265}
1266
1267/*
1268 * Converts a pxe_menu struct into a menu struct for use with U-boot's generic
1269 * menu code.
1270 */
1271static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
1272{
1273 struct pxe_label *label;
1274 struct list_head *pos;
1275 struct menu *m;
1276 int err;
Rob Herring32d2ffe2012-12-02 21:00:26 -06001277 int i = 1;
1278 char *default_num = NULL;
Jason Hobbs06283a62011-08-31 10:37:30 -05001279
1280 /*
1281 * Create a menu and add items for all the labels.
1282 */
Pali Rohárfc9d64f2013-03-23 14:50:40 +00001283 m = menu_create(cfg->title, cfg->timeout, cfg->prompt, label_print,
1284 NULL, NULL);
Jason Hobbs06283a62011-08-31 10:37:30 -05001285
1286 if (!m)
1287 return NULL;
1288
1289 list_for_each(pos, &cfg->labels) {
1290 label = list_entry(pos, struct pxe_label, list);
1291
Rob Herring32d2ffe2012-12-02 21:00:26 -06001292 sprintf(label->num, "%d", i++);
1293 if (menu_item_add(m, label->num, label) != 1) {
Jason Hobbs06283a62011-08-31 10:37:30 -05001294 menu_destroy(m);
1295 return NULL;
1296 }
Rob Herring32d2ffe2012-12-02 21:00:26 -06001297 if (cfg->default_label &&
Rob Herring8577fec2012-12-02 21:00:27 -06001298 (strcmp(label->name, cfg->default_label) == 0))
Rob Herring32d2ffe2012-12-02 21:00:26 -06001299 default_num = label->num;
1300
Jason Hobbs06283a62011-08-31 10:37:30 -05001301 }
1302
1303 /*
1304 * After we've created items for each label in the menu, set the
1305 * menu's default label if one was specified.
1306 */
Rob Herring32d2ffe2012-12-02 21:00:26 -06001307 if (default_num) {
1308 err = menu_default_set(m, default_num);
Jason Hobbs06283a62011-08-31 10:37:30 -05001309 if (err != 1) {
1310 if (err != -ENOENT) {
1311 menu_destroy(m);
1312 return NULL;
1313 }
1314
1315 printf("Missing default: %s\n", cfg->default_label);
1316 }
1317 }
1318
1319 return m;
1320}
1321
1322/*
1323 * Try to boot any labels we have yet to attempt to boot.
1324 */
1325static void boot_unattempted_labels(struct pxe_menu *cfg)
1326{
1327 struct list_head *pos;
1328 struct pxe_label *label;
1329
1330 list_for_each(pos, &cfg->labels) {
1331 label = list_entry(pos, struct pxe_label, list);
1332
1333 if (!label->attempted)
1334 label_boot(label);
1335 }
1336}
1337
1338/*
1339 * Boot the system as prescribed by a pxe_menu.
1340 *
1341 * Use the menu system to either get the user's choice or the default, based
1342 * on config or user input. If there is no default or user's choice,
1343 * attempted to boot labels in the order they were given in pxe files.
1344 * If the default or user's choice fails to boot, attempt to boot other
1345 * labels in the order they were given in pxe files.
1346 *
1347 * If this function returns, there weren't any labels that successfully
1348 * booted, or the user interrupted the menu selection via ctrl+c.
1349 */
1350static void handle_pxe_menu(struct pxe_menu *cfg)
1351{
1352 void *choice;
1353 struct menu *m;
1354 int err;
1355
1356 m = pxe_menu_to_menu(cfg);
1357 if (!m)
1358 return;
1359
1360 err = menu_get_choice(m, &choice);
1361
1362 menu_destroy(m);
1363
Jason Hobbs6f40f272011-11-07 03:07:15 +00001364 /*
1365 * err == 1 means we got a choice back from menu_get_choice.
1366 *
1367 * err == -ENOENT if the menu was setup to select the default but no
1368 * default was set. in that case, we should continue trying to boot
1369 * labels that haven't been attempted yet.
1370 *
1371 * otherwise, the user interrupted or there was some other error and
1372 * we give up.
1373 */
Jason Hobbs06283a62011-08-31 10:37:30 -05001374
Rob Herring500f3042012-12-02 21:00:22 -06001375 if (err == 1) {
1376 err = label_boot(choice);
1377 if (!err)
1378 return;
1379 } else if (err != -ENOENT) {
Jason Hobbs6f40f272011-11-07 03:07:15 +00001380 return;
Rob Herring500f3042012-12-02 21:00:22 -06001381 }
Jason Hobbs06283a62011-08-31 10:37:30 -05001382
1383 boot_unattempted_labels(cfg);
1384}
1385
1386/*
1387 * Boots a system using a pxe file
1388 *
1389 * Returns 0 on success, 1 on error.
1390 */
1391static int
1392do_pxe_boot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1393{
1394 unsigned long pxefile_addr_r;
1395 struct pxe_menu *cfg;
1396 char *pxefile_addr_str;
1397
Rob Herring669df7e2012-05-25 10:47:39 +00001398 do_getfile = do_get_tftp;
1399
Jason Hobbs06283a62011-08-31 10:37:30 -05001400 if (argc == 1) {
1401 pxefile_addr_str = from_env("pxefile_addr_r");
1402 if (!pxefile_addr_str)
1403 return 1;
1404
1405 } else if (argc == 2) {
1406 pxefile_addr_str = argv[1];
1407 } else {
Simon Glass4c12eeb2011-12-10 08:44:01 +00001408 return CMD_RET_USAGE;
Jason Hobbs06283a62011-08-31 10:37:30 -05001409 }
1410
1411 if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) {
1412 printf("Invalid pxefile address: %s\n", pxefile_addr_str);
1413 return 1;
1414 }
1415
1416 cfg = parse_pxefile((char *)(pxefile_addr_r));
1417
1418 if (cfg == NULL) {
1419 printf("Error parsing config file\n");
1420 return 1;
1421 }
1422
1423 handle_pxe_menu(cfg);
1424
1425 destroy_pxe_menu(cfg);
1426
1427 return 0;
1428}
1429
1430static cmd_tbl_t cmd_pxe_sub[] = {
1431 U_BOOT_CMD_MKENT(get, 1, 1, do_pxe_get, "", ""),
1432 U_BOOT_CMD_MKENT(boot, 2, 1, do_pxe_boot, "", "")
1433};
1434
1435int do_pxe(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1436{
1437 cmd_tbl_t *cp;
1438
1439 if (argc < 2)
Simon Glass4c12eeb2011-12-10 08:44:01 +00001440 return CMD_RET_USAGE;
Jason Hobbs06283a62011-08-31 10:37:30 -05001441
1442 /* drop initial "pxe" arg */
1443 argc--;
1444 argv++;
1445
1446 cp = find_cmd_tbl(argv[0], cmd_pxe_sub, ARRAY_SIZE(cmd_pxe_sub));
1447
1448 if (cp)
1449 return cp->cmd(cmdtp, flag, argc, argv);
1450
Simon Glass4c12eeb2011-12-10 08:44:01 +00001451 return CMD_RET_USAGE;
Jason Hobbs06283a62011-08-31 10:37:30 -05001452}
1453
1454U_BOOT_CMD(
1455 pxe, 3, 1, do_pxe,
1456 "commands to get and boot from pxe files",
1457 "get - try to retrieve a pxe file using tftp\npxe "
1458 "boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n"
1459);
Rob Herring669df7e2012-05-25 10:47:39 +00001460
1461/*
1462 * Boots a system using a local disk syslinux/extlinux file
1463 *
1464 * Returns 0 on success, 1 on error.
1465 */
1466int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1467{
1468 unsigned long pxefile_addr_r;
1469 struct pxe_menu *cfg;
1470 char *pxefile_addr_str;
1471 char *filename;
1472 int prompt = 0;
1473
1474 if (strstr(argv[1], "-p")) {
1475 prompt = 1;
1476 argc--;
1477 argv++;
1478 }
1479
1480 if (argc < 4)
1481 return cmd_usage(cmdtp);
1482
1483 if (argc < 5) {
1484 pxefile_addr_str = from_env("pxefile_addr_r");
1485 if (!pxefile_addr_str)
1486 return 1;
1487 } else {
1488 pxefile_addr_str = argv[4];
1489 }
1490
1491 if (argc < 6)
1492 filename = getenv("bootfile");
1493 else {
1494 filename = argv[5];
1495 setenv("bootfile", filename);
1496 }
1497
1498 if (strstr(argv[3], "ext2"))
1499 do_getfile = do_get_ext2;
1500 else if (strstr(argv[3], "fat"))
1501 do_getfile = do_get_fat;
1502 else {
1503 printf("Invalid filesystem: %s\n", argv[3]);
1504 return 1;
1505 }
1506 fs_argv[1] = argv[1];
1507 fs_argv[2] = argv[2];
1508
1509 if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) {
1510 printf("Invalid pxefile address: %s\n", pxefile_addr_str);
1511 return 1;
1512 }
1513
1514 if (get_pxe_file(filename, (void *)pxefile_addr_r) < 0) {
1515 printf("Error reading config file\n");
1516 return 1;
1517 }
1518
1519 cfg = parse_pxefile((char *)(pxefile_addr_r));
1520
1521 if (cfg == NULL) {
1522 printf("Error parsing config file\n");
1523 return 1;
1524 }
1525
1526 if (prompt)
1527 cfg->prompt = 1;
1528
1529 handle_pxe_menu(cfg);
1530
1531 destroy_pxe_menu(cfg);
1532
1533 return 0;
1534}
1535
1536U_BOOT_CMD(
1537 sysboot, 7, 1, do_sysboot,
1538 "command to get and boot from syslinux files",
1539 "[-p] <interface> <dev[:part]> <ext2|fat> [addr] [filename]\n"
1540 " - load and parse syslinux menu file 'filename' from ext2 or fat\n"
1541 " filesystem on 'dev' on 'interface' to address 'addr'"
1542);