1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2000-2004 4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 5 * 6 * (C) Copyright 2003 7 * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de> 8 */ 9 10 11/* 12 * Multi Image extract 13 */ 14#include <common.h> 15#include <command.h> 16#include <cpu_func.h> 17#include <env.h> 18#include <gzip.h> 19#include <image.h> 20#include <malloc.h> 21#include <mapmem.h> 22#include <watchdog.h> 23#if defined(CONFIG_BZIP2) 24#include <bzlib.h> 25#endif 26#include <asm/byteorder.h> 27#include <asm/cache.h> 28#include <asm/io.h> 29 30static int 31do_imgextract(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) 32{ 33 ulong addr = image_load_addr; 34 ulong dest = 0; 35 ulong data, len; 36 int verify; 37 int part = 0; 38#if defined(CONFIG_LEGACY_IMAGE_FORMAT) 39 ulong count; 40 struct legacy_img_hdr *hdr = NULL; 41#endif 42#if defined(CONFIG_FIT) 43 const char *uname = NULL; 44 const void* fit_hdr; 45 int noffset; 46 const void *fit_data; 47 size_t fit_len; 48#endif 49#ifdef CONFIG_GZIP 50 uint unc_len = CONFIG_SYS_XIMG_LEN; 51#endif 52 uint8_t comp; 53 54 verify = env_get_yesno("verify"); 55 56 if (argc > 1) { 57 addr = hextoul(argv[1], NULL); 58 } 59 if (argc > 2) { 60 part = hextoul(argv[2], NULL); 61#if defined(CONFIG_FIT) 62 uname = argv[2]; 63#endif 64 } 65 if (argc > 3) { 66 dest = hextoul(argv[3], NULL); 67 } 68 69 switch (genimg_get_format((void *)addr)) { 70#if defined(CONFIG_LEGACY_IMAGE_FORMAT) 71 case IMAGE_FORMAT_LEGACY: 72 73 printf("## Copying part %d from legacy image " 74 "at %08lx ...\n", part, addr); 75 76 hdr = (struct legacy_img_hdr *)addr; 77 if (!image_check_magic(hdr)) { 78 printf("Bad Magic Number\n"); 79 return 1; 80 } 81 82 if (!image_check_hcrc(hdr)) { 83 printf("Bad Header Checksum\n"); 84 return 1; 85 } 86#ifdef DEBUG 87 image_print_contents(hdr); 88#endif 89 90 if (!image_check_type(hdr, IH_TYPE_MULTI) && 91 !image_check_type(hdr, IH_TYPE_SCRIPT)) { 92 printf("Wrong Image Type for %s command\n", 93 cmdtp->name); 94 return 1; 95 } 96 97 comp = image_get_comp(hdr); 98 if ((comp != IH_COMP_NONE) && (argc < 4)) { 99 printf("Must specify load address for %s command " 100 "with compressed image\n", 101 cmdtp->name); 102 return 1; 103 } 104 105 if (verify) { 106 printf(" Verifying Checksum ... "); 107 if (!image_check_dcrc(hdr)) { 108 printf("Bad Data CRC\n"); 109 return 1; 110 } 111 printf("OK\n"); 112 } 113 114 count = image_multi_count(hdr); 115 if (part >= count) { 116 printf("Bad Image Part\n"); 117 return 1; 118 } 119 120 image_multi_getimg(hdr, part, &data, &len); 121 break; 122#endif 123#if defined(CONFIG_FIT) 124 case IMAGE_FORMAT_FIT: 125 if (uname == NULL) { 126 puts("No FIT subimage unit name\n"); 127 return 1; 128 } 129 130 printf("## Copying '%s' subimage from FIT image " 131 "at %08lx ...\n", uname, addr); 132 133 fit_hdr = (const void *)addr; 134 if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { 135 puts("Bad FIT image format\n"); 136 return 1; 137 } 138 139 /* get subimage node offset */ 140 noffset = fit_image_get_node(fit_hdr, uname); 141 if (noffset < 0) { 142 printf("Can't find '%s' FIT subimage\n", uname); 143 return 1; 144 } 145 146 if (!fit_image_check_comp(fit_hdr, noffset, IH_COMP_NONE) 147 && (argc < 4)) { 148 printf("Must specify load address for %s command " 149 "with compressed image\n", 150 cmdtp->name); 151 return 1; 152 } 153 154 /* verify integrity */ 155 if (verify) { 156 if (!fit_image_verify(fit_hdr, noffset)) { 157 puts("Bad Data Hash\n"); 158 return 1; 159 } 160 } 161 162 /* get subimage/external data address and length */ 163 if (fit_image_get_data_and_size(fit_hdr, noffset, 164 &fit_data, &fit_len)) { 165 puts("Could not find script subimage data\n"); 166 return 1; 167 } 168 169 if (fit_image_get_comp(fit_hdr, noffset, &comp)) 170 comp = IH_COMP_NONE; 171 172 data = (ulong)fit_data; 173 len = (ulong)fit_len; 174 break; 175#endif 176 default: 177 puts("Invalid image type for imxtract\n"); 178 return 1; 179 } 180 181 if (argc > 3) { 182 switch (comp) { 183 case IH_COMP_NONE: 184#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) 185 { 186 size_t l = len; 187 size_t tail; 188 void *to = (void *) dest; 189 void *from = (void *)data; 190 191 printf(" Loading part %d ... ", part); 192 193 while (l > 0) { 194 tail = (l > CHUNKSZ) ? CHUNKSZ : l; 195 schedule(); 196 memmove(to, from, tail); 197 to += tail; 198 from += tail; 199 l -= tail; 200 } 201 } 202#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ 203 printf(" Loading part %d ... ", part); 204 memmove((char *) dest, (char *)data, len); 205#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ 206 break; 207#ifdef CONFIG_GZIP 208 case IH_COMP_GZIP: 209 printf(" Uncompressing part %d ... ", part); 210 if (gunzip((void *) dest, unc_len, 211 (uchar *) data, &len) != 0) { 212 puts("GUNZIP ERROR - image not loaded\n"); 213 return 1; 214 } 215 break; 216#endif 217#if defined(CONFIG_BZIP2) && defined(CONFIG_LEGACY_IMAGE_FORMAT) 218 case IH_COMP_BZIP2: 219 { 220 int i; 221 222 printf(" Uncompressing part %d ... ", part); 223 /* 224 * If we've got less than 4 MB of malloc() 225 * space, use slower decompression algorithm 226 * which requires at most 2300 KB of memory. 227 */ 228 i = BZ2_bzBuffToBuffDecompress( 229 map_sysmem(ntohl(hdr->ih_load), 0), 230 &unc_len, (char *)data, len, 231 CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 232 0); 233 if (i != BZ_OK) { 234 printf("BUNZIP2 ERROR %d - " 235 "image not loaded\n", i); 236 return 1; 237 } 238 } 239 break; 240#endif /* CONFIG_BZIP2 */ 241 default: 242 printf("Unimplemented compression type %d\n", comp); 243 return 1; 244 } 245 puts("OK\n"); 246 } 247 248 flush_cache(dest, ALIGN(len, ARCH_DMA_MINALIGN)); 249 250 env_set_hex("fileaddr", data); 251 env_set_hex("filesize", len); 252 253 return 0; 254} 255 256U_BOOT_LONGHELP(imgextract, 257 "addr part [dest]\n" 258 " - extract <part> from legacy image at <addr> and copy to <dest>" 259#if defined(CONFIG_FIT) 260 "\n" 261 "addr uname [dest]\n" 262 " - extract <uname> subimage from FIT image at <addr> and copy to <dest>" 263#endif 264 ); 265 266U_BOOT_CMD( 267 imxtract, 4, 1, do_imgextract, 268 "extract a part of a multi-image", imgextract_help_text 269); 270