static int fit_check_kernel(const void *fit, int os_noffset, int verify) { fit_image_print(fit, os_noffset, " "); if (verify) { puts(" Verifying Hash Integrity ... "); if (!fit_image_verify(fit, os_noffset)) { puts("Bad Data Hash\n"); bootstage_error(BOOTSTAGE_ID_FIT_CHECK_HASH); return 0; } puts("OK\n"); } bootstage_mark(BOOTSTAGE_ID_FIT_CHECK_ARCH); if (!fit_image_check_target_arch(fit, os_noffset)) { puts("Unsupported Architecture\n"); bootstage_error(BOOTSTAGE_ID_FIT_CHECK_ARCH); return 0; } bootstage_mark(BOOTSTAGE_ID_FIT_CHECK_KERNEL); if (!fit_image_check_type(fit, os_noffset, IH_TYPE_KERNEL) && !fit_image_check_type(fit, os_noffset, IH_TYPE_KERNEL_NOLOAD)) { puts("Not a kernel image\n"); bootstage_error(BOOTSTAGE_ID_FIT_CHECK_KERNEL); return 0; } bootstage_mark(BOOTSTAGE_ID_FIT_CHECKED); return 1; }
static int bootm_load_os(bootm_headers_t *images, int boot_progress) { image_info_t os = images->os; ulong load = os.load; ulong load_end; ulong blob_start = os.start; ulong blob_end = os.end; ulong image_start = os.image_start; ulong image_len = os.image_len; ulong flush_start = ALIGN_DOWN(load, ARCH_DMA_MINALIGN); ulong flush_len; bool no_overlap; void *load_buf, *image_buf; int err; load_buf = map_sysmem(load, 0); image_buf = map_sysmem(os.image_start, image_len); err = bootm_decomp_image(os.comp, load, os.image_start, os.type, load_buf, image_buf, image_len, CONFIG_SYS_BOOTM_LEN, &load_end); if (err) { bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return err; } flush_len = load_end - load; if (flush_start < load) flush_len += load - flush_start; flush_cache(flush_start, ALIGN(flush_len, ARCH_DMA_MINALIGN)); debug(" kernel loaded at 0x%08lx, end = 0x%08lx\n", load, load_end); bootstage_mark(BOOTSTAGE_ID_KERNEL_LOADED); no_overlap = (os.comp == IH_COMP_NONE && load == image_start); if (!no_overlap && load < blob_end && load_end > blob_start) { debug("images.os.start = 0x%lX, images.os.end = 0x%lx\n", blob_start, blob_end); debug("images.os.load = 0x%lx, load_end = 0x%lx\n", load, load_end); /* Check what type of image this is. */ if (images->legacy_hdr_valid) { if (image_get_type(&images->legacy_hdr_os_copy) == IH_TYPE_MULTI) puts("WARNING: legacy format multi component image overwritten\n"); return BOOTM_ERR_OVERLAP; } else { puts("ERROR: new format image overwritten - must RESET the board to recover\n"); bootstage_error(BOOTSTAGE_ID_OVERWRITTEN); return BOOTM_ERR_RESET; } } lmb_reserve(&images->lmb, images->os.load, (load_end - images->os.load)); return 0; }
void hang(void) { puts("### ERROR ### Please RESET the board ###\n"); #ifdef CONFIG_SHOW_BOOT_PROGRESS bootstage_error(BOOTSTAGE_ID_NEED_RESET); #endif for (;;) ; }
/** * image_get_ramdisk - get and verify ramdisk image * @rd_addr: ramdisk image start address * @arch: expected ramdisk architecture * @verify: checksum verification flag * * image_get_ramdisk() returns a pointer to the verified ramdisk image * header. Routine receives image start address and expected architecture * flag. Verification done covers data and header integrity and os/type/arch * fields checking. * * If dataflash support is enabled routine checks for dataflash addresses * and handles required dataflash reads. * * returns: * pointer to a ramdisk image header, if image was found and valid * otherwise, return NULL */ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch, int verify) { const image_header_t *rd_hdr = (const image_header_t *)rd_addr; if (!image_check_magic(rd_hdr)) { puts("Bad Magic Number\n"); bootstage_error(BOOTSTAGE_ID_RD_MAGIC); return NULL; } if (!image_check_hcrc(rd_hdr)) { puts("Bad Header Checksum\n"); bootstage_error(BOOTSTAGE_ID_RD_HDR_CHECKSUM); return NULL; } bootstage_mark(BOOTSTAGE_ID_RD_MAGIC); image_print_contents(rd_hdr); if (verify) { puts(" Verifying Checksum ... "); if (!image_check_dcrc(rd_hdr)) { puts("Bad Data CRC\n"); bootstage_error(BOOTSTAGE_ID_RD_CHECKSUM); return NULL; } puts("OK\n"); } bootstage_mark(BOOTSTAGE_ID_RD_HDR_CHECKSUM); if (!image_check_os(rd_hdr, IH_OS_LINUX) || !image_check_arch(rd_hdr, arch) || !image_check_type(rd_hdr, IH_TYPE_RAMDISK)) { printf("No Linux %s Ramdisk Image\n", genimg_get_arch_name(arch)); bootstage_error(BOOTSTAGE_ID_RAMDISK); return NULL; } return rd_hdr; }
/** * hang - stop processing by staying in an endless loop * * The purpose of this function is to stop further execution of code cause * something went completely wrong. To catch this and give some feedback to * the user one needs to catch the bootstage_error (see show_boot_progress()) * in the board code. */ void hang(void) { #if !defined(CONFIG_SPL_BUILD) || (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ defined(CONFIG_SPL_SERIAL_SUPPORT)) puts("### ERROR ### Please RESET the board ###\n"); #endif bootstage_error(BOOTSTAGE_ID_NEED_RESET); for (;;) ; }
int eth_initialize(void) { int num_devices = 0; struct udevice *dev; eth_common_init(); /* * Devices need to write the hwaddr even if not started so that Linux * will have access to the hwaddr that u-boot stored for the device. * This is accomplished by attempting to probe each device and calling * their write_hwaddr() operation. */ uclass_first_device(UCLASS_ETH, &dev); if (!dev) { printf("No ethernet found.\n"); bootstage_error(BOOTSTAGE_ID_NET_ETH_START); } else { char *ethprime = getenv("ethprime"); struct udevice *prime_dev = NULL; if (ethprime) prime_dev = eth_get_dev_by_name(ethprime); if (prime_dev) { eth_set_dev(prime_dev); eth_current_changed(); } else { eth_set_dev(NULL); } bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); do { if (num_devices) printf(", "); printf("eth%d: %s", dev->seq, dev->name); if (ethprime && dev == prime_dev) printf(" [PRIME]"); eth_write_hwaddr(dev); uclass_next_device(&dev); num_devices++; } while (dev); putc('\n'); } return num_devices; }
/** * image_get_kernel - verify legacy format kernel image * @img_addr: in RAM address of the legacy format image to be verified * @verify: data CRC verification flag * * image_get_kernel() verifies legacy image integrity and returns pointer to * legacy image header if image verification was completed successfully. * * returns: * pointer to a legacy image header if valid image was found * otherwise return NULL */ static image_header_t *image_get_kernel(ulong img_addr, int verify) { image_header_t *hdr = (image_header_t *)img_addr; if (!image_check_magic(hdr)) { puts("Bad Magic Number\n"); bootstage_error(BOOTSTAGE_ID_CHECK_MAGIC); return NULL; } bootstage_mark(BOOTSTAGE_ID_CHECK_HEADER); if (!image_check_hcrc(hdr)) { puts("Bad Header Checksum\n"); bootstage_error(BOOTSTAGE_ID_CHECK_HEADER); return NULL; } bootstage_mark(BOOTSTAGE_ID_CHECK_CHECKSUM); image_print_contents(hdr); if (verify) { puts(" Verifying Checksum ... "); if (!image_check_dcrc(hdr)) { printf("Bad Data CRC\n"); bootstage_error(BOOTSTAGE_ID_CHECK_CHECKSUM); return NULL; } puts("OK\n"); } bootstage_mark(BOOTSTAGE_ID_CHECK_ARCH); if (!image_check_target_arch(hdr)) { printf("Unsupported Architecture 0x%x\n", image_get_arch(hdr)); bootstage_error(BOOTSTAGE_ID_CHECK_ARCH); return NULL; } return hdr; }
void env_relocate(void) { #if defined(CONFIG_NEEDS_MANUAL_RELOC) env_reloc(); #endif if (gd->env_valid == 0) { #if defined(CONFIG_ENV_IS_NOWHERE) /* Environment not changable */ set_default_env(NULL); #else bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM); set_default_env("!bad CRC"); #endif } else { env_relocate_spec(); } }
static int boot_selected_os(int argc, char * const argv[], int state, bootm_headers_t *images, boot_os_fn *boot_fn) { arch_preboot_os(); boot_fn(state, argc, argv, images); /* Stand-alone may return when 'autostart' is 'no' */ if (images->os.type == IH_TYPE_STANDALONE || state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */ return 0; bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED); #ifdef DEBUG puts("\n## Control returned to monitor - resetting...\n"); #endif return BOOTM_ERR_RESET; }
void env_relocate(void) { #if defined(CONFIG_NEEDS_MANUAL_RELOC) env_reloc(); env_htab.change_ok += gd->reloc_off; #endif if (gd->env_valid == ENV_INVALID) { #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD) /* Environment not changable */ set_default_env(NULL); #else bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM); set_default_env("!bad CRC"); #endif } else { env_load(); } }
static int boot_selected_os(int argc, char * const argv[], int state, bootm_headers_t *images, boot_os_fn *boot_fn) { if (images->os.type == IH_TYPE_STANDALONE) { /* This may return when 'autostart' is 'no' */ bootm_start_standalone(argc, argv); return 0; } #ifdef CONFIG_SILENT_CONSOLE if (images->os.os == IH_OS_LINUX) fixup_silent_linux(); #endif arch_preboot_os(); boot_fn(state, argc, argv, images); if (state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */ return 0; bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED); #ifdef DEBUG puts("\n## Control returned to monitor - resetting...\n"); #endif return BOOTM_ERR_RESET; }
/** * handle_decomp_error() - display a decompression error * * This function tries to produce a useful message. In the case where the * uncompressed size is the same as the available space, we can assume that * the image is too large for the buffer. * * @comp_type: Compression type being used (IH_COMP_...) * @uncomp_size: Number of bytes uncompressed * @unc_len: Amount of space available for decompression * @ret: Error code to report * @return BOOTM_ERR_RESET, indicating that the board must be reset */ static int handle_decomp_error(int comp_type, size_t uncomp_size, size_t unc_len, int ret) { const char *name = genimg_get_comp_name(comp_type); if (uncomp_size >= unc_len) printf("Image too large: increase CONFIG_SYS_BOOTM_LEN\n"); else printf("%s: uncompress error %d\n", name, ret); /* * The decompression routines are now safe, so will not write beyond * their bounds. Probably it is not necessary to reset, but maintain * the current behaviour for now. */ printf("Must RESET board to recover\n"); #ifndef USE_HOSTCC bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); #endif return BOOTM_ERR_RESET; }
int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { ulong iflag; ulong load_end = 0; int ret; boot_os_fn *boot_fn; #ifdef CONFIG_NEEDS_MANUAL_RELOC static int relocated = 0; if (!relocated) { int i; /* relocate boot function table */ for (i = 0; i < ARRAY_SIZE(boot_os); i++) if (boot_os[i] != NULL) boot_os[i] += gd->reloc_off; /* relocate names of sub-command table */ for (i = 0; i < ARRAY_SIZE(cmd_bootm_sub); i++) cmd_bootm_sub[i].name += gd->reloc_off; relocated = 1; } #endif /* determine if we have a sub command */ if (argc > 1) { char *endp; simple_strtoul(argv[1], &endp, 16); /* endp pointing to NULL means that argv[1] was just a * valid number, pass it along to the normal bootm processing * * If endp is ':' or '#' assume a FIT identifier so pass * along for normal processing. * * Right now we assume the first arg should never be '-' */ if ((*endp != 0) && (*endp != ':') && (*endp != '#')) return do_bootm_subcommand(cmdtp, flag, argc, argv); } if (bootm_start(cmdtp, flag, argc, argv)) return 1; /* * We have reached the point of no return: we are going to * overwrite all exception vector code, so we cannot easily * recover from any failures any more... */ iflag = disable_interrupts(); #ifdef CONFIG_NETCONSOLE /* Stop the ethernet stack if NetConsole could have left it up */ eth_halt(); #endif #if defined(CONFIG_CMD_USB) /* * turn off USB to prevent the host controller from writing to the * SDRAM while Linux is booting. This could happen (at least for OHCI * controller), because the HCCA (Host Controller Communication Area) * lies within the SDRAM and the host controller writes continously to * this area (as busmaster!). The HccaFrameNumber is for example * updated every 1 ms within the HCCA structure in SDRAM! For more * details see the OpenHCI specification. */ usb_stop(); #endif ret = bootm_load_os(images.os, &load_end, 1); if (ret < 0) { if (ret == BOOTM_ERR_RESET) do_reset(cmdtp, flag, argc, argv); if (ret == BOOTM_ERR_OVERLAP) { if (images.legacy_hdr_valid) { image_header_t *hdr; hdr = &images.legacy_hdr_os_copy; if (image_get_type(hdr) == IH_TYPE_MULTI) puts("WARNING: legacy format multi " "component image " "overwritten\n"); } else { puts("ERROR: new format image overwritten - " "must RESET the board to recover\n"); bootstage_error(BOOTSTAGE_ID_OVERWRITTEN); do_reset(cmdtp, flag, argc, argv); } } if (ret == BOOTM_ERR_UNIMPLEMENTED) { if (iflag) enable_interrupts(); bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); return 1; } } lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load)); if (images.os.type == IH_TYPE_STANDALONE) { if (iflag) enable_interrupts(); /* This may return when 'autostart' is 'no' */ bootm_start_standalone(iflag, argc, argv); return 0; } bootstage_mark(BOOTSTAGE_ID_CHECK_BOOT_OS); #if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) if (images.os.os == IH_OS_LINUX) fixup_silent_linux(); #endif boot_fn = boot_os[images.os.os]; if (boot_fn == NULL) { if (iflag) enable_interrupts(); printf("ERROR: booting os '%s' (%d) is not supported\n", genimg_get_os_name(images.os.os), images.os.os); bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); return 1; } arch_preboot_os(); boot_fn(0, argc, argv, &images); bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED); #ifdef DEBUG puts("\n## Control returned to monitor - resetting...\n"); #endif do_reset(cmdtp, flag, argc, argv); return 1; }
static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) { uint8_t comp = os.comp; ulong load = os.load; ulong blob_start = os.start; ulong blob_end = os.end; ulong image_start = os.image_start; ulong image_len = os.image_len; __maybe_unused uint unc_len = CONFIG_SYS_BOOTM_LEN; int no_overlap = 0; #if defined(CONFIG_LZMA) || defined(CONFIG_LZO) int ret; #endif /* defined(CONFIG_LZMA) || defined(CONFIG_LZO) */ const char *type_name = genimg_get_type_name(os.type); switch (comp) { case IH_COMP_NONE: if (load == blob_start || load == image_start) { printf(" XIP %s ... ", type_name); no_overlap = 1; } else { printf(" Loading %s ... ", type_name); memmove_wd((void *)load, (void *)image_start, image_len, CHUNKSZ); } *load_end = load + image_len; puts("OK\n"); break; #ifdef CONFIG_GZIP case IH_COMP_GZIP: printf(" Uncompressing %s ... ", type_name); if (gunzip((void *)load, unc_len, (uchar *)image_start, &image_len) != 0) { puts("GUNZIP: uncompress, out-of-mem or overwrite " "error - must RESET board to recover\n"); if (boot_progress) bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return BOOTM_ERR_RESET; } *load_end = load + image_len; break; #endif /* CONFIG_GZIP */ #ifdef CONFIG_BZIP2 case IH_COMP_BZIP2: printf(" Uncompressing %s ... ", type_name); /* * If we've got less than 4 MB of malloc() space, * use slower decompression algorithm which requires * at most 2300 KB of memory. */ int i = BZ2_bzBuffToBuffDecompress((char *)load, &unc_len, (char *)image_start, image_len, CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0); if (i != BZ_OK) { printf("BUNZIP2: uncompress or overwrite error %d " "- must RESET board to recover\n", i); if (boot_progress) bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return BOOTM_ERR_RESET; } *load_end = load + unc_len; break; #endif /* CONFIG_BZIP2 */ #ifdef CONFIG_LZMA case IH_COMP_LZMA: { SizeT lzma_len = unc_len; printf(" Uncompressing %s ... ", type_name); ret = lzmaBuffToBuffDecompress( (unsigned char *)load, &lzma_len, (unsigned char *)image_start, image_len); unc_len = lzma_len; if (ret != SZ_OK) { printf("LZMA: uncompress or overwrite error %d " "- must RESET board to recover\n", ret); bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return BOOTM_ERR_RESET; } *load_end = load + unc_len; break; } #endif /* CONFIG_LZMA */ #ifdef CONFIG_LZO case IH_COMP_LZO: printf(" Uncompressing %s ... ", type_name); ret = lzop_decompress((const unsigned char *)image_start, image_len, (unsigned char *)load, &unc_len); if (ret != LZO_E_OK) { printf("LZO: uncompress or overwrite error %d " "- must RESET board to recover\n", ret); if (boot_progress) bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return BOOTM_ERR_RESET; } *load_end = load + unc_len; break; #endif /* CONFIG_LZO */ default: printf("Unimplemented compression type %d\n", comp); return BOOTM_ERR_UNIMPLEMENTED; } flush_cache(load, (*load_end - load) * sizeof(ulong)); puts("OK\n"); debug(" kernel loaded at 0x%08lx, end = 0x%08lx\n", load, *load_end); bootstage_mark(BOOTSTAGE_ID_KERNEL_LOADED); if (!no_overlap && (load < blob_end) && (*load_end > blob_start)) { debug("images.os.start = 0x%lX, images.os.end = 0x%lx\n", blob_start, blob_end); debug("images.os.load = 0x%lx, load_end = 0x%lx\n", load, *load_end); return BOOTM_ERR_OVERLAP; } return 0; }
static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { const void *os_hdr; int ret; memset((void *)&images, 0, sizeof(images)); images.verify = getenv_yesno("verify"); boot_start_lmb(&images); bootstage_mark_name(BOOTSTAGE_ID_BOOTM_START, "bootm_start"); /* get kernel image header, start address and length */ os_hdr = boot_get_kernel(cmdtp, flag, argc, argv, &images, &images.os.image_start, &images.os.image_len); if (images.os.image_len == 0) { puts("ERROR: can't get kernel image!\n"); return 1; } /* get image parameters */ switch (genimg_get_format(os_hdr)) { case IMAGE_FORMAT_LEGACY: images.os.type = image_get_type(os_hdr); images.os.comp = image_get_comp(os_hdr); images.os.os = image_get_os(os_hdr); images.os.end = image_get_image_end(os_hdr); images.os.load = image_get_load(os_hdr); break; #if defined(CONFIG_FIT) case IMAGE_FORMAT_FIT: if (fit_image_get_type(images.fit_hdr_os, images.fit_noffset_os, &images.os.type)) { puts("Can't get image type!\n"); bootstage_error(BOOTSTAGE_ID_FIT_TYPE); return 1; } if (fit_image_get_comp(images.fit_hdr_os, images.fit_noffset_os, &images.os.comp)) { puts("Can't get image compression!\n"); bootstage_error(BOOTSTAGE_ID_FIT_COMPRESSION); return 1; } if (fit_image_get_os(images.fit_hdr_os, images.fit_noffset_os, &images.os.os)) { puts("Can't get image OS!\n"); bootstage_error(BOOTSTAGE_ID_FIT_OS); return 1; } images.os.end = fit_get_end(images.fit_hdr_os); if (fit_image_get_load(images.fit_hdr_os, images.fit_noffset_os, &images.os.load)) { puts("Can't get image load address!\n"); bootstage_error(BOOTSTAGE_ID_FIT_LOADADDR); return 1; } break; #endif default: puts("ERROR: unknown image format type!\n"); return 1; } /* find kernel entry point */ if (images.legacy_hdr_valid) { images.ep = image_get_ep(&images.legacy_hdr_os_copy); #if defined(CONFIG_FIT) } else if (images.fit_uname_os) { ret = fit_image_get_entry(images.fit_hdr_os, images.fit_noffset_os, &images.ep); if (ret) { puts("Can't get entry point property!\n"); return 1; } #endif } else { puts("Could not find kernel entry point!\n"); return 1; } if (images.os.type == IH_TYPE_KERNEL_NOLOAD) { images.os.load = images.os.image_start; images.ep += images.os.load; } if (((images.os.type == IH_TYPE_KERNEL) || (images.os.type == IH_TYPE_KERNEL_NOLOAD) || (images.os.type == IH_TYPE_MULTI)) && (images.os.os == IH_OS_LINUX)) { /* find ramdisk */ ret = boot_get_ramdisk(argc, argv, &images, IH_INITRD_ARCH, &images.rd_start, &images.rd_end); if (ret) { puts("Ramdisk image is corrupt or invalid\n"); return 1; } #if defined(CONFIG_OF_LIBFDT) /* find flattened device tree */ ret = boot_get_fdt(flag, argc, argv, &images, &images.ft_addr, &images.ft_len); if (ret) { puts("Could not find a valid device tree\n"); return 1; } set_working_fdt_addr(images.ft_addr); #endif } images.os.start = (ulong)os_hdr; images.state = BOOTM_STATE_START; return 0; }
/** * boot_get_kernel - find kernel image * @os_data: pointer to a ulong variable, will hold os data start address * @os_len: pointer to a ulong variable, will hold os data length * * boot_get_kernel() tries to find a kernel image, verifies its integrity * and locates kernel data. * * returns: * pointer to image header if valid image was found, plus kernel start * address and length, otherwise NULL */ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], bootm_headers_t *images, ulong *os_data, ulong *os_len) { image_header_t *hdr; ulong img_addr; const void *buf; #if defined(CONFIG_FIT) const char *fit_uname_config = NULL; const char *fit_uname_kernel = NULL; int os_noffset; #endif /* find out kernel image address */ if (argc < 1) { img_addr = load_addr; debug("* kernel: default image load address = 0x%08lx\n", load_addr); #if defined(CONFIG_FIT) } else if (fit_parse_conf(argv[0], load_addr, &img_addr, &fit_uname_config)) { debug("* kernel: config '%s' from image at 0x%08lx\n", fit_uname_config, img_addr); } else if (fit_parse_subimage(argv[0], load_addr, &img_addr, &fit_uname_kernel)) { debug("* kernel: subimage '%s' from image at 0x%08lx\n", fit_uname_kernel, img_addr); #endif } else { img_addr = simple_strtoul(argv[0], NULL, 16); debug("* kernel: cmdline image address = 0x%08lx\n", img_addr); } bootstage_mark(BOOTSTAGE_ID_CHECK_MAGIC); /* copy from dataflash if needed */ img_addr = genimg_get_image(img_addr); /* check image type, for FIT images get FIT kernel node */ *os_data = *os_len = 0; buf = map_sysmem(img_addr, 0); switch (genimg_get_format(buf)) { case IMAGE_FORMAT_LEGACY: printf("## Booting kernel from Legacy Image at %08lx ...\n", img_addr); hdr = image_get_kernel(img_addr, images->verify); if (!hdr) return NULL; bootstage_mark(BOOTSTAGE_ID_CHECK_IMAGETYPE); /* get os_data and os_len */ switch (image_get_type(hdr)) { case IH_TYPE_KERNEL: case IH_TYPE_KERNEL_NOLOAD: *os_data = image_get_data(hdr); *os_len = image_get_data_size(hdr); break; case IH_TYPE_MULTI: image_multi_getimg(hdr, 0, os_data, os_len); break; case IH_TYPE_STANDALONE: *os_data = image_get_data(hdr); *os_len = image_get_data_size(hdr); break; default: printf("Wrong Image Type for %s command\n", cmdtp->name); bootstage_error(BOOTSTAGE_ID_CHECK_IMAGETYPE); return NULL; } /* * copy image header to allow for image overwrites during * kernel decompression. */ memmove(&images->legacy_hdr_os_copy, hdr, sizeof(image_header_t)); /* save pointer to image header */ images->legacy_hdr_os = hdr; images->legacy_hdr_valid = 1; bootstage_mark(BOOTSTAGE_ID_DECOMP_IMAGE); break; #if defined(CONFIG_FIT) case IMAGE_FORMAT_FIT: os_noffset = fit_image_load(images, FIT_KERNEL_PROP, img_addr, &fit_uname_kernel, &fit_uname_config, IH_ARCH_DEFAULT, IH_TYPE_KERNEL, BOOTSTAGE_ID_FIT_KERNEL_START, FIT_LOAD_IGNORED, os_data, os_len); if (os_noffset < 0) return NULL; images->fit_hdr_os = map_sysmem(img_addr, 0); images->fit_uname_os = fit_uname_kernel; images->fit_uname_cfg = fit_uname_config; images->fit_noffset_os = os_noffset; break; #endif #ifdef CONFIG_ANDROID_BOOT_IMAGE case IMAGE_FORMAT_ANDROID: printf("## Booting Android Image at 0x%08lx ...\n", img_addr); if (android_image_get_kernel((void *)img_addr, images->verify, os_data, os_len)) return NULL; break; #endif default: printf("Wrong Image Format for %s command\n", cmdtp->name); bootstage_error(BOOTSTAGE_ID_FIT_KERNEL_INFO); return NULL; } debug(" kernel data at 0x%08lx, len = 0x%08lx (%ld)\n", *os_data, *os_len, *os_len); return buf; }
/** * Execute selected states of the bootm command. * * Note the arguments to this state must be the first argument, Any 'bootm' * or sub-command arguments must have already been taken. * * Note that if states contains more than one flag it MUST contain * BOOTM_STATE_START, since this handles and consumes the command line args. * * Also note that aside from boot_os_fn functions and bootm_load_os no other * functions we store the return value of in 'ret' may use a negative return * value, without special handling. * * @param cmdtp Pointer to bootm command table entry * @param flag Command flags (CMD_FLAG_...) * @param argc Number of subcommand arguments (0 = no arguments) * @param argv Arguments * @param states Mask containing states to run (BOOTM_STATE_...) * @param images Image header information * @param boot_progress 1 to show boot progress, 0 to not do this * @return 0 if ok, something else on error. Some errors will cause this * function to perform a reboot! If states contains BOOTM_STATE_OS_GO * then the intent is to boot an OS, so this function will not return * unless the image type is standalone. */ static int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], int states, bootm_headers_t *images, int boot_progress) { boot_os_fn *boot_fn; ulong iflag = 0; int ret = 0, need_boot_fn; images->state |= states; /* * Work through the states and see how far we get. We stop on * any error. */ if (states & BOOTM_STATE_START) ret = bootm_start(cmdtp, flag, argc, argv); if (!ret && (states & BOOTM_STATE_FINDOS)) ret = bootm_find_os(cmdtp, flag, argc, argv); if (!ret && (states & BOOTM_STATE_FINDOTHER)) { ret = bootm_find_other(cmdtp, flag, argc, argv); argc = 0; /* consume the args */ } /* Load the OS */ if (!ret && (states & BOOTM_STATE_LOADOS)) { ulong load_end; iflag = bootm_disable_interrupts(); ret = bootm_load_os(images, &load_end, 0); if (ret == 0) lmb_reserve(&images->lmb, images->os.load, (load_end - images->os.load)); else if (ret && ret != BOOTM_ERR_OVERLAP) goto err; else if (ret == BOOTM_ERR_OVERLAP) ret = 0; #if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) if (images->os.os == IH_OS_LINUX) fixup_silent_linux(); #endif } /* Relocate the ramdisk */ #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH if (!ret && (states & BOOTM_STATE_RAMDISK)) { ulong rd_len = images->rd_end - images->rd_start; ret = boot_ramdisk_high(&images->lmb, images->rd_start, rd_len, &images->initrd_start, &images->initrd_end); if (!ret) { setenv_hex("initrd_start", images->initrd_start); setenv_hex("initrd_end", images->initrd_end); } } #endif #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB) if (!ret && (states & BOOTM_STATE_FDT)) { boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr); ret = boot_relocate_fdt(&images->lmb, &images->ft_addr, &images->ft_len); } #endif /* From now on, we need the OS boot function */ if (ret) return ret; boot_fn = boot_os[images->os.os]; need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE | BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO); if (boot_fn == NULL && need_boot_fn) { if (iflag) enable_interrupts(); printf("ERROR: booting os '%s' (%d) is not supported\n", genimg_get_os_name(images->os.os), images->os.os); bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); return 1; } /* Call various other states that are not generally used */ if (!ret && (states & BOOTM_STATE_OS_CMDLINE)) ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images); if (!ret && (states & BOOTM_STATE_OS_BD_T)) ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images); if (!ret && (states & BOOTM_STATE_OS_PREP)) ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images); #ifdef CONFIG_TRACE /* Pretend to run the OS, then run a user command */ if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) { char *cmd_list = getenv("fakegocmd"); ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO, images, boot_fn); if (!ret && cmd_list) ret = run_command_list(cmd_list, -1, flag); } #endif /* Check for unsupported subcommand. */ if (ret) { puts("subcommand not supported\n"); return ret; } /* Now run the OS! We hope this doesn't return */ if (!ret && (states & BOOTM_STATE_OS_GO)) ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO, images, boot_fn); /* Deal with any fallout */ err: if (iflag) enable_interrupts(); if (ret == BOOTM_ERR_UNIMPLEMENTED) bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); else if (ret == BOOTM_ERR_RESET) do_reset(cmdtp, flag, argc, argv); return ret; }
static int bootm_load_os(bootm_headers_t *images, unsigned long *load_end, int boot_progress) { image_info_t os = images->os; uint8_t comp = os.comp; ulong load = os.load; ulong blob_start = os.start; ulong blob_end = os.end; ulong image_start = os.image_start; ulong image_len = os.image_len; __maybe_unused uint unc_len = CONFIG_SYS_BOOTM_LEN; int no_overlap = 0; void *load_buf, *image_buf; #if defined(CONFIG_LZMA) || defined(CONFIG_LZO) int ret; #endif /* defined(CONFIG_LZMA) || defined(CONFIG_LZO) */ const char *type_name = genimg_get_type_name(os.type); load_buf = map_sysmem(load, unc_len); image_buf = map_sysmem(image_start, image_len); switch (comp) { case IH_COMP_NONE: if (load == image_start) { printf(" XIP %s ... ", type_name); no_overlap = 1; } else { printf(" Loading %s ... ", type_name); memmove_wd(load_buf, image_buf, image_len, CHUNKSZ); } *load_end = load + image_len; break; #ifdef CONFIG_GZIP case IH_COMP_GZIP: printf(" Uncompressing %s ... ", type_name); if (gunzip(load_buf, unc_len, image_buf, &image_len) != 0) { puts("GUNZIP: uncompress, out-of-mem or overwrite " "error - must RESET board to recover\n"); if (boot_progress) bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return BOOTM_ERR_RESET; } *load_end = load + image_len; break; #endif /* CONFIG_GZIP */ #ifdef CONFIG_BZIP2 case IH_COMP_BZIP2: printf(" Uncompressing %s ... ", type_name); /* * If we've got less than 4 MB of malloc() space, * use slower decompression algorithm which requires * at most 2300 KB of memory. */ int i = BZ2_bzBuffToBuffDecompress(load_buf, &unc_len, image_buf, image_len, CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0); if (i != BZ_OK) { printf("BUNZIP2: uncompress or overwrite error %d " "- must RESET board to recover\n", i); if (boot_progress) bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return BOOTM_ERR_RESET; } *load_end = load + unc_len; break; #endif /* CONFIG_BZIP2 */ #ifdef CONFIG_LZMA case IH_COMP_LZMA: { SizeT lzma_len = unc_len; printf(" Uncompressing %s ... ", type_name); ret = lzmaBuffToBuffDecompress(load_buf, &lzma_len, image_buf, image_len); unc_len = lzma_len; if (ret != SZ_OK) { printf("LZMA: uncompress or overwrite error %d " "- must RESET board to recover\n", ret); bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return BOOTM_ERR_RESET; } *load_end = load + unc_len; break; } #endif /* CONFIG_LZMA */ #ifdef CONFIG_LZO case IH_COMP_LZO: { size_t size = unc_len; printf(" Uncompressing %s ... ", type_name); ret = lzop_decompress(image_buf, image_len, load_buf, &size); if (ret != LZO_E_OK) { printf("LZO: uncompress or overwrite error %d " "- must RESET board to recover\n", ret); if (boot_progress) bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return BOOTM_ERR_RESET; } *load_end = load + size; break; } #endif /* CONFIG_LZO */ default: printf("Unimplemented compression type %d\n", comp); return BOOTM_ERR_UNIMPLEMENTED; } flush_cache(load, (*load_end - load) * sizeof(ulong)); puts("OK\n"); debug(" kernel loaded at 0x%08lx, end = 0x%08lx\n", load, *load_end); bootstage_mark(BOOTSTAGE_ID_KERNEL_LOADED); if (!no_overlap && (load < blob_end) && (*load_end > blob_start)) { debug("images.os.start = 0x%lX, images.os.end = 0x%lx\n", blob_start, blob_end); debug("images.os.load = 0x%lx, load_end = 0x%lx\n", load, *load_end); /* Check what type of image this is. */ if (images->legacy_hdr_valid) { if (image_get_type(&images->legacy_hdr_os_copy) == IH_TYPE_MULTI) puts("WARNING: legacy format multi component image overwritten\n"); return BOOTM_ERR_OVERLAP; } else { puts("ERROR: new format image overwritten - must RESET the board to recover\n"); bootstage_error(BOOTSTAGE_ID_OVERWRITTEN); return BOOTM_ERR_RESET; } } return 0; }
/** * Execute selected states of the bootm command. * * Note the arguments to this state must be the first argument, Any 'bootm' * or sub-command arguments must have already been taken. * * Note that if states contains more than one flag it MUST contain * BOOTM_STATE_START, since this handles and consumes the command line args. * * Also note that aside from boot_os_fn functions and bootm_load_os no other * functions we store the return value of in 'ret' may use a negative return * value, without special handling. * * @param cmdtp Pointer to bootm command table entry * @param flag Command flags (CMD_FLAG_...) * @param argc Number of subcommand arguments (0 = no arguments) * @param argv Arguments * @param states Mask containing states to run (BOOTM_STATE_...) * @param images Image header information * @param boot_progress 1 to show boot progress, 0 to not do this * @return 0 if ok, something else on error. Some errors will cause this * function to perform a reboot! If states contains BOOTM_STATE_OS_GO * then the intent is to boot an OS, so this function will not return * unless the image type is standalone. */ static int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], int states, bootm_headers_t *images, int boot_progress) { boot_os_fn *boot_fn; ulong iflag = 0; int ret = 0; images->state |= states; /* * Work through the states and see how far we get. We stop on * any error. */ if (states & BOOTM_STATE_START) ret = bootm_start(cmdtp, flag, argc, argv); if (!ret && (states & BOOTM_STATE_FINDOS)) ret = bootm_find_os(cmdtp, flag, argc, argv); if (!ret && (states & BOOTM_STATE_FINDOTHER)) { ret = bootm_find_other(cmdtp, flag, argc, argv); argc = 0; /* consume the args */ } /* * We have reached the point of no return: we are going to * overwrite all exception vector code, so we cannot easily * recover from any failures any more... */ iflag = disable_interrupts(); #ifdef CONFIG_NETCONSOLE /* Stop the ethernet stack if NetConsole could have left it up */ eth_halt(); #endif #if defined(CONFIG_CMD_USB) /* * turn off USB to prevent the host controller from writing to the * SDRAM while Linux is booting. This could happen (at least for OHCI * controller), because the HCCA (Host Controller Communication Area) * lies within the SDRAM and the host controller writes continously to * this area (as busmaster!). The HccaFrameNumber is for example * updated every 1 ms within the HCCA structure in SDRAM! For more * details see the OpenHCI specification. */ usb_stop(); #endif /* Load the OS */ if (!ret && (states & BOOTM_STATE_LOADOS)) { ulong load_end; ret = bootm_load_os(images, &load_end, 0); if (ret && ret != BOOTM_ERR_OVERLAP) goto err; if (ret == 0) lmb_reserve(&images->lmb, images->os.load, (load_end - images->os.load)); else if (ret == BOOTM_ERR_OVERLAP) ret = 0; } /* Relocate the ramdisk */ #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH if (!ret && (states & BOOTM_STATE_RAMDISK)) { ulong rd_len = images->rd_end - images->rd_start; ret = boot_ramdisk_high(&images->lmb, images->rd_start, rd_len, &images->initrd_start, &images->initrd_end); if (!ret) { setenv_hex("initrd_start", images->initrd_start); setenv_hex("initrd_end", images->initrd_end); } } #endif #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB) if (!ret && (states & BOOTM_STATE_FDT)) { boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr); ret = boot_relocate_fdt(&images->lmb, &images->ft_addr, &images->ft_len); } #endif /* From now on, we need the OS boot function */ if (ret) return ret; boot_fn = boot_os[images->os.os]; if (boot_fn == NULL) { if (iflag) enable_interrupts(); printf("ERROR: booting os '%s' (%d) is not supported\n", genimg_get_os_name(images->os.os), images->os.os); bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); return 1; } /* Call various other states that are not generally used */ if (!ret && (states & BOOTM_STATE_OS_CMDLINE)) ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images); if (!ret && (states & BOOTM_STATE_OS_BD_T)) ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images); if (!ret && (states & BOOTM_STATE_OS_PREP)) ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images); #ifdef CONFIG_TRACE /* Pretend to run the OS, then run a user command */ if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) { char *cmd_list = getenv("fakegocmd"); ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO, images, boot_fn); if (!ret && cmd_list) ret = run_command_list(cmd_list, -1, flag); } #endif /* Now run the OS! We hope this doesn't return */ if (!ret && (states & BOOTM_STATE_OS_GO)) { ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO, images, boot_fn); if (ret) goto err; } return ret; /* Deal with any fallout */ err: if (iflag) enable_interrupts(); if (ret == BOOTM_ERR_UNIMPLEMENTED) bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); else if (ret == BOOTM_ERR_RESET) do_reset(cmdtp, flag, argc, argv); else puts("subcommand not supported\n"); return ret; }
/** * boot_get_kernel - find kernel image * @os_data: pointer to a ulong variable, will hold os data start address * @os_len: pointer to a ulong variable, will hold os data length * * boot_get_kernel() tries to find a kernel image, verifies its integrity * and locates kernel data. * * returns: * pointer to image header if valid image was found, plus kernel start * address and length, otherwise NULL */ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], bootm_headers_t *images, ulong *os_data, ulong *os_len) { image_header_t *hdr; ulong img_addr; const void *buf; #if defined(CONFIG_FIT) const void *fit_hdr; const char *fit_uname_config = NULL; const char *fit_uname_kernel = NULL; const void *data; size_t len; int cfg_noffset; int os_noffset; #endif /* find out kernel image address */ if (argc < 2) { img_addr = load_addr; debug("* kernel: default image load address = 0x%08lx\n", load_addr); #if defined(CONFIG_FIT) } else if (fit_parse_conf(argv[1], load_addr, &img_addr, &fit_uname_config)) { debug("* kernel: config '%s' from image at 0x%08lx\n", fit_uname_config, img_addr); } else if (fit_parse_subimage(argv[1], load_addr, &img_addr, &fit_uname_kernel)) { debug("* kernel: subimage '%s' from image at 0x%08lx\n", fit_uname_kernel, img_addr); #endif } else { img_addr = simple_strtoul(argv[1], NULL, 16); debug("* kernel: cmdline image address = 0x%08lx\n", img_addr); } bootstage_mark(BOOTSTAGE_ID_CHECK_MAGIC); /* copy from dataflash if needed */ img_addr = genimg_get_image(img_addr); /* check image type, for FIT images get FIT kernel node */ *os_data = *os_len = 0; buf = map_sysmem(img_addr, 0); switch (genimg_get_format(buf)) { case IMAGE_FORMAT_LEGACY: printf("## Booting kernel from Legacy Image at %08lx ...\n", img_addr); hdr = image_get_kernel(img_addr, images->verify); if (!hdr) return NULL; bootstage_mark(BOOTSTAGE_ID_CHECK_IMAGETYPE); /* get os_data and os_len */ switch (image_get_type(hdr)) { case IH_TYPE_KERNEL: case IH_TYPE_KERNEL_NOLOAD: *os_data = image_get_data(hdr); *os_len = image_get_data_size(hdr); break; case IH_TYPE_MULTI: image_multi_getimg(hdr, 0, os_data, os_len); break; case IH_TYPE_STANDALONE: *os_data = image_get_data(hdr); *os_len = image_get_data_size(hdr); break; default: printf("Wrong Image Type for %s command\n", cmdtp->name); bootstage_error(BOOTSTAGE_ID_CHECK_IMAGETYPE); return NULL; } /* * copy image header to allow for image overwrites during * kernel decompression. */ memmove(&images->legacy_hdr_os_copy, hdr, sizeof(image_header_t)); /* save pointer to image header */ images->legacy_hdr_os = hdr; images->legacy_hdr_valid = 1; bootstage_mark(BOOTSTAGE_ID_DECOMP_IMAGE); break; #if defined(CONFIG_FIT) case IMAGE_FORMAT_FIT: fit_hdr = buf; printf("## Booting kernel from FIT Image at %08lx ...\n", img_addr); if (!fit_check_format(fit_hdr)) { puts("Bad FIT kernel image format!\n"); bootstage_error(BOOTSTAGE_ID_FIT_FORMAT); return NULL; } bootstage_mark(BOOTSTAGE_ID_FIT_FORMAT); if (!fit_uname_kernel) { /* * no kernel image node unit name, try to get config * node first. If config unit node name is NULL * fit_conf_get_node() will try to find default config * node */ bootstage_mark(BOOTSTAGE_ID_FIT_NO_UNIT_NAME); #ifdef CONFIG_FIT_BEST_MATCH if (fit_uname_config) cfg_noffset = fit_conf_get_node(fit_hdr, fit_uname_config); else cfg_noffset = fit_conf_find_compat(fit_hdr, gd->fdt_blob); #else cfg_noffset = fit_conf_get_node(fit_hdr, fit_uname_config); #endif if (cfg_noffset < 0) { bootstage_error(BOOTSTAGE_ID_FIT_NO_UNIT_NAME); return NULL; } /* save configuration uname provided in the first * bootm argument */ images->fit_uname_cfg = fdt_get_name(fit_hdr, cfg_noffset, NULL); printf(" Using '%s' configuration\n", images->fit_uname_cfg); bootstage_mark(BOOTSTAGE_ID_FIT_CONFIG); os_noffset = fit_conf_get_kernel_node(fit_hdr, cfg_noffset); fit_uname_kernel = fit_get_name(fit_hdr, os_noffset, NULL); } else { /* get kernel component image node offset */ bootstage_mark(BOOTSTAGE_ID_FIT_UNIT_NAME); os_noffset = fit_image_get_node(fit_hdr, fit_uname_kernel); } if (os_noffset < 0) { bootstage_error(BOOTSTAGE_ID_FIT_CONFIG); return NULL; } printf(" Trying '%s' kernel subimage\n", fit_uname_kernel); bootstage_mark(BOOTSTAGE_ID_FIT_CHECK_SUBIMAGE); if (!fit_check_kernel(fit_hdr, os_noffset, images->verify)) return NULL; /* get kernel image data address and length */ if (fit_image_get_data(fit_hdr, os_noffset, &data, &len)) { puts("Could not find kernel subimage data!\n"); bootstage_error(BOOTSTAGE_ID_FIT_KERNEL_INFO_ERR); return NULL; } bootstage_mark(BOOTSTAGE_ID_FIT_KERNEL_INFO); *os_len = len; *os_data = (ulong)data; images->fit_hdr_os = (void *)fit_hdr; images->fit_uname_os = fit_uname_kernel; images->fit_noffset_os = os_noffset; break; #endif default: printf("Wrong Image Format for %s command\n", cmdtp->name); bootstage_error(BOOTSTAGE_ID_FIT_KERNEL_INFO); return NULL; } debug(" kernel data at 0x%08lx, len = 0x%08lx (%ld)\n", *os_data, *os_len, *os_len); return buf; }
/** * decomp_image() - decompress the operating system * * @comp: Compression algorithm that is used (IH_COMP_...) * @load: Destination load address in U-Boot memory * @image_start Image start address (where we are decompressing from) * @type: OS type (IH_OS_...) * @load_bug: Place to decompress to * @image_buf: Address to decompress from * @return 0 if OK, -ve on error (BOOTM_ERR_...) */ static int decomp_image(int comp, ulong load, ulong image_start, int type, void *load_buf, void *image_buf, ulong image_len, ulong *load_end) { const char *type_name = genimg_get_type_name(type); __attribute__((unused)) uint unc_len = CONFIG_SYS_BOOTM_LEN; *load_end = load; switch (comp) { case IH_COMP_NONE: if (load == image_start) { printf(" XIP %s ... ", type_name); } else { printf(" Loading %s ... ", type_name); memmove_wd(load_buf, image_buf, image_len, CHUNKSZ); } *load_end = load + image_len; break; #ifdef CONFIG_GZIP case IH_COMP_GZIP: printf(" Uncompressing %s ... ", type_name); if (gunzip(load_buf, unc_len, image_buf, &image_len) != 0) { puts("GUNZIP: uncompress, out-of-mem or overwrite error - must RESET board to recover\n"); return BOOTM_ERR_RESET; } *load_end = load + image_len; break; #endif /* CONFIG_GZIP */ #ifdef CONFIG_BZIP2 case IH_COMP_BZIP2: printf(" Uncompressing %s ... ", type_name); /* * If we've got less than 4 MB of malloc() space, * use slower decompression algorithm which requires * at most 2300 KB of memory. */ int i = BZ2_bzBuffToBuffDecompress(load_buf, &unc_len, image_buf, image_len, CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0); if (i != BZ_OK) { printf("BUNZIP2: uncompress or overwrite error %d - must RESET board to recover\n", i); return BOOTM_ERR_RESET; } *load_end = load + unc_len; break; #endif /* CONFIG_BZIP2 */ #ifdef CONFIG_LZMA case IH_COMP_LZMA: { SizeT lzma_len = unc_len; int ret; printf(" Uncompressing %s ... ", type_name); ret = lzmaBuffToBuffDecompress(load_buf, &lzma_len, image_buf, image_len); unc_len = lzma_len; if (ret != SZ_OK) { printf("LZMA: uncompress or overwrite error %d - must RESET board to recover\n", ret); bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return BOOTM_ERR_RESET; } *load_end = load + unc_len; break; } #endif /* CONFIG_LZMA */ #ifdef CONFIG_LZO case IH_COMP_LZO: { size_t size = unc_len; int ret; printf(" Uncompressing %s ... ", type_name); ret = lzop_decompress(image_buf, image_len, load_buf, &size); if (ret != LZO_E_OK) { printf("LZO: uncompress or overwrite error %d - must RESET board to recover\n", ret); return BOOTM_ERR_RESET; } *load_end = load + size; break; } #endif /* CONFIG_LZO */ default: printf("Unimplemented compression type %d\n", comp); return BOOTM_ERR_UNIMPLEMENTED; } puts("OK\n"); return 0; }
int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc, char *const argv[]) { int dev, part; ulong addr = CONFIG_SYS_LOAD_ADDR; ulong cnt; disk_partition_t info; #if defined(CONFIG_IMAGE_FORMAT_LEGACY) image_header_t *hdr; #endif block_dev_desc_t *dev_desc; #if defined(CONFIG_FIT) const void *fit_hdr = NULL; #endif bootstage_mark(BOOTSTAGE_ID_IDE_START); if (argc > 3) { bootstage_error(BOOTSTAGE_ID_IDE_ADDR); return CMD_RET_USAGE; } bootstage_mark(BOOTSTAGE_ID_IDE_ADDR); if (argc > 1) addr = simple_strtoul(argv[1], NULL, 16); bootstage_mark(BOOTSTAGE_ID_IDE_BOOT_DEVICE); part = get_device_and_partition(intf, (argc == 3) ? argv[2] : NULL, &dev_desc, &info, 1); if (part < 0) { bootstage_error(BOOTSTAGE_ID_IDE_TYPE); return 1; } dev = dev_desc->dev; bootstage_mark(BOOTSTAGE_ID_IDE_TYPE); printf("\nLoading from %s device %d, partition %d: " "Name: %.32s Type: %.32s\n", intf, dev, part, info.name, info.type); debug("First Block: " LBAFU ", # of blocks: " LBAFU ", Block Size: %ld\n", info.start, info.size, info.blksz); if (dev_desc->block_read(dev, info.start, 1, (ulong *) addr) != 1) { printf("** Read error on %d:%d\n", dev, part); bootstage_error(BOOTSTAGE_ID_IDE_PART_READ); return 1; } bootstage_mark(BOOTSTAGE_ID_IDE_PART_READ); switch (genimg_get_format((void *) addr)) { #if defined(CONFIG_IMAGE_FORMAT_LEGACY) case IMAGE_FORMAT_LEGACY: hdr = (image_header_t *) addr; bootstage_mark(BOOTSTAGE_ID_IDE_FORMAT); if (!image_check_hcrc(hdr)) { puts("\n** Bad Header Checksum **\n"); bootstage_error(BOOTSTAGE_ID_IDE_CHECKSUM); return 1; } bootstage_mark(BOOTSTAGE_ID_IDE_CHECKSUM); image_print_contents(hdr); cnt = image_get_image_size(hdr); break; #endif #if defined(CONFIG_FIT) case IMAGE_FORMAT_FIT: fit_hdr = (const void *) addr; puts("Fit image detected...\n"); cnt = fit_get_size(fit_hdr); break; #endif default: bootstage_error(BOOTSTAGE_ID_IDE_FORMAT); puts("** Unknown image type\n"); return 1; } cnt += info.blksz - 1; cnt /= info.blksz; cnt -= 1; if (dev_desc->block_read(dev, info.start + 1, cnt, (ulong *)(addr + info.blksz)) != cnt) { printf("** Read error on %d:%d\n", dev, part); bootstage_error(BOOTSTAGE_ID_IDE_READ); return 1; } bootstage_mark(BOOTSTAGE_ID_IDE_READ); #if defined(CONFIG_FIT) /* This cannot be done earlier, * we need complete FIT image in RAM first */ if (genimg_get_format((void *) addr) == IMAGE_FORMAT_FIT) { if (!fit_check_format(fit_hdr)) { bootstage_error(BOOTSTAGE_ID_IDE_FIT_READ); puts("** Bad FIT image format\n"); return 1; } bootstage_mark(BOOTSTAGE_ID_IDE_FIT_READ_OK); fit_print_contents(fit_hdr); } #endif flush_cache(addr, (cnt+1)*info.blksz); /* Loading ok, update default load address */ load_addr = addr; return bootm_maybe_autostart(cmdtp, argv[0]); }
static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc, char * const argv[]) { char *s; char *end; int rcode = 0; int size; ulong addr; /* pre-set load_addr */ if ((s = getenv("loadaddr")) != NULL) { load_addr = simple_strtoul(s, NULL, 16); } switch (argc) { case 1: break; case 2: /* * Only one arg - accept two forms: * Just load address, or just boot file name. The latter * form must be written in a format which can not be * mis-interpreted as a valid number. */ addr = simple_strtoul(argv[1], &end, 16); if (end == (argv[1] + strlen(argv[1]))) load_addr = addr; else copy_filename(BootFile, argv[1], sizeof(BootFile)); break; case 3: load_addr = simple_strtoul(argv[1], NULL, 16); copy_filename(BootFile, argv[2], sizeof(BootFile)); break; #ifdef CONFIG_CMD_TFTPPUT case 4: if (strict_strtoul(argv[1], 16, &save_addr) < 0 || strict_strtoul(argv[2], 16, &save_size) < 0) { printf("Invalid address/size\n"); return cmd_usage(cmdtp); } copy_filename(BootFile, argv[3], sizeof(BootFile)); break; #endif default: bootstage_error(BOOTSTAGE_ID_NET_START); return CMD_RET_USAGE; } bootstage_mark(BOOTSTAGE_ID_NET_START); if ((size = NetLoop(proto)) < 0) { bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); return 1; } bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK); /* NetLoop ok, update environment */ netboot_update_env(); /* done if no file was loaded (no errors though) */ if (size == 0) { bootstage_error(BOOTSTAGE_ID_NET_LOADED); return 0; } /* flush cache */ flush_cache(load_addr, size); bootstage_mark(BOOTSTAGE_ID_NET_LOADED); rcode = bootm_maybe_autostart(cmdtp, argv[0]); if (rcode < 0) bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR); else bootstage_mark(BOOTSTAGE_ID_NET_DONE); return rcode; }
static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { const void *os_hdr; bool ep_found = false; /* get kernel image header, start address and length */ os_hdr = boot_get_kernel(cmdtp, flag, argc, argv, &images, &images.os.image_start, &images.os.image_len); if (images.os.image_len == 0) { puts("ERROR: can't get kernel image!\n"); return 1; } /* get image parameters */ switch (genimg_get_format(os_hdr)) { case IMAGE_FORMAT_LEGACY: images.os.type = image_get_type(os_hdr); images.os.comp = image_get_comp(os_hdr); images.os.os = image_get_os(os_hdr); images.os.end = image_get_image_end(os_hdr); images.os.load = image_get_load(os_hdr); break; #if defined(CONFIG_FIT) case IMAGE_FORMAT_FIT: if (fit_image_get_type(images.fit_hdr_os, images.fit_noffset_os, &images.os.type)) { puts("Can't get image type!\n"); bootstage_error(BOOTSTAGE_ID_FIT_TYPE); return 1; } if (fit_image_get_comp(images.fit_hdr_os, images.fit_noffset_os, &images.os.comp)) { puts("Can't get image compression!\n"); bootstage_error(BOOTSTAGE_ID_FIT_COMPRESSION); return 1; } if (fit_image_get_os(images.fit_hdr_os, images.fit_noffset_os, &images.os.os)) { puts("Can't get image OS!\n"); bootstage_error(BOOTSTAGE_ID_FIT_OS); return 1; } images.os.end = fit_get_end(images.fit_hdr_os); if (fit_image_get_load(images.fit_hdr_os, images.fit_noffset_os, &images.os.load)) { puts("Can't get image load address!\n"); bootstage_error(BOOTSTAGE_ID_FIT_LOADADDR); return 1; } break; #endif #ifdef CONFIG_ANDROID_BOOT_IMAGE case IMAGE_FORMAT_ANDROID: images.os.type = IH_TYPE_KERNEL; images.os.comp = IH_COMP_NONE; images.os.os = IH_OS_LINUX; images.ep = images.os.load; ep_found = true; images.os.end = android_image_get_end(os_hdr); images.os.load = android_image_get_kload(os_hdr); break; #endif default: puts("ERROR: unknown image format type!\n"); return 1; } /* find kernel entry point */ if (images.legacy_hdr_valid) { images.ep = image_get_ep(&images.legacy_hdr_os_copy); #if defined(CONFIG_FIT) } else if (images.fit_uname_os) { int ret; ret = fit_image_get_entry(images.fit_hdr_os, images.fit_noffset_os, &images.ep); if (ret) { puts("Can't get entry point property!\n"); return 1; } #endif } else if (!ep_found) { puts("Could not find kernel entry point!\n"); return 1; } if (images.os.type == IH_TYPE_KERNEL_NOLOAD) { images.os.load = images.os.image_start; images.ep += images.os.load; } images.os.start = (ulong)os_hdr; return 0; }
static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { const void *os_hdr; bool ep_found = false; int ret; /* get kernel image header, start address and length */ os_hdr = boot_get_kernel(cmdtp, flag, argc, argv, &images, &images.os.image_start, &images.os.image_len); if (images.os.image_len == 0) { puts("ERROR: can't get kernel image!\n"); return 1; } /* get image parameters */ switch (genimg_get_format(os_hdr)) { #if defined(CONFIG_IMAGE_FORMAT_LEGACY) case IMAGE_FORMAT_LEGACY: images.os.type = image_get_type(os_hdr); images.os.comp = image_get_comp(os_hdr); images.os.os = image_get_os(os_hdr); images.os.end = image_get_image_end(os_hdr); images.os.load = image_get_load(os_hdr); images.os.arch = image_get_arch(os_hdr); break; #endif #if IMAGE_ENABLE_FIT case IMAGE_FORMAT_FIT: if (fit_image_get_type(images.fit_hdr_os, images.fit_noffset_os, &images.os.type)) { puts("Can't get image type!\n"); bootstage_error(BOOTSTAGE_ID_FIT_TYPE); return 1; } if (fit_image_get_comp(images.fit_hdr_os, images.fit_noffset_os, &images.os.comp)) { puts("Can't get image compression!\n"); bootstage_error(BOOTSTAGE_ID_FIT_COMPRESSION); return 1; } if (fit_image_get_os(images.fit_hdr_os, images.fit_noffset_os, &images.os.os)) { puts("Can't get image OS!\n"); bootstage_error(BOOTSTAGE_ID_FIT_OS); return 1; } if (fit_image_get_arch(images.fit_hdr_os, images.fit_noffset_os, &images.os.arch)) { puts("Can't get image ARCH!\n"); return 1; } images.os.end = fit_get_end(images.fit_hdr_os); if (fit_image_get_load(images.fit_hdr_os, images.fit_noffset_os, &images.os.load)) { puts("Can't get image load address!\n"); bootstage_error(BOOTSTAGE_ID_FIT_LOADADDR); return 1; } break; #endif #ifdef CONFIG_ANDROID_BOOT_IMAGE case IMAGE_FORMAT_ANDROID: images.os.type = IH_TYPE_KERNEL; images.os.comp = IH_COMP_NONE; images.os.os = IH_OS_LINUX; images.os.end = android_image_get_end(os_hdr); images.os.load = android_image_get_kload(os_hdr); images.ep = images.os.load; ep_found = true; break; #endif default: puts("ERROR: unknown image format type!\n"); return 1; } /* If we have a valid setup.bin, we will use that for entry (x86) */ if (images.os.arch == IH_ARCH_I386 || images.os.arch == IH_ARCH_X86_64) { ulong len; ret = boot_get_setup(&images, IH_ARCH_I386, &images.ep, &len); if (ret < 0 && ret != -ENOENT) { puts("Could not find a valid setup.bin for x86\n"); return 1; } /* Kernel entry point is the setup.bin */ } else if (images.legacy_hdr_valid) { images.ep = image_get_ep(&images.legacy_hdr_os_copy); #if IMAGE_ENABLE_FIT } else if (images.fit_uname_os) { int ret; ret = fit_image_get_entry(images.fit_hdr_os, images.fit_noffset_os, &images.ep); if (ret) { puts("Can't get entry point property!\n"); return 1; } #endif } else if (!ep_found) { puts("Could not find kernel entry point!\n"); return 1; } if (images.os.type == IH_TYPE_KERNEL_NOLOAD) { if (CONFIG_IS_ENABLED(CMD_BOOTI) && images.os.arch == IH_ARCH_ARM64) { ulong image_addr; ulong image_size; ret = booti_setup(images.os.image_start, &image_addr, &image_size, true); if (ret != 0) return 1; images.os.type = IH_TYPE_KERNEL; images.os.load = image_addr; images.ep = image_addr; } else { images.os.load = images.os.image_start; images.ep += images.os.image_start; } } images.os.start = map_to_sysmem(os_hdr); return 0; }
int fit_image_load(bootm_headers_t *images, const char *prop_name, ulong addr, const char **fit_unamep, const char **fit_uname_configp, int arch, int image_type, int bootstage_id, enum fit_load_op load_op, ulong *datap, ulong *lenp) { int cfg_noffset, noffset; const char *fit_uname; const char *fit_uname_config; const void *fit; const void *buf; size_t size; int type_ok, os_ok; ulong load, data, len; int ret; fit = map_sysmem(addr, 0); fit_uname = fit_unamep ? *fit_unamep : NULL; fit_uname_config = fit_uname_configp ? *fit_uname_configp : NULL; printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr); bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT); if (!fit_check_format(fit)) { printf("Bad FIT %s image format!\n", prop_name); bootstage_error(bootstage_id + BOOTSTAGE_SUB_FORMAT); return -ENOEXEC; } bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT_OK); if (fit_uname) { /* get ramdisk component image node offset */ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_UNIT_NAME); noffset = fit_image_get_node(fit, fit_uname); } else { /* * no image node unit name, try to get config * node first. If config unit node name is NULL * fit_conf_get_node() will try to find default config node */ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_NO_UNIT_NAME); if (IMAGE_ENABLE_BEST_MATCH && !fit_uname_config) { cfg_noffset = fit_conf_find_compat(fit, gd_fdt_blob()); } else { cfg_noffset = fit_conf_get_node(fit, fit_uname_config); } if (cfg_noffset < 0) { puts("Could not find configuration node\n"); bootstage_error(bootstage_id + BOOTSTAGE_SUB_NO_UNIT_NAME); return -ENOENT; } fit_uname_config = fdt_get_name(fit, cfg_noffset, NULL); printf(" Using '%s' configuration\n", fit_uname_config); if (image_type == IH_TYPE_KERNEL) { /* Remember (and possibly verify) this config */ images->fit_uname_cfg = fit_uname_config; if (IMAGE_ENABLE_VERIFY && images->verify) { puts(" Verifying Hash Integrity ... "); if (!fit_config_verify(fit, cfg_noffset)) { puts("Bad Data Hash\n"); bootstage_error(bootstage_id + BOOTSTAGE_SUB_HASH); return -EACCES; } puts("OK\n"); } bootstage_mark(BOOTSTAGE_ID_FIT_CONFIG); } noffset = fit_conf_get_prop_node(fit, cfg_noffset, prop_name); fit_uname = fit_get_name(fit, noffset, NULL); } if (noffset < 0) { puts("Could not find subimage node\n"); bootstage_error(bootstage_id + BOOTSTAGE_SUB_SUBNODE); return -ENOENT; } printf(" Trying '%s' %s subimage\n", fit_uname, prop_name); ret = fit_image_select(fit, noffset, images->verify); if (ret) { bootstage_error(bootstage_id + BOOTSTAGE_SUB_HASH); return ret; } bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH); if (!fit_image_check_target_arch(fit, noffset)) { puts("Unsupported Architecture\n"); bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH); return -ENOEXEC; } if (image_type == IH_TYPE_FLATDT && !fit_image_check_comp(fit, noffset, IH_COMP_NONE)) { puts("FDT image is compressed"); return -EPROTONOSUPPORT; } bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL); type_ok = fit_image_check_type(fit, noffset, image_type) || (image_type == IH_TYPE_KERNEL && fit_image_check_type(fit, noffset, IH_TYPE_KERNEL_NOLOAD)); os_ok = image_type == IH_TYPE_FLATDT || fit_image_check_os(fit, noffset, IH_OS_LINUX); if (!type_ok || !os_ok) { printf("No Linux %s %s Image\n", genimg_get_arch_name(arch), genimg_get_type_name(image_type)); bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL); return -EIO; } bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL_OK); /* get image data address and length */ if (fit_image_get_data(fit, noffset, &buf, &size)) { printf("Could not find %s subimage data!\n", prop_name); bootstage_error(bootstage_id + BOOTSTAGE_SUB_GET_DATA); return -ENOENT; } len = (ulong)size; /* verify that image data is a proper FDT blob */ if (image_type == IH_TYPE_FLATDT && fdt_check_header((char *)buf)) { puts("Subimage data is not a FDT"); return -ENOEXEC; } bootstage_mark(bootstage_id + BOOTSTAGE_SUB_GET_DATA_OK); /* * Work-around for eldk-4.2 which gives this warning if we try to * case in the unmap_sysmem() call: * warning: initialization discards qualifiers from pointer target type */ { void *vbuf = (void *)buf; data = map_to_sysmem(vbuf); } if (load_op == FIT_LOAD_IGNORED) { /* Don't load */ } else if (fit_image_get_load(fit, noffset, &load)) { if (load_op == FIT_LOAD_REQUIRED) { printf("Can't get %s subimage load address!\n", prop_name); bootstage_error(bootstage_id + BOOTSTAGE_SUB_LOAD); return -EBADF; } } else { ulong image_start, image_end; ulong load_end; void *dst; /* * move image data to the load address, * make sure we don't overwrite initial image */ image_start = addr; image_end = addr + fit_get_size(fit); load_end = load + len; if (image_type != IH_TYPE_KERNEL && load < image_end && load_end > image_start) { printf("Error: %s overwritten\n", prop_name); return -EXDEV; } printf(" Loading %s from 0x%08lx to 0x%08lx\n", prop_name, data, load); dst = map_sysmem(load, len); memmove(dst, buf, len); data = load; } bootstage_mark(bootstage_id + BOOTSTAGE_SUB_LOAD); *datap = data; *lenp = len; if (fit_unamep) *fit_unamep = (char *)fit_uname; if (fit_uname_configp) *fit_uname_configp = (char *)fit_uname_config; return noffset; }
static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) { uint8_t comp = os.comp; ulong load = os.load; ulong blob_start = os.start; ulong blob_end = os.end; ulong image_start = os.image_start; ulong image_len = os.image_len; __maybe_unused uint unc_len = CONFIG_SYS_BOOTM_LEN; int no_overlap = 0; void *load_buf, *image_buf; const char *type_name = genimg_get_type_name(os.type); load_buf = map_sysmem(load, image_len); image_buf = map_sysmem(image_start, image_len); switch (comp) { case IH_COMP_NONE: if (load == blob_start || load == image_start) { printf(" XIP %s ... ", type_name); no_overlap = 1; } else { printf(" Loading %s ... ", type_name); memmove_wd(load_buf, image_buf, image_len, CHUNKSZ); } *load_end = load + image_len; puts("OK\n"); break; #ifdef CONFIG_GZIP case IH_COMP_GZIP: printf(" Uncompressing %s ... ", type_name); if (gunzip(load_buf, unc_len, image_buf, &image_len) != 0) { puts("GUNZIP: uncompress, out-of-mem or overwrite " "error - must RESET board to recover\n"); if (boot_progress) bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return BOOTM_ERR_RESET; } *load_end = load + image_len; break; #endif /* CONFIG_GZIP */ default: printf("Unimplemented compression type %d\n", comp); return BOOTM_ERR_UNIMPLEMENTED; } flush_cache(load, (*load_end - load) * sizeof(ulong)); puts("OK\n"); debug(" kernel loaded at 0x%08lx, end = 0x%08lx\n", load, *load_end); bootstage_mark(BOOTSTAGE_ID_KERNEL_LOADED); if (!no_overlap && (load < blob_end) && (*load_end > blob_start)) { debug("images.os.start = 0x%lX, images.os.end = 0x%lx\n", blob_start, blob_end); debug("images.os.load = 0x%lx, load_end = 0x%lx\n", load, *load_end); return BOOTM_ERR_OVERLAP; } return 0; }