blob: 64b9186d738920dabf3e8573dcebaecdbb3ee562 [file] [log] [blame]
wdenk0359dde2004-06-09 10:15:00 +00001/*
2 * (C) Copyright 2000-2004
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * (C) Copyright 2003
6 * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de>
7 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02008 * SPDX-License-Identifier: GPL-2.0+
wdenk0359dde2004-06-09 10:15:00 +00009 */
10
wdenk0359dde2004-06-09 10:15:00 +000011
12/*
13 * Multi Image extract
14 */
15#include <common.h>
16#include <command.h>
17#include <image.h>
Wolfgang Wegner781afa92009-12-10 10:11:21 +010018#include <watchdog.h>
19#if defined(CONFIG_BZIP2)
20#include <bzlib.h>
21#endif
wdenk0359dde2004-06-09 10:15:00 +000022#include <asm/byteorder.h>
Simon Glass208d8e82013-08-30 11:00:09 -060023#include <asm/io.h>
wdenk0359dde2004-06-09 10:15:00 +000024
Wolfgang Wegner781afa92009-12-10 10:11:21 +010025#ifndef CONFIG_SYS_XIMG_LEN
26/* use 8MByte as default max gunzip size */
27#define CONFIG_SYS_XIMG_LEN 0x800000
28#endif
29
Kim Phillipsdc00a682012-10-29 13:34:31 +000030static int
Wolfgang Denk6262d0212010-06-28 22:00:46 +020031do_imgextract(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
wdenk0359dde2004-06-09 10:15:00 +000032{
Marian Balakowicz2321ed02008-03-12 10:33:00 +010033 ulong addr = load_addr;
34 ulong dest = 0;
Heiko Schocher515eb122014-05-28 11:33:33 +020035 ulong data, len;
Bartlomiej Sieka3b8cc712008-03-20 19:38:45 +010036 int verify;
Marian Balakowicz2321ed02008-03-12 10:33:00 +010037 int part = 0;
Heiko Schocher515eb122014-05-28 11:33:33 +020038#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
39 ulong count;
Simon Glass208d8e82013-08-30 11:00:09 -060040 image_header_t *hdr = NULL;
Heiko Schocher515eb122014-05-28 11:33:33 +020041#endif
Marian Balakowicz2321ed02008-03-12 10:33:00 +010042#if defined(CONFIG_FIT)
Bartlomiej Sieka3b8cc712008-03-20 19:38:45 +010043 const char *uname = NULL;
Marian Balakowicz2321ed02008-03-12 10:33:00 +010044 const void* fit_hdr;
45 int noffset;
46 const void *fit_data;
47 size_t fit_len;
48#endif
Simon Glassa0395272013-04-17 16:13:45 +000049#ifdef CONFIG_GZIP
Wolfgang Wegner781afa92009-12-10 10:11:21 +010050 uint unc_len = CONFIG_SYS_XIMG_LEN;
Simon Glassa0395272013-04-17 16:13:45 +000051#endif
Wolfgang Wegner781afa92009-12-10 10:11:21 +010052 uint8_t comp;
wdenk0359dde2004-06-09 10:15:00 +000053
Stephen Warren6904b6e2011-10-18 11:11:49 +000054 verify = getenv_yesno("verify");
wdenk0359dde2004-06-09 10:15:00 +000055
56 if (argc > 1) {
57 addr = simple_strtoul(argv[1], NULL, 16);
58 }
59 if (argc > 2) {
60 part = simple_strtoul(argv[2], NULL, 16);
Marian Balakowicz2321ed02008-03-12 10:33:00 +010061#if defined(CONFIG_FIT)
62 uname = argv[2];
63#endif
wdenk0359dde2004-06-09 10:15:00 +000064 }
65 if (argc > 3) {
66 dest = simple_strtoul(argv[3], NULL, 16);
67 }
68
Stephen Warren6904b6e2011-10-18 11:11:49 +000069 switch (genimg_get_format((void *)addr)) {
Heiko Schocher515eb122014-05-28 11:33:33 +020070#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010071 case IMAGE_FORMAT_LEGACY:
wdenk0359dde2004-06-09 10:15:00 +000072
Marian Balakowicz2321ed02008-03-12 10:33:00 +010073 printf("## Copying part %d from legacy image "
74 "at %08lx ...\n", part, addr);
75
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010076 hdr = (image_header_t *)addr;
Stephen Warren6904b6e2011-10-18 11:11:49 +000077 if (!image_check_magic(hdr)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010078 printf("Bad Magic Number\n");
79 return 1;
80 }
wdenk0359dde2004-06-09 10:15:00 +000081
Stephen Warren6904b6e2011-10-18 11:11:49 +000082 if (!image_check_hcrc(hdr)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010083 printf("Bad Header Checksum\n");
84 return 1;
85 }
Marian Balakowicz2321ed02008-03-12 10:33:00 +010086#ifdef DEBUG
Stephen Warren6904b6e2011-10-18 11:11:49 +000087 image_print_contents(hdr);
Marian Balakowicz2321ed02008-03-12 10:33:00 +010088#endif
wdenk0359dde2004-06-09 10:15:00 +000089
Stephen Warren6904b6e2011-10-18 11:11:49 +000090 if (!image_check_type(hdr, IH_TYPE_MULTI)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010091 printf("Wrong Image Type for %s command\n",
92 cmdtp->name);
93 return 1;
94 }
wdenk0359dde2004-06-09 10:15:00 +000095
Stephen Warren6904b6e2011-10-18 11:11:49 +000096 comp = image_get_comp(hdr);
Wolfgang Wegner781afa92009-12-10 10:11:21 +010097 if ((comp != IH_COMP_NONE) && (argc < 4)) {
98 printf("Must specify load address for %s command "
99 "with compressed image\n",
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100100 cmdtp->name);
wdenk0359dde2004-06-09 10:15:00 +0000101 return 1;
102 }
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100103
104 if (verify) {
105 printf(" Verifying Checksum ... ");
Stephen Warren6904b6e2011-10-18 11:11:49 +0000106 if (!image_check_dcrc(hdr)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100107 printf("Bad Data CRC\n");
108 return 1;
109 }
110 printf("OK\n");
111 }
wdenk0359dde2004-06-09 10:15:00 +0000112
Stephen Warren6904b6e2011-10-18 11:11:49 +0000113 count = image_multi_count(hdr);
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100114 if (part >= count) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100115 printf("Bad Image Part\n");
116 return 1;
117 }
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100118
Stephen Warren6904b6e2011-10-18 11:11:49 +0000119 image_multi_getimg(hdr, part, &data, &len);
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100120 break;
Heiko Schocher515eb122014-05-28 11:33:33 +0200121#endif
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100122#if defined(CONFIG_FIT)
123 case IMAGE_FORMAT_FIT:
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100124 if (uname == NULL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000125 puts("No FIT subimage unit name\n");
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100126 return 1;
127 }
128
129 printf("## Copying '%s' subimage from FIT image "
130 "at %08lx ...\n", uname, addr);
131
132 fit_hdr = (const void *)addr;
Stephen Warren6904b6e2011-10-18 11:11:49 +0000133 if (!fit_check_format(fit_hdr)) {
134 puts("Bad FIT image format\n");
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100135 return 1;
136 }
137
138 /* get subimage node offset */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000139 noffset = fit_image_get_node(fit_hdr, uname);
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100140 if (noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000141 printf("Can't find '%s' FIT subimage\n", uname);
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100142 return 1;
143 }
144
Stephen Warren6904b6e2011-10-18 11:11:49 +0000145 if (fit_image_check_comp(fit_hdr, noffset, IH_COMP_NONE)
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100146 && (argc < 4)) {
147 printf("Must specify load address for %s command "
148 "with compressed image\n",
149 cmdtp->name);
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100150 return 1;
151 }
152
153 /* verify integrity */
154 if (verify) {
Simon Glass7428ad12013-05-07 06:11:57 +0000155 if (!fit_image_verify(fit_hdr, noffset)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000156 puts("Bad Data Hash\n");
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100157 return 1;
158 }
159 }
160
161 /* get subimage data address and length */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000162 if (fit_image_get_data(fit_hdr, noffset,
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100163 &fit_data, &fit_len)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000164 puts("Could not find script subimage data\n");
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100165 return 1;
166 }
167
Stephen Warren6904b6e2011-10-18 11:11:49 +0000168 if (fit_image_get_comp(fit_hdr, noffset, &comp)) {
169 puts("Could not find script subimage "
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100170 "compression type\n");
171 return 1;
172 }
173
Bartlomiej Sieka3b8cc712008-03-20 19:38:45 +0100174 data = (ulong)fit_data;
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100175 len = (ulong)fit_len;
176 break;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100177#endif
178 default:
Stephen Warren6904b6e2011-10-18 11:11:49 +0000179 puts("Invalid image type for imxtract\n");
wdenk0359dde2004-06-09 10:15:00 +0000180 return 1;
181 }
wdenk0359dde2004-06-09 10:15:00 +0000182
183 if (argc > 3) {
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100184 switch (comp) {
185 case IH_COMP_NONE:
186#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
187 {
188 size_t l = len;
189 size_t tail;
190 void *to = (void *) dest;
191 void *from = (void *)data;
192
Stephen Warren6904b6e2011-10-18 11:11:49 +0000193 printf(" Loading part %d ... ", part);
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100194
195 while (l > 0) {
196 tail = (l > CHUNKSZ) ? CHUNKSZ : l;
197 WATCHDOG_RESET();
Stephen Warren6904b6e2011-10-18 11:11:49 +0000198 memmove(to, from, tail);
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100199 to += tail;
200 from += tail;
201 l -= tail;
202 }
203 }
204#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000205 printf(" Loading part %d ... ", part);
206 memmove((char *) dest, (char *)data, len);
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100207#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
208 break;
Matthew McClintockc93a7542011-05-24 05:48:26 +0000209#ifdef CONFIG_GZIP
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100210 case IH_COMP_GZIP:
Stephen Warren6904b6e2011-10-18 11:11:49 +0000211 printf(" Uncompressing part %d ... ", part);
212 if (gunzip((void *) dest, unc_len,
213 (uchar *) data, &len) != 0) {
214 puts("GUNZIP ERROR - image not loaded\n");
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100215 return 1;
216 }
217 break;
Matthew McClintockc93a7542011-05-24 05:48:26 +0000218#endif
Heiko Schocher515eb122014-05-28 11:33:33 +0200219#if defined(CONFIG_BZIP2) && defined(CONFIG_IMAGE_FORMAT_LEGACY)
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100220 case IH_COMP_BZIP2:
Wolfgang Denk3207afd2010-01-31 21:51:43 +0100221 {
222 int i;
223
Stephen Warren6904b6e2011-10-18 11:11:49 +0000224 printf(" Uncompressing part %d ... ", part);
Wolfgang Denk3207afd2010-01-31 21:51:43 +0100225 /*
Wolfgang Denka2cfb242010-03-12 23:06:04 +0100226 * If we've got less than 4 MB of malloc()
Wolfgang Denk3207afd2010-01-31 21:51:43 +0100227 * space, use slower decompression algorithm
228 * which requires at most 2300 KB of memory.
229 */
230 i = BZ2_bzBuffToBuffDecompress(
Simon Glass208d8e82013-08-30 11:00:09 -0600231 map_sysmem(ntohl(hdr->ih_load), 0),
Wolfgang Denk3207afd2010-01-31 21:51:43 +0100232 &unc_len, (char *)data, len,
233 CONFIG_SYS_MALLOC_LEN < (4096 * 1024),
234 0);
235 if (i != BZ_OK) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000236 printf("BUNZIP2 ERROR %d - "
Wolfgang Denk3207afd2010-01-31 21:51:43 +0100237 "image not loaded\n", i);
238 return 1;
239 }
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100240 }
241 break;
242#endif /* CONFIG_BZIP2 */
243 default:
Stephen Warren6904b6e2011-10-18 11:11:49 +0000244 printf("Unimplemented compression type %d\n", comp);
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100245 return 1;
246 }
Stephen Warren6904b6e2011-10-18 11:11:49 +0000247 puts("OK\n");
wdenk0359dde2004-06-09 10:15:00 +0000248 }
249
Pieter Voorthuijsenf52d2812015-01-12 16:23:18 +0100250 flush_cache(dest, len);
251
Simon Glass103789d2013-02-24 17:33:22 +0000252 setenv_hex("fileaddr", data);
253 setenv_hex("filesize", len);
wdenk0359dde2004-06-09 10:15:00 +0000254
255 return 0;
256}
257
Kim Phillipsdc00a682012-10-29 13:34:31 +0000258#ifdef CONFIG_SYS_LONGHELP
259static char imgextract_help_text[] =
Wolfgang Denkc54781c2009-05-24 17:06:54 +0200260 "addr part [dest]\n"
261 " - extract <part> from legacy image at <addr> and copy to <dest>"
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100262#if defined(CONFIG_FIT)
Wolfgang Denkc54781c2009-05-24 17:06:54 +0200263 "\n"
264 "addr uname [dest]\n"
265 " - extract <uname> subimage from FIT image at <addr> and copy to <dest>"
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100266#endif
Kim Phillipsdc00a682012-10-29 13:34:31 +0000267 "";
268#endif
269
270U_BOOT_CMD(
271 imxtract, 4, 1, do_imgextract,
272 "extract a part of a multi-image", imgextract_help_text
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100273);