Merge tag 'u-boot-rockchip-20200501' of https://gitlab.denx.de/u-boot/custodians...
[oweals/u-boot.git] / common / image.c
index 1493c3a874e1f0f0ebbc63570cd77a4d8bbb459d..d8d14e871c6473b68c11938c5357ab7edfefe157 100644 (file)
@@ -8,6 +8,10 @@
 
 #ifndef USE_HOSTCC
 #include <common.h>
+#include <cpu_func.h>
+#include <env.h>
+#include <malloc.h>
+#include <u-boot/crc.h>
 #include <watchdog.h>
 
 #ifdef CONFIG_SHOW_BOOT_PROGRESS
@@ -16,8 +20,9 @@
 
 #include <rtc.h>
 
-#include <environment.h>
+#include <gzip.h>
 #include <image.h>
+#include <lz4.h>
 #include <mapmem.h>
 
 #if IMAGE_ENABLE_FIT || IMAGE_ENABLE_OF_LIBFDT
 #include <linux/errno.h>
 #include <asm/io.h>
 
+#include <bzlib.h>
+#include <linux/lzo.h>
+#include <lzma/LzmaTypes.h>
+#include <lzma/LzmaDec.h>
+#include <lzma/LzmaTools.h>
+
 #ifdef CONFIG_CMD_BDI
 extern int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 #endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
 static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
                                                int verify);
 #endif
@@ -54,6 +65,7 @@ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
 #endif /* !USE_HOSTCC*/
 
 #include <u-boot/crc.h>
+#include <imximage.h>
 
 #ifndef CONFIG_SYS_BARGSIZE
 #define CONFIG_SYS_BARGSIZE 512
@@ -125,6 +137,8 @@ static const table_entry_t uimage_os[] = {
 #if defined(CONFIG_BOOTM_OPENRTOS) || defined(USE_HOSTCC)
        {       IH_OS_OPENRTOS, "openrtos",     "OpenRTOS",             },
 #endif
+       {       IH_OS_OPENSBI,  "opensbi",      "RISC-V OpenSBI",       },
+       {       IH_OS_EFI,      "efi",          "EFI Firmware" },
 
        {       -1,             "",             "",                     },
 };
