12e192b24SSimon Glass /*
22e192b24SSimon Glass * Copyright 2010-2011 Calxeda, Inc.
32e192b24SSimon Glass * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
42e192b24SSimon Glass *
52e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+
62e192b24SSimon Glass */
72e192b24SSimon Glass
82e192b24SSimon Glass #include <common.h>
92e192b24SSimon Glass #include <command.h>
102e192b24SSimon Glass #include <malloc.h>
112e192b24SSimon Glass #include <mapmem.h>
122e192b24SSimon Glass #include <linux/string.h>
132e192b24SSimon Glass #include <linux/ctype.h>
142e192b24SSimon Glass #include <errno.h>
152e192b24SSimon Glass #include <linux/list.h>
162e192b24SSimon Glass #include <fs.h>
172e192b24SSimon Glass #include <asm/io.h>
182e192b24SSimon Glass
192e192b24SSimon Glass #include "menu.h"
202e192b24SSimon Glass #include "cli.h"
212e192b24SSimon Glass
222e192b24SSimon Glass #define MAX_TFTP_PATH_LEN 127
232e192b24SSimon Glass
242e192b24SSimon Glass const char *pxe_default_paths[] = {
252e192b24SSimon Glass #ifdef CONFIG_SYS_SOC
262e192b24SSimon Glass "default-" CONFIG_SYS_ARCH "-" CONFIG_SYS_SOC,
272e192b24SSimon Glass #endif
282e192b24SSimon Glass "default-" CONFIG_SYS_ARCH,
292e192b24SSimon Glass "default",
302e192b24SSimon Glass NULL
312e192b24SSimon Glass };
322e192b24SSimon Glass
332e192b24SSimon Glass static bool is_pxe;
342e192b24SSimon Glass
352e192b24SSimon Glass /*
3600caae6dSSimon Glass * Like env_get, but prints an error if envvar isn't defined in the
3700caae6dSSimon Glass * environment. It always returns what env_get does, so it can be used in
3800caae6dSSimon Glass * place of env_get without changing error handling otherwise.
392e192b24SSimon Glass */
from_env(const char * envvar)402e192b24SSimon Glass static char *from_env(const char *envvar)
412e192b24SSimon Glass {
422e192b24SSimon Glass char *ret;
432e192b24SSimon Glass
4400caae6dSSimon Glass ret = env_get(envvar);
452e192b24SSimon Glass
462e192b24SSimon Glass if (!ret)
472e192b24SSimon Glass printf("missing environment variable: %s\n", envvar);
482e192b24SSimon Glass
492e192b24SSimon Glass return ret;
502e192b24SSimon Glass }
512e192b24SSimon Glass
522e192b24SSimon Glass #ifdef CONFIG_CMD_NET
532e192b24SSimon Glass /*
542e192b24SSimon Glass * Convert an ethaddr from the environment to the format used by pxelinux
552e192b24SSimon Glass * filenames based on mac addresses. Convert's ':' to '-', and adds "01-" to
562e192b24SSimon Glass * the beginning of the ethernet address to indicate a hardware type of
572e192b24SSimon Glass * Ethernet. Also converts uppercase hex characters into lowercase, to match
582e192b24SSimon Glass * pxelinux's behavior.
592e192b24SSimon Glass *
602e192b24SSimon Glass * Returns 1 for success, -ENOENT if 'ethaddr' is undefined in the
612e192b24SSimon Glass * environment, or some other value < 0 on error.
622e192b24SSimon Glass */
format_mac_pxe(char * outbuf,size_t outbuf_len)632e192b24SSimon Glass static int format_mac_pxe(char *outbuf, size_t outbuf_len)
642e192b24SSimon Glass {
652e192b24SSimon Glass uchar ethaddr[6];
662e192b24SSimon Glass
672e192b24SSimon Glass if (outbuf_len < 21) {
682e192b24SSimon Glass printf("outbuf is too small (%zd < 21)\n", outbuf_len);
692e192b24SSimon Glass
702e192b24SSimon Glass return -EINVAL;
712e192b24SSimon Glass }
722e192b24SSimon Glass
7335affd7aSSimon Glass if (!eth_env_get_enetaddr_by_index("eth", eth_get_dev_index(), ethaddr))
742e192b24SSimon Glass return -ENOENT;
752e192b24SSimon Glass
762e192b24SSimon Glass sprintf(outbuf, "01-%02x-%02x-%02x-%02x-%02x-%02x",
772e192b24SSimon Glass ethaddr[0], ethaddr[1], ethaddr[2],
782e192b24SSimon Glass ethaddr[3], ethaddr[4], ethaddr[5]);
792e192b24SSimon Glass
802e192b24SSimon Glass return 1;
812e192b24SSimon Glass }
822e192b24SSimon Glass #endif
832e192b24SSimon Glass
842e192b24SSimon Glass /*
852e192b24SSimon Glass * Returns the directory the file specified in the bootfile env variable is
862e192b24SSimon Glass * in. If bootfile isn't defined in the environment, return NULL, which should
872e192b24SSimon Glass * be interpreted as "don't prepend anything to paths".
882e192b24SSimon Glass */
get_bootfile_path(const char * file_path,char * bootfile_path,size_t bootfile_path_size)892e192b24SSimon Glass static int get_bootfile_path(const char *file_path, char *bootfile_path,
902e192b24SSimon Glass size_t bootfile_path_size)
912e192b24SSimon Glass {
922e192b24SSimon Glass char *bootfile, *last_slash;
932e192b24SSimon Glass size_t path_len = 0;
942e192b24SSimon Glass
952e192b24SSimon Glass /* Only syslinux allows absolute paths */
962e192b24SSimon Glass if (file_path[0] == '/' && !is_pxe)
972e192b24SSimon Glass goto ret;
982e192b24SSimon Glass
992e192b24SSimon Glass bootfile = from_env("bootfile");
1002e192b24SSimon Glass
1012e192b24SSimon Glass if (!bootfile)
1022e192b24SSimon Glass goto ret;
1032e192b24SSimon Glass
1042e192b24SSimon Glass last_slash = strrchr(bootfile, '/');
1052e192b24SSimon Glass
1062e192b24SSimon Glass if (last_slash == NULL)
1072e192b24SSimon Glass goto ret;
1082e192b24SSimon Glass
1092e192b24SSimon Glass path_len = (last_slash - bootfile) + 1;
1102e192b24SSimon Glass
1112e192b24SSimon Glass if (bootfile_path_size < path_len) {
1122e192b24SSimon Glass printf("bootfile_path too small. (%zd < %zd)\n",
1132e192b24SSimon Glass bootfile_path_size, path_len);
1142e192b24SSimon Glass
1152e192b24SSimon Glass return -1;
1162e192b24SSimon Glass }
1172e192b24SSimon Glass
1182e192b24SSimon Glass strncpy(bootfile_path, bootfile, path_len);
1192e192b24SSimon Glass
1202e192b24SSimon Glass ret:
1212e192b24SSimon Glass bootfile_path[path_len] = '\0';
1222e192b24SSimon Glass
1232e192b24SSimon Glass return 1;
1242e192b24SSimon Glass }
1252e192b24SSimon Glass
1262e192b24SSimon Glass static int (*do_getfile)(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr);
1272e192b24SSimon Glass
1282e192b24SSimon Glass #ifdef CONFIG_CMD_NET
do_get_tftp(cmd_tbl_t * cmdtp,const char * file_path,char * file_addr)1292e192b24SSimon Glass static int do_get_tftp(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
1302e192b24SSimon Glass {
1312e192b24SSimon Glass char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
1322e192b24SSimon Glass
1332e192b24SSimon Glass tftp_argv[1] = file_addr;
1342e192b24SSimon Glass tftp_argv[2] = (void *)file_path;
1352e192b24SSimon Glass
1362e192b24SSimon Glass if (do_tftpb(cmdtp, 0, 3, tftp_argv))
1372e192b24SSimon Glass return -ENOENT;
1382e192b24SSimon Glass
1392e192b24SSimon Glass return 1;
1402e192b24SSimon Glass }
1412e192b24SSimon Glass #endif
1422e192b24SSimon Glass
1432e192b24SSimon Glass static char *fs_argv[5];
1442e192b24SSimon Glass
do_get_ext2(cmd_tbl_t * cmdtp,const char * file_path,char * file_addr)1452e192b24SSimon Glass static int do_get_ext2(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
1462e192b24SSimon Glass {
1472e192b24SSimon Glass #ifdef CONFIG_CMD_EXT2
1482e192b24SSimon Glass fs_argv[0] = "ext2load";
1492e192b24SSimon Glass fs_argv[3] = file_addr;
1502e192b24SSimon Glass fs_argv[4] = (void *)file_path;
1512e192b24SSimon Glass
1522e192b24SSimon Glass if (!do_ext2load(cmdtp, 0, 5, fs_argv))
1532e192b24SSimon Glass return 1;
1542e192b24SSimon Glass #endif
1552e192b24SSimon Glass return -ENOENT;
1562e192b24SSimon Glass }
1572e192b24SSimon Glass
do_get_fat(cmd_tbl_t * cmdtp,const char * file_path,char * file_addr)1582e192b24SSimon Glass static int do_get_fat(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
1592e192b24SSimon Glass {
1602e192b24SSimon Glass #ifdef CONFIG_CMD_FAT
1612e192b24SSimon Glass fs_argv[0] = "fatload";
1622e192b24SSimon Glass fs_argv[3] = file_addr;
1632e192b24SSimon Glass fs_argv[4] = (void *)file_path;
1642e192b24SSimon Glass
1652e192b24SSimon Glass if (!do_fat_fsload(cmdtp, 0, 5, fs_argv))
1662e192b24SSimon Glass return 1;
1672e192b24SSimon Glass #endif
1682e192b24SSimon Glass return -ENOENT;
1692e192b24SSimon Glass }
1702e192b24SSimon Glass
do_get_any(cmd_tbl_t * cmdtp,const char * file_path,char * file_addr)1712e192b24SSimon Glass static int do_get_any(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
1722e192b24SSimon Glass {
1732e192b24SSimon Glass #ifdef CONFIG_CMD_FS_GENERIC
1742e192b24SSimon Glass fs_argv[0] = "load";
1752e192b24SSimon Glass fs_argv[3] = file_addr;
1762e192b24SSimon Glass fs_argv[4] = (void *)file_path;
1772e192b24SSimon Glass
1782e192b24SSimon Glass if (!do_load(cmdtp, 0, 5, fs_argv, FS_TYPE_ANY))
1792e192b24SSimon Glass return 1;
1802e192b24SSimon Glass #endif
1812e192b24SSimon Glass return -ENOENT;
1822e192b24SSimon Glass }
1832e192b24SSimon Glass
1842e192b24SSimon Glass /*
1852e192b24SSimon Glass * As in pxelinux, paths to files referenced from files we retrieve are
1862e192b24SSimon Glass * relative to the location of bootfile. get_relfile takes such a path and
1872e192b24SSimon Glass * joins it with the bootfile path to get the full path to the target file. If
1882e192b24SSimon Glass * the bootfile path is NULL, we use file_path as is.
1892e192b24SSimon Glass *
1902e192b24SSimon Glass * Returns 1 for success, or < 0 on error.
1912e192b24SSimon Glass */
get_relfile(cmd_tbl_t * cmdtp,const char * file_path,unsigned long file_addr)1922e192b24SSimon Glass static int get_relfile(cmd_tbl_t *cmdtp, const char *file_path,
1932e192b24SSimon Glass unsigned long file_addr)
1942e192b24SSimon Glass {
1952e192b24SSimon Glass size_t path_len;
1962e192b24SSimon Glass char relfile[MAX_TFTP_PATH_LEN+1];
1972e192b24SSimon Glass char addr_buf[18];
1982e192b24SSimon Glass int err;
1992e192b24SSimon Glass
2002e192b24SSimon Glass err = get_bootfile_path(file_path, relfile, sizeof(relfile));
2012e192b24SSimon Glass
2022e192b24SSimon Glass if (err < 0)
2032e192b24SSimon Glass return err;
2042e192b24SSimon Glass
2052e192b24SSimon Glass path_len = strlen(file_path);
2062e192b24SSimon Glass path_len += strlen(relfile);
2072e192b24SSimon Glass
2082e192b24SSimon Glass if (path_len > MAX_TFTP_PATH_LEN) {
2092e192b24SSimon Glass printf("Base path too long (%s%s)\n",
2102e192b24SSimon Glass relfile,
2112e192b24SSimon Glass file_path);
2122e192b24SSimon Glass
2132e192b24SSimon Glass return -ENAMETOOLONG;
2142e192b24SSimon Glass }
2152e192b24SSimon Glass
2162e192b24SSimon Glass strcat(relfile, file_path);
2172e192b24SSimon Glass
2182e192b24SSimon Glass printf("Retrieving file: %s\n", relfile);
2192e192b24SSimon Glass
2202e192b24SSimon Glass sprintf(addr_buf, "%lx", file_addr);
2212e192b24SSimon Glass
2222e192b24SSimon Glass return do_getfile(cmdtp, relfile, addr_buf);
2232e192b24SSimon Glass }
2242e192b24SSimon Glass
2252e192b24SSimon Glass /*
2262e192b24SSimon Glass * Retrieve the file at 'file_path' to the locate given by 'file_addr'. If
2272e192b24SSimon Glass * 'bootfile' was specified in the environment, the path to bootfile will be
2282e192b24SSimon Glass * prepended to 'file_path' and the resulting path will be used.
2292e192b24SSimon Glass *
2302e192b24SSimon Glass * Returns 1 on success, or < 0 for error.
2312e192b24SSimon Glass */
get_pxe_file(cmd_tbl_t * cmdtp,const char * file_path,unsigned long file_addr)2322e192b24SSimon Glass static int get_pxe_file(cmd_tbl_t *cmdtp, const char *file_path,
2332e192b24SSimon Glass unsigned long file_addr)
2342e192b24SSimon Glass {
2352e192b24SSimon Glass unsigned long config_file_size;
2362e192b24SSimon Glass char *tftp_filesize;
2372e192b24SSimon Glass int err;
2382e192b24SSimon Glass char *buf;
2392e192b24SSimon Glass
2402e192b24SSimon Glass err = get_relfile(cmdtp, file_path, file_addr);
2412e192b24SSimon Glass
2422e192b24SSimon Glass if (err < 0)
2432e192b24SSimon Glass return err;
2442e192b24SSimon Glass
2452e192b24SSimon Glass /*
2462e192b24SSimon Glass * the file comes without a NUL byte at the end, so find out its size
2472e192b24SSimon Glass * and add the NUL byte.
2482e192b24SSimon Glass */
2492e192b24SSimon Glass tftp_filesize = from_env("filesize");
2502e192b24SSimon Glass
2512e192b24SSimon Glass if (!tftp_filesize)
2522e192b24SSimon Glass return -ENOENT;
2532e192b24SSimon Glass
2542e192b24SSimon Glass if (strict_strtoul(tftp_filesize, 16, &config_file_size) < 0)
2552e192b24SSimon Glass return -EINVAL;
2562e192b24SSimon Glass
2572e192b24SSimon Glass buf = map_sysmem(file_addr + config_file_size, 1);
2582e192b24SSimon Glass *buf = '\0';
2592e192b24SSimon Glass unmap_sysmem(buf);
2602e192b24SSimon Glass
2612e192b24SSimon Glass return 1;
2622e192b24SSimon Glass }
2632e192b24SSimon Glass
2642e192b24SSimon Glass #ifdef CONFIG_CMD_NET
2652e192b24SSimon Glass
2662e192b24SSimon Glass #define PXELINUX_DIR "pxelinux.cfg/"
2672e192b24SSimon Glass
2682e192b24SSimon Glass /*
2692e192b24SSimon Glass * Retrieves a file in the 'pxelinux.cfg' folder. Since this uses get_pxe_file
2702e192b24SSimon Glass * to do the hard work, the location of the 'pxelinux.cfg' folder is generated
2712e192b24SSimon Glass * from the bootfile path, as described above.
2722e192b24SSimon Glass *
2732e192b24SSimon Glass * Returns 1 on success or < 0 on error.
2742e192b24SSimon Glass */
get_pxelinux_path(cmd_tbl_t * cmdtp,const char * file,unsigned long pxefile_addr_r)2752e192b24SSimon Glass static int get_pxelinux_path(cmd_tbl_t *cmdtp, const char *file,
2762e192b24SSimon Glass unsigned long pxefile_addr_r)
2772e192b24SSimon Glass {
2782e192b24SSimon Glass size_t base_len = strlen(PXELINUX_DIR);
2792e192b24SSimon Glass char path[MAX_TFTP_PATH_LEN+1];
2802e192b24SSimon Glass
2812e192b24SSimon Glass if (base_len + strlen(file) > MAX_TFTP_PATH_LEN) {
2822e192b24SSimon Glass printf("path (%s%s) too long, skipping\n",
2832e192b24SSimon Glass PXELINUX_DIR, file);
2842e192b24SSimon Glass return -ENAMETOOLONG;
2852e192b24SSimon Glass }
2862e192b24SSimon Glass
2872e192b24SSimon Glass sprintf(path, PXELINUX_DIR "%s", file);
2882e192b24SSimon Glass
2892e192b24SSimon Glass return get_pxe_file(cmdtp, path, pxefile_addr_r);
2902e192b24SSimon Glass }
2912e192b24SSimon Glass
2922e192b24SSimon Glass /*
2932e192b24SSimon Glass * Looks for a pxe file with a name based on the pxeuuid environment variable.
2942e192b24SSimon Glass *
2952e192b24SSimon Glass * Returns 1 on success or < 0 on error.
2962e192b24SSimon Glass */
pxe_uuid_path(cmd_tbl_t * cmdtp,unsigned long pxefile_addr_r)2972e192b24SSimon Glass static int pxe_uuid_path(cmd_tbl_t *cmdtp, unsigned long pxefile_addr_r)
2982e192b24SSimon Glass {
2992e192b24SSimon Glass char *uuid_str;
3002e192b24SSimon Glass
3012e192b24SSimon Glass uuid_str = from_env("pxeuuid");
3022e192b24SSimon Glass
3032e192b24SSimon Glass if (!uuid_str)
3042e192b24SSimon Glass return -ENOENT;
3052e192b24SSimon Glass
3062e192b24SSimon Glass return get_pxelinux_path(cmdtp, uuid_str, pxefile_addr_r);
3072e192b24SSimon Glass }
3082e192b24SSimon Glass
3092e192b24SSimon Glass /*
3102e192b24SSimon Glass * Looks for a pxe file with a name based on the 'ethaddr' environment
3112e192b24SSimon Glass * variable.
3122e192b24SSimon Glass *
3132e192b24SSimon Glass * Returns 1 on success or < 0 on error.
3142e192b24SSimon Glass */
pxe_mac_path(cmd_tbl_t * cmdtp,unsigned long pxefile_addr_r)3152e192b24SSimon Glass static int pxe_mac_path(cmd_tbl_t *cmdtp, unsigned long pxefile_addr_r)
3162e192b24SSimon Glass {
3172e192b24SSimon Glass char mac_str[21];
3182e192b24SSimon Glass int err;
3192e192b24SSimon Glass
3202e192b24SSimon Glass err = format_mac_pxe(mac_str, sizeof(mac_str));
3212e192b24SSimon Glass
3222e192b24SSimon Glass if (err < 0)
3232e192b24SSimon Glass return err;
3242e192b24SSimon Glass
3252e192b24SSimon Glass return get_pxelinux_path(cmdtp, mac_str, pxefile_addr_r);
3262e192b24SSimon Glass }
3272e192b24SSimon Glass
3282e192b24SSimon Glass /*
3292e192b24SSimon Glass * Looks for pxe files with names based on our IP address. See pxelinux
3302e192b24SSimon Glass * documentation for details on what these file names look like. We match
3312e192b24SSimon Glass * that exactly.
3322e192b24SSimon Glass *
3332e192b24SSimon Glass * Returns 1 on success or < 0 on error.
3342e192b24SSimon Glass */
pxe_ipaddr_paths(cmd_tbl_t * cmdtp,unsigned long pxefile_addr_r)3352e192b24SSimon Glass static int pxe_ipaddr_paths(cmd_tbl_t *cmdtp, unsigned long pxefile_addr_r)
3362e192b24SSimon Glass {
3372e192b24SSimon Glass char ip_addr[9];
3382e192b24SSimon Glass int mask_pos, err;
3392e192b24SSimon Glass
3402e192b24SSimon Glass sprintf(ip_addr, "%08X", ntohl(net_ip.s_addr));
3412e192b24SSimon Glass
3422e192b24SSimon Glass for (mask_pos = 7; mask_pos >= 0; mask_pos--) {
3432e192b24SSimon Glass err = get_pxelinux_path(cmdtp, ip_addr, pxefile_addr_r);
3442e192b24SSimon Glass
3452e192b24SSimon Glass if (err > 0)
3462e192b24SSimon Glass return err;
3472e192b24SSimon Glass
3482e192b24SSimon Glass ip_addr[mask_pos] = '\0';
3492e192b24SSimon Glass }
3502e192b24SSimon Glass
3512e192b24SSimon Glass return -ENOENT;
3522e192b24SSimon Glass }
3532e192b24SSimon Glass
3542e192b24SSimon Glass /*
3552e192b24SSimon Glass * Entry point for the 'pxe get' command.
3562e192b24SSimon Glass * This Follows pxelinux's rules to download a config file from a tftp server.
3572e192b24SSimon Glass * The file is stored at the location given by the pxefile_addr_r environment
3582e192b24SSimon Glass * variable, which must be set.
3592e192b24SSimon Glass *
3602e192b24SSimon Glass * UUID comes from pxeuuid env variable, if defined
3612e192b24SSimon Glass * MAC addr comes from ethaddr env variable, if defined
3622e192b24SSimon Glass * IP
3632e192b24SSimon Glass *
3642e192b24SSimon Glass * see http://syslinux.zytor.com/wiki/index.php/PXELINUX
3652e192b24SSimon Glass *
3662e192b24SSimon Glass * Returns 0 on success or 1 on error.
3672e192b24SSimon Glass */
3682e192b24SSimon Glass static int
do_pxe_get(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])3692e192b24SSimon Glass do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
3702e192b24SSimon Glass {
3712e192b24SSimon Glass char *pxefile_addr_str;
3722e192b24SSimon Glass unsigned long pxefile_addr_r;
3732e192b24SSimon Glass int err, i = 0;
3742e192b24SSimon Glass
3752e192b24SSimon Glass do_getfile = do_get_tftp;
3762e192b24SSimon Glass
3772e192b24SSimon Glass if (argc != 1)
3782e192b24SSimon Glass return CMD_RET_USAGE;
3792e192b24SSimon Glass
3802e192b24SSimon Glass pxefile_addr_str = from_env("pxefile_addr_r");
3812e192b24SSimon Glass
3822e192b24SSimon Glass if (!pxefile_addr_str)
3832e192b24SSimon Glass return 1;
3842e192b24SSimon Glass
3852e192b24SSimon Glass err = strict_strtoul(pxefile_addr_str, 16,
3862e192b24SSimon Glass (unsigned long *)&pxefile_addr_r);
3872e192b24SSimon Glass if (err < 0)
3882e192b24SSimon Glass return 1;
3892e192b24SSimon Glass
3902e192b24SSimon Glass /*
3912e192b24SSimon Glass * Keep trying paths until we successfully get a file we're looking
3922e192b24SSimon Glass * for.
3932e192b24SSimon Glass */
3942e192b24SSimon Glass if (pxe_uuid_path(cmdtp, pxefile_addr_r) > 0 ||
3952e192b24SSimon Glass pxe_mac_path(cmdtp, pxefile_addr_r) > 0 ||
3962e192b24SSimon Glass pxe_ipaddr_paths(cmdtp, pxefile_addr_r) > 0) {
3972e192b24SSimon Glass printf("Config file found\n");
3982e192b24SSimon Glass
3992e192b24SSimon Glass return 0;
4002e192b24SSimon Glass }
4012e192b24SSimon Glass
4022e192b24SSimon Glass while (pxe_default_paths[i]) {
4032e192b24SSimon Glass if (get_pxelinux_path(cmdtp, pxe_default_paths[i],
4042e192b24SSimon Glass pxefile_addr_r) > 0) {
4052e192b24SSimon Glass printf("Config file found\n");
4062e192b24SSimon Glass return 0;
4072e192b24SSimon Glass }
4082e192b24SSimon Glass i++;
4092e192b24SSimon Glass }
4102e192b24SSimon Glass
4112e192b24SSimon Glass printf("Config file not found\n");
4122e192b24SSimon Glass
4132e192b24SSimon Glass return 1;
4142e192b24SSimon Glass }
4152e192b24SSimon Glass #endif
4162e192b24SSimon Glass
4172e192b24SSimon Glass /*
4182e192b24SSimon Glass * Wrapper to make it easier to store the file at file_path in the location
4192e192b24SSimon Glass * specified by envaddr_name. file_path will be joined to the bootfile path,
4202e192b24SSimon Glass * if any is specified.
4212e192b24SSimon Glass *
4222e192b24SSimon Glass * Returns 1 on success or < 0 on error.
4232e192b24SSimon Glass */
get_relfile_envaddr(cmd_tbl_t * cmdtp,const char * file_path,const char * envaddr_name)4242e192b24SSimon Glass static int get_relfile_envaddr(cmd_tbl_t *cmdtp, const char *file_path, const char *envaddr_name)
4252e192b24SSimon Glass {
4262e192b24SSimon Glass unsigned long file_addr;
4272e192b24SSimon Glass char *envaddr;
4282e192b24SSimon Glass
4292e192b24SSimon Glass envaddr = from_env(envaddr_name);
4302e192b24SSimon Glass
4312e192b24SSimon Glass if (!envaddr)
4322e192b24SSimon Glass return -ENOENT;
4332e192b24SSimon Glass
4342e192b24SSimon Glass if (strict_strtoul(envaddr, 16, &file_addr) < 0)
4352e192b24SSimon Glass return -EINVAL;
4362e192b24SSimon Glass
4372e192b24SSimon Glass return get_relfile(cmdtp, file_path, file_addr);
4382e192b24SSimon Glass }
4392e192b24SSimon Glass
4402e192b24SSimon Glass /*
4412e192b24SSimon Glass * A note on the pxe file parser.
4422e192b24SSimon Glass *
4432e192b24SSimon Glass * We're parsing files that use syslinux grammar, which has a few quirks.
4442e192b24SSimon Glass * String literals must be recognized based on context - there is no
4452e192b24SSimon Glass * quoting or escaping support. There's also nothing to explicitly indicate
4462e192b24SSimon Glass * when a label section completes. We deal with that by ending a label
4472e192b24SSimon Glass * section whenever we see a line that doesn't include.
4482e192b24SSimon Glass *
4492e192b24SSimon Glass * As with the syslinux family, this same file format could be reused in the
4502e192b24SSimon Glass * future for non pxe purposes. The only action it takes during parsing that
4512e192b24SSimon Glass * would throw this off is handling of include files. It assumes we're using
4522e192b24SSimon Glass * pxe, and does a tftp download of a file listed as an include file in the
4532e192b24SSimon Glass * middle of the parsing operation. That could be handled by refactoring it to
4542e192b24SSimon Glass * take a 'include file getter' function.
4552e192b24SSimon Glass */
4562e192b24SSimon Glass
4572e192b24SSimon Glass /*
4582e192b24SSimon Glass * Describes a single label given in a pxe file.
4592e192b24SSimon Glass *
4602e192b24SSimon Glass * Create these with the 'label_create' function given below.
4612e192b24SSimon Glass *
4622e192b24SSimon Glass * name - the name of the menu as given on the 'menu label' line.
4632e192b24SSimon Glass * kernel - the path to the kernel file to use for this label.
4642e192b24SSimon Glass * append - kernel command line to use when booting this label
4652e192b24SSimon Glass * initrd - path to the initrd to use for this label.
4662e192b24SSimon Glass * attempted - 0 if we haven't tried to boot this label, 1 if we have.
4672e192b24SSimon Glass * localboot - 1 if this label specified 'localboot', 0 otherwise.
4682e192b24SSimon Glass * list - lets these form a list, which a pxe_menu struct will hold.
4692e192b24SSimon Glass */
4702e192b24SSimon Glass struct pxe_label {
4712e192b24SSimon Glass char num[4];
4722e192b24SSimon Glass char *name;
4732e192b24SSimon Glass char *menu;
4742e192b24SSimon Glass char *kernel;
4752e192b24SSimon Glass char *append;
4762e192b24SSimon Glass char *initrd;
4772e192b24SSimon Glass char *fdt;
4782e192b24SSimon Glass char *fdtdir;
4792e192b24SSimon Glass int ipappend;
4802e192b24SSimon Glass int attempted;
4812e192b24SSimon Glass int localboot;
4822e192b24SSimon Glass int localboot_val;
4832e192b24SSimon Glass struct list_head list;
4842e192b24SSimon Glass };
4852e192b24SSimon Glass
4862e192b24SSimon Glass /*
4872e192b24SSimon Glass * Describes a pxe menu as given via pxe files.
4882e192b24SSimon Glass *
4892e192b24SSimon Glass * title - the name of the menu as given by a 'menu title' line.
4902e192b24SSimon Glass * default_label - the name of the default label, if any.
4912e192b24SSimon Glass * timeout - time in tenths of a second to wait for a user key-press before
4922e192b24SSimon Glass * booting the default label.
4932e192b24SSimon Glass * prompt - if 0, don't prompt for a choice unless the timeout period is
4942e192b24SSimon Glass * interrupted. If 1, always prompt for a choice regardless of
4952e192b24SSimon Glass * timeout.
4962e192b24SSimon Glass * labels - a list of labels defined for the menu.
4972e192b24SSimon Glass */
4982e192b24SSimon Glass struct pxe_menu {
4992e192b24SSimon Glass char *title;
5002e192b24SSimon Glass char *default_label;
5012e192b24SSimon Glass int timeout;
5022e192b24SSimon Glass int prompt;
5032e192b24SSimon Glass struct list_head labels;
5042e192b24SSimon Glass };
5052e192b24SSimon Glass
5062e192b24SSimon Glass /*
5072e192b24SSimon Glass * Allocates memory for and initializes a pxe_label. This uses malloc, so the
5082e192b24SSimon Glass * result must be free()'d to reclaim the memory.
5092e192b24SSimon Glass *
5102e192b24SSimon Glass * Returns NULL if malloc fails.
5112e192b24SSimon Glass */
label_create(void)5122e192b24SSimon Glass static struct pxe_label *label_create(void)
5132e192b24SSimon Glass {
5142e192b24SSimon Glass struct pxe_label *label;
5152e192b24SSimon Glass
5162e192b24SSimon Glass label = malloc(sizeof(struct pxe_label));
5172e192b24SSimon Glass
5182e192b24SSimon Glass if (!label)
5192e192b24SSimon Glass return NULL;
5202e192b24SSimon Glass
5212e192b24SSimon Glass memset(label, 0, sizeof(struct pxe_label));
5222e192b24SSimon Glass
5232e192b24SSimon Glass return label;
5242e192b24SSimon Glass }
5252e192b24SSimon Glass
5262e192b24SSimon Glass /*
5272e192b24SSimon Glass * Free the memory used by a pxe_label, including that used by its name,
5282e192b24SSimon Glass * kernel, append and initrd members, if they're non NULL.
5292e192b24SSimon Glass *
5302e192b24SSimon Glass * So - be sure to only use dynamically allocated memory for the members of
5312e192b24SSimon Glass * the pxe_label struct, unless you want to clean it up first. These are
5322e192b24SSimon Glass * currently only created by the pxe file parsing code.
5332e192b24SSimon Glass */
label_destroy(struct pxe_label * label)5342e192b24SSimon Glass static void label_destroy(struct pxe_label *label)
5352e192b24SSimon Glass {
5362e192b24SSimon Glass if (label->name)
5372e192b24SSimon Glass free(label->name);
5382e192b24SSimon Glass
5392e192b24SSimon Glass if (label->kernel)
5402e192b24SSimon Glass free(label->kernel);
5412e192b24SSimon Glass
5422e192b24SSimon Glass if (label->append)
5432e192b24SSimon Glass free(label->append);
5442e192b24SSimon Glass
5452e192b24SSimon Glass if (label->initrd)
5462e192b24SSimon Glass free(label->initrd);
5472e192b24SSimon Glass
5482e192b24SSimon Glass if (label->fdt)
5492e192b24SSimon Glass free(label->fdt);
5502e192b24SSimon Glass
5512e192b24SSimon Glass if (label->fdtdir)
5522e192b24SSimon Glass free(label->fdtdir);
5532e192b24SSimon Glass
5542e192b24SSimon Glass free(label);
5552e192b24SSimon Glass }
5562e192b24SSimon Glass
5572e192b24SSimon Glass /*
5582e192b24SSimon Glass * Print a label and its string members if they're defined.
5592e192b24SSimon Glass *
5602e192b24SSimon Glass * This is passed as a callback to the menu code for displaying each
5612e192b24SSimon Glass * menu entry.
5622e192b24SSimon Glass */
label_print(void * data)5632e192b24SSimon Glass static void label_print(void *data)
5642e192b24SSimon Glass {
5652e192b24SSimon Glass struct pxe_label *label = data;
5662e192b24SSimon Glass const char *c = label->menu ? label->menu : label->name;
5672e192b24SSimon Glass
5682e192b24SSimon Glass printf("%s:\t%s\n", label->num, c);
5692e192b24SSimon Glass }
5702e192b24SSimon Glass
5712e192b24SSimon Glass /*
5722e192b24SSimon Glass * Boot a label that specified 'localboot'. This requires that the 'localcmd'
573a187559eSBin Meng * environment variable is defined. Its contents will be executed as U-Boot
5742e192b24SSimon Glass * command. If the label specified an 'append' line, its contents will be
5752e192b24SSimon Glass * used to overwrite the contents of the 'bootargs' environment variable prior
5762e192b24SSimon Glass * to running 'localcmd'.
5772e192b24SSimon Glass *
5782e192b24SSimon Glass * Returns 1 on success or < 0 on error.
5792e192b24SSimon Glass */
label_localboot(struct pxe_label * label)5802e192b24SSimon Glass static int label_localboot(struct pxe_label *label)
5812e192b24SSimon Glass {
5822e192b24SSimon Glass char *localcmd;
5832e192b24SSimon Glass
5842e192b24SSimon Glass localcmd = from_env("localcmd");
5852e192b24SSimon Glass
5862e192b24SSimon Glass if (!localcmd)
5872e192b24SSimon Glass return -ENOENT;
5882e192b24SSimon Glass
5892e192b24SSimon Glass if (label->append) {
5902e192b24SSimon Glass char bootargs[CONFIG_SYS_CBSIZE];
5912e192b24SSimon Glass
5922e192b24SSimon Glass cli_simple_process_macros(label->append, bootargs);
593382bee57SSimon Glass env_set("bootargs", bootargs);
5942e192b24SSimon Glass }
5952e192b24SSimon Glass
5962e192b24SSimon Glass debug("running: %s\n", localcmd);
5972e192b24SSimon Glass
5982e192b24SSimon Glass return run_command_list(localcmd, strlen(localcmd), 0);
5992e192b24SSimon Glass }
6002e192b24SSimon Glass
6012e192b24SSimon Glass /*
6022e192b24SSimon Glass * Boot according to the contents of a pxe_label.
6032e192b24SSimon Glass *
6042e192b24SSimon Glass * If we can't boot for any reason, we return. A successful boot never
6052e192b24SSimon Glass * returns.
6062e192b24SSimon Glass *
6072e192b24SSimon Glass * The kernel will be stored in the location given by the 'kernel_addr_r'
6082e192b24SSimon Glass * environment variable.
6092e192b24SSimon Glass *
6102e192b24SSimon Glass * If the label specifies an initrd file, it will be stored in the location
6112e192b24SSimon Glass * given by the 'ramdisk_addr_r' environment variable.
6122e192b24SSimon Glass *
6132e192b24SSimon Glass * If the label specifies an 'append' line, its contents will overwrite that
6142e192b24SSimon Glass * of the 'bootargs' environment variable.
6152e192b24SSimon Glass */
label_boot(cmd_tbl_t * cmdtp,struct pxe_label * label)6162e192b24SSimon Glass static int label_boot(cmd_tbl_t *cmdtp, struct pxe_label *label)
6172e192b24SSimon Glass {
6182e192b24SSimon Glass char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
6197f2f3661STom Rini char initrd_str[28];
6202e192b24SSimon Glass char mac_str[29] = "";
6212e192b24SSimon Glass char ip_str[68] = "";
622f63963f0SYork Sun int bootm_argc = 2;
6232e192b24SSimon Glass int len = 0;
6242e192b24SSimon Glass ulong kernel_addr;
6252e192b24SSimon Glass void *buf;
6262e192b24SSimon Glass
6272e192b24SSimon Glass label_print(label);
6282e192b24SSimon Glass
6292e192b24SSimon Glass label->attempted = 1;
6302e192b24SSimon Glass
6312e192b24SSimon Glass if (label->localboot) {
6322e192b24SSimon Glass if (label->localboot_val >= 0)
6332e192b24SSimon Glass label_localboot(label);
6342e192b24SSimon Glass return 0;
6352e192b24SSimon Glass }
6362e192b24SSimon Glass
6372e192b24SSimon Glass if (label->kernel == NULL) {
6382e192b24SSimon Glass printf("No kernel given, skipping %s\n",
6392e192b24SSimon Glass label->name);
6402e192b24SSimon Glass return 1;
6412e192b24SSimon Glass }
6422e192b24SSimon Glass
6432e192b24SSimon Glass if (label->initrd) {
6442e192b24SSimon Glass if (get_relfile_envaddr(cmdtp, label->initrd, "ramdisk_addr_r") < 0) {
6452e192b24SSimon Glass printf("Skipping %s for failure retrieving initrd\n",
6462e192b24SSimon Glass label->name);
6472e192b24SSimon Glass return 1;
6482e192b24SSimon Glass }
6492e192b24SSimon Glass
6502e192b24SSimon Glass bootm_argv[2] = initrd_str;
6517f2f3661STom Rini strncpy(bootm_argv[2], env_get("ramdisk_addr_r"), 18);
6522e192b24SSimon Glass strcat(bootm_argv[2], ":");
6537f2f3661STom Rini strncat(bootm_argv[2], env_get("filesize"), 9);
6542e192b24SSimon Glass }
6552e192b24SSimon Glass
6562e192b24SSimon Glass if (get_relfile_envaddr(cmdtp, label->kernel, "kernel_addr_r") < 0) {
6572e192b24SSimon Glass printf("Skipping %s for failure retrieving kernel\n",
6582e192b24SSimon Glass label->name);
6592e192b24SSimon Glass return 1;
6602e192b24SSimon Glass }
6612e192b24SSimon Glass
6622e192b24SSimon Glass if (label->ipappend & 0x1) {
6632e192b24SSimon Glass sprintf(ip_str, " ip=%s:%s:%s:%s",
66400caae6dSSimon Glass env_get("ipaddr"), env_get("serverip"),
66500caae6dSSimon Glass env_get("gatewayip"), env_get("netmask"));
6662e192b24SSimon Glass }
6672e192b24SSimon Glass
6682e192b24SSimon Glass #ifdef CONFIG_CMD_NET
6692e192b24SSimon Glass if (label->ipappend & 0x2) {
6702e192b24SSimon Glass int err;
6712e192b24SSimon Glass strcpy(mac_str, " BOOTIF=");
6722e192b24SSimon Glass err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8);
6732e192b24SSimon Glass if (err < 0)
6742e192b24SSimon Glass mac_str[0] = '\0';
6752e192b24SSimon Glass }
6762e192b24SSimon Glass #endif
6772e192b24SSimon Glass
6782e192b24SSimon Glass if ((label->ipappend & 0x3) || label->append) {
6792e192b24SSimon Glass char bootargs[CONFIG_SYS_CBSIZE] = "";
6802e192b24SSimon Glass char finalbootargs[CONFIG_SYS_CBSIZE];
6812e192b24SSimon Glass
6822e192b24SSimon Glass if (strlen(label->append ?: "") +
6832e192b24SSimon Glass strlen(ip_str) + strlen(mac_str) + 1 > sizeof(bootargs)) {
6842e192b24SSimon Glass printf("bootarg overflow %zd+%zd+%zd+1 > %zd\n",
6852e192b24SSimon Glass strlen(label->append ?: ""),
6862e192b24SSimon Glass strlen(ip_str), strlen(mac_str),
6872e192b24SSimon Glass sizeof(bootargs));
6882e192b24SSimon Glass return 1;
689*c9bf1d5aSTom Rini } else {
6902e192b24SSimon Glass if (label->append)
691*c9bf1d5aSTom Rini strncpy(bootargs, label->append,
692*c9bf1d5aSTom Rini sizeof(bootargs));
693*c9bf1d5aSTom Rini strcat(bootargs, ip_str);
694*c9bf1d5aSTom Rini strcat(bootargs, mac_str);
6952e192b24SSimon Glass
6962e192b24SSimon Glass cli_simple_process_macros(bootargs, finalbootargs);
697382bee57SSimon Glass env_set("bootargs", finalbootargs);
6982e192b24SSimon Glass printf("append: %s\n", finalbootargs);
6992e192b24SSimon Glass }
700*c9bf1d5aSTom Rini }
7012e192b24SSimon Glass
70200caae6dSSimon Glass bootm_argv[1] = env_get("kernel_addr_r");
7032e192b24SSimon Glass
7042e192b24SSimon Glass /*
7052e192b24SSimon Glass * fdt usage is optional:
7062e192b24SSimon Glass * It handles the following scenarios. All scenarios are exclusive
7072e192b24SSimon Glass *
7082e192b24SSimon Glass * Scenario 1: If fdt_addr_r specified and "fdt" label is defined in
7092e192b24SSimon Glass * pxe file, retrieve fdt blob from server. Pass fdt_addr_r to bootm,
7102e192b24SSimon Glass * and adjust argc appropriately.
7112e192b24SSimon Glass *
7122e192b24SSimon Glass * Scenario 2: If there is an fdt_addr specified, pass it along to
7132e192b24SSimon Glass * bootm, and adjust argc appropriately.
7142e192b24SSimon Glass *
7152e192b24SSimon Glass * Scenario 3: fdt blob is not available.
7162e192b24SSimon Glass */
71700caae6dSSimon Glass bootm_argv[3] = env_get("fdt_addr_r");
7182e192b24SSimon Glass
7192e192b24SSimon Glass /* if fdt label is defined then get fdt from server */
7202e192b24SSimon Glass if (bootm_argv[3]) {
7212e192b24SSimon Glass char *fdtfile = NULL;
7222e192b24SSimon Glass char *fdtfilefree = NULL;
7232e192b24SSimon Glass
7242e192b24SSimon Glass if (label->fdt) {
7252e192b24SSimon Glass fdtfile = label->fdt;
7262e192b24SSimon Glass } else if (label->fdtdir) {
7272e192b24SSimon Glass char *f1, *f2, *f3, *f4, *slash;
7282e192b24SSimon Glass
72900caae6dSSimon Glass f1 = env_get("fdtfile");
7302e192b24SSimon Glass if (f1) {
7312e192b24SSimon Glass f2 = "";
7322e192b24SSimon Glass f3 = "";
7332e192b24SSimon Glass f4 = "";
7342e192b24SSimon Glass } else {
7352e192b24SSimon Glass /*
7362e192b24SSimon Glass * For complex cases where this code doesn't
7372e192b24SSimon Glass * generate the correct filename, the board
7382e192b24SSimon Glass * code should set $fdtfile during early boot,
7392e192b24SSimon Glass * or the boot scripts should set $fdtfile
7402e192b24SSimon Glass * before invoking "pxe" or "sysboot".
7412e192b24SSimon Glass */
74200caae6dSSimon Glass f1 = env_get("soc");
7432e192b24SSimon Glass f2 = "-";
74400caae6dSSimon Glass f3 = env_get("board");
7452e192b24SSimon Glass f4 = ".dtb";
7462e192b24SSimon Glass }
7472e192b24SSimon Glass
7482e192b24SSimon Glass len = strlen(label->fdtdir);
7492e192b24SSimon Glass if (!len)
7502e192b24SSimon Glass slash = "./";
7512e192b24SSimon Glass else if (label->fdtdir[len - 1] != '/')
7522e192b24SSimon Glass slash = "/";
7532e192b24SSimon Glass else
7542e192b24SSimon Glass slash = "";
7552e192b24SSimon Glass
7562e192b24SSimon Glass len = strlen(label->fdtdir) + strlen(slash) +
7572e192b24SSimon Glass strlen(f1) + strlen(f2) + strlen(f3) +
7582e192b24SSimon Glass strlen(f4) + 1;
7592e192b24SSimon Glass fdtfilefree = malloc(len);
7602e192b24SSimon Glass if (!fdtfilefree) {
7612e192b24SSimon Glass printf("malloc fail (FDT filename)\n");
7622e192b24SSimon Glass return 1;
7632e192b24SSimon Glass }
7642e192b24SSimon Glass
7652e192b24SSimon Glass snprintf(fdtfilefree, len, "%s%s%s%s%s%s",
7662e192b24SSimon Glass label->fdtdir, slash, f1, f2, f3, f4);
7672e192b24SSimon Glass fdtfile = fdtfilefree;
7682e192b24SSimon Glass }
7692e192b24SSimon Glass
7702e192b24SSimon Glass if (fdtfile) {
7712e192b24SSimon Glass int err = get_relfile_envaddr(cmdtp, fdtfile, "fdt_addr_r");
7722e192b24SSimon Glass free(fdtfilefree);
7732e192b24SSimon Glass if (err < 0) {
7742e192b24SSimon Glass printf("Skipping %s for failure retrieving fdt\n",
7752e192b24SSimon Glass label->name);
7762e192b24SSimon Glass return 1;
7772e192b24SSimon Glass }
7782e192b24SSimon Glass } else {
7792e192b24SSimon Glass bootm_argv[3] = NULL;
7802e192b24SSimon Glass }
7812e192b24SSimon Glass }
7822e192b24SSimon Glass
7832e192b24SSimon Glass if (!bootm_argv[3])
78400caae6dSSimon Glass bootm_argv[3] = env_get("fdt_addr");
7852e192b24SSimon Glass
786f63963f0SYork Sun if (bootm_argv[3]) {
787f63963f0SYork Sun if (!bootm_argv[2])
788f63963f0SYork Sun bootm_argv[2] = "-";
7892e192b24SSimon Glass bootm_argc = 4;
790f63963f0SYork Sun }
7912e192b24SSimon Glass
7922e192b24SSimon Glass kernel_addr = genimg_get_kernel_addr(bootm_argv[1]);
7932e192b24SSimon Glass buf = map_sysmem(kernel_addr, 0);
7942e192b24SSimon Glass /* Try bootm for legacy and FIT format image */
7952e192b24SSimon Glass if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID)
7962e192b24SSimon Glass do_bootm(cmdtp, 0, bootm_argc, bootm_argv);
7972e192b24SSimon Glass #ifdef CONFIG_CMD_BOOTI
7982e192b24SSimon Glass /* Try booting an AArch64 Linux kernel image */
7992e192b24SSimon Glass else
8002e192b24SSimon Glass do_booti(cmdtp, 0, bootm_argc, bootm_argv);
8012e192b24SSimon Glass #elif defined(CONFIG_CMD_BOOTZ)
8022e192b24SSimon Glass /* Try booting a Image */
8032e192b24SSimon Glass else
8042e192b24SSimon Glass do_bootz(cmdtp, 0, bootm_argc, bootm_argv);
8052e192b24SSimon Glass #endif
8062e192b24SSimon Glass unmap_sysmem(buf);
8072e192b24SSimon Glass return 1;
8082e192b24SSimon Glass }
8092e192b24SSimon Glass
8102e192b24SSimon Glass /*
8112e192b24SSimon Glass * Tokens for the pxe file parser.
8122e192b24SSimon Glass */
8132e192b24SSimon Glass enum token_type {
8142e192b24SSimon Glass T_EOL,
8152e192b24SSimon Glass T_STRING,
8162e192b24SSimon Glass T_EOF,
8172e192b24SSimon Glass T_MENU,
8182e192b24SSimon Glass T_TITLE,
8192e192b24SSimon Glass T_TIMEOUT,
8202e192b24SSimon Glass T_LABEL,
8212e192b24SSimon Glass T_KERNEL,
8222e192b24SSimon Glass T_LINUX,
8232e192b24SSimon Glass T_APPEND,
8242e192b24SSimon Glass T_INITRD,
8252e192b24SSimon Glass T_LOCALBOOT,
8262e192b24SSimon Glass T_DEFAULT,
8272e192b24SSimon Glass T_PROMPT,
8282e192b24SSimon Glass T_INCLUDE,
8292e192b24SSimon Glass T_FDT,
8302e192b24SSimon Glass T_FDTDIR,
8312e192b24SSimon Glass T_ONTIMEOUT,
8322e192b24SSimon Glass T_IPAPPEND,
8332e192b24SSimon Glass T_INVALID
8342e192b24SSimon Glass };
8352e192b24SSimon Glass
8362e192b24SSimon Glass /*
8372e192b24SSimon Glass * A token - given by a value and a type.
8382e192b24SSimon Glass */
8392e192b24SSimon Glass struct token {
8402e192b24SSimon Glass char *val;
8412e192b24SSimon Glass enum token_type type;
8422e192b24SSimon Glass };
8432e192b24SSimon Glass
8442e192b24SSimon Glass /*
8452e192b24SSimon Glass * Keywords recognized.
8462e192b24SSimon Glass */
8472e192b24SSimon Glass static const struct token keywords[] = {
8482e192b24SSimon Glass {"menu", T_MENU},
8492e192b24SSimon Glass {"title", T_TITLE},
8502e192b24SSimon Glass {"timeout", T_TIMEOUT},
8512e192b24SSimon Glass {"default", T_DEFAULT},
8522e192b24SSimon Glass {"prompt", T_PROMPT},
8532e192b24SSimon Glass {"label", T_LABEL},
8542e192b24SSimon Glass {"kernel", T_KERNEL},
8552e192b24SSimon Glass {"linux", T_LINUX},
8562e192b24SSimon Glass {"localboot", T_LOCALBOOT},
8572e192b24SSimon Glass {"append", T_APPEND},
8582e192b24SSimon Glass {"initrd", T_INITRD},
8592e192b24SSimon Glass {"include", T_INCLUDE},
8602e192b24SSimon Glass {"devicetree", T_FDT},
8612e192b24SSimon Glass {"fdt", T_FDT},
8622e192b24SSimon Glass {"devicetreedir", T_FDTDIR},
8632e192b24SSimon Glass {"fdtdir", T_FDTDIR},
8642e192b24SSimon Glass {"ontimeout", T_ONTIMEOUT,},
8652e192b24SSimon Glass {"ipappend", T_IPAPPEND,},
8662e192b24SSimon Glass {NULL, T_INVALID}
8672e192b24SSimon Glass };
8682e192b24SSimon Glass
8692e192b24SSimon Glass /*
8702e192b24SSimon Glass * Since pxe(linux) files don't have a token to identify the start of a
8712e192b24SSimon Glass * literal, we have to keep track of when we're in a state where a literal is
8722e192b24SSimon Glass * expected vs when we're in a state a keyword is expected.
8732e192b24SSimon Glass */
8742e192b24SSimon Glass enum lex_state {
8752e192b24SSimon Glass L_NORMAL = 0,
8762e192b24SSimon Glass L_KEYWORD,
8772e192b24SSimon Glass L_SLITERAL
8782e192b24SSimon Glass };
8792e192b24SSimon Glass
8802e192b24SSimon Glass /*
8812e192b24SSimon Glass * get_string retrieves a string from *p and stores it as a token in
8822e192b24SSimon Glass * *t.
8832e192b24SSimon Glass *
8842e192b24SSimon Glass * get_string used for scanning both string literals and keywords.
8852e192b24SSimon Glass *
8862e192b24SSimon Glass * Characters from *p are copied into t-val until a character equal to
8872e192b24SSimon Glass * delim is found, or a NUL byte is reached. If delim has the special value of
8882e192b24SSimon Glass * ' ', any whitespace character will be used as a delimiter.
8892e192b24SSimon Glass *
8902e192b24SSimon Glass * If lower is unequal to 0, uppercase characters will be converted to
8912e192b24SSimon Glass * lowercase in the result. This is useful to make keywords case
8922e192b24SSimon Glass * insensitive.
8932e192b24SSimon Glass *
8942e192b24SSimon Glass * The location of *p is updated to point to the first character after the end
8952e192b24SSimon Glass * of the token - the ending delimiter.
8962e192b24SSimon Glass *
8972e192b24SSimon Glass * On success, the new value of t->val is returned. Memory for t->val is
8982e192b24SSimon Glass * allocated using malloc and must be free()'d to reclaim it. If insufficient
8992e192b24SSimon Glass * memory is available, NULL is returned.
9002e192b24SSimon Glass */
get_string(char ** p,struct token * t,char delim,int lower)9012e192b24SSimon Glass static char *get_string(char **p, struct token *t, char delim, int lower)
9022e192b24SSimon Glass {
9032e192b24SSimon Glass char *b, *e;
9042e192b24SSimon Glass size_t len, i;
9052e192b24SSimon Glass
9062e192b24SSimon Glass /*
9072e192b24SSimon Glass * b and e both start at the beginning of the input stream.
9082e192b24SSimon Glass *
9092e192b24SSimon Glass * e is incremented until we find the ending delimiter, or a NUL byte
9102e192b24SSimon Glass * is reached. Then, we take e - b to find the length of the token.
9112e192b24SSimon Glass */
9122e192b24SSimon Glass b = e = *p;
9132e192b24SSimon Glass
9142e192b24SSimon Glass while (*e) {
9152e192b24SSimon Glass if ((delim == ' ' && isspace(*e)) || delim == *e)
9162e192b24SSimon Glass break;
9172e192b24SSimon Glass e++;
9182e192b24SSimon Glass }
9192e192b24SSimon Glass
9202e192b24SSimon Glass len = e - b;
9212e192b24SSimon Glass
9222e192b24SSimon Glass /*
9232e192b24SSimon Glass * Allocate memory to hold the string, and copy it in, converting
9242e192b24SSimon Glass * characters to lowercase if lower is != 0.
9252e192b24SSimon Glass */
9262e192b24SSimon Glass t->val = malloc(len + 1);
9272e192b24SSimon Glass if (!t->val)
9282e192b24SSimon Glass return NULL;
9292e192b24SSimon Glass
9302e192b24SSimon Glass for (i = 0; i < len; i++, b++) {
9312e192b24SSimon Glass if (lower)
9322e192b24SSimon Glass t->val[i] = tolower(*b);
9332e192b24SSimon Glass else
9342e192b24SSimon Glass t->val[i] = *b;
9352e192b24SSimon Glass }
9362e192b24SSimon Glass
9372e192b24SSimon Glass t->val[len] = '\0';
9382e192b24SSimon Glass
9392e192b24SSimon Glass /*
9402e192b24SSimon Glass * Update *p so the caller knows where to continue scanning.
9412e192b24SSimon Glass */
9422e192b24SSimon Glass *p = e;
9432e192b24SSimon Glass
9442e192b24SSimon Glass t->type = T_STRING;
9452e192b24SSimon Glass
9462e192b24SSimon Glass return t->val;
9472e192b24SSimon Glass }
9482e192b24SSimon Glass
9492e192b24SSimon Glass /*
9502e192b24SSimon Glass * Populate a keyword token with a type and value.
9512e192b24SSimon Glass */
get_keyword(struct token * t)9522e192b24SSimon Glass static void get_keyword(struct token *t)
9532e192b24SSimon Glass {
9542e192b24SSimon Glass int i;
9552e192b24SSimon Glass
9562e192b24SSimon Glass for (i = 0; keywords[i].val; i++) {
9572e192b24SSimon Glass if (!strcmp(t->val, keywords[i].val)) {
9582e192b24SSimon Glass t->type = keywords[i].type;
9592e192b24SSimon Glass break;
9602e192b24SSimon Glass }
9612e192b24SSimon Glass }
9622e192b24SSimon Glass }
9632e192b24SSimon Glass
9642e192b24SSimon Glass /*
9652e192b24SSimon Glass * Get the next token. We have to keep track of which state we're in to know
9662e192b24SSimon Glass * if we're looking to get a string literal or a keyword.
9672e192b24SSimon Glass *
9682e192b24SSimon Glass * *p is updated to point at the first character after the current token.
9692e192b24SSimon Glass */
get_token(char ** p,struct token * t,enum lex_state state)9702e192b24SSimon Glass static void get_token(char **p, struct token *t, enum lex_state state)
9712e192b24SSimon Glass {
9722e192b24SSimon Glass char *c = *p;
9732e192b24SSimon Glass
9742e192b24SSimon Glass t->type = T_INVALID;
9752e192b24SSimon Glass
9762e192b24SSimon Glass /* eat non EOL whitespace */
9772e192b24SSimon Glass while (isblank(*c))
9782e192b24SSimon Glass c++;
9792e192b24SSimon Glass
9802e192b24SSimon Glass /*
9812e192b24SSimon Glass * eat comments. note that string literals can't begin with #, but
9822e192b24SSimon Glass * can contain a # after their first character.
9832e192b24SSimon Glass */
9842e192b24SSimon Glass if (*c == '#') {
9852e192b24SSimon Glass while (*c && *c != '\n')
9862e192b24SSimon Glass c++;
9872e192b24SSimon Glass }
9882e192b24SSimon Glass
9892e192b24SSimon Glass if (*c == '\n') {
9902e192b24SSimon Glass t->type = T_EOL;
9912e192b24SSimon Glass c++;
9922e192b24SSimon Glass } else if (*c == '\0') {
9932e192b24SSimon Glass t->type = T_EOF;
9942e192b24SSimon Glass c++;
9952e192b24SSimon Glass } else if (state == L_SLITERAL) {
9962e192b24SSimon Glass get_string(&c, t, '\n', 0);
9972e192b24SSimon Glass } else if (state == L_KEYWORD) {
9982e192b24SSimon Glass /*
9992e192b24SSimon Glass * when we expect a keyword, we first get the next string
10002e192b24SSimon Glass * token delimited by whitespace, and then check if it
10012e192b24SSimon Glass * matches a keyword in our keyword list. if it does, it's
10022e192b24SSimon Glass * converted to a keyword token of the appropriate type, and
10032e192b24SSimon Glass * if not, it remains a string token.
10042e192b24SSimon Glass */
10052e192b24SSimon Glass get_string(&c, t, ' ', 1);
10062e192b24SSimon Glass get_keyword(t);
10072e192b24SSimon Glass }
10082e192b24SSimon Glass
10092e192b24SSimon Glass *p = c;
10102e192b24SSimon Glass }
10112e192b24SSimon Glass
10122e192b24SSimon Glass /*
10132e192b24SSimon Glass * Increment *c until we get to the end of the current line, or EOF.
10142e192b24SSimon Glass */
eol_or_eof(char ** c)10152e192b24SSimon Glass static void eol_or_eof(char **c)
10162e192b24SSimon Glass {
10172e192b24SSimon Glass while (**c && **c != '\n')
10182e192b24SSimon Glass (*c)++;
10192e192b24SSimon Glass }
10202e192b24SSimon Glass
10212e192b24SSimon Glass /*
10222e192b24SSimon Glass * All of these parse_* functions share some common behavior.
10232e192b24SSimon Glass *
10242e192b24SSimon Glass * They finish with *c pointing after the token they parse, and return 1 on
10252e192b24SSimon Glass * success, or < 0 on error.
10262e192b24SSimon Glass */
10272e192b24SSimon Glass
10282e192b24SSimon Glass /*
10292e192b24SSimon Glass * Parse a string literal and store a pointer it at *dst. String literals
10302e192b24SSimon Glass * terminate at the end of the line.
10312e192b24SSimon Glass */
parse_sliteral(char ** c,char ** dst)10322e192b24SSimon Glass static int parse_sliteral(char **c, char **dst)
10332e192b24SSimon Glass {
10342e192b24SSimon Glass struct token t;
10352e192b24SSimon Glass char *s = *c;
10362e192b24SSimon Glass
10372e192b24SSimon Glass get_token(c, &t, L_SLITERAL);
10382e192b24SSimon Glass
10392e192b24SSimon Glass if (t.type != T_STRING) {
10402e192b24SSimon Glass printf("Expected string literal: %.*s\n", (int)(*c - s), s);
10412e192b24SSimon Glass return -EINVAL;
10422e192b24SSimon Glass }
10432e192b24SSimon Glass
10442e192b24SSimon Glass *dst = t.val;
10452e192b24SSimon Glass
10462e192b24SSimon Glass return 1;
10472e192b24SSimon Glass }
10482e192b24SSimon Glass
10492e192b24SSimon Glass /*
10502e192b24SSimon Glass * Parse a base 10 (unsigned) integer and store it at *dst.
10512e192b24SSimon Glass */
parse_integer(char ** c,int * dst)10522e192b24SSimon Glass static int parse_integer(char **c, int *dst)
10532e192b24SSimon Glass {
10542e192b24SSimon Glass struct token t;
10552e192b24SSimon Glass char *s = *c;
10562e192b24SSimon Glass
10572e192b24SSimon Glass get_token(c, &t, L_SLITERAL);
10582e192b24SSimon Glass
10592e192b24SSimon Glass if (t.type != T_STRING) {
10602e192b24SSimon Glass printf("Expected string: %.*s\n", (int)(*c - s), s);
10612e192b24SSimon Glass return -EINVAL;
10622e192b24SSimon Glass }
10632e192b24SSimon Glass
10642e192b24SSimon Glass *dst = simple_strtol(t.val, NULL, 10);
10652e192b24SSimon Glass
10662e192b24SSimon Glass free(t.val);
10672e192b24SSimon Glass
10682e192b24SSimon Glass return 1;
10692e192b24SSimon Glass }
10702e192b24SSimon Glass
10712e192b24SSimon Glass static int parse_pxefile_top(cmd_tbl_t *cmdtp, char *p, unsigned long base,
10722e192b24SSimon Glass struct pxe_menu *cfg, int nest_level);
10732e192b24SSimon Glass
10742e192b24SSimon Glass /*
10752e192b24SSimon Glass * Parse an include statement, and retrieve and parse the file it mentions.
10762e192b24SSimon Glass *
10772e192b24SSimon Glass * base should point to a location where it's safe to store the file, and
10782e192b24SSimon Glass * nest_level should indicate how many nested includes have occurred. For this
10792e192b24SSimon Glass * include, nest_level has already been incremented and doesn't need to be
10802e192b24SSimon Glass * incremented here.
10812e192b24SSimon Glass */
handle_include(cmd_tbl_t * cmdtp,char ** c,unsigned long base,struct pxe_menu * cfg,int nest_level)10822e192b24SSimon Glass static int handle_include(cmd_tbl_t *cmdtp, char **c, unsigned long base,
10832e192b24SSimon Glass struct pxe_menu *cfg, int nest_level)
10842e192b24SSimon Glass {
10852e192b24SSimon Glass char *include_path;
10862e192b24SSimon Glass char *s = *c;
10872e192b24SSimon Glass int err;
10882e192b24SSimon Glass char *buf;
10892e192b24SSimon Glass int ret;
10902e192b24SSimon Glass
10912e192b24SSimon Glass err = parse_sliteral(c, &include_path);
10922e192b24SSimon Glass
10932e192b24SSimon Glass if (err < 0) {
10942e192b24SSimon Glass printf("Expected include path: %.*s\n",
10952e192b24SSimon Glass (int)(*c - s), s);
10962e192b24SSimon Glass return err;
10972e192b24SSimon Glass }
10982e192b24SSimon Glass
10992e192b24SSimon Glass err = get_pxe_file(cmdtp, include_path, base);
11002e192b24SSimon Glass
11012e192b24SSimon Glass if (err < 0) {
11022e192b24SSimon Glass printf("Couldn't retrieve %s\n", include_path);
11032e192b24SSimon Glass return err;
11042e192b24SSimon Glass }
11052e192b24SSimon Glass
11062e192b24SSimon Glass buf = map_sysmem(base, 0);
11072e192b24SSimon Glass ret = parse_pxefile_top(cmdtp, buf, base, cfg, nest_level);
11082e192b24SSimon Glass unmap_sysmem(buf);
11092e192b24SSimon Glass
11102e192b24SSimon Glass return ret;
11112e192b24SSimon Glass }
11122e192b24SSimon Glass
11132e192b24SSimon Glass /*
11142e192b24SSimon Glass * Parse lines that begin with 'menu'.
11152e192b24SSimon Glass *
11162e192b24SSimon Glass * base and nest are provided to handle the 'menu include' case.
11172e192b24SSimon Glass *
11182e192b24SSimon Glass * base should point to a location where it's safe to store the included file.
11192e192b24SSimon Glass *
11202e192b24SSimon Glass * nest_level should be 1 when parsing the top level pxe file, 2 when parsing
11212e192b24SSimon Glass * a file it includes, 3 when parsing a file included by that file, and so on.
11222e192b24SSimon Glass */
parse_menu(cmd_tbl_t * cmdtp,char ** c,struct pxe_menu * cfg,unsigned long base,int nest_level)11232e192b24SSimon Glass static int parse_menu(cmd_tbl_t *cmdtp, char **c, struct pxe_menu *cfg,
11242e192b24SSimon Glass unsigned long base, int nest_level)
11252e192b24SSimon Glass {
11262e192b24SSimon Glass struct token t;
11272e192b24SSimon Glass char *s = *c;
11282e192b24SSimon Glass int err = 0;
11292e192b24SSimon Glass
11302e192b24SSimon Glass get_token(c, &t, L_KEYWORD);
11312e192b24SSimon Glass
11322e192b24SSimon Glass switch (t.type) {
11332e192b24SSimon Glass case T_TITLE:
11342e192b24SSimon Glass err = parse_sliteral(c, &cfg->title);
11352e192b24SSimon Glass
11362e192b24SSimon Glass break;
11372e192b24SSimon Glass
11382e192b24SSimon Glass case T_INCLUDE:
11392e192b24SSimon Glass err = handle_include(cmdtp, c, base, cfg,
11402e192b24SSimon Glass nest_level + 1);
11412e192b24SSimon Glass break;
11422e192b24SSimon Glass
11432e192b24SSimon Glass default:
11442e192b24SSimon Glass printf("Ignoring malformed menu command: %.*s\n",
11452e192b24SSimon Glass (int)(*c - s), s);
11462e192b24SSimon Glass }
11472e192b24SSimon Glass
11482e192b24SSimon Glass if (err < 0)
11492e192b24SSimon Glass return err;
11502e192b24SSimon Glass
11512e192b24SSimon Glass eol_or_eof(c);
11522e192b24SSimon Glass
11532e192b24SSimon Glass return 1;
11542e192b24SSimon Glass }
11552e192b24SSimon Glass
11562e192b24SSimon Glass /*
11572e192b24SSimon Glass * Handles parsing a 'menu line' when we're parsing a label.
11582e192b24SSimon Glass */
parse_label_menu(char ** c,struct pxe_menu * cfg,struct pxe_label * label)11592e192b24SSimon Glass static int parse_label_menu(char **c, struct pxe_menu *cfg,
11602e192b24SSimon Glass struct pxe_label *label)
11612e192b24SSimon Glass {
11622e192b24SSimon Glass struct token t;
11632e192b24SSimon Glass char *s;
11642e192b24SSimon Glass
11652e192b24SSimon Glass s = *c;
11662e192b24SSimon Glass
11672e192b24SSimon Glass get_token(c, &t, L_KEYWORD);
11682e192b24SSimon Glass
11692e192b24SSimon Glass switch (t.type) {
11702e192b24SSimon Glass case T_DEFAULT:
11712e192b24SSimon Glass if (!cfg->default_label)
11722e192b24SSimon Glass cfg->default_label = strdup(label->name);
11732e192b24SSimon Glass
11742e192b24SSimon Glass if (!cfg->default_label)
11752e192b24SSimon Glass return -ENOMEM;
11762e192b24SSimon Glass
11772e192b24SSimon Glass break;
11782e192b24SSimon Glass case T_LABEL:
11792e192b24SSimon Glass parse_sliteral(c, &label->menu);
11802e192b24SSimon Glass break;
11812e192b24SSimon Glass default:
11822e192b24SSimon Glass printf("Ignoring malformed menu command: %.*s\n",
11832e192b24SSimon Glass (int)(*c - s), s);
11842e192b24SSimon Glass }
11852e192b24SSimon Glass
11862e192b24SSimon Glass eol_or_eof(c);
11872e192b24SSimon Glass
11882e192b24SSimon Glass return 0;
11892e192b24SSimon Glass }
11902e192b24SSimon Glass
11912e192b24SSimon Glass /*
11922e192b24SSimon Glass * Parses a label and adds it to the list of labels for a menu.
11932e192b24SSimon Glass *
11942e192b24SSimon Glass * A label ends when we either get to the end of a file, or
11952e192b24SSimon Glass * get some input we otherwise don't have a handler defined
11962e192b24SSimon Glass * for.
11972e192b24SSimon Glass *
11982e192b24SSimon Glass */
parse_label(char ** c,struct pxe_menu * cfg)11992e192b24SSimon Glass static int parse_label(char **c, struct pxe_menu *cfg)
12002e192b24SSimon Glass {
12012e192b24SSimon Glass struct token t;
12022e192b24SSimon Glass int len;
12032e192b24SSimon Glass char *s = *c;
12042e192b24SSimon Glass struct pxe_label *label;
12052e192b24SSimon Glass int err;
12062e192b24SSimon Glass
12072e192b24SSimon Glass label = label_create();
12082e192b24SSimon Glass if (!label)
12092e192b24SSimon Glass return -ENOMEM;
12102e192b24SSimon Glass
12112e192b24SSimon Glass err = parse_sliteral(c, &label->name);
12122e192b24SSimon Glass if (err < 0) {
12132e192b24SSimon Glass printf("Expected label name: %.*s\n", (int)(*c - s), s);
12142e192b24SSimon Glass label_destroy(label);
12152e192b24SSimon Glass return -EINVAL;
12162e192b24SSimon Glass }
12172e192b24SSimon Glass
12182e192b24SSimon Glass list_add_tail(&label->list, &cfg->labels);
12192e192b24SSimon Glass
12202e192b24SSimon Glass while (1) {
12212e192b24SSimon Glass s = *c;
12222e192b24SSimon Glass get_token(c, &t, L_KEYWORD);
12232e192b24SSimon Glass
12242e192b24SSimon Glass err = 0;
12252e192b24SSimon Glass switch (t.type) {
12262e192b24SSimon Glass case T_MENU:
12272e192b24SSimon Glass err = parse_label_menu(c, cfg, label);
12282e192b24SSimon Glass break;
12292e192b24SSimon Glass
12302e192b24SSimon Glass case T_KERNEL:
12312e192b24SSimon Glass case T_LINUX:
12322e192b24SSimon Glass err = parse_sliteral(c, &label->kernel);
12332e192b24SSimon Glass break;
12342e192b24SSimon Glass
12352e192b24SSimon Glass case T_APPEND:
12362e192b24SSimon Glass err = parse_sliteral(c, &label->append);
12372e192b24SSimon Glass if (label->initrd)
12382e192b24SSimon Glass break;
12392e192b24SSimon Glass s = strstr(label->append, "initrd=");
12402e192b24SSimon Glass if (!s)
12412e192b24SSimon Glass break;
12422e192b24SSimon Glass s += 7;
12432e192b24SSimon Glass len = (int)(strchr(s, ' ') - s);
12442e192b24SSimon Glass label->initrd = malloc(len + 1);
12452e192b24SSimon Glass strncpy(label->initrd, s, len);
12462e192b24SSimon Glass label->initrd[len] = '\0';
12472e192b24SSimon Glass
12482e192b24SSimon Glass break;
12492e192b24SSimon Glass
12502e192b24SSimon Glass case T_INITRD:
12512e192b24SSimon Glass if (!label->initrd)
12522e192b24SSimon Glass err = parse_sliteral(c, &label->initrd);
12532e192b24SSimon Glass break;
12542e192b24SSimon Glass
12552e192b24SSimon Glass case T_FDT:
12562e192b24SSimon Glass if (!label->fdt)
12572e192b24SSimon Glass err = parse_sliteral(c, &label->fdt);
12582e192b24SSimon Glass break;
12592e192b24SSimon Glass
12602e192b24SSimon Glass case T_FDTDIR:
12612e192b24SSimon Glass if (!label->fdtdir)
12622e192b24SSimon Glass err = parse_sliteral(c, &label->fdtdir);
12632e192b24SSimon Glass break;
12642e192b24SSimon Glass
12652e192b24SSimon Glass case T_LOCALBOOT:
12662e192b24SSimon Glass label->localboot = 1;
12672e192b24SSimon Glass err = parse_integer(c, &label->localboot_val);
12682e192b24SSimon Glass break;
12692e192b24SSimon Glass
12702e192b24SSimon Glass case T_IPAPPEND:
12712e192b24SSimon Glass err = parse_integer(c, &label->ipappend);
12722e192b24SSimon Glass break;
12732e192b24SSimon Glass
12742e192b24SSimon Glass case T_EOL:
12752e192b24SSimon Glass break;
12762e192b24SSimon Glass
12772e192b24SSimon Glass default:
12782e192b24SSimon Glass /*
12792e192b24SSimon Glass * put the token back! we don't want it - it's the end
12802e192b24SSimon Glass * of a label and whatever token this is, it's
12812e192b24SSimon Glass * something for the menu level context to handle.
12822e192b24SSimon Glass */
12832e192b24SSimon Glass *c = s;
12842e192b24SSimon Glass return 1;
12852e192b24SSimon Glass }
12862e192b24SSimon Glass
12872e192b24SSimon Glass if (err < 0)
12882e192b24SSimon Glass return err;
12892e192b24SSimon Glass }
12902e192b24SSimon Glass }
12912e192b24SSimon Glass
12922e192b24SSimon Glass /*
12932e192b24SSimon Glass * This 16 comes from the limit pxelinux imposes on nested includes.
12942e192b24SSimon Glass *
12952e192b24SSimon Glass * There is no reason at all we couldn't do more, but some limit helps prevent
12962e192b24SSimon Glass * infinite (until crash occurs) recursion if a file tries to include itself.
12972e192b24SSimon Glass */
12982e192b24SSimon Glass #define MAX_NEST_LEVEL 16
12992e192b24SSimon Glass
13002e192b24SSimon Glass /*
13012e192b24SSimon Glass * Entry point for parsing a menu file. nest_level indicates how many times
13022e192b24SSimon Glass * we've nested in includes. It will be 1 for the top level menu file.
13032e192b24SSimon Glass *
13042e192b24SSimon Glass * Returns 1 on success, < 0 on error.
13052e192b24SSimon Glass */
parse_pxefile_top(cmd_tbl_t * cmdtp,char * p,unsigned long base,struct pxe_menu * cfg,int nest_level)13062e192b24SSimon Glass static int parse_pxefile_top(cmd_tbl_t *cmdtp, char *p, unsigned long base,
13072e192b24SSimon Glass struct pxe_menu *cfg, int nest_level)
13082e192b24SSimon Glass {
13092e192b24SSimon Glass struct token t;
13102e192b24SSimon Glass char *s, *b, *label_name;
13112e192b24SSimon Glass int err;
13122e192b24SSimon Glass
13132e192b24SSimon Glass b = p;
13142e192b24SSimon Glass
13152e192b24SSimon Glass if (nest_level > MAX_NEST_LEVEL) {
13162e192b24SSimon Glass printf("Maximum nesting (%d) exceeded\n", MAX_NEST_LEVEL);
13172e192b24SSimon Glass return -EMLINK;
13182e192b24SSimon Glass }
13192e192b24SSimon Glass
13202e192b24SSimon Glass while (1) {
13212e192b24SSimon Glass s = p;
13222e192b24SSimon Glass
13232e192b24SSimon Glass get_token(&p, &t, L_KEYWORD);
13242e192b24SSimon Glass
13252e192b24SSimon Glass err = 0;
13262e192b24SSimon Glass switch (t.type) {
13272e192b24SSimon Glass case T_MENU:
13282e192b24SSimon Glass cfg->prompt = 1;
13292e192b24SSimon Glass err = parse_menu(cmdtp, &p, cfg,
13302e192b24SSimon Glass base + ALIGN(strlen(b) + 1, 4),
13312e192b24SSimon Glass nest_level);
13322e192b24SSimon Glass break;
13332e192b24SSimon Glass
13342e192b24SSimon Glass case T_TIMEOUT:
13352e192b24SSimon Glass err = parse_integer(&p, &cfg->timeout);
13362e192b24SSimon Glass break;
13372e192b24SSimon Glass
13382e192b24SSimon Glass case T_LABEL:
13392e192b24SSimon Glass err = parse_label(&p, cfg);
13402e192b24SSimon Glass break;
13412e192b24SSimon Glass
13422e192b24SSimon Glass case T_DEFAULT:
13432e192b24SSimon Glass case T_ONTIMEOUT:
13442e192b24SSimon Glass err = parse_sliteral(&p, &label_name);
13452e192b24SSimon Glass
13462e192b24SSimon Glass if (label_name) {
13472e192b24SSimon Glass if (cfg->default_label)
13482e192b24SSimon Glass free(cfg->default_label);
13492e192b24SSimon Glass
13502e192b24SSimon Glass cfg->default_label = label_name;
13512e192b24SSimon Glass }
13522e192b24SSimon Glass
13532e192b24SSimon Glass break;
13542e192b24SSimon Glass
13552e192b24SSimon Glass case T_INCLUDE:
13562e192b24SSimon Glass err = handle_include(cmdtp, &p,
13572e192b24SSimon Glass base + ALIGN(strlen(b), 4), cfg,
13582e192b24SSimon Glass nest_level + 1);
13592e192b24SSimon Glass break;
13602e192b24SSimon Glass
13612e192b24SSimon Glass case T_PROMPT:
13622e192b24SSimon Glass eol_or_eof(&p);
13632e192b24SSimon Glass break;
13642e192b24SSimon Glass
13652e192b24SSimon Glass case T_EOL:
13662e192b24SSimon Glass break;
13672e192b24SSimon Glass
13682e192b24SSimon Glass case T_EOF:
13692e192b24SSimon Glass return 1;
13702e192b24SSimon Glass
13712e192b24SSimon Glass default:
13722e192b24SSimon Glass printf("Ignoring unknown command: %.*s\n",
13732e192b24SSimon Glass (int)(p - s), s);
13742e192b24SSimon Glass eol_or_eof(&p);
13752e192b24SSimon Glass }
13762e192b24SSimon Glass
13772e192b24SSimon Glass if (err < 0)
13782e192b24SSimon Glass return err;
13792e192b24SSimon Glass }
13802e192b24SSimon Glass }
13812e192b24SSimon Glass
13822e192b24SSimon Glass /*
13832e192b24SSimon Glass * Free the memory used by a pxe_menu and its labels.
13842e192b24SSimon Glass */
destroy_pxe_menu(struct pxe_menu * cfg)13852e192b24SSimon Glass static void destroy_pxe_menu(struct pxe_menu *cfg)
13862e192b24SSimon Glass {
13872e192b24SSimon Glass struct list_head *pos, *n;
13882e192b24SSimon Glass struct pxe_label *label;
13892e192b24SSimon Glass
13902e192b24SSimon Glass if (cfg->title)
13912e192b24SSimon Glass free(cfg->title);
13922e192b24SSimon Glass
13932e192b24SSimon Glass if (cfg->default_label)
13942e192b24SSimon Glass free(cfg->default_label);
13952e192b24SSimon Glass
13962e192b24SSimon Glass list_for_each_safe(pos, n, &cfg->labels) {
13972e192b24SSimon Glass label = list_entry(pos, struct pxe_label, list);
13982e192b24SSimon Glass
13992e192b24SSimon Glass label_destroy(label);
14002e192b24SSimon Glass }
14012e192b24SSimon Glass
14022e192b24SSimon Glass free(cfg);
14032e192b24SSimon Glass }
14042e192b24SSimon Glass
14052e192b24SSimon Glass /*
14062e192b24SSimon Glass * Entry point for parsing a pxe file. This is only used for the top level
14072e192b24SSimon Glass * file.
14082e192b24SSimon Glass *
14092e192b24SSimon Glass * Returns NULL if there is an error, otherwise, returns a pointer to a
14102e192b24SSimon Glass * pxe_menu struct populated with the results of parsing the pxe file (and any
14112e192b24SSimon Glass * files it includes). The resulting pxe_menu struct can be free()'d by using
14122e192b24SSimon Glass * the destroy_pxe_menu() function.
14132e192b24SSimon Glass */
parse_pxefile(cmd_tbl_t * cmdtp,unsigned long menucfg)14142e192b24SSimon Glass static struct pxe_menu *parse_pxefile(cmd_tbl_t *cmdtp, unsigned long menucfg)
14152e192b24SSimon Glass {
14162e192b24SSimon Glass struct pxe_menu *cfg;
14172e192b24SSimon Glass char *buf;
14182e192b24SSimon Glass int r;
14192e192b24SSimon Glass
14202e192b24SSimon Glass cfg = malloc(sizeof(struct pxe_menu));
14212e192b24SSimon Glass
14222e192b24SSimon Glass if (!cfg)
14232e192b24SSimon Glass return NULL;
14242e192b24SSimon Glass
14252e192b24SSimon Glass memset(cfg, 0, sizeof(struct pxe_menu));
14262e192b24SSimon Glass
14272e192b24SSimon Glass INIT_LIST_HEAD(&cfg->labels);
14282e192b24SSimon Glass
14292e192b24SSimon Glass buf = map_sysmem(menucfg, 0);
14302e192b24SSimon Glass r = parse_pxefile_top(cmdtp, buf, menucfg, cfg, 1);
14312e192b24SSimon Glass unmap_sysmem(buf);
14322e192b24SSimon Glass
14332e192b24SSimon Glass if (r < 0) {
14342e192b24SSimon Glass destroy_pxe_menu(cfg);
14352e192b24SSimon Glass return NULL;
14362e192b24SSimon Glass }
14372e192b24SSimon Glass
14382e192b24SSimon Glass return cfg;
14392e192b24SSimon Glass }
14402e192b24SSimon Glass
14412e192b24SSimon Glass /*
1442a187559eSBin Meng * Converts a pxe_menu struct into a menu struct for use with U-Boot's generic
14432e192b24SSimon Glass * menu code.
14442e192b24SSimon Glass */
pxe_menu_to_menu(struct pxe_menu * cfg)14452e192b24SSimon Glass static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
14462e192b24SSimon Glass {
14472e192b24SSimon Glass struct pxe_label *label;
14482e192b24SSimon Glass struct list_head *pos;
14492e192b24SSimon Glass struct menu *m;
14502e192b24SSimon Glass int err;
14512e192b24SSimon Glass int i = 1;
14522e192b24SSimon Glass char *default_num = NULL;
14532e192b24SSimon Glass
14542e192b24SSimon Glass /*
14552e192b24SSimon Glass * Create a menu and add items for all the labels.
14562e192b24SSimon Glass */
14572e192b24SSimon Glass m = menu_create(cfg->title, cfg->timeout, cfg->prompt, label_print,
14582e192b24SSimon Glass NULL, NULL);
14592e192b24SSimon Glass
14602e192b24SSimon Glass if (!m)
14612e192b24SSimon Glass return NULL;
14622e192b24SSimon Glass
14632e192b24SSimon Glass list_for_each(pos, &cfg->labels) {
14642e192b24SSimon Glass label = list_entry(pos, struct pxe_label, list);
14652e192b24SSimon Glass
14662e192b24SSimon Glass sprintf(label->num, "%d", i++);
14672e192b24SSimon Glass if (menu_item_add(m, label->num, label) != 1) {
14682e192b24SSimon Glass menu_destroy(m);
14692e192b24SSimon Glass return NULL;
14702e192b24SSimon Glass }
14712e192b24SSimon Glass if (cfg->default_label &&
14722e192b24SSimon Glass (strcmp(label->name, cfg->default_label) == 0))
14732e192b24SSimon Glass default_num = label->num;
14742e192b24SSimon Glass
14752e192b24SSimon Glass }
14762e192b24SSimon Glass
14772e192b24SSimon Glass /*
14782e192b24SSimon Glass * After we've created items for each label in the menu, set the
14792e192b24SSimon Glass * menu's default label if one was specified.
14802e192b24SSimon Glass */
14812e192b24SSimon Glass if (default_num) {
14822e192b24SSimon Glass err = menu_default_set(m, default_num);
14832e192b24SSimon Glass if (err != 1) {
14842e192b24SSimon Glass if (err != -ENOENT) {
14852e192b24SSimon Glass menu_destroy(m);
14862e192b24SSimon Glass return NULL;
14872e192b24SSimon Glass }
14882e192b24SSimon Glass
14892e192b24SSimon Glass printf("Missing default: %s\n", cfg->default_label);
14902e192b24SSimon Glass }
14912e192b24SSimon Glass }
14922e192b24SSimon Glass
14932e192b24SSimon Glass return m;
14942e192b24SSimon Glass }
14952e192b24SSimon Glass
14962e192b24SSimon Glass /*
14972e192b24SSimon Glass * Try to boot any labels we have yet to attempt to boot.
14982e192b24SSimon Glass */
boot_unattempted_labels(cmd_tbl_t * cmdtp,struct pxe_menu * cfg)14992e192b24SSimon Glass static void boot_unattempted_labels(cmd_tbl_t *cmdtp, struct pxe_menu *cfg)
15002e192b24SSimon Glass {
15012e192b24SSimon Glass struct list_head *pos;
15022e192b24SSimon Glass struct pxe_label *label;
15032e192b24SSimon Glass
15042e192b24SSimon Glass list_for_each(pos, &cfg->labels) {
15052e192b24SSimon Glass label = list_entry(pos, struct pxe_label, list);
15062e192b24SSimon Glass
15072e192b24SSimon Glass if (!label->attempted)
15082e192b24SSimon Glass label_boot(cmdtp, label);
15092e192b24SSimon Glass }
15102e192b24SSimon Glass }
15112e192b24SSimon Glass
15122e192b24SSimon Glass /*
15132e192b24SSimon Glass * Boot the system as prescribed by a pxe_menu.
15142e192b24SSimon Glass *
15152e192b24SSimon Glass * Use the menu system to either get the user's choice or the default, based
15162e192b24SSimon Glass * on config or user input. If there is no default or user's choice,
15172e192b24SSimon Glass * attempted to boot labels in the order they were given in pxe files.
15182e192b24SSimon Glass * If the default or user's choice fails to boot, attempt to boot other
15192e192b24SSimon Glass * labels in the order they were given in pxe files.
15202e192b24SSimon Glass *
15212e192b24SSimon Glass * If this function returns, there weren't any labels that successfully
15222e192b24SSimon Glass * booted, or the user interrupted the menu selection via ctrl+c.
15232e192b24SSimon Glass */
handle_pxe_menu(cmd_tbl_t * cmdtp,struct pxe_menu * cfg)15242e192b24SSimon Glass static void handle_pxe_menu(cmd_tbl_t *cmdtp, struct pxe_menu *cfg)
15252e192b24SSimon Glass {
15262e192b24SSimon Glass void *choice;
15272e192b24SSimon Glass struct menu *m;
15282e192b24SSimon Glass int err;
15292e192b24SSimon Glass
15302e192b24SSimon Glass m = pxe_menu_to_menu(cfg);
15312e192b24SSimon Glass if (!m)
15322e192b24SSimon Glass return;
15332e192b24SSimon Glass
15342e192b24SSimon Glass err = menu_get_choice(m, &choice);
15352e192b24SSimon Glass
15362e192b24SSimon Glass menu_destroy(m);
15372e192b24SSimon Glass
15382e192b24SSimon Glass /*
15392e192b24SSimon Glass * err == 1 means we got a choice back from menu_get_choice.
15402e192b24SSimon Glass *
15412e192b24SSimon Glass * err == -ENOENT if the menu was setup to select the default but no
15422e192b24SSimon Glass * default was set. in that case, we should continue trying to boot
15432e192b24SSimon Glass * labels that haven't been attempted yet.
15442e192b24SSimon Glass *
15452e192b24SSimon Glass * otherwise, the user interrupted or there was some other error and
15462e192b24SSimon Glass * we give up.
15472e192b24SSimon Glass */
15482e192b24SSimon Glass
15492e192b24SSimon Glass if (err == 1) {
15502e192b24SSimon Glass err = label_boot(cmdtp, choice);
15512e192b24SSimon Glass if (!err)
15522e192b24SSimon Glass return;
15532e192b24SSimon Glass } else if (err != -ENOENT) {
15542e192b24SSimon Glass return;
15552e192b24SSimon Glass }
15562e192b24SSimon Glass
15572e192b24SSimon Glass boot_unattempted_labels(cmdtp, cfg);
15582e192b24SSimon Glass }
15592e192b24SSimon Glass
15602e192b24SSimon Glass #ifdef CONFIG_CMD_NET
15612e192b24SSimon Glass /*
15622e192b24SSimon Glass * Boots a system using a pxe file
15632e192b24SSimon Glass *
15642e192b24SSimon Glass * Returns 0 on success, 1 on error.
15652e192b24SSimon Glass */
15662e192b24SSimon Glass static int
do_pxe_boot(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])15672e192b24SSimon Glass do_pxe_boot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
15682e192b24SSimon Glass {
15692e192b24SSimon Glass unsigned long pxefile_addr_r;
15702e192b24SSimon Glass struct pxe_menu *cfg;
15712e192b24SSimon Glass char *pxefile_addr_str;
15722e192b24SSimon Glass
15732e192b24SSimon Glass do_getfile = do_get_tftp;
15742e192b24SSimon Glass
15752e192b24SSimon Glass if (argc == 1) {
15762e192b24SSimon Glass pxefile_addr_str = from_env("pxefile_addr_r");
15772e192b24SSimon Glass if (!pxefile_addr_str)
15782e192b24SSimon Glass return 1;
15792e192b24SSimon Glass
15802e192b24SSimon Glass } else if (argc == 2) {
15812e192b24SSimon Glass pxefile_addr_str = argv[1];
15822e192b24SSimon Glass } else {
15832e192b24SSimon Glass return CMD_RET_USAGE;
15842e192b24SSimon Glass }
15852e192b24SSimon Glass
15862e192b24SSimon Glass if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) {
15872e192b24SSimon Glass printf("Invalid pxefile address: %s\n", pxefile_addr_str);
15882e192b24SSimon Glass return 1;
15892e192b24SSimon Glass }
15902e192b24SSimon Glass
15912e192b24SSimon Glass cfg = parse_pxefile(cmdtp, pxefile_addr_r);
15922e192b24SSimon Glass
15932e192b24SSimon Glass if (cfg == NULL) {
15942e192b24SSimon Glass printf("Error parsing config file\n");
15952e192b24SSimon Glass return 1;
15962e192b24SSimon Glass }
15972e192b24SSimon Glass
15982e192b24SSimon Glass handle_pxe_menu(cmdtp, cfg);
15992e192b24SSimon Glass
16002e192b24SSimon Glass destroy_pxe_menu(cfg);
16012e192b24SSimon Glass
16022e192b24SSimon Glass copy_filename(net_boot_file_name, "", sizeof(net_boot_file_name));
16032e192b24SSimon Glass
16042e192b24SSimon Glass return 0;
16052e192b24SSimon Glass }
16062e192b24SSimon Glass
16072e192b24SSimon Glass static cmd_tbl_t cmd_pxe_sub[] = {
16082e192b24SSimon Glass U_BOOT_CMD_MKENT(get, 1, 1, do_pxe_get, "", ""),
16092e192b24SSimon Glass U_BOOT_CMD_MKENT(boot, 2, 1, do_pxe_boot, "", "")
16102e192b24SSimon Glass };
16112e192b24SSimon Glass
do_pxe(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])16122e192b24SSimon Glass static int do_pxe(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
16132e192b24SSimon Glass {
16142e192b24SSimon Glass cmd_tbl_t *cp;
16152e192b24SSimon Glass
16162e192b24SSimon Glass if (argc < 2)
16172e192b24SSimon Glass return CMD_RET_USAGE;
16182e192b24SSimon Glass
16192e192b24SSimon Glass is_pxe = true;
16202e192b24SSimon Glass
16212e192b24SSimon Glass /* drop initial "pxe" arg */
16222e192b24SSimon Glass argc--;
16232e192b24SSimon Glass argv++;
16242e192b24SSimon Glass
16252e192b24SSimon Glass cp = find_cmd_tbl(argv[0], cmd_pxe_sub, ARRAY_SIZE(cmd_pxe_sub));
16262e192b24SSimon Glass
16272e192b24SSimon Glass if (cp)
16282e192b24SSimon Glass return cp->cmd(cmdtp, flag, argc, argv);
16292e192b24SSimon Glass
16302e192b24SSimon Glass return CMD_RET_USAGE;
16312e192b24SSimon Glass }
16322e192b24SSimon Glass
16332e192b24SSimon Glass U_BOOT_CMD(
16342e192b24SSimon Glass pxe, 3, 1, do_pxe,
16352e192b24SSimon Glass "commands to get and boot from pxe files",
16362e192b24SSimon Glass "get - try to retrieve a pxe file using tftp\npxe "
16372e192b24SSimon Glass "boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n"
16382e192b24SSimon Glass );
16392e192b24SSimon Glass #endif
16402e192b24SSimon Glass
16412e192b24SSimon Glass /*
16422e192b24SSimon Glass * Boots a system using a local disk syslinux/extlinux file
16432e192b24SSimon Glass *
16442e192b24SSimon Glass * Returns 0 on success, 1 on error.
16452e192b24SSimon Glass */
do_sysboot(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])16462e192b24SSimon Glass static int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
16472e192b24SSimon Glass {
16482e192b24SSimon Glass unsigned long pxefile_addr_r;
16492e192b24SSimon Glass struct pxe_menu *cfg;
16502e192b24SSimon Glass char *pxefile_addr_str;
16512e192b24SSimon Glass char *filename;
16522e192b24SSimon Glass int prompt = 0;
16532e192b24SSimon Glass
16542e192b24SSimon Glass is_pxe = false;
16552e192b24SSimon Glass
16562e192b24SSimon Glass if (argc > 1 && strstr(argv[1], "-p")) {
16572e192b24SSimon Glass prompt = 1;
16582e192b24SSimon Glass argc--;
16592e192b24SSimon Glass argv++;
16602e192b24SSimon Glass }
16612e192b24SSimon Glass
16622e192b24SSimon Glass if (argc < 4)
16632e192b24SSimon Glass return cmd_usage(cmdtp);
16642e192b24SSimon Glass
16652e192b24SSimon Glass if (argc < 5) {
16662e192b24SSimon Glass pxefile_addr_str = from_env("pxefile_addr_r");
16672e192b24SSimon Glass if (!pxefile_addr_str)
16682e192b24SSimon Glass return 1;
16692e192b24SSimon Glass } else {
16702e192b24SSimon Glass pxefile_addr_str = argv[4];
16712e192b24SSimon Glass }
16722e192b24SSimon Glass
16732e192b24SSimon Glass if (argc < 6)
167400caae6dSSimon Glass filename = env_get("bootfile");
16752e192b24SSimon Glass else {
16762e192b24SSimon Glass filename = argv[5];
1677382bee57SSimon Glass env_set("bootfile", filename);
16782e192b24SSimon Glass }
16792e192b24SSimon Glass
16802e192b24SSimon Glass if (strstr(argv[3], "ext2"))
16812e192b24SSimon Glass do_getfile = do_get_ext2;
16822e192b24SSimon Glass else if (strstr(argv[3], "fat"))
16832e192b24SSimon Glass do_getfile = do_get_fat;
16842e192b24SSimon Glass else if (strstr(argv[3], "any"))
16852e192b24SSimon Glass do_getfile = do_get_any;
16862e192b24SSimon Glass else {
16872e192b24SSimon Glass printf("Invalid filesystem: %s\n", argv[3]);
16882e192b24SSimon Glass return 1;
16892e192b24SSimon Glass }
16902e192b24SSimon Glass fs_argv[1] = argv[1];
16912e192b24SSimon Glass fs_argv[2] = argv[2];
16922e192b24SSimon Glass
16932e192b24SSimon Glass if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) {
16942e192b24SSimon Glass printf("Invalid pxefile address: %s\n", pxefile_addr_str);
16952e192b24SSimon Glass return 1;
16962e192b24SSimon Glass }
16972e192b24SSimon Glass
16982e192b24SSimon Glass if (get_pxe_file(cmdtp, filename, pxefile_addr_r) < 0) {
16992e192b24SSimon Glass printf("Error reading config file\n");
17002e192b24SSimon Glass return 1;
17012e192b24SSimon Glass }
17022e192b24SSimon Glass
17032e192b24SSimon Glass cfg = parse_pxefile(cmdtp, pxefile_addr_r);
17042e192b24SSimon Glass
17052e192b24SSimon Glass if (cfg == NULL) {
17062e192b24SSimon Glass printf("Error parsing config file\n");
17072e192b24SSimon Glass return 1;
17082e192b24SSimon Glass }
17092e192b24SSimon Glass
17102e192b24SSimon Glass if (prompt)
17112e192b24SSimon Glass cfg->prompt = 1;
17122e192b24SSimon Glass
17132e192b24SSimon Glass handle_pxe_menu(cmdtp, cfg);
17142e192b24SSimon Glass
17152e192b24SSimon Glass destroy_pxe_menu(cfg);
17162e192b24SSimon Glass
17172e192b24SSimon Glass return 0;
17182e192b24SSimon Glass }
17192e192b24SSimon Glass
17202e192b24SSimon Glass U_BOOT_CMD(
17212e192b24SSimon Glass sysboot, 7, 1, do_sysboot,
17222e192b24SSimon Glass "command to get and boot from syslinux files",
17232e192b24SSimon Glass "[-p] <interface> <dev[:part]> <ext2|fat|any> [addr] [filename]\n"
17242e192b24SSimon Glass " - load and parse syslinux menu file 'filename' from ext2, fat\n"
17252e192b24SSimon Glass " or any filesystem on 'dev' on 'interface' to address 'addr'"
17262e192b24SSimon Glass );
1727