1f1dcee59SSimon Glass /* 2f1dcee59SSimon Glass * Copyright (C) 2016 Google, Inc 3f1dcee59SSimon Glass * Written by Simon Glass <sjg@chromium.org> 4f1dcee59SSimon Glass * 5f1dcee59SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 6f1dcee59SSimon Glass */ 7f1dcee59SSimon Glass 8f1dcee59SSimon Glass #include <common.h> 9e12dde2dSJoseph Chen #include <boot_rkimg.h> 105dd9177cSXuhui Lin #include <keylad.h> 115dd9177cSXuhui Lin #include <crypto.h> 12f1dcee59SSimon Glass #include <errno.h> 13a712f631SJason Zhu #include <fdt_support.h> 14f1dcee59SSimon Glass #include <image.h> 1590d1164aSKever Yang #include <malloc.h> 16a741b19cSJason Zhu #include <mtd_blk.h> 1736c449feSJoseph Chen #include <mp_boot.h> 181f5c7b64SJason Zhu #include <spl.h> 191f5c7b64SJason Zhu #include <spl_ab.h> 20a741b19cSJason Zhu #include <linux/libfdt.h> 21f1dcee59SSimon Glass 22b81c4739SYork Sun #ifndef CONFIG_SYS_BOOTM_LEN 23b81c4739SYork Sun #define CONFIG_SYS_BOOTM_LEN (64 << 20) 24b81c4739SYork Sun #endif 25b81c4739SYork Sun 26736806fbSAndre Przywara /** 271f1cf67bSPhilipp Tomsich * spl_fit_get_image_name(): By using the matching configuration subnode, 28736806fbSAndre Przywara * retrieve the name of an image, specified by a property name and an index 29736806fbSAndre Przywara * into that. 30736806fbSAndre Przywara * @fit: Pointer to the FDT blob. 31736806fbSAndre Przywara * @images: Offset of the /images subnode. 32736806fbSAndre Przywara * @type: Name of the property within the configuration subnode. 33736806fbSAndre Przywara * @index: Index into the list of strings in this property. 341f1cf67bSPhilipp Tomsich * @outname: Name of the image 35736806fbSAndre Przywara * 361f1cf67bSPhilipp Tomsich * Return: 0 on success, or a negative error number 37736806fbSAndre Przywara */ 381f1cf67bSPhilipp Tomsich static int spl_fit_get_image_name(const void *fit, int images, 391f1cf67bSPhilipp Tomsich const char *type, int index, 401f1cf67bSPhilipp Tomsich char **outname) 414b9340abSAndre Przywara { 424b9340abSAndre Przywara const char *name, *str; 431f1cf67bSPhilipp Tomsich __maybe_unused int node; 441f1cf67bSPhilipp Tomsich int conf_node; 454b9340abSAndre Przywara int len, i; 46f1dcee59SSimon Glass 473863f840SCooper Jr., Franklin conf_node = fit_find_config_node(fit); 484b9340abSAndre Przywara if (conf_node < 0) { 49f1dcee59SSimon Glass #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 50f1dcee59SSimon Glass printf("No matching DT out of these options:\n"); 514b9340abSAndre Przywara for (node = fdt_first_subnode(fit, conf_node); 52f1dcee59SSimon Glass node >= 0; 534b9340abSAndre Przywara node = fdt_next_subnode(fit, node)) { 544b9340abSAndre Przywara name = fdt_getprop(fit, node, "description", &len); 55f1dcee59SSimon Glass printf(" %s\n", name); 56f1dcee59SSimon Glass } 57f1dcee59SSimon Glass #endif 584b9340abSAndre Przywara return conf_node; 594b9340abSAndre Przywara } 60f1dcee59SSimon Glass 614b9340abSAndre Przywara name = fdt_getprop(fit, conf_node, type, &len); 624b9340abSAndre Przywara if (!name) { 634b9340abSAndre Przywara debug("cannot find property '%s': %d\n", type, len); 644b9340abSAndre Przywara return -EINVAL; 654b9340abSAndre Przywara } 664b9340abSAndre Przywara 674b9340abSAndre Przywara str = name; 684b9340abSAndre Przywara for (i = 0; i < index; i++) { 694b9340abSAndre Przywara str = strchr(str, '\0') + 1; 704b9340abSAndre Przywara if (!str || (str - name >= len)) { 714b9340abSAndre Przywara debug("no string for index %d\n", index); 724b9340abSAndre Przywara return -E2BIG; 734b9340abSAndre Przywara } 744b9340abSAndre Przywara } 754b9340abSAndre Przywara 761f1cf67bSPhilipp Tomsich *outname = (char *)str; 771f1cf67bSPhilipp Tomsich return 0; 781f1cf67bSPhilipp Tomsich } 791f1cf67bSPhilipp Tomsich 801f1cf67bSPhilipp Tomsich /** 811f1cf67bSPhilipp Tomsich * spl_fit_get_image_node(): By using the matching configuration subnode, 821f1cf67bSPhilipp Tomsich * retrieve the name of an image, specified by a property name and an index 831f1cf67bSPhilipp Tomsich * into that. 841f1cf67bSPhilipp Tomsich * @fit: Pointer to the FDT blob. 851f1cf67bSPhilipp Tomsich * @images: Offset of the /images subnode. 861f1cf67bSPhilipp Tomsich * @type: Name of the property within the configuration subnode. 871f1cf67bSPhilipp Tomsich * @index: Index into the list of strings in this property. 881f1cf67bSPhilipp Tomsich * 891f1cf67bSPhilipp Tomsich * Return: the node offset of the respective image node or a negative 901f1cf67bSPhilipp Tomsich * error number. 911f1cf67bSPhilipp Tomsich */ 921f1cf67bSPhilipp Tomsich static int spl_fit_get_image_node(const void *fit, int images, 931f1cf67bSPhilipp Tomsich const char *type, int index) 941f1cf67bSPhilipp Tomsich { 951f1cf67bSPhilipp Tomsich char *str; 961f1cf67bSPhilipp Tomsich int err; 971f1cf67bSPhilipp Tomsich int node; 981f1cf67bSPhilipp Tomsich 991f1cf67bSPhilipp Tomsich err = spl_fit_get_image_name(fit, images, type, index, &str); 1001f1cf67bSPhilipp Tomsich if (err) 1011f1cf67bSPhilipp Tomsich return err; 1021f1cf67bSPhilipp Tomsich 1034b9340abSAndre Przywara debug("%s: '%s'\n", type, str); 1041f1cf67bSPhilipp Tomsich 1054b9340abSAndre Przywara node = fdt_subnode_offset(fit, images, str); 1064b9340abSAndre Przywara if (node < 0) { 1074b9340abSAndre Przywara debug("cannot find image node '%s': %d\n", str, node); 1084b9340abSAndre Przywara return -EINVAL; 1094b9340abSAndre Przywara } 1104b9340abSAndre Przywara 111736806fbSAndre Przywara return node; 112f1dcee59SSimon Glass } 113f1dcee59SSimon Glass 114eafd5410SLokesh Vutla static int get_aligned_image_offset(struct spl_load_info *info, int offset) 115eafd5410SLokesh Vutla { 116eafd5410SLokesh Vutla /* 117eafd5410SLokesh Vutla * If it is a FS read, get the first address before offset which is 118eafd5410SLokesh Vutla * aligned to ARCH_DMA_MINALIGN. If it is raw read return the 119eafd5410SLokesh Vutla * block number to which offset belongs. 120eafd5410SLokesh Vutla */ 121eafd5410SLokesh Vutla if (info->filename) 122eafd5410SLokesh Vutla return offset & ~(ARCH_DMA_MINALIGN - 1); 123eafd5410SLokesh Vutla 124eafd5410SLokesh Vutla return offset / info->bl_len; 125eafd5410SLokesh Vutla } 126eafd5410SLokesh Vutla 127eafd5410SLokesh Vutla static int get_aligned_image_overhead(struct spl_load_info *info, int offset) 128eafd5410SLokesh Vutla { 129eafd5410SLokesh Vutla /* 130eafd5410SLokesh Vutla * If it is a FS read, get the difference between the offset and 131eafd5410SLokesh Vutla * the first address before offset which is aligned to 132eafd5410SLokesh Vutla * ARCH_DMA_MINALIGN. If it is raw read return the offset within the 133eafd5410SLokesh Vutla * block. 134eafd5410SLokesh Vutla */ 135eafd5410SLokesh Vutla if (info->filename) 136eafd5410SLokesh Vutla return offset & (ARCH_DMA_MINALIGN - 1); 137eafd5410SLokesh Vutla 138eafd5410SLokesh Vutla return offset % info->bl_len; 139eafd5410SLokesh Vutla } 140eafd5410SLokesh Vutla 141eafd5410SLokesh Vutla static int get_aligned_image_size(struct spl_load_info *info, int data_size, 142eafd5410SLokesh Vutla int offset) 143eafd5410SLokesh Vutla { 1443cc1f380SLokesh Vutla data_size = data_size + get_aligned_image_overhead(info, offset); 1453cc1f380SLokesh Vutla 146eafd5410SLokesh Vutla if (info->filename) 1473cc1f380SLokesh Vutla return data_size; 148eafd5410SLokesh Vutla 149eafd5410SLokesh Vutla return (data_size + info->bl_len - 1) / info->bl_len; 150eafd5410SLokesh Vutla } 151eafd5410SLokesh Vutla 1525dd9177cSXuhui Lin #ifdef CONFIG_SPL_FIT_CIPHER 1535dd9177cSXuhui Lin static int spl_fit_image_uncipher(const void *fit, int noffset, 1545dd9177cSXuhui Lin ulong cipher_addr, size_t cipher_sz, 1555dd9177cSXuhui Lin ulong uncipher_addr) 1565dd9177cSXuhui Lin { 1575dd9177cSXuhui Lin struct udevice *dev; 1585dd9177cSXuhui Lin cipher_fw_context ctx; 1595dd9177cSXuhui Lin int cipher_noffset; 1605dd9177cSXuhui Lin const char *node_name; 1615dd9177cSXuhui Lin const void *iv; 1625dd9177cSXuhui Lin char *algo_name; 1635dd9177cSXuhui Lin int key_len = 16; 1645dd9177cSXuhui Lin int iv_len; 1655dd9177cSXuhui Lin int ret; 1665dd9177cSXuhui Lin 1675dd9177cSXuhui Lin node_name = fdt_get_name(fit, noffset, NULL); 1685dd9177cSXuhui Lin if (!node_name) { 1695dd9177cSXuhui Lin printf("Can't get node name.\n"); 1705dd9177cSXuhui Lin return -1; 1715dd9177cSXuhui Lin } 1725dd9177cSXuhui Lin 1735dd9177cSXuhui Lin cipher_noffset = fdt_subnode_offset(fit, noffset, FIT_CIPHER_NODENAME); 1745dd9177cSXuhui Lin if (cipher_noffset < 0) { 1755dd9177cSXuhui Lin printf("Can't get cipher node offset for image '%s'\n", 1765dd9177cSXuhui Lin node_name); 1775dd9177cSXuhui Lin return -1; 1785dd9177cSXuhui Lin } 1795dd9177cSXuhui Lin 1805dd9177cSXuhui Lin if (fit_image_cipher_get_algo(fit, cipher_noffset, &algo_name)) { 1815dd9177cSXuhui Lin printf("Can't get cipher algo for image '%s'\n", 1825dd9177cSXuhui Lin node_name); 1835dd9177cSXuhui Lin return -1; 1845dd9177cSXuhui Lin } 1855dd9177cSXuhui Lin 1865dd9177cSXuhui Lin if (strcmp(algo_name, "aes128")) { 1875dd9177cSXuhui Lin printf("Invalid cipher algo '%s'\n", algo_name); 1885dd9177cSXuhui Lin return -1; 1895dd9177cSXuhui Lin } 1905dd9177cSXuhui Lin 1915dd9177cSXuhui Lin iv = fdt_getprop(fit, cipher_noffset, "iv", &iv_len); 1925dd9177cSXuhui Lin if (!iv) { 1935dd9177cSXuhui Lin printf("Can't get IV for image '%s'\n", node_name); 1945dd9177cSXuhui Lin return -1; 1955dd9177cSXuhui Lin } 1965dd9177cSXuhui Lin 1975dd9177cSXuhui Lin if (iv_len != key_len) { 1985dd9177cSXuhui Lin printf("Len iv(%d) != key(%d) for image '%s'\n", 1995dd9177cSXuhui Lin iv_len, key_len, node_name); 2005dd9177cSXuhui Lin return -1; 2015dd9177cSXuhui Lin } 2025dd9177cSXuhui Lin 2035dd9177cSXuhui Lin memset(&ctx, 0x00, sizeof(ctx)); 2045dd9177cSXuhui Lin 2055dd9177cSXuhui Lin ctx.algo = CRYPTO_AES; 2065dd9177cSXuhui Lin ctx.mode = RK_MODE_CTR; 2075dd9177cSXuhui Lin ctx.key_len = key_len; 2085dd9177cSXuhui Lin ctx.iv = iv; 2095dd9177cSXuhui Lin ctx.iv_len = iv_len; 2105dd9177cSXuhui Lin ctx.fw_keyid = RK_FW_KEY0; 2115dd9177cSXuhui Lin 2125dd9177cSXuhui Lin dev = crypto_get_device(CRYPTO_AES); 2135dd9177cSXuhui Lin if (!dev) { 2145dd9177cSXuhui Lin printf("No crypto device for expected AES\n"); 2155dd9177cSXuhui Lin return -ENODEV; 2165dd9177cSXuhui Lin } 2175dd9177cSXuhui Lin 2185dd9177cSXuhui Lin /* uncipher */ 2195dd9177cSXuhui Lin ret = crypto_fw_cipher(dev, &ctx, (void *)cipher_addr, 2205dd9177cSXuhui Lin (void *)uncipher_addr, cipher_sz, true); 2215dd9177cSXuhui Lin 2225dd9177cSXuhui Lin if (ret) { 2235dd9177cSXuhui Lin printf("Uncipher data failed for image '%s', ret=%d\n", 2245dd9177cSXuhui Lin node_name, ret); 2255dd9177cSXuhui Lin return ret; 2265dd9177cSXuhui Lin } 2275dd9177cSXuhui Lin 2285dd9177cSXuhui Lin return 0; 2295dd9177cSXuhui Lin } 2305dd9177cSXuhui Lin #endif 2315dd9177cSXuhui Lin 2328baa3818SAndre Przywara /** 2338baa3818SAndre Przywara * spl_load_fit_image(): load the image described in a certain FIT node 2348baa3818SAndre Przywara * @info: points to information about the device to load data from 2358baa3818SAndre Przywara * @sector: the start sector of the FIT image on the device 2368baa3818SAndre Przywara * @fit: points to the flattened device tree blob describing the FIT 2378baa3818SAndre Przywara * image 2388baa3818SAndre Przywara * @base_offset: the beginning of the data area containing the actual 2398baa3818SAndre Przywara * image data, relative to the beginning of the FIT 2408baa3818SAndre Przywara * @node: offset of the DT node describing the image to load (relative 2418baa3818SAndre Przywara * to @fit) 2428baa3818SAndre Przywara * @image_info: will be filled with information about the loaded image 2438baa3818SAndre Przywara * If the FIT node does not contain a "load" (address) property, 2448baa3818SAndre Przywara * the image gets loaded to the address pointed to by the 2458baa3818SAndre Przywara * load_addr member in this struct. 2468baa3818SAndre Przywara * 2478baa3818SAndre Przywara * Return: 0 on success or a negative error number. 2488baa3818SAndre Przywara */ 2498baa3818SAndre Przywara static int spl_load_fit_image(struct spl_load_info *info, ulong sector, 2508baa3818SAndre Przywara void *fit, ulong base_offset, int node, 2518baa3818SAndre Przywara struct spl_image_info *image_info) 2528baa3818SAndre Przywara { 2530ea10b9fSYork Sun int offset; 2548baa3818SAndre Przywara size_t length; 2550ea10b9fSYork Sun int len; 256d18ad2e6SYork Sun ulong size; 257d3bfb68bSJoseph Chen ulong comp_addr, load_addr, load_ptr; 2588baa3818SAndre Przywara void *src; 2598baa3818SAndre Przywara ulong overhead; 2608baa3818SAndre Przywara int nr_sectors; 2618baa3818SAndre Przywara int align_len = ARCH_DMA_MINALIGN - 1; 262b81c4739SYork Sun uint8_t image_comp = -1, type = -1; 2630ea10b9fSYork Sun const void *data; 264b86dc419SPeng Fan bool external_data = false; 265b81c4739SYork Sun 266b81c4739SYork Sun if (IS_ENABLED(CONFIG_SPL_OS_BOOT) && IS_ENABLED(CONFIG_SPL_GZIP)) { 267b81c4739SYork Sun if (fit_image_get_comp(fit, node, &image_comp)) 268b81c4739SYork Sun puts("Cannot get image compression format.\n"); 269b81c4739SYork Sun else 270b81c4739SYork Sun debug("%s ", genimg_get_comp_name(image_comp)); 271b81c4739SYork Sun 272b81c4739SYork Sun if (fit_image_get_type(fit, node, &type)) 273b81c4739SYork Sun puts("Cannot get image type.\n"); 274b81c4739SYork Sun else 275b81c4739SYork Sun debug("%s ", genimg_get_type_name(type)); 276d3bfb68bSJoseph Chen } else { 277d3bfb68bSJoseph Chen fit_image_get_comp(fit, node, &image_comp); 278b81c4739SYork Sun } 2798baa3818SAndre Przywara 2800ea10b9fSYork Sun if (fit_image_get_load(fit, node, &load_addr)) 2818baa3818SAndre Przywara load_addr = image_info->load_addr; 2820ea10b9fSYork Sun 283d3bfb68bSJoseph Chen if (image_comp != IH_COMP_NONE && image_comp != IH_COMP_ZIMAGE) { 2843e9875cdSJoseph Chen /* Empirically, 2MB is enough for U-Boot, tee and atf */ 285d3bfb68bSJoseph Chen if (fit_image_get_comp_addr(fit, node, &comp_addr)) 2863e9875cdSJoseph Chen comp_addr = load_addr + FIT_MAX_SPL_IMAGE_SZ; 287d3bfb68bSJoseph Chen } else { 288d3bfb68bSJoseph Chen comp_addr = load_addr; 289d3bfb68bSJoseph Chen } 290d3bfb68bSJoseph Chen 2915dd9177cSXuhui Lin #ifdef CONFIG_SPL_FIT_CIPHER 2925dd9177cSXuhui Lin ulong cipher_addr; 2935dd9177cSXuhui Lin 2945dd9177cSXuhui Lin if (fit_image_get_cipher_addr(fit, node, &cipher_addr)) 2955dd9177cSXuhui Lin cipher_addr = comp_addr + FIT_MAX_SPL_IMAGE_SZ; 2965dd9177cSXuhui Lin #endif 2975dd9177cSXuhui Lin 298b86dc419SPeng Fan if (!fit_image_get_data_position(fit, node, &offset)) { 299b86dc419SPeng Fan external_data = true; 300b86dc419SPeng Fan } else if (!fit_image_get_data_offset(fit, node, &offset)) { 3010ea10b9fSYork Sun offset += base_offset; 302b86dc419SPeng Fan external_data = true; 303b86dc419SPeng Fan } 304b86dc419SPeng Fan 305b86dc419SPeng Fan if (external_data) { 306b86dc419SPeng Fan /* External data */ 3070ea10b9fSYork Sun if (fit_image_get_data_size(fit, node, &len)) 3080ea10b9fSYork Sun return -ENOENT; 3090ea10b9fSYork Sun 310d3bfb68bSJoseph Chen load_ptr = (comp_addr + align_len) & ~align_len; 31163363c40SAndy Yan #if defined(CONFIG_ARCH_ROCKCHIP) 312a5e7a2d4SKever Yang if ((load_ptr < CONFIG_SYS_SDRAM_BASE) || 313a5e7a2d4SKever Yang (load_ptr >= CONFIG_SYS_SDRAM_BASE + SDRAM_MAX_SIZE)) 31490d1164aSKever Yang load_ptr = (ulong)memalign(ARCH_DMA_MINALIGN, len); 31590d1164aSKever Yang #endif 3160ea10b9fSYork Sun length = len; 3178baa3818SAndre Przywara 3188baa3818SAndre Przywara overhead = get_aligned_image_overhead(info, offset); 3198baa3818SAndre Przywara nr_sectors = get_aligned_image_size(info, length, offset); 3208baa3818SAndre Przywara 3210ea10b9fSYork Sun if (info->read(info, 3220ea10b9fSYork Sun sector + get_aligned_image_offset(info, offset), 3238baa3818SAndre Przywara nr_sectors, (void *)load_ptr) != nr_sectors) 3248baa3818SAndre Przywara return -EIO; 3258baa3818SAndre Przywara 3260ea10b9fSYork Sun debug("External data: dst=%lx, offset=%x, size=%lx\n", 3270ea10b9fSYork Sun load_ptr, offset, (unsigned long)length); 3288baa3818SAndre Przywara src = (void *)load_ptr + overhead; 3290ea10b9fSYork Sun } else { 3300ea10b9fSYork Sun /* Embedded data */ 3310ea10b9fSYork Sun if (fit_image_get_data(fit, node, &data, &length)) { 3320ea10b9fSYork Sun puts("Cannot get image data/size\n"); 3330ea10b9fSYork Sun return -ENOENT; 3340ea10b9fSYork Sun } 3350ea10b9fSYork Sun debug("Embedded data: dst=%lx, size=%lx\n", load_addr, 3360ea10b9fSYork Sun (unsigned long)length); 3370ea10b9fSYork Sun src = (void *)data; 3380ea10b9fSYork Sun } 3390ea10b9fSYork Sun 340a515b6d2SJoseph Chen /* Check hashes and signature */ 341d3bfb68bSJoseph Chen if (image_comp != IH_COMP_NONE && image_comp != IH_COMP_ZIMAGE) 342d3bfb68bSJoseph Chen printf("## Checking %s 0x%08lx (%s @0x%08lx) ... ", 343d3bfb68bSJoseph Chen fit_get_name(fit, node, NULL), load_addr, 344d3bfb68bSJoseph Chen (char *)fdt_getprop(fit, node, FIT_COMP_PROP, NULL), 345d3bfb68bSJoseph Chen (long)src); 346d3bfb68bSJoseph Chen else 347d3bfb68bSJoseph Chen printf("## Checking %s 0x%08lx ... ", 348d3bfb68bSJoseph Chen fit_get_name(fit, node, NULL), load_addr); 349d3bfb68bSJoseph Chen 350b92c7cf4SJoseph Chen #ifdef CONFIG_FIT_SPL_PRINT 351b92c7cf4SJoseph Chen printf("\n"); 352b92c7cf4SJoseph Chen fit_image_print(fit, node, ""); 353b92c7cf4SJoseph Chen #endif 354f3219d95SBen Whitten if (!fit_image_verify_with_data(fit, node, 355f3219d95SBen Whitten src, length)) 356f3219d95SBen Whitten return -EPERM; 357f3219d95SBen Whitten 3585dd9177cSXuhui Lin #ifdef CONFIG_SPL_FIT_CIPHER 3595dd9177cSXuhui Lin if (fdt_subnode_offset(fit, node, FIT_CIPHER_NODENAME) > 0) { 3605dd9177cSXuhui Lin printf(" Decrypting Data ..."); 3615dd9177cSXuhui Lin memcpy((void *)cipher_addr, src, length); 3625dd9177cSXuhui Lin if (spl_fit_image_uncipher(fit, node, cipher_addr, length, (ulong)src)) 3635dd9177cSXuhui Lin return -EACCES; 3645dd9177cSXuhui Lin printf(" OK "); 3655dd9177cSXuhui Lin } 3665dd9177cSXuhui Lin #endif 3675dd9177cSXuhui Lin 3688baa3818SAndre Przywara #ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS 3696da15b9fSXuhui Lin if (board_fit_image_post_process(fit, node, (ulong *)&load_addr, 3706da15b9fSXuhui Lin (ulong **)&src, &length, info)) 3716da15b9fSXuhui Lin return -EINVAL; 3728baa3818SAndre Przywara #endif 37350466f58SJoseph Chen puts("OK\n"); 3748baa3818SAndre Przywara 375b81c4739SYork Sun if (IS_ENABLED(CONFIG_SPL_OS_BOOT) && 376b81c4739SYork Sun IS_ENABLED(CONFIG_SPL_GZIP) && 377b81c4739SYork Sun image_comp == IH_COMP_GZIP && 378b81c4739SYork Sun type == IH_TYPE_KERNEL) { 379d18ad2e6SYork Sun size = length; 380b81c4739SYork Sun if (gunzip((void *)load_addr, CONFIG_SYS_BOOTM_LEN, 381d18ad2e6SYork Sun src, &size)) { 382b81c4739SYork Sun puts("Uncompressing error\n"); 383b81c4739SYork Sun return -EIO; 384b81c4739SYork Sun } 385d18ad2e6SYork Sun length = size; 386b81c4739SYork Sun } else { 3878baa3818SAndre Przywara memcpy((void *)load_addr, src, length); 388b81c4739SYork Sun } 3898baa3818SAndre Przywara 3908baa3818SAndre Przywara if (image_info) { 3918baa3818SAndre Przywara image_info->load_addr = load_addr; 3928baa3818SAndre Przywara image_info->size = length; 3938baa3818SAndre Przywara image_info->entry_point = fdt_getprop_u32(fit, node, "entry"); 3948baa3818SAndre Przywara } 3958baa3818SAndre Przywara 3968baa3818SAndre Przywara return 0; 3978baa3818SAndre Przywara } 3988baa3818SAndre Przywara 3999719e14fSPhilipp Tomsich static int spl_fit_append_fdt(struct spl_image_info *spl_image, 4009719e14fSPhilipp Tomsich struct spl_load_info *info, ulong sector, 4019719e14fSPhilipp Tomsich void *fit, int images, ulong base_offset) 4029719e14fSPhilipp Tomsich { 4039719e14fSPhilipp Tomsich struct spl_image_info image_info; 4049719e14fSPhilipp Tomsich int node, ret; 4059719e14fSPhilipp Tomsich 4069719e14fSPhilipp Tomsich /* Figure out which device tree the board wants to use */ 4079719e14fSPhilipp Tomsich node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, 0); 4089719e14fSPhilipp Tomsich if (node < 0) { 4099719e14fSPhilipp Tomsich debug("%s: cannot find FDT node\n", __func__); 4109719e14fSPhilipp Tomsich return node; 4119719e14fSPhilipp Tomsich } 4129719e14fSPhilipp Tomsich 4139719e14fSPhilipp Tomsich /* 4149719e14fSPhilipp Tomsich * Read the device tree and place it after the image. 4159719e14fSPhilipp Tomsich * Align the destination address to ARCH_DMA_MINALIGN. 4169719e14fSPhilipp Tomsich */ 4179719e14fSPhilipp Tomsich image_info.load_addr = spl_image->load_addr + spl_image->size; 4189719e14fSPhilipp Tomsich ret = spl_load_fit_image(info, sector, fit, base_offset, node, 4199719e14fSPhilipp Tomsich &image_info); 4201f1cf67bSPhilipp Tomsich 4211f1cf67bSPhilipp Tomsich if (ret < 0) 4221f1cf67bSPhilipp Tomsich return ret; 4231f1cf67bSPhilipp Tomsich 4241f1cf67bSPhilipp Tomsich /* Make the load-address of the FDT available for the SPL framework */ 4251f1cf67bSPhilipp Tomsich spl_image->fdt_addr = (void *)image_info.load_addr; 4268118cce3SPhilipp Tomsich #if !CONFIG_IS_ENABLED(FIT_IMAGE_TINY) 4271f1cf67bSPhilipp Tomsich /* Try to make space, so we can inject details on the loadables */ 4284024d9e5SJoseph Chen fdt_shrink_to_minimum(spl_image->fdt_addr, 8192); 4298118cce3SPhilipp Tomsich #endif 4301f1cf67bSPhilipp Tomsich 4319d23fbe3SJoseph Chen /* 4329d23fbe3SJoseph Chen * If need, load kernel FDT right after U-Boot FDT. 4339d23fbe3SJoseph Chen * 4349d23fbe3SJoseph Chen * kernel FDT is for U-Boot if there is not valid one 4359d23fbe3SJoseph Chen * from images, ie: resource.img, boot.img or recovery.img. 4369d23fbe3SJoseph Chen */ 4370f74a651SJoseph Chen node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, 1); 4380f74a651SJoseph Chen if (node < 0) { 4394024d9e5SJoseph Chen debug("%s: cannot find kernel FDT node\n", __func__); 4404024d9e5SJoseph Chen /* attention: here return ret but not node */ 4419d23fbe3SJoseph Chen return ret; 4420f74a651SJoseph Chen } 4439d23fbe3SJoseph Chen 4449d23fbe3SJoseph Chen image_info.load_addr = 4459d23fbe3SJoseph Chen (ulong)spl_image->fdt_addr + fdt_totalsize(spl_image->fdt_addr); 4469d23fbe3SJoseph Chen ret = spl_load_fit_image(info, sector, fit, base_offset, node, 4479d23fbe3SJoseph Chen &image_info); 4489d23fbe3SJoseph Chen 4491f1cf67bSPhilipp Tomsich return ret; 4501f1cf67bSPhilipp Tomsich } 4511f1cf67bSPhilipp Tomsich 4521f1cf67bSPhilipp Tomsich static int spl_fit_record_loadable(const void *fit, int images, int index, 4531f1cf67bSPhilipp Tomsich void *blob, struct spl_image_info *image) 4541f1cf67bSPhilipp Tomsich { 4558118cce3SPhilipp Tomsich int ret = 0; 4568118cce3SPhilipp Tomsich #if !CONFIG_IS_ENABLED(FIT_IMAGE_TINY) 4571f1cf67bSPhilipp Tomsich char *name; 4588118cce3SPhilipp Tomsich int node; 4591f1cf67bSPhilipp Tomsich 4601f1cf67bSPhilipp Tomsich ret = spl_fit_get_image_name(fit, images, "loadables", 4611f1cf67bSPhilipp Tomsich index, &name); 4621f1cf67bSPhilipp Tomsich if (ret < 0) 4631f1cf67bSPhilipp Tomsich return ret; 4641f1cf67bSPhilipp Tomsich 4651f1cf67bSPhilipp Tomsich node = spl_fit_get_image_node(fit, images, "loadables", index); 4661f1cf67bSPhilipp Tomsich 4671f1cf67bSPhilipp Tomsich ret = fdt_record_loadable(blob, index, name, image->load_addr, 4681f1cf67bSPhilipp Tomsich image->size, image->entry_point, 4691f1cf67bSPhilipp Tomsich fdt_getprop(fit, node, "type", NULL), 4701f1cf67bSPhilipp Tomsich fdt_getprop(fit, node, "os", NULL)); 4718118cce3SPhilipp Tomsich #endif 4729719e14fSPhilipp Tomsich return ret; 4739719e14fSPhilipp Tomsich } 4749719e14fSPhilipp Tomsich 4758118cce3SPhilipp Tomsich static int spl_fit_image_get_os(const void *fit, int noffset, uint8_t *os) 4768118cce3SPhilipp Tomsich { 4778118cce3SPhilipp Tomsich #if CONFIG_IS_ENABLED(FIT_IMAGE_TINY) 4788118cce3SPhilipp Tomsich return -ENOTSUPP; 4798118cce3SPhilipp Tomsich #else 4808118cce3SPhilipp Tomsich return fit_image_get_os(fit, noffset, os); 4818118cce3SPhilipp Tomsich #endif 4828118cce3SPhilipp Tomsich } 4838118cce3SPhilipp Tomsich 484c1006ae0SJoseph Chen __weak int spl_fit_standalone_release(char *id, uintptr_t entry_point) 485342d050eSJason Zhu { 486342d050eSJason Zhu return 0; 487342d050eSJason Zhu } 488342d050eSJason Zhu 489569a1737SJoseph Chen static void *spl_fit_load_blob(struct spl_load_info *info, 490569a1737SJoseph Chen ulong sector, void *fit_header, 491569a1737SJoseph Chen int *base_offset) 492f1dcee59SSimon Glass { 493569a1737SJoseph Chen int align_len = ARCH_DMA_MINALIGN - 1; 494569a1737SJoseph Chen ulong count; 4958baa3818SAndre Przywara ulong size; 496569a1737SJoseph Chen int sectors; 497569a1737SJoseph Chen void *fit; 498f1dcee59SSimon Glass 499f1dcee59SSimon Glass /* 500ebec805aSYork Sun * For FIT with external data, figure out where the external images 501ebec805aSYork Sun * start. This is the base for the data-offset properties in each 502ebec805aSYork Sun * image. 503f1dcee59SSimon Glass */ 504569a1737SJoseph Chen size = fdt_totalsize(fit_header); 505acd43290SJoseph Chen size = FIT_ALIGN(size); 506569a1737SJoseph Chen *base_offset = FIT_ALIGN(size); 507f1dcee59SSimon Glass 508f1dcee59SSimon Glass /* 509f1dcee59SSimon Glass * So far we only have one block of data from the FIT. Read the entire 510f1dcee59SSimon Glass * thing, including that first block, placing it so it finishes before 511f1dcee59SSimon Glass * where we will load the image. 512f1dcee59SSimon Glass * 513f1dcee59SSimon Glass * Note that we will load the image such that its first byte will be 514f1dcee59SSimon Glass * at the load address. Since that byte may be part-way through a 515f1dcee59SSimon Glass * block, we may load the image up to one block before the load 516f1dcee59SSimon Glass * address. So take account of that here by subtracting an addition 517f1dcee59SSimon Glass * block length from the FIT start position. 518f1dcee59SSimon Glass * 519f1dcee59SSimon Glass * In fact the FIT has its own load address, but we assume it cannot 520f1dcee59SSimon Glass * be before CONFIG_SYS_TEXT_BASE. 521ebec805aSYork Sun * 522ebec805aSYork Sun * For FIT with data embedded, data is loaded as part of FIT image. 523ebec805aSYork Sun * For FIT with external data, data is not loaded in this step. 524f1dcee59SSimon Glass */ 5258b528709SLokesh Vutla fit = (void *)((CONFIG_SYS_TEXT_BASE - size - info->bl_len - 5268b528709SLokesh Vutla align_len) & ~align_len); 527eafd5410SLokesh Vutla sectors = get_aligned_image_size(info, size, 0); 528f1dcee59SSimon Glass count = info->read(info, sector, sectors, fit); 52999011ac4SXuhui Lin #if defined(CONFIG_SPL_MTD_SUPPORT) && !defined(CONFIG_FPGA_RAM) 530a741b19cSJason Zhu mtd_blk_map_fit(info->dev, sector, fit); 531a741b19cSJason Zhu #endif 532f1dcee59SSimon Glass debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu\n", 533f1dcee59SSimon Glass sector, sectors, fit, count); 534f1dcee59SSimon Glass if (count == 0) 535569a1737SJoseph Chen return NULL; 536569a1737SJoseph Chen 537569a1737SJoseph Chen return fit; 538569a1737SJoseph Chen } 539569a1737SJoseph Chen 540a00b516fSJoseph Chen #ifdef CONFIG_SPL_KERNEL_BOOT 541e12dde2dSJoseph Chen #ifdef CONFIG_SPL_LIBDISK_SUPPORT 542e12dde2dSJoseph Chen __weak const char *spl_kernel_partition(struct spl_image_info *spl, 543e12dde2dSJoseph Chen struct spl_load_info *info) 544e12dde2dSJoseph Chen { 545e12dde2dSJoseph Chen return PART_BOOT; 546e12dde2dSJoseph Chen } 547e12dde2dSJoseph Chen #endif 548e12dde2dSJoseph Chen 54944f37eaaSXuhui Lin static int spl_fit_get_kernel_dtb(const void *fit, int images_noffset) 55044f37eaaSXuhui Lin { 55144f37eaaSXuhui Lin const char *name = NULL; 55244f37eaaSXuhui Lin int node, index = 0; 55344f37eaaSXuhui Lin 55444f37eaaSXuhui Lin for (; ; index++) { 55544f37eaaSXuhui Lin node = spl_fit_get_image_node(fit, images_noffset, 55644f37eaaSXuhui Lin FIT_FDT_PROP, index); 55744f37eaaSXuhui Lin if (node < 0) 55844f37eaaSXuhui Lin break; 55944f37eaaSXuhui Lin name = fdt_get_name(fit, node, NULL); 56044f37eaaSXuhui Lin if(!strcmp(name, "fdt")) 56144f37eaaSXuhui Lin return node; 56244f37eaaSXuhui Lin #if defined(CONFIG_SPL_ROCKCHIP_HWID_DTB) 56344f37eaaSXuhui Lin if (spl_find_hwid_dtb(name)) { 56444f37eaaSXuhui Lin printf("HWID DTB: %s\n", name); 56544f37eaaSXuhui Lin break; 56644f37eaaSXuhui Lin } 56744f37eaaSXuhui Lin #endif 56844f37eaaSXuhui Lin } 56944f37eaaSXuhui Lin 57044f37eaaSXuhui Lin return node; 57144f37eaaSXuhui Lin } 57244f37eaaSXuhui Lin 573e12dde2dSJoseph Chen static int spl_load_kernel_fit(struct spl_image_info *spl_image, 574e12dde2dSJoseph Chen struct spl_load_info *info) 575e12dde2dSJoseph Chen { 576e12dde2dSJoseph Chen /* 577e12dde2dSJoseph Chen * Never change the image order. 578e12dde2dSJoseph Chen * 579e12dde2dSJoseph Chen * Considering thunder-boot feature, there maybe asynchronous 580e12dde2dSJoseph Chen * loading operation of these images and ramdisk is usually to 581e12dde2dSJoseph Chen * be the last one. 582e12dde2dSJoseph Chen * 583e12dde2dSJoseph Chen * The .its content rule of kernel fit image follows U-Boot proper. 584e12dde2dSJoseph Chen */ 585e12dde2dSJoseph Chen const char *images[] = { FIT_FDT_PROP, FIT_KERNEL_PROP, FIT_RAMDISK_PROP, }; 586e12dde2dSJoseph Chen struct spl_image_info image_info; 587e12dde2dSJoseph Chen char fit_header[info->bl_len]; 588e12dde2dSJoseph Chen int images_noffset; 589e12dde2dSJoseph Chen int base_offset; 590e12dde2dSJoseph Chen int sector; 591e12dde2dSJoseph Chen int node, ret, i; 592e12dde2dSJoseph Chen void *fit; 593e12dde2dSJoseph Chen 594e12dde2dSJoseph Chen if (spl_image->next_stage != SPL_NEXT_STAGE_KERNEL) 595e12dde2dSJoseph Chen return 0; 596e12dde2dSJoseph Chen 597e12dde2dSJoseph Chen #ifdef CONFIG_SPL_LIBDISK_SUPPORT 598e12dde2dSJoseph Chen const char *part_name = PART_BOOT; 599e12dde2dSJoseph Chen disk_partition_t part_info; 600e12dde2dSJoseph Chen 601e12dde2dSJoseph Chen part_name = spl_kernel_partition(spl_image, info); 602e12dde2dSJoseph Chen if (part_get_info_by_name(info->dev, part_name, &part_info) <= 0) { 603e12dde2dSJoseph Chen printf("%s: no partition\n", __func__); 604e12dde2dSJoseph Chen return -EINVAL; 605e12dde2dSJoseph Chen } 606e12dde2dSJoseph Chen sector = part_info.start; 607e12dde2dSJoseph Chen #else 608a00b516fSJoseph Chen sector = CONFIG_SPL_KERNEL_BOOT_SECTOR; 609e12dde2dSJoseph Chen #endif 6109d3df7afSJoseph Chen printf("Trying kernel at 0x%x sector from '%s' part\n", sector, part_name); 6119d3df7afSJoseph Chen 612e12dde2dSJoseph Chen if (info->read(info, sector, 1, &fit_header) != 1) { 61329725e85SJoseph Chen debug("%s: Failed to read header\n", __func__); 614e12dde2dSJoseph Chen return -EIO; 615e12dde2dSJoseph Chen } 616e12dde2dSJoseph Chen 617e12dde2dSJoseph Chen if (image_get_magic((void *)&fit_header) != FDT_MAGIC) { 61829725e85SJoseph Chen printf("%s: Not fit magic\n", __func__); 619e12dde2dSJoseph Chen return -EINVAL; 620e12dde2dSJoseph Chen } 621e12dde2dSJoseph Chen 622e12dde2dSJoseph Chen fit = spl_fit_load_blob(info, sector, fit_header, &base_offset); 623e12dde2dSJoseph Chen if (!fit) { 624e12dde2dSJoseph Chen debug("%s: Cannot load blob\n", __func__); 625e12dde2dSJoseph Chen return -ENODEV; 626e12dde2dSJoseph Chen } 627e12dde2dSJoseph Chen 628e12dde2dSJoseph Chen /* verify the configure node by keys, if required */ 629e12dde2dSJoseph Chen #ifdef CONFIG_SPL_FIT_SIGNATURE 630e12dde2dSJoseph Chen int conf_noffset; 631e12dde2dSJoseph Chen 632e12dde2dSJoseph Chen conf_noffset = fit_conf_get_node(fit, NULL); 633e12dde2dSJoseph Chen if (conf_noffset <= 0) { 634e12dde2dSJoseph Chen printf("No default config node\n"); 635e12dde2dSJoseph Chen return -EINVAL; 636e12dde2dSJoseph Chen } 637e12dde2dSJoseph Chen 638e12dde2dSJoseph Chen ret = fit_config_verify(fit, conf_noffset); 639e12dde2dSJoseph Chen if (ret) { 640e12dde2dSJoseph Chen printf("fit verify configure failed, ret=%d\n", ret); 641e12dde2dSJoseph Chen return ret; 642e12dde2dSJoseph Chen } 643e12dde2dSJoseph Chen printf("\n"); 644e12dde2dSJoseph Chen #endif 645e12dde2dSJoseph Chen images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); 646e12dde2dSJoseph Chen if (images_noffset < 0) { 647e12dde2dSJoseph Chen debug("%s: Cannot find /images node: %d\n", 648e12dde2dSJoseph Chen __func__, images_noffset); 649e12dde2dSJoseph Chen return images_noffset; 650e12dde2dSJoseph Chen } 651e12dde2dSJoseph Chen 652e12dde2dSJoseph Chen for (i = 0; i < ARRAY_SIZE(images); i++) { 65344f37eaaSXuhui Lin if (!strcmp(images[i], FIT_FDT_PROP)) 65444f37eaaSXuhui Lin node = spl_fit_get_kernel_dtb(fit, images_noffset); 65544f37eaaSXuhui Lin else 656e12dde2dSJoseph Chen node = spl_fit_get_image_node(fit, images_noffset, 657e12dde2dSJoseph Chen images[i], 0); 658e12dde2dSJoseph Chen if (node < 0) { 659e12dde2dSJoseph Chen debug("No image: %s\n", images[i]); 660e12dde2dSJoseph Chen continue; 661e12dde2dSJoseph Chen } 662e12dde2dSJoseph Chen 663e12dde2dSJoseph Chen ret = spl_load_fit_image(info, sector, fit, base_offset, 664e12dde2dSJoseph Chen node, &image_info); 665e12dde2dSJoseph Chen if (ret) 666e12dde2dSJoseph Chen return ret; 667e12dde2dSJoseph Chen 668e12dde2dSJoseph Chen /* initial addr or entry point */ 669a712f631SJason Zhu if (!strcmp(images[i], FIT_FDT_PROP)) { 670*b6bda7d5SXuhui Lin if (spl_fdt_chosen_bootargs(info, (void *)image_info.load_addr)) { 671*b6bda7d5SXuhui Lin printf("ERROR: Append bootargs failed\n"); 672*b6bda7d5SXuhui Lin return -EINVAL; 673*b6bda7d5SXuhui Lin } 674a712f631SJason Zhu } else if (!strcmp(images[i], FIT_KERNEL_PROP)) { 675a00b516fSJoseph Chen #if CONFIG_IS_ENABLED(OPTEE) 676e12dde2dSJoseph Chen spl_image->entry_point_os = image_info.load_addr; 677a00b516fSJoseph Chen #endif 678a00b516fSJoseph Chen #if CONFIG_IS_ENABLED(ATF) 679a00b516fSJoseph Chen spl_image->entry_point_bl33 = image_info.load_addr; 680a00b516fSJoseph Chen #endif 68122ad705aSZain Wang } else if (!strcmp(images[i], FIT_RAMDISK_PROP)) { 68222ad705aSZain Wang fdt_initrd(spl_image->fdt_addr, image_info.load_addr, 68322ad705aSZain Wang image_info.load_addr + image_info.size); 684e12dde2dSJoseph Chen } 685a712f631SJason Zhu } 686e12dde2dSJoseph Chen 687a00b516fSJoseph Chen debug("fdt_addr=0x%08lx, entry_point=0x%08lx, entry_point_os=0x%08lx\n", 688a00b516fSJoseph Chen (ulong)spl_image->fdt_addr, 689a00b516fSJoseph Chen spl_image->entry_point, 690a00b516fSJoseph Chen #if CONFIG_IS_ENABLED(OPTEE) 691a00b516fSJoseph Chen spl_image->entry_point_os); 692a00b516fSJoseph Chen #endif 693a00b516fSJoseph Chen #if CONFIG_IS_ENABLED(ATF) 694a00b516fSJoseph Chen spl_image->entry_point_bl33); 695a00b516fSJoseph Chen #endif 696e12dde2dSJoseph Chen 697e12dde2dSJoseph Chen return 0; 698e12dde2dSJoseph Chen } 699e12dde2dSJoseph Chen #endif 700e12dde2dSJoseph Chen 701569a1737SJoseph Chen static int spl_internal_load_simple_fit(struct spl_image_info *spl_image, 702569a1737SJoseph Chen struct spl_load_info *info, 703569a1737SJoseph Chen ulong sector, void *fit_header) 704569a1737SJoseph Chen { 705569a1737SJoseph Chen struct spl_image_info image_info; 706c1006ae0SJoseph Chen char *desc; 7072e71311cSXuhui Lin #if CONFIG_IS_ENABLED(ATF) 7082e71311cSXuhui Lin uint8_t ih_arch; 7092e71311cSXuhui Lin #endif 710569a1737SJoseph Chen int base_offset; 711569a1737SJoseph Chen int images, ret; 712569a1737SJoseph Chen int index = 0; 713569a1737SJoseph Chen int node = -1; 714569a1737SJoseph Chen void *fit; 715569a1737SJoseph Chen 716569a1737SJoseph Chen fit = spl_fit_load_blob(info, sector, fit_header, &base_offset); 717569a1737SJoseph Chen if (!fit) { 718569a1737SJoseph Chen debug("%s: Cannot load blob\n", __func__); 719569a1737SJoseph Chen return -1; 720569a1737SJoseph Chen } 721f1dcee59SSimon Glass 722736806fbSAndre Przywara /* find the node holding the images information */ 723f1dcee59SSimon Glass images = fdt_path_offset(fit, FIT_IMAGES_PATH); 724f1dcee59SSimon Glass if (images < 0) { 725f1dcee59SSimon Glass debug("%s: Cannot find /images node: %d\n", __func__, images); 726f1dcee59SSimon Glass return -1; 727f1dcee59SSimon Glass } 728736806fbSAndre Przywara 7291f452cbfSJoseph Chen /* if board sigs verify required, check self */ 7301f452cbfSJoseph Chen if (fit_board_verify_required_sigs() && 7311f452cbfSJoseph Chen !IS_ENABLED(CONFIG_SPL_FIT_SIGNATURE)) { 7321f452cbfSJoseph Chen printf("Verified-boot requires CONFIG_SPL_FIT_SIGNATURE enabled\n"); 7331f452cbfSJoseph Chen hang(); 7341f452cbfSJoseph Chen } 7351f452cbfSJoseph Chen 736583377c4SJoseph Chen /* verify the configure node by keys, if required */ 737583377c4SJoseph Chen #ifdef CONFIG_SPL_FIT_SIGNATURE 738583377c4SJoseph Chen int conf_noffset; 739583377c4SJoseph Chen 740583377c4SJoseph Chen conf_noffset = fit_conf_get_node(fit, NULL); 741a7560f55SJoseph Chen if (conf_noffset <= 0) { 742a7560f55SJoseph Chen printf("No default config node\n"); 743a7560f55SJoseph Chen return -EINVAL; 744a7560f55SJoseph Chen } 745a7560f55SJoseph Chen 746583377c4SJoseph Chen ret = fit_config_verify(fit, conf_noffset); 747583377c4SJoseph Chen if (ret) { 748583377c4SJoseph Chen printf("fit verify configure failed, ret=%d\n", ret); 749583377c4SJoseph Chen return ret; 750583377c4SJoseph Chen } 751583377c4SJoseph Chen printf("\n"); 752583377c4SJoseph Chen 7537a137075SJoseph Chen #ifdef CONFIG_SPL_FIT_ROLLBACK_PROTECT 7547a137075SJoseph Chen uint32_t this_index, min_index; 7557a137075SJoseph Chen 7567a137075SJoseph Chen ret = fit_rollback_index_verify(fit, FIT_ROLLBACK_INDEX_SPL, 7577a137075SJoseph Chen &this_index, &min_index); 7587a137075SJoseph Chen if (ret) { 7597a137075SJoseph Chen printf("fit failed to get rollback index, ret=%d\n", ret); 7607a137075SJoseph Chen return ret; 7617a137075SJoseph Chen } else if (this_index < min_index) { 7627a137075SJoseph Chen printf("fit reject rollback: %d < %d(min)\n", 7637a137075SJoseph Chen this_index, min_index); 7647a137075SJoseph Chen return -EINVAL; 7657a137075SJoseph Chen } 7667a137075SJoseph Chen 767e5ca21e8SJoseph Chen printf("rollback index: %d >= %d(min), OK\n", this_index, min_index); 7687a137075SJoseph Chen #endif 7697a137075SJoseph Chen #endif 770342d050eSJason Zhu 771342d050eSJason Zhu /* 772342d050eSJason Zhu * If required to start the other core before load "loadables" 773342d050eSJason Zhu * firmwares, use the config "standalone" to load the other core's 774342d050eSJason Zhu * firmware, then start it. 775342d050eSJason Zhu * Normally, different cores' firmware is attach to the config 776342d050eSJason Zhu * "loadables" and load them together. 777342d050eSJason Zhu */ 778c1006ae0SJoseph Chen for (; ; index++) { 779c1006ae0SJoseph Chen node = spl_fit_get_image_node(fit, images, 780c1006ae0SJoseph Chen FIT_STANDALONE_PROP, index); 781342d050eSJason Zhu if (node < 0) 782c1006ae0SJoseph Chen break; 783c1006ae0SJoseph Chen 784c1006ae0SJoseph Chen ret = spl_load_fit_image(info, sector, fit, base_offset, 785c1006ae0SJoseph Chen node, &image_info); 786c1006ae0SJoseph Chen if (ret) 787c1006ae0SJoseph Chen return ret; 788c1006ae0SJoseph Chen 789c1006ae0SJoseph Chen ret = fit_get_desc(fit, node, &desc); 790ecfe22e6SJoseph Chen if (ret) 791ecfe22e6SJoseph Chen return ret; 792ecfe22e6SJoseph Chen 7939a65720bSJason Zhu if (image_info.entry_point == FDT_ERROR) 7949a65720bSJason Zhu image_info.entry_point = image_info.load_addr; 7959a65720bSJason Zhu 7967db562c3SJason Zhu flush_dcache_range(image_info.load_addr, 7977db562c3SJason Zhu image_info.load_addr + image_info.size); 798c1006ae0SJoseph Chen ret = spl_fit_standalone_release(desc, image_info.entry_point); 799342d050eSJason Zhu if (ret) 800c1006ae0SJoseph Chen printf("%s: start standalone fail, ret=%d\n", desc, ret); 801c1006ae0SJoseph Chen } 802342d050eSJason Zhu 803e12dde2dSJoseph Chen /* standalone is special one, continue to find others */ 804342d050eSJason Zhu node = -1; 805c1006ae0SJoseph Chen index = 0; 806342d050eSJason Zhu 8079719e14fSPhilipp Tomsich /* 8089719e14fSPhilipp Tomsich * Find the U-Boot image using the following search order: 8099719e14fSPhilipp Tomsich * - start at 'firmware' (e.g. an ARM Trusted Firmware) 8109719e14fSPhilipp Tomsich * - fall back 'kernel' (e.g. a Falcon-mode OS boot 8119719e14fSPhilipp Tomsich * - fall back to using the first 'loadables' entry 8129719e14fSPhilipp Tomsich */ 813ebec805aSYork Sun if (node < 0) 814c04fe8bfSMichal Simek node = spl_fit_get_image_node(fit, images, FIT_FIRMWARE_PROP, 815c04fe8bfSMichal Simek 0); 8169719e14fSPhilipp Tomsich #ifdef CONFIG_SPL_OS_BOOT 8179719e14fSPhilipp Tomsich if (node < 0) 8189719e14fSPhilipp Tomsich node = spl_fit_get_image_node(fit, images, FIT_KERNEL_PROP, 0); 8199719e14fSPhilipp Tomsich #endif 820f1dcee59SSimon Glass if (node < 0) { 821736806fbSAndre Przywara debug("could not find firmware image, trying loadables...\n"); 822736806fbSAndre Przywara node = spl_fit_get_image_node(fit, images, "loadables", 0); 823411cf32dSAndre Przywara /* 824411cf32dSAndre Przywara * If we pick the U-Boot image from "loadables", start at 825411cf32dSAndre Przywara * the second image when later loading additional images. 826411cf32dSAndre Przywara */ 827411cf32dSAndre Przywara index = 1; 828736806fbSAndre Przywara } 829736806fbSAndre Przywara if (node < 0) { 830736806fbSAndre Przywara debug("%s: Cannot find u-boot image node: %d\n", 831736806fbSAndre Przywara __func__, node); 832f1dcee59SSimon Glass return -1; 833f1dcee59SSimon Glass } 834f1dcee59SSimon Glass 8358baa3818SAndre Przywara /* Load the image and set up the spl_image structure */ 8368baa3818SAndre Przywara ret = spl_load_fit_image(info, sector, fit, base_offset, node, 8378baa3818SAndre Przywara spl_image); 8388baa3818SAndre Przywara if (ret) 8398baa3818SAndre Przywara return ret; 8408baa3818SAndre Przywara 8419719e14fSPhilipp Tomsich /* 8429719e14fSPhilipp Tomsich * For backward compatibility, we treat the first node that is 8439719e14fSPhilipp Tomsich * as a U-Boot image, if no OS-type has been declared. 8449719e14fSPhilipp Tomsich */ 8458118cce3SPhilipp Tomsich if (!spl_fit_image_get_os(fit, node, &spl_image->os)) 846ebec805aSYork Sun debug("Image OS is %s\n", genimg_get_os_name(spl_image->os)); 8479719e14fSPhilipp Tomsich #if !defined(CONFIG_SPL_OS_BOOT) 8489719e14fSPhilipp Tomsich else 849f4d7d859SSimon Glass spl_image->os = IH_OS_U_BOOT; 850ebec805aSYork Sun #endif 851f1dcee59SSimon Glass 8524024d9e5SJoseph Chen /* Booting a next-stage U-Boot may require us to append the FDT. */ 8534024d9e5SJoseph Chen if (spl_image->os == IH_OS_U_BOOT) { 8544024d9e5SJoseph Chen ret = spl_fit_append_fdt(spl_image, info, sector, fit, 8559719e14fSPhilipp Tomsich images, base_offset); 8564024d9e5SJoseph Chen if (ret < 0) 8574024d9e5SJoseph Chen return ret; 8584024d9e5SJoseph Chen } 859411cf32dSAndre Przywara 860411cf32dSAndre Przywara /* Now check if there are more images for us to load */ 861411cf32dSAndre Przywara for (; ; index++) { 8629719e14fSPhilipp Tomsich uint8_t os_type = IH_OS_INVALID; 8639719e14fSPhilipp Tomsich 864411cf32dSAndre Przywara node = spl_fit_get_image_node(fit, images, "loadables", index); 865411cf32dSAndre Przywara if (node < 0) 866411cf32dSAndre Przywara break; 867411cf32dSAndre Przywara 868e12dde2dSJoseph Chen if (!spl_fit_image_get_os(fit, node, &os_type)) 869e12dde2dSJoseph Chen debug("Loadable is %s\n", genimg_get_os_name(os_type)); 870e12dde2dSJoseph Chen 871e12dde2dSJoseph Chen /* skip U-Boot ? */ 872e12dde2dSJoseph Chen if (spl_image->next_stage == SPL_NEXT_STAGE_KERNEL && 873e12dde2dSJoseph Chen os_type == IH_OS_U_BOOT) 874e12dde2dSJoseph Chen continue; 875e12dde2dSJoseph Chen 876411cf32dSAndre Przywara ret = spl_load_fit_image(info, sector, fit, base_offset, node, 877411cf32dSAndre Przywara &image_info); 878411cf32dSAndre Przywara if (ret < 0) 879ecfe22e6SJoseph Chen return ret; 880411cf32dSAndre Przywara 8811f1cf67bSPhilipp Tomsich if (os_type == IH_OS_U_BOOT) { 88239b9f515SJoseph Chen #if CONFIG_IS_ENABLED(ATF) 8832e71311cSXuhui Lin fit_image_get_arch(fit, node, &ih_arch); 8842e71311cSXuhui Lin debug("Image ARCH is %s\n", genimg_get_arch_name(ih_arch)); 8852e71311cSXuhui Lin if (ih_arch == IH_ARCH_ARM) 8862e71311cSXuhui Lin spl_image->flags |= SPL_ATF_AARCH32_BL33; 88739b9f515SJoseph Chen spl_image->entry_point_bl33 = image_info.load_addr; 88839b9f515SJoseph Chen #elif CONFIG_IS_ENABLED(OPTEE) 88939b9f515SJoseph Chen spl_image->entry_point_os = image_info.load_addr; 89039b9f515SJoseph Chen #endif 8914024d9e5SJoseph Chen ret = spl_fit_append_fdt(&image_info, info, sector, 8929719e14fSPhilipp Tomsich fit, images, base_offset); 8934024d9e5SJoseph Chen if (ret < 0) 8944024d9e5SJoseph Chen return ret; 8951f1cf67bSPhilipp Tomsich spl_image->fdt_addr = image_info.fdt_addr; 8961f1cf67bSPhilipp Tomsich } 8979719e14fSPhilipp Tomsich 898411cf32dSAndre Przywara /* 899411cf32dSAndre Przywara * If the "firmware" image did not provide an entry point, 900411cf32dSAndre Przywara * use the first valid entry point from the loadables. 901411cf32dSAndre Przywara */ 902411cf32dSAndre Przywara if (spl_image->entry_point == FDT_ERROR && 903411cf32dSAndre Przywara image_info.entry_point != FDT_ERROR) 904411cf32dSAndre Przywara spl_image->entry_point = image_info.entry_point; 9051f1cf67bSPhilipp Tomsich 9061f1cf67bSPhilipp Tomsich /* Record our loadables into the FDT */ 907c8ec6b59SXuhui Lin if (spl_image->fdt_addr && spl_image->next_stage == SPL_NEXT_STAGE_UBOOT) 9081f1cf67bSPhilipp Tomsich spl_fit_record_loadable(fit, images, index, 9091f1cf67bSPhilipp Tomsich spl_image->fdt_addr, 9101f1cf67bSPhilipp Tomsich &image_info); 911c8ec6b59SXuhui Lin #if CONFIG_IS_ENABLED(ATF) 912c8ec6b59SXuhui Lin else if (os_type == IH_OS_OP_TEE) 913c8ec6b59SXuhui Lin spl_image->entry_point_bl32 = image_info.load_addr; 914c8ec6b59SXuhui Lin #endif 915411cf32dSAndre Przywara } 916411cf32dSAndre Przywara 917411cf32dSAndre Przywara /* 918411cf32dSAndre Przywara * If a platform does not provide CONFIG_SYS_UBOOT_START, U-Boot's 919411cf32dSAndre Przywara * Makefile will set it to 0 and it will end up as the entry point 920411cf32dSAndre Przywara * here. What it actually means is: use the load address. 921411cf32dSAndre Przywara */ 922411cf32dSAndre Przywara if (spl_image->entry_point == FDT_ERROR || spl_image->entry_point == 0) 923411cf32dSAndre Przywara spl_image->entry_point = spl_image->load_addr; 924411cf32dSAndre Przywara 925411cf32dSAndre Przywara return 0; 926f1dcee59SSimon Glass } 92722c7c1a8SJoseph Chen 92822c7c1a8SJoseph Chen int spl_load_simple_fit(struct spl_image_info *spl_image, 92922c7c1a8SJoseph Chen struct spl_load_info *info, ulong sector, void *fit) 93022c7c1a8SJoseph Chen { 93122c7c1a8SJoseph Chen ulong sector_offs = sector; 932e12dde2dSJoseph Chen int ret = -EINVAL; 93322c7c1a8SJoseph Chen int i; 93422c7c1a8SJoseph Chen 93536c449feSJoseph Chen #ifdef CONFIG_MP_BOOT 93636c449feSJoseph Chen mpb_init_1(*info); 93736c449feSJoseph Chen #endif 93836c449feSJoseph Chen 9397e6f3a66SJoseph Chen printf("Trying fit image at 0x%lx sector\n", sector_offs); 94022c7c1a8SJoseph Chen for (i = 0; i < CONFIG_SPL_FIT_IMAGE_MULTIPLE; i++) { 94122c7c1a8SJoseph Chen if (i > 0) { 94222c7c1a8SJoseph Chen sector_offs += 94322c7c1a8SJoseph Chen i * ((CONFIG_SPL_FIT_IMAGE_KB << 10) / info->bl_len); 94422c7c1a8SJoseph Chen printf("Trying fit image at 0x%lx sector\n", sector_offs); 94522c7c1a8SJoseph Chen if (info->read(info, sector_offs, 1, fit) != 1) { 94622c7c1a8SJoseph Chen printf("IO error\n"); 94722c7c1a8SJoseph Chen continue; 94822c7c1a8SJoseph Chen } 94922c7c1a8SJoseph Chen } 95022c7c1a8SJoseph Chen 95122c7c1a8SJoseph Chen if (image_get_magic(fit) != FDT_MAGIC) { 952e12dde2dSJoseph Chen printf("Not fit magic\n"); 95322c7c1a8SJoseph Chen continue; 95422c7c1a8SJoseph Chen } 95522c7c1a8SJoseph Chen 956e12dde2dSJoseph Chen ret = spl_internal_load_simple_fit(spl_image, info, 957e12dde2dSJoseph Chen sector_offs, fit); 958e12dde2dSJoseph Chen if (!ret) { 959a00b516fSJoseph Chen #ifdef CONFIG_SPL_KERNEL_BOOT 960e12dde2dSJoseph Chen ret = spl_load_kernel_fit(spl_image, info); 961e12dde2dSJoseph Chen #endif 9621f5c7b64SJason Zhu break; 963e12dde2dSJoseph Chen } 96422c7c1a8SJoseph Chen } 9651f5c7b64SJason Zhu #ifdef CONFIG_SPL_AB 966f34b44cfSXuhui Lin /* If boot fail in spl, spl must decrease 1 and do_reset. */ 967f34b44cfSXuhui Lin if (ret) 968f34b44cfSXuhui Lin return spl_ab_decrease_reset(info->dev); 9691f5c7b64SJason Zhu /* 970f34b44cfSXuhui Lin * If boot successfully, it is no need to do decrease 971f34b44cfSXuhui Lin * and U-boot will always decrease 1. 972f34b44cfSXuhui Lin * If in thunderboot process, always need to decrease 1. 9731f5c7b64SJason Zhu */ 974f34b44cfSXuhui Lin if (spl_image->next_stage == SPL_NEXT_STAGE_KERNEL) 9751f5c7b64SJason Zhu spl_ab_decrease_tries(info->dev); 9761f5c7b64SJason Zhu #endif 977f34b44cfSXuhui Lin 978e12dde2dSJoseph Chen return ret; 97922c7c1a8SJoseph Chen } 98022c7c1a8SJoseph Chen 981