]> git.sur5r.net Git - u-boot/blobdiff - common/cmd_pxe.c
pxe: try bootz if bootm fails to find a valid image
[u-boot] / common / cmd_pxe.c
index 77a7dd17ac1d595b4baa77bec92d251050427654..4e2811e156ffe6f505f2a1dcbff070c22fe8fe7d 100644 (file)
@@ -31,7 +31,7 @@
  * environment.  It always returns what getenv does, so it can be used in
  * place of getenv without changing error handling otherwise.
  */
-static char *from_env(char *envvar)
+static char *from_env(const char *envvar)
 {
        char *ret;
 
@@ -55,37 +55,21 @@ static char *from_env(char *envvar)
  */
 static int format_mac_pxe(char *outbuf, size_t outbuf_len)
 {
-       size_t ethaddr_len;
-       char *p, *ethaddr;
+       uchar ethaddr[6];
 
-       ethaddr = from_env("ethaddr");
-
-       if (!ethaddr)
-               return -ENOENT;
-
-       ethaddr_len = strlen(ethaddr);
-
-       /*
-        * ethaddr_len + 4 gives room for "01-", ethaddr, and a NUL byte at
-        * the end.
-        */
-       if (outbuf_len < ethaddr_len + 4) {
-               printf("outbuf is too small (%d < %d)\n",
-                               outbuf_len, ethaddr_len + 4);
+       if (outbuf_len < 21) {
+               printf("outbuf is too small (%d < 21)\n", outbuf_len);
 
                return -EINVAL;
        }
 
-       strcpy(outbuf, "01-");
-
-       for (p = outbuf + 3; *ethaddr; ethaddr++, p++) {
-               if (*ethaddr == ':')
-                       *p = '-';
-               else
-                       *p = tolower(*ethaddr);
-       }
+       if (!eth_getenv_enetaddr_by_index("eth", eth_get_dev_index(),
+                                         ethaddr))
+               return -ENOENT;
 
-       *p = '\0';
+       sprintf(outbuf, "01-%02x-%02x-%02x-%02x-%02x-%02x",
+               ethaddr[0], ethaddr[1], ethaddr[2],
+               ethaddr[3], ethaddr[4], ethaddr[5]);
 
        return 1;
 }
@@ -131,14 +115,14 @@ static int get_bootfile_path(const char *file_path, char *bootfile_path,
        return 1;
 }
 
-static int (*do_getfile)(char *file_path, char *file_addr);
+static int (*do_getfile)(const char *file_path, char *file_addr);
 
-static int do_get_tftp(char *file_path, char *file_addr)
+static int do_get_tftp(const char *file_path, char *file_addr)
 {
        char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
 
        tftp_argv[1] = file_addr;
-       tftp_argv[2] = file_path;
+       tftp_argv[2] = (void *)file_path;
 
        if (do_tftpb(NULL, 0, 3, tftp_argv))
                return -ENOENT;
@@ -148,12 +132,12 @@ static int do_get_tftp(char *file_path, char *file_addr)
 
 static char *fs_argv[5];
 
-static int do_get_ext2(char *file_path, char *file_addr)
+static int do_get_ext2(const char *file_path, char *file_addr)
 {
 #ifdef CONFIG_CMD_EXT2
        fs_argv[0] = "ext2load";
        fs_argv[3] = file_addr;
-       fs_argv[4] = file_path;
+       fs_argv[4] = (void *)file_path;
 
        if (!do_ext2load(NULL, 0, 5, fs_argv))
                return 1;
@@ -161,12 +145,12 @@ static int do_get_ext2(char *file_path, char *file_addr)
        return -ENOENT;
 }
 
-static int do_get_fat(char *file_path, char *file_addr)
+static int do_get_fat(const char *file_path, char *file_addr)
 {
 #ifdef CONFIG_CMD_FAT
        fs_argv[0] = "fatload";
        fs_argv[3] = file_addr;
-       fs_argv[4] = file_path;
+       fs_argv[4] = (void *)file_path;
 
        if (!do_fat_fsload(NULL, 0, 5, fs_argv))
                return 1;
@@ -182,7 +166,7 @@ static int do_get_fat(char *file_path, char *file_addr)
  *
  * Returns 1 for success, or < 0 on error.
  */
-static int get_relfile(char *file_path, void *file_addr)
+static int get_relfile(const char *file_path, void *file_addr)
 {
        size_t path_len;
        char relfile[MAX_TFTP_PATH_LEN+1];
@@ -221,7 +205,7 @@ static int get_relfile(char *file_path, void *file_addr)
  *
  * Returns 1 on success, or < 0 for error.
  */
-static int get_pxe_file(char *file_path, void *file_addr)
+static int get_pxe_file(const char *file_path, void *file_addr)
 {
        unsigned long config_file_size;
        char *tftp_filesize;
@@ -258,7 +242,7 @@ static int get_pxe_file(char *file_path, void *file_addr)
  *
  * Returns 1 on success or < 0 on error.
  */
-static int get_pxelinux_path(char *file, void *pxefile_addr_r)
+static int get_pxelinux_path(const char *file, void *pxefile_addr_r)
 {
        size_t base_len = strlen(PXELINUX_DIR);
        char path[MAX_TFTP_PATH_LEN+1];
@@ -398,7 +382,7 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  *
  * Returns 1 on success or < 0 on error.
  */
-static int get_relfile_envaddr(char *file_path, char *envaddr_name)
+static int get_relfile_envaddr(const char *file_path, const char *envaddr_name)
 {
        unsigned long file_addr;
        char *envaddr;
@@ -450,8 +434,10 @@ struct pxe_label {
        char *kernel;
        char *append;
        char *initrd;
+       char *fdt;
        int attempted;
        int localboot;
+       int localboot_val;
        struct list_head list;
 };
 
@@ -517,6 +503,9 @@ static void label_destroy(struct pxe_label *label)
        if (label->initrd)
                free(label->initrd);
 
+       if (label->fdt)
+               free(label->fdt);
+
        free(label);
 }
 
@@ -541,6 +530,9 @@ static void label_print(void *data)
 
        if (label->initrd)
                printf("\t\tinitrd: %s\n", label->initrd);
+
+       if (label->fdt)
+               printf("\tfdt: %s\n", label->fdt);
 }
 
 /*
@@ -554,33 +546,19 @@ static void label_print(void *data)
  */
 static int label_localboot(struct pxe_label *label)
 {
-       char *localcmd, *dupcmd;
-       int ret;
+       char *localcmd;
 
        localcmd = from_env("localcmd");
 
        if (!localcmd)
                return -ENOENT;
 
-       /*
-        * dup the command to avoid any issues with the version of it existing
-        * in the environment changing during the execution of the command.
-        */
-       dupcmd = strdup(localcmd);
-
-       if (!dupcmd)
-               return -ENOMEM;
-
        if (label->append)
                setenv("bootargs", label->append);
 
-       printf("running: %s\n", dupcmd);
-
-       ret = run_command(dupcmd, 0);
+       debug("running: %s\n", localcmd);
 
-       free(dupcmd);
-
-       return ret;
+       return run_command_list(localcmd, strlen(localcmd), 0);
 }
 
 /*
@@ -598,9 +576,10 @@ 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];
        int bootm_argc = 3;
 
        label_print(label);
@@ -608,24 +587,28 @@ static void label_boot(struct pxe_label *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] = "-";
        }
@@ -633,7 +616,7 @@ 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->append)
@@ -642,15 +625,40 @@ static void label_boot(struct pxe_label *label)
        bootm_argv[1] = getenv("kernel_addr_r");
 
        /*
-        * fdt usage is optional.  If there is an fdt_addr specified, we will
-        * pass it along to bootm, and adjust argc appropriately.
+        * fdt usage is optional:
+        * It handles the following scenarios. All scenarios are exclusive
+        *
+        * Scenario 1: If fdt_addr_r specified and "fdt" label is defined in
+        * pxe file, retrieve fdt blob from server. Pass fdt_addr_r to bootm,
+        * and adjust argc appropriately.
+        *
+        * Scenario 2: If there is an fdt_addr specified, pass it along to
+        * bootm, and adjust argc appropriately.
+        *
+        * Scenario 3: fdt blob is not available.
         */
-       bootm_argv[3] = getenv("fdt_addr");
+       bootm_argv[3] = getenv("fdt_addr_r");
+
+       /* if fdt label is defined then get fdt from server */
+       if (bootm_argv[3] && label->fdt) {
+               if (get_relfile_envaddr(label->fdt, "fdt_addr_r") < 0) {
+                       printf("Skipping %s for failure retrieving fdt\n",
+                                       label->name);
+                       return 1;
+               }
+       } else
+               bootm_argv[3] = getenv("fdt_addr");
 
        if (bootm_argv[3])
                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;
 }
 
 /*
@@ -672,6 +680,7 @@ enum token_type {
        T_DEFAULT,
        T_PROMPT,
        T_INCLUDE,
+       T_FDT,
        T_INVALID
 };
 
@@ -699,6 +708,7 @@ static const struct token keywords[] = {
        {"append", T_APPEND},
        {"initrd", T_INITRD},
        {"include", T_INCLUDE},
+       {"fdt", T_FDT},
        {NULL, T_INVALID}
 };
 
@@ -889,7 +899,6 @@ static int parse_integer(char **c, int *dst)
 {
        struct token t;
        char *s = *c;
-       unsigned long temp;
 
        get_token(c, &t, L_SLITERAL);
 
@@ -898,12 +907,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);
 
@@ -1088,8 +1092,14 @@ static int parse_label(char **c, struct pxe_menu *cfg)
                                err = parse_sliteral(c, &label->initrd);
                        break;
 
+               case T_FDT:
+                       if (!label->fdt)
+                               err = parse_sliteral(c, &label->fdt);
+                       break;
+
                case T_LOCALBOOT:
-                       err = parse_integer(c, &label->localboot);
+                       label->localboot = 1;
+                       err = parse_integer(c, &label->localboot_val);
                        break;
 
                case T_EOL:
@@ -1261,7 +1271,8 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
        /*
         * Create a menu and add items for all the labels.
         */
-       m = menu_create(cfg->title, cfg->timeout, cfg->prompt, label_print);
+       m = menu_create(cfg->title, cfg->timeout, cfg->prompt, label_print,
+                       NULL, NULL);
 
        if (!m)
                return NULL;
@@ -1347,10 +1358,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);
 }