diff options
Diffstat (limited to 'boot/pxe_utils.c')
-rw-r--r-- | boot/pxe_utils.c | 404 |
1 files changed, 183 insertions, 221 deletions
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index d5e1bead125..96205626750 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -5,7 +5,6 @@ */ #include <common.h> -#include <bootm.h> #include <command.h> #include <dm.h> #include <env.h> @@ -471,220 +470,6 @@ skip_overlay: #endif /** - * calc_fdt_fname() - Figure out the filename to use for the FDT - * - * Determine the path to the FDT filename, based on the "fdtfile" environment - * variable. Use <soc>-<board>.dtb as a fallback - * - * @fdtdir: Directory to use for the FDT file - * Return: allocated filename (including directory), or NULL if out of memory - */ -static char *calc_fdt_fname(const char *fdtdir) -{ - char *fdtfile; - char *f1, *f2, *f3, *f4, *slash; - int len; - - f1 = env_get("fdtfile"); - if (f1) { - f2 = ""; - f3 = ""; - f4 = ""; - } else { - /* - * For complex cases where this code doesn't generate the - * correct filename, the board code should set $fdtfile during - * early boot, or the boot scripts should set $fdtfile before - * invoking "pxe" or "sysboot". - */ - f1 = env_get("soc"); - f2 = "-"; - f3 = env_get("board"); - f4 = ".dtb"; - if (!f1) { - f1 = ""; - f2 = ""; - } - if (!f3) { - f2 = ""; - f3 = ""; - } - } - - len = strlen(fdtdir); - if (!len) - slash = "./"; - else if (fdtdir[len - 1] != '/') - slash = "/"; - else - slash = ""; - - len = strlen(fdtdir) + strlen(slash) + strlen(f1) + strlen(f2) + - strlen(f3) + strlen(f4) + 1; - fdtfile = malloc(len); - if (!fdtfile) { - printf("malloc fail (FDT filename)\n"); - return NULL; - } - - snprintf(fdtfile, len, "%s%s%s%s%s%s", fdtdir, slash, f1, f2, f3, f4); - - return fdtfile; -} - -/** - * label_run_boot() - Run the correct boot procedure - * - * fdt usage is optional: - * It handles the following scenarios. - * - * Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is - * defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to - * bootm, and adjust argc appropriately. - * - * If retrieve fails and no exact fdt blob is specified in pxe file with - * "fdt" label, try Scenario 2. - * - * Scenario 2: If there is an fdt_addr specified, pass it along to - * bootm, and adjust argc appropriately. - * - * Scenario 3: If there is an fdtcontroladdr specified, pass it along to - * bootm, and adjust argc appropriately, unless the image type is fitImage. - * - * Scenario 4: fdt blob is not available. - * - * @ctx: PXE context - * @label: Label to process - * @kernel_addr: string containing the kernel address / config - * @initrd_str: string containing the initrd address / size - * @initrd_addr_str: initrd address, or NULL if none - * @initrd_filesize: initrd size in bytes; only valid if initrd_addr_str is not - * NULL - * Returns does not return on success, otherwise returns 0 if a localboot - * label was processed, or 1 on error - */ -static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, - char *kernel_addr, char *initrd_str, - char *initrd_addr_str, char *initrd_filesize) -{ - struct bootm_info bmi; - const char *fdt_addr; - ulong kernel_addr_r; - void *buf; - int ret; - - if (IS_ENABLED(CONFIG_BOOTM)) - bootm_init(&bmi); - - fdt_addr = env_get("fdt_addr_r"); - - /* For FIT, the label can be identical to kernel one */ - if (label->fdt && !strcmp(label->kernel_label, label->fdt)) { - fdt_addr = kernel_addr; - /* if fdt label is defined then get fdt from server */ - } else if (fdt_addr) { - char *fdtfile = NULL; - char *fdtfilefree = NULL; - - if (label->fdt) { - if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { - if (strcmp("-", label->fdt)) - fdtfile = label->fdt; - } else { - fdtfile = label->fdt; - } - } else if (label->fdtdir) { - fdtfilefree = calc_fdt_fname(label->fdtdir); - if (!fdtfilefree) - return -ENOMEM; - fdtfile = fdtfilefree; - } - - if (fdtfile) { - int err = get_relfile_envaddr(ctx, fdtfile, - "fdt_addr_r", NULL); - - free(fdtfilefree); - if (err < 0) { - fdt_addr = NULL; - - if (label->fdt) { - printf("Skipping %s for failure retrieving FDT\n", - label->name); - return -ENOENT; - } - - if (label->fdtdir) { - printf("Skipping fdtdir %s for failure retrieving dts\n", - label->fdtdir); - } - } - - if (label->kaslrseed) - label_boot_kaslrseed(); - -#ifdef CONFIG_OF_LIBFDT_OVERLAY - if (label->fdtoverlays) - label_boot_fdtoverlay(ctx, label); -#endif - } else { - fdt_addr = NULL; - } - } - - bmi.addr_img = kernel_addr; - - if (initrd_addr_str) - bmi.conf_ramdisk = initrd_str; - - if (!fdt_addr) { - if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { - if (strcmp("-", label->fdt)) - fdt_addr = env_get("fdt_addr"); - } else { - fdt_addr = env_get("fdt_addr"); - } - } - - kernel_addr_r = genimg_get_kernel_addr(kernel_addr); - buf = map_sysmem(kernel_addr_r, 0); - - if (!fdt_addr && genimg_get_format(buf) != IMAGE_FORMAT_FIT) { - if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { - if (strcmp("-", label->fdt)) - fdt_addr = env_get("fdtcontroladdr"); - } else { - fdt_addr = env_get("fdtcontroladdr"); - } - } - - bmi.conf_fdt = fdt_addr; - - /* Try bootm for legacy and FIT format image */ - if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID && - IS_ENABLED(CONFIG_BOOTM)) - ret = bootm_run(&bmi); - /* Try booting an AArch64 Linux kernel image */ - else if (IS_ENABLED(CONFIG_BOOTM)) - ret = booti_run(&bmi); - /* Try booting a Image */ - else if (IS_ENABLED(CONFIG_BOOTM)) - ret = bootz_run(&bmi); - /* Try booting an x86_64 Linux kernel image */ - else if (IS_ENABLED(CONFIG_ZBOOT)) - ret = zboot_run(hextoul(kernel_addr, NULL), 0, - initrd_addr_str ? - hextoul(initrd_addr_str, NULL) : 0, - initrd_addr_str ? - hextoul(initrd_filesize, NULL) : 0, - 0, NULL); - - unmap_sysmem(buf); - - return 0; -} - -/** * label_boot() - Boot according to the contents of a pxe_label * * If we can't boot for any reason, we return. A successful boot never @@ -706,6 +491,8 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, */ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) { + char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL }; + char *zboot_argv[] = { "zboot", NULL, "0", NULL, NULL }; char *kernel_addr = NULL; char *initrd_addr_str = NULL; char initrd_filesize[10]; @@ -713,7 +500,11 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) char mac_str[29] = ""; char ip_str[68] = ""; char *fit_addr = NULL; - int ret; + int bootm_argc = 2; + int zboot_argc = 3; + int len = 0; + ulong kernel_addr_r; + void *buf; label_print(label); @@ -754,10 +545,9 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) /* For FIT, the label can be identical to kernel one */ if (label->initrd && !strcmp(label->kernel_label, label->initrd)) { - initrd_addr_str = kernel_addr; + initrd_addr_str = kernel_addr; } else if (label->initrd) { ulong size; - if (get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r", &size) < 0) { printf("Skipping %s for failure retrieving initrd\n", @@ -803,7 +593,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) } if (label->append) - strlcpy(bootargs, label->append, sizeof(bootargs)); + strncpy(bootargs, label->append, sizeof(bootargs)); strcat(bootargs, ip_str); strcat(bootargs, mac_str); @@ -814,8 +604,180 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) printf("append: %s\n", finalbootargs); } - ret = label_run_boot(ctx, label, kernel_addr, initrd_str, - initrd_addr_str, initrd_filesize); + /* + * fdt usage is optional: + * It handles the following scenarios. + * + * Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is + * defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to + * bootm, and adjust argc appropriately. + * + * If retrieve fails and no exact fdt blob is specified in pxe file with + * "fdt" label, try Scenario 2. + * + * Scenario 2: If there is an fdt_addr specified, pass it along to + * bootm, and adjust argc appropriately. + * + * Scenario 3: If there is an fdtcontroladdr specified, pass it along to + * bootm, and adjust argc appropriately, unless the image type is fitImage. + * + * Scenario 4: fdt blob is not available. + */ + bootm_argv[3] = env_get("fdt_addr_r"); + + /* For FIT, the label can be identical to kernel one */ + if (label->fdt && !strcmp(label->kernel_label, label->fdt)) { + bootm_argv[3] = kernel_addr; + /* if fdt label is defined then get fdt from server */ + } else if (bootm_argv[3]) { + char *fdtfile = NULL; + char *fdtfilefree = NULL; + + if (label->fdt) { + if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { + if (strcmp("-", label->fdt)) + fdtfile = label->fdt; + } else { + fdtfile = label->fdt; + } + } else if (label->fdtdir) { + char *f1, *f2, *f3, *f4, *slash; + + f1 = env_get("fdtfile"); + if (f1) { + f2 = ""; + f3 = ""; + f4 = ""; + } else { + /* + * For complex cases where this code doesn't + * generate the correct filename, the board + * code should set $fdtfile during early boot, + * or the boot scripts should set $fdtfile + * before invoking "pxe" or "sysboot". + */ + f1 = env_get("soc"); + f2 = "-"; + f3 = env_get("board"); + f4 = ".dtb"; + if (!f1) { + f1 = ""; + f2 = ""; + } + if (!f3) { + f2 = ""; + f3 = ""; + } + } + + len = strlen(label->fdtdir); + if (!len) + slash = "./"; + else if (label->fdtdir[len - 1] != '/') + slash = "/"; + else + slash = ""; + + len = strlen(label->fdtdir) + strlen(slash) + + strlen(f1) + strlen(f2) + strlen(f3) + + strlen(f4) + 1; + fdtfilefree = malloc(len); + if (!fdtfilefree) { + printf("malloc fail (FDT filename)\n"); + goto cleanup; + } + + snprintf(fdtfilefree, len, "%s%s%s%s%s%s", + label->fdtdir, slash, f1, f2, f3, f4); + fdtfile = fdtfilefree; + } + + if (fdtfile) { + int err = get_relfile_envaddr(ctx, fdtfile, + "fdt_addr_r", NULL); + + free(fdtfilefree); + if (err < 0) { + bootm_argv[3] = NULL; + + if (label->fdt) { + printf("Skipping %s for failure retrieving FDT\n", + label->name); + goto cleanup; + } + + if (label->fdtdir) { + printf("Skipping fdtdir %s for failure retrieving dts\n", + label->fdtdir); + } + } + + if (label->kaslrseed) + label_boot_kaslrseed(); + +#ifdef CONFIG_OF_LIBFDT_OVERLAY + if (label->fdtoverlays) + label_boot_fdtoverlay(ctx, label); +#endif + } else { + bootm_argv[3] = NULL; + } + } + + bootm_argv[1] = kernel_addr; + zboot_argv[1] = kernel_addr; + + if (initrd_addr_str) { + bootm_argv[2] = initrd_str; + bootm_argc = 3; + + zboot_argv[3] = initrd_addr_str; + zboot_argv[4] = initrd_filesize; + zboot_argc = 5; + } + + if (!bootm_argv[3]) { + if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { + if (strcmp("-", label->fdt)) + bootm_argv[3] = env_get("fdt_addr"); + } else { + bootm_argv[3] = env_get("fdt_addr"); + } + } + + kernel_addr_r = genimg_get_kernel_addr(kernel_addr); + buf = map_sysmem(kernel_addr_r, 0); + + if (!bootm_argv[3] && genimg_get_format(buf) != IMAGE_FORMAT_FIT) { + if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) { + if (strcmp("-", label->fdt)) + bootm_argv[3] = env_get("fdtcontroladdr"); + } else { + bootm_argv[3] = env_get("fdtcontroladdr"); + } + } + + if (bootm_argv[3]) { + if (!bootm_argv[2]) + bootm_argv[2] = "-"; + bootm_argc = 4; + } + + /* Try bootm for legacy and FIT format image */ + if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID && + IS_ENABLED(CONFIG_CMD_BOOTM)) + do_bootm(ctx->cmdtp, 0, bootm_argc, bootm_argv); + /* Try booting an AArch64 Linux kernel image */ + else if (IS_ENABLED(CONFIG_CMD_BOOTI)) + do_booti(ctx->cmdtp, 0, bootm_argc, bootm_argv); + /* Try booting a Image */ + else if (IS_ENABLED(CONFIG_CMD_BOOTZ)) + do_bootz(ctx->cmdtp, 0, bootm_argc, bootm_argv); + /* Try booting an x86_64 Linux kernel image */ + else if (IS_ENABLED(CONFIG_CMD_ZBOOT)) + do_zboot_parent(ctx->cmdtp, 0, zboot_argc, zboot_argv, NULL); + + unmap_sysmem(buf); cleanup: free(fit_addr); |