diff options
Diffstat (limited to 'boot/pxe_utils.c')
-rw-r--r-- | boot/pxe_utils.c | 404 |
1 files changed, 221 insertions, 183 deletions
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index 96205626750..d5e1bead125 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -5,6 +5,7 @@ */ #include <common.h> +#include <bootm.h> #include <command.h> #include <dm.h> #include <env.h> @@ -470,6 +471,220 @@ 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 @@ -491,8 +706,6 @@ skip_overlay: */ 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]; @@ -500,11 +713,7 @@ 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 bootm_argc = 2; - int zboot_argc = 3; - int len = 0; - ulong kernel_addr_r; - void *buf; + int ret; label_print(label); @@ -545,9 +754,10 @@ 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", @@ -593,7 +803,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) } if (label->append) - strncpy(bootargs, label->append, sizeof(bootargs)); + strlcpy(bootargs, label->append, sizeof(bootargs)); strcat(bootargs, ip_str); strcat(bootargs, mac_str); @@ -604,180 +814,8 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) printf("append: %s\n", finalbootargs); } - /* - * 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); + ret = label_run_boot(ctx, label, kernel_addr, initrd_str, + initrd_addr_str, initrd_filesize); cleanup: free(fit_addr); |