]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - common/cmd_pxe.c
Merge branch 'master' of git://git.denx.de/u-boot-i2c
[karo-tx-uboot.git] / common / cmd_pxe.c
index 817114515f6dfa8e6b7c0a5904f310de96e3a050..a2fb50ab9d2e93e16d729de5f9f6190737448f06 100644 (file)
@@ -1,19 +1,9 @@
 /*
  * Copyright 2010-2011 Calxeda, Inc.
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier:    GPL-2.0+
  */
+
 #include <common.h>
 #include <command.h>
 #include <malloc.h>
 
 #define MAX_TFTP_PATH_LEN 127
 
+const char *pxe_default_paths[] = {
+#ifdef CONFIG_SYS_SOC
+       "default-" CONFIG_SYS_ARCH "-" CONFIG_SYS_SOC,
+#endif
+       "default-" CONFIG_SYS_ARCH,
+       "default",
+       NULL
+};
+
 /*
  * Like getenv, but prints an error if envvar isn't defined in the
  * environment.  It always returns what getenv does, so it can be used in
@@ -339,7 +338,7 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
        char *pxefile_addr_str;
        unsigned long pxefile_addr_r;
-       int err;
+       int err, i = 0;
 
        do_getfile = do_get_tftp;
 
@@ -360,16 +359,23 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
         * Keep trying paths until we successfully get a file we're looking
         * for.
         */