@@ -139,6 +153,8 @@ static const table_entry_t uimage_type[] = {
        {       IH_TYPE_KERNEL_NOLOAD, "kernel_noload",  "Kernel Image (no loading done)", },
        {       IH_TYPE_KWBIMAGE,   "kwbimage",   "Kirkwood Boot Image",},
        {       IH_TYPE_IMXIMAGE,   "imximage",   "Freescale i.MX Boot Image",},
+       {       IH_TYPE_IMX8IMAGE,  "imx8image",  "NXP i.MX8 Boot Image",},
+       {       IH_TYPE_IMX8MIMAGE, "imx8mimage", "NXP i.MX8M Boot Image",},
        {       IH_TYPE_INVALID,    "invalid",    "Invalid Image",      },
        {       IH_TYPE_MULTI,      "multi",      "Multi-File Image",   },
        {       IH_TYPE_OMAPIMAGE,  "omapimage",  "TI OMAP SPL With GP CH",},
@@ -159,11 +175,14 @@ static const table_entry_t uimage_type[] = {
        {       IH_TYPE_VYBRIDIMAGE, "vybridimage",  "Vybrid Boot Image", },
        {       IH_TYPE_ZYNQIMAGE,  "zynqimage",  "Xilinx Zynq Boot Image" },
        {       IH_TYPE_ZYNQMPIMAGE, "zynqmpimage", "Xilinx ZynqMP Boot Image" },
+       {       IH_TYPE_ZYNQMPBIF,  "zynqmpbif",  "Xilinx ZynqMP Boot Image (bif)" },
        {       IH_TYPE_FPGA,       "fpga",       "FPGA Image" },
        {       IH_TYPE_TEE,        "tee",        "Trusted Execution Environment Image",},
        {       IH_TYPE_FIRMWARE_IVT, "firmware_ivt", "Firmware with HABv4 IVT" },
        {       IH_TYPE_PMMC,        "pmmc",        "TI Power Management Micro-Controller Firmware",},
        {       IH_TYPE_STM32IMAGE, "stm32image", "STMicroelectronics STM32 Image" },
+       {       IH_TYPE_MTKIMAGE,   "mtk_image",   "MediaTek BootROM loadable Image" },
+       {       IH_TYPE_COPRO, "copro", "Coprocessor Image"},
        {       -1,                 "",           "",                   },
 };
 
@@ -183,6 +202,14 @@ struct table_info {
        const table_entry_t *table;
 };
 
+static const struct comp_magic_map image_comp[] = {
+       {       IH_COMP_BZIP2,  "bzip2",        {0x42, 0x5a},},
+       {       IH_COMP_GZIP,   "gzip",         {0x1f, 0x8b},},
+       {       IH_COMP_LZMA,   "lzma",         {0x5d, 0x00},},
+       {       IH_COMP_LZO,    "lzo",          {0x89, 0x4c},},
+       {       IH_COMP_NONE,   "none",         {},     },
+};
+
 static const struct table_info table_info[IH_COUNT] = {
        { "architecture", IH_ARCH_COUNT, uimage_arch },
        { "compression", IH_COMP_COUNT, uimage_comp },
@@ -365,15 +392,130 @@ void image_print_contents(const void *ptr)
                }
        } else if (image_check_type(hdr, IH_TYPE_FIRMWARE_IVT)) {
                printf("HAB Blocks:   0x%08x   0x0000   0x%08x\n",
-                               image_get_load(hdr) - image_get_header_size(),
-                               image_get_size(hdr) + image_get_header_size()
-                                               - 0x1FE0);
+                       image_get_load(hdr) - image_get_header_size(),
+                       (int)(image_get_size(hdr) + image_get_header_size()
+                       + sizeof(flash_header_v2_t) - 0x2060));
+       }
+}
+
+/**
+ * print_decomp_msg() - Print a suitable decompression/loading message
+ *
+ * @type:      OS type (IH_OS_...)
+ * @comp_type: Compression type being used (IH_COMP_...)
+ * @is_xip:    true if the load address matches the image start
+ */
+static void print_decomp_msg(int comp_type, int type, bool is_xip)
+{
+       const char *name = genimg_get_type_name(type);
+
+       if (comp_type == IH_COMP_NONE)
+               printf("   %s %s\n", is_xip ? "XIP" : "Loading", name);
+       else
+               printf("   Uncompressing %s\n", name);
+}
+
+int image_decomp_type(const unsigned char *buf, ulong len)
+{
+       const struct comp_magic_map *cmagic = image_comp;
+
+       if (len < 2)
+               return -EINVAL;
+
+       for (; cmagic->comp_id > 0; cmagic++) {
+               if (!memcmp(buf, cmagic->magic, 2))
+                       break;
+       }
+
+       return cmagic->comp_id;
+}
+
+int image_decomp(int comp, ulong load, ulong image_start, int type,
+                void *load_buf, void *image_buf, ulong image_len,
+                uint unc_len, ulong *load_end)
+{
+       int ret = 0;
+
+       *load_end = load;
+       print_decomp_msg(comp, type, load == image_start);
+
+       /*
+        * Load the image to the right place, decompressing if needed. After
+        * this, image_len will be set to the number of uncompressed bytes
+        * loaded, ret will be non-zero on error.
+        */
+       switch (comp) {
+       case IH_COMP_NONE:
+               if (load == image_start)
+                       break;
+               if (image_len <= unc_len)
+                       memmove_wd(load_buf, image_buf, image_len, CHUNKSZ);
+               else
+                       ret = -ENOSPC;
+               break;
+#ifdef CONFIG_GZIP
+       case IH_COMP_GZIP: {
+               ret = gunzip(load_buf, unc_len, image_buf, &image_len);
+               break;
+       }
+#endif /* CONFIG_GZIP */
+#ifdef CONFIG_BZIP2
+       case IH_COMP_BZIP2: {
+               uint size = unc_len;
+
+               /*
+                * If we've got less than 4 MB of malloc() space,
+                * use slower decompression algorithm which requires
+                * at most 2300 KB of memory.
+                */
+               ret = BZ2_bzBuffToBuffDecompress(load_buf, &size,
+                       image_buf, image_len,
+                       CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0);
+               image_len = size;
+               break;
+       }
+#endif /* CONFIG_BZIP2 */
+#ifdef CONFIG_LZMA
+       case IH_COMP_LZMA: {
+               SizeT lzma_len = unc_len;
+
+               ret = lzmaBuffToBuffDecompress(load_buf, &lzma_len,
+                                              image_buf, image_len);
+               image_len = lzma_len;
+               break;
+       }
+#endif /* CONFIG_LZMA */
+#ifdef CONFIG_LZO
+       case IH_COMP_LZO: {
+               size_t size = unc_len;
+
+               ret = lzop_decompress(image_buf, image_len, load_buf, &size);
+               image_len = size;
+               break;
+       }
+#endif /* CONFIG_LZO */
+#ifdef CONFIG_LZ4
+       case IH_COMP_LZ4: {
+               size_t size = unc_len;
+
+               ret = ulz4fn(image_buf, image_len, load_buf, &size);
+               image_len = size;
+               break;
+       }
+#endif /* CONFIG_LZ4 */
+       default:
+               printf("Unimplemented compression type %d\n", comp);
+               return -ENOSYS;
        }
+
+       *load_end = load + image_len;
+
+       return ret;
 }
 
 
 #ifndef USE_HOSTCC
-#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
 /**
  * image_get_ramdisk - get and verify ramdisk image
  * @rd_addr: ramdisk image start address
@@ -439,9 +581,9 @@ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
 /* Shared dual-format routines */
 /*****************************************************************************/
 #ifndef USE_HOSTCC
-ulong load_addr = CONFIG_SYS_LOAD_ADDR;        /* Default Load Address */
-ulong save_addr;                       /* Default Save Address */
-ulong save_size;                       /* Default Save Size (in bytes) */
+ulong image_load_addr = CONFIG_SYS_LOAD_ADDR;  /* Default Load Address */
+ulong image_save_addr;                 /* Default Save Address */
+ulong image_save_size;                 /* Default Save Size (in bytes) */
 
 static int on_loadaddr(const char *name, const char *value, enum env_op op,
        int flags)