-       if (pxe_uuid_path((void *)pxefile_addr_r) > 0
-               || pxe_mac_path((void *)pxefile_addr_r) > 0
-               || pxe_ipaddr_paths((void *)pxefile_addr_r) > 0
-               || get_pxelinux_path("default", (void *)pxefile_addr_r) > 0) {
-
+       if (pxe_uuid_path((void *)pxefile_addr_r) > 0 ||
+           pxe_mac_path((void *)pxefile_addr_r) > 0 ||
+           pxe_ipaddr_paths((void *)pxefile_addr_r) > 0) {
                printf("Config file found\n");
 
                return 0;
        }
 
+       while (pxe_default_paths[i]) {
+               if (get_pxelinux_path(pxe_default_paths[i],
+                                     (void *)pxefile_addr_r) > 0) {
+                       printf("Config file found\n");
+                       return 0;
+               }
+               i++;
+       }
+
        printf("Config file not found\n");
 
        return 1;
@@ -429,14 +435,17 @@ static int get_relfile_envaddr(const char *file_path, const char *envaddr_name)
  * list - lets these form a list, which a pxe_menu struct will hold.
  */
 struct pxe_label {
+       char num[4];
        char *name;
        char *menu;
        char *kernel;
        char *append;
        char *initrd;
        char *fdt;
+       int ipappend;
        int attempted;
        int localboot;
+       int localboot_val;
        struct list_head list;
 };
 
@@ -517,21 +526,9 @@ static void label_destroy(struct pxe_label *label)
 static void label_print(void *data)
 {
        struct pxe_label *label = data;
-       const char *c = label->menu ? label->menu : label->kernel;
-
-       printf("%s:\t%s\n", label->name, c);
-
-       if (label->kernel)
-               printf("\t\tkernel: %s\n", label->kernel);
+       const char *c = label->menu ? label->menu : label->name;
 
-       if (label->append)
-               printf("\t\tappend: %s\n", label->append);
-
-       if (label->initrd)
-               printf("\t\tinitrd: %s\n", label->initrd);
-
-       if (label->fdt)
-               printf("\tfdt: %s\n", label->fdt);
+       printf("%s:\t%s\n", label->num, c);
 }
 
 /*
@@ -575,34 +572,43 @@ static int label_localboot(struct pxe_label *label)
  * If the label specifies an 'append' line, its contents will overwrite that
  * of the 'bootargs' environment variable.
  */
-static void label_boot(struct pxe_label *label)
+static int label_boot(struct pxe_label *label)
 {
        char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
+       char initrd_str[22];
+       char mac_str[29] = "";
+       char ip_str[68] = "";
+       char *bootargs;
        int bootm_argc = 3;
+       int len = 0;
 
        label_print(label);
 
        label->attempted = 1;
 
        if (label->localboot) {
-               label_localboot(label);
-               return;
+               if (label->localboot_val >= 0)
+                       label_localboot(label);
+               return 0;
        }
 
        if (label->kernel == NULL) {
                printf("No kernel given, skipping %s\n",
                                label->name);
-               return;
+               return 1;
        }
 
        if (label->initrd) {
                if (get_relfile_envaddr(label->initrd, "ramdisk_addr_r") < 0) {
                        printf("Skipping %s for failure retrieving initrd\n",
                                        label->name);
-                       return;
+                       return 1;
                }
 
-               bootm_argv[2] = getenv("ramdisk_addr_r");
+               bootm_argv[2] = initrd_str;
+               strcpy(bootm_argv[2], getenv("ramdisk_addr_r"));
+               strcat(bootm_argv[2], ":");
+               strcat(bootm_argv[2], getenv("filesize"));
        } else {
                bootm_argv[2] = "-";
        }
@@ -610,11 +616,43 @@ static void label_boot(struct pxe_label *label)
        if (get_relfile_envaddr(label->kernel, "kernel_addr_r") < 0) {
                printf("Skipping %s for failure retrieving kernel\n",
                                label->name);
-               return;
+               return 1;
+       }
+
+       if (label->ipappend & 0x1) {
+               sprintf(ip_str, " ip=%s:%s:%s:%s",
+                       getenv("ipaddr"), getenv("serverip"),
+                       getenv("gatewayip"), getenv("netmask"));
+               len += strlen(ip_str);
+       }
+
+       if (label->ipappend & 0x2) {
+               int err;
+               strcpy(mac_str, " BOOTIF=");
+               err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8);
+               if (err < 0)
+                       mac_str[0] = '\0';
+               len += strlen(mac_str);
        }
 
        if (label->append)
-               setenv("bootargs", label->append);
+               len += strlen(label->append);
+
+       if (len) {
+               bootargs = malloc(len + 1);
+               if (!bootargs)
+                       return 1;
+               bootargs[0] = '\0';
+               if (label->append)
+                       strcpy(bootargs, label->append);
+               strcat(bootargs, ip_str);
+               strcat(bootargs, mac_str);
+
+               setenv("bootargs", bootargs);
+               printf("append: %s\n", bootargs);
+
+               free(bootargs);
+       }
 
        bootm_argv[1] = getenv("kernel_addr_r");
 
@@ -638,7 +676,7 @@ static void label_boot(struct pxe_label *label)
                if (get_relfile_envaddr(label->fdt, "fdt_addr_r") < 0) {
                        printf("Skipping %s for failure retrieving fdt\n",
                                        label->name);
-                       return;
+                       return 1;
                }
        } else
                bootm_argv[3] = getenv("fdt_addr");
@@ -647,6 +685,12 @@ static void label_boot(struct pxe_label *label)
                bootm_argc = 4;
 
        do_bootm(NULL, 0, bootm_argc, bootm_argv);
+
+#ifdef CONFIG_CMD_BOOTZ
+       /* Try booting a zImage if do_bootm returns */
+       do_bootz(NULL, 0, bootm_argc, bootm_argv);
+#endif
+       return 1;
 }
 
 /*
@@ -669,6 +713,8 @@ enum token_type {
        T_PROMPT,
        T_INCLUDE,
        T_FDT,
+       T_ONTIMEOUT,
+       T_IPAPPEND,
        T_INVALID
 };
 
@@ -697,6 +743,8 @@ static const struct token keywords[] = {
        {"initrd", T_INITRD},
        {"include", T_INCLUDE},
        {"fdt", T_FDT},
+       {"ontimeout", T_ONTIMEOUT,},
+       {"ipappend", T_IPAPPEND,},
        {NULL, T_INVALID}
 };
 
@@ -887,7 +935,6 @@ static int parse_integer(char **c, int *dst)
 {
        struct token t;
        char *s = *c;
-       unsigned long temp;
 
        get_token(c, &t, L_SLITERAL);
 
@@ -896,12 +943,7 @@ static int parse_integer(char **c, int *dst)
                return -EINVAL;
        }
 
-       if (strict_strtoul(t.val, 10, &temp) < 0) {
-               printf("Expected unsigned integer: %s\n", t.val);
-               return -EINVAL;
-       }
-
-       *dst = (int)temp;
+       *dst = simple_strtol(t.val, NULL, 10);
 
        free(t.val);
 
@@ -1000,10 +1042,8 @@ static int parse_label_menu(char **c, struct pxe_menu *cfg,
 
        switch (t.type) {
        case T_DEFAULT:
-               if (cfg->default_label)
-                       free(cfg->default_label);
-
-               cfg->default_label = strdup(label->name);
+               if (!cfg->default_label)
+                       cfg->default_label = strdup(label->name);
 
                if (!cfg->default_label)
                        return -ENOMEM;
@@ -1092,7 +1132,12 @@ static int parse_label(char **c, struct pxe_menu *cfg)
                        break;
 
                case T_LOCALBOOT:
-                       err = parse_integer(c, &label->localboot);
+                       label->localboot = 1;
+                       err = parse_integer(c, &label->localboot_val);
+                       break;
+
+               case T_IPAPPEND:
+                       err = parse_integer(c, &label->ipappend);
                        break;
 
                case T_EOL:
@@ -1148,6 +1193,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level)
                err = 0;
                switch (t.type) {
                case T_MENU:
+                       cfg->prompt = 1;
                        err = parse_menu(&p, cfg, b, nest_level);
                        break;
 
@@ -1160,6 +1206,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level)
                        break;
 
                case T_DEFAULT:
+               case T_ONTIMEOUT:
                        err = parse_sliteral(&p, &label_name);
 
                        if (label_name) {
@@ -1177,7 +1224,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level)
                        break;
 
                case T_PROMPT:
-                       err = parse_integer(&p, &cfg->prompt);
+                       eol_or_eof(&p);
                        break;
 
                case T_EOL:
@@ -1260,6 +1307,8 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
        struct list_head *pos;
        struct menu *m;
        int err;
+       int i = 1;
+       char *default_num = NULL;
 
        /*
         * Create a menu and add items for all the labels.
@@ -1273,18 +1322,23 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
        list_for_each(pos, &cfg->labels) {
                label = list_entry(pos, struct pxe_label, list);
 
-               if (menu_item_add(m, label->name, label) != 1) {
+               sprintf(label->num, "%d", i++);
+               if (menu_item_add(m, label->num, label) != 1) {
                        menu_destroy(m);
                        return NULL;
                }
+               if (cfg->default_label &&
+                   (strcmp(label->name, cfg->default_label) == 0))
+                       default_num = label->num;
+
        }
 
        /*
         * After we've created items for each label in the menu, set the
         * menu's default label if one was specified.
         */
-       if (cfg->default_label) {
-               err = menu_default_set(m, cfg->default_label);
+       if (default_num) {
+               err = menu_default_set(m, default_num);
                if (err != 1) {
                        if (err != -ENOENT) {
                                menu_destroy(m);
@@ -1351,10 +1405,13 @@ static void handle_pxe_menu(struct pxe_menu *cfg)
         * we give up.
         */
 
-       if (err == 1)
-               label_boot(choice);
-       else if (err != -ENOENT)
+       if (err == 1) {
+               err = label_boot(choice);
+               if (!err)
+                       return;
+       } else if (err != -ENOENT) {
                return;
+       }
 
        boot_unattempted_labels(cfg);
 }