@@ -449,7 +591,7 @@ static int on_loadaddr(const char *name, const char *value, enum env_op op,
        switch (op) {
        case env_op_create:
        case env_op_overwrite:
-               load_addr = simple_strtoul(value, NULL, 16);
+               image_load_addr = simple_strtoul(value, NULL, 16);
                break;
        default:
                break;
@@ -469,7 +611,7 @@ ulong env_get_bootm_low(void)
 
 #if defined(CONFIG_SYS_SDRAM_BASE)
        return CONFIG_SYS_SDRAM_BASE;
-#elif defined(CONFIG_ARM)
+#elif defined(CONFIG_ARM) || defined(CONFIG_MICROBLAZE)
        return gd->bd->bi_dram[0].start;
 #else
        return 0;
@@ -486,7 +628,8 @@ phys_size_t env_get_bootm_size(void)
                return tmp;
        }
 
-#if defined(CONFIG_ARM) && defined(CONFIG_NR_DRAM_BANKS)
+#if (defined(CONFIG_ARM) || defined(CONFIG_MICROBLAZE)) && \
+     defined(CONFIG_NR_DRAM_BANKS)
        start = gd->bd->bi_dram[0].start;
        size = gd->bd->bi_dram[0].size;
 #else
@@ -547,6 +690,11 @@ void memmove_wd(void *to, void *from, size_t len, ulong chunksz)
        memmove(to, from, len);
 #endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
 }
+#else  /* USE_HOSTCC */
+void memmove_wd(void *to, void *from, size_t len, ulong chunksz)
+{
+       memmove(to, from, len);
+}
 #endif /* !USE_HOSTCC */
 
 void genimg_print_size(uint32_t size)
@@ -812,15 +960,15 @@ ulong genimg_get_kernel_addr_fit(char * const img_addr,
 
        /* find out kernel image address */
        if (!img_addr) {
-               kernel_addr = load_addr;
+               kernel_addr = image_load_addr;
                debug("*  kernel: default image load address = 0x%08lx\n",
-                     load_addr);
+                     image_load_addr);
 #if CONFIG_IS_ENABLED(FIT)
-       } else if (fit_parse_conf(img_addr, load_addr, &kernel_addr,
+       } else if (fit_parse_conf(img_addr, image_load_addr, &kernel_addr,
                                  fit_uname_config)) {
                debug("*  kernel: config '%s' from image at 0x%08lx\n",
                      *fit_uname_config, kernel_addr);
-       } else if (fit_parse_subimage(img_addr, load_addr, &kernel_addr,
+       } else if (fit_parse_subimage(img_addr, image_load_addr, &kernel_addr,
                                     fit_uname_kernel)) {
                debug("*  kernel: subimage '%s' from image at 0x%08lx\n",
                      *fit_uname_kernel, kernel_addr);
@@ -863,7 +1011,7 @@ ulong genimg_get_kernel_addr(char * const img_addr)
  */
 int genimg_get_format(const void *img_addr)
 {
-#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
        const image_header_t *hdr;
 
        hdr = (const image_header_t *)img_addr;
@@ -929,7 +1077,7 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
 {
        ulong rd_addr, rd_load;
        ulong rd_data, rd_len;
-#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
        const image_header_t *rd_hdr;
 #endif
        void *buf;
@@ -953,7 +1101,7 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
         */
        buf = map_sysmem(images->os.start, 0);
        if (buf && genimg_get_format(buf) == IMAGE_FORMAT_ANDROID)
-               select = argv[0];
+               select = (argc == 0) ? env_get("loadaddr") : argv[0];
 #endif
 
        if (argc >= 2)
@@ -978,7 +1126,7 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
                        if (images->fit_uname_os)
                                default_addr = (ulong)images->fit_hdr_os;
                        else
-                               default_addr = load_addr;
+                               default_addr = image_load_addr;
 
                        if (fit_parse_conf(select, default_addr,
                                           &rd_addr, &fit_uname_config)) {
@@ -1021,7 +1169,7 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
                 */
                buf = map_sysmem(rd_addr, 0);
                switch (genimg_get_format(buf)) {
-#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
+#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
                case IMAGE_FORMAT_LEGACY:
                        printf("## Loading init Ramdisk from Legacy "
                                        "Image at %08lx ...\n", rd_addr);
@@ -1412,7 +1560,7 @@ int boot_get_loadable(int argc, char * const argv[], bootm_headers_t *images,
  * @cmd_end: pointer to a ulong variable, will hold cmdline end
  *
  * boot_get_cmdline() allocates space for kernel command line below
- * BOOTMAPSZ + env_get_bootm_low() address. If "bootargs" U-Boot environemnt
+ * BOOTMAPSZ + env_get_bootm_low() address. If "bootargs" U-Boot environment
  * variable is present its contents is copied to allocated kernel
  * command line.
  *