blob: b439be3d088526eb48c0fb9c95cd6f805203728f [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>
23
Wolfgang Wegner781afa92009-12-10 10:11:21 +010024#ifndef CONFIG_SYS_XIMG_LEN
25/* use 8MByte as default max gunzip size */
26#define CONFIG_SYS_XIMG_LEN 0x800000
27#endif
28
Kim Phillipsdc00a682012-10-29 13:34:31 +000029static int
Wolfgang Denk6262d0212010-06-28 22:00:46 +020030do_imgextract(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
wdenk0359dde2004-06-09 10:15:00 +000031{
Marian Balakowicz2321ed02008-03-12 10:33:00 +010032 ulong addr = load_addr;
33 ulong dest = 0;
34 ulong data, len, count;
Bartlomiej Sieka3b8cc712008-03-20 19:38:45 +010035 int verify;
Marian Balakowicz2321ed02008-03-12 10:33:00 +010036 int part = 0;
Marian Balakowicz2321ed02008-03-12 10:33:00 +010037 image_header_t *hdr;
38#if defined(CONFIG_FIT)
Bartlomiej Sieka3b8cc712008-03-20 19:38:45 +010039 const char *uname = NULL;
Marian Balakowicz2321ed02008-03-12 10:33:00 +010040 const void* fit_hdr;
41 int noffset;
42 const void *fit_data;
43 size_t fit_len;
44#endif
Simon Glassa0395272013-04-17 16:13:45 +000045#ifdef CONFIG_GZIP
Wolfgang Wegner781afa92009-12-10 10:11:21 +010046 uint unc_len = CONFIG_SYS_XIMG_LEN;
Simon Glassa0395272013-04-17 16:13:45 +000047#endif
Wolfgang Wegner781afa92009-12-10 10:11:21 +010048 uint8_t comp;
wdenk0359dde2004-06-09 10:15:00 +000049
Stephen Warren6904b6e2011-10-18 11:11:49 +000050 verify = getenv_yesno("verify");
wdenk0359dde2004-06-09 10:15:00 +000051
52 if (argc > 1) {
53 addr = simple_strtoul(argv[1], NULL, 16);
54 }
55 if (argc > 2) {
56 part = simple_strtoul(argv[2], NULL, 16);
Marian Balakowicz2321ed02008-03-12 10:33:00 +010057#if defined(CONFIG_FIT)
58 uname = argv[2];
59#endif
wdenk0359dde2004-06-09 10:15:00 +000060 }
61 if (argc > 3) {
62 dest = simple_strtoul(argv[3], NULL, 16);
63 }
64
Stephen Warren6904b6e2011-10-18 11:11:49 +000065 switch (genimg_get_format((void *)addr)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010066 case IMAGE_FORMAT_LEGACY:
wdenk0359dde2004-06-09 10:15:00 +000067
Marian Balakowicz2321ed02008-03-12 10:33:00 +010068 printf("## Copying part %d from legacy image "
69 "at %08lx ...\n", part, addr);
70
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010071 hdr = (image_header_t *)addr;
Stephen Warren6904b6e2011-10-18 11:11:49 +000072 if (!image_check_magic(hdr)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010073 printf("Bad Magic Number\n");
74 return 1;
75 }
wdenk0359dde2004-06-09 10:15:00 +000076
Stephen Warren6904b6e2011-10-18 11:11:49 +000077 if (!image_check_hcrc(hdr)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010078 printf("Bad Header Checksum\n");
79 return 1;
80 }
Marian Balakowicz2321ed02008-03-12 10:33:00 +010081#ifdef DEBUG
Stephen Warren6904b6e2011-10-18 11:11:49 +000082 image_print_contents(hdr);
Marian Balakowicz2321ed02008-03-12 10:33:00 +010083#endif
wdenk0359dde2004-06-09 10:15:00 +000084
Stephen Warren6904b6e2011-10-18 11:11:49 +000085 if (!image_check_type(hdr, IH_TYPE_MULTI)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010086 printf("Wrong Image Type for %s command\n",
87 cmdtp->name);
88 return 1;
89 }
wdenk0359dde2004-06-09 10:15:00 +000090
Stephen Warren6904b6e2011-10-18 11:11:49 +000091 comp = image_get_comp(hdr);
Wolfgang Wegner781afa92009-12-10 10:11:21 +010092 if ((comp != IH_COMP_NONE) && (argc < 4)) {
93 printf("Must specify load address for %s command "
94 "with compressed image\n",
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010095 cmdtp->name);
wdenk0359dde2004-06-09 10:15:00 +000096 return 1;
97 }
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010098
99 if (verify) {
100 printf(" Verifying Checksum ... ");
Stephen Warren6904b6e2011-10-18 11:11:49 +0000101 if (!image_check_dcrc(hdr)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100102 printf("Bad Data CRC\n");
103 return 1;
104 }
105 printf("OK\n");
106 }
wdenk0359dde2004-06-09 10:15:00 +0000107
Stephen Warren6904b6e2011-10-18 11:11:49 +0000108 count = image_multi_count(hdr);
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100109 if (part >= count) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100110 printf("Bad Image Part\n");
111 return 1;
112 }
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100113
Stephen Warren6904b6e2011-10-18 11:11:49 +0000114 image_multi_getimg(hdr, part, &data, &len);
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100115 break;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100116#if defined(CONFIG_FIT)
117 case IMAGE_FORMAT_FIT:
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100118 if (uname == NULL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000119 puts("No FIT subimage unit name\n");
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100120 return 1;
121 }
122
123 printf("## Copying '%s' subimage from FIT image "
124 "at %08lx ...\n", uname, addr);
125
126 fit_hdr = (const void *)addr;
Stephen Warren6904b6e2011-10-18 11:11:49 +0000127 if (!fit_check_format(fit_hdr)) {
128 puts("Bad FIT image format\n");
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100129 return 1;
130 }
131
132 /* get subimage node offset */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000133 noffset = fit_image_get_node(fit_hdr, uname);
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100134 if (noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000135 printf("Can't find '%s' FIT subimage\n", uname);
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100136 return 1;
137 }
138
Stephen Warren6904b6e2011-10-18 11:11:49 +0000139 if (fit_image_check_comp(fit_hdr, noffset, IH_COMP_NONE)
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100140 && (argc < 4)) {
141 printf("Must specify load address for %s command "
142 "with compressed image\n",
143 cmdtp->name);
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100144 return 1;
145 }
146
147 /* verify integrity */
148 if (verify) {
Simon Glass7428ad12013-05-07 06:11:57 +0000149 if (!fit_image_verify(fit_hdr, noffset)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000150 puts("Bad Data Hash\n");
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100151 return 1;
152 }
153 }
154
155 /* get subimage data address and length */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000156 if (fit_image_get_data(fit_hdr, noffset,
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100157 &fit_data, &fit_len)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000158 puts("Could not find script subimage data\n");
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100159 return 1;
160 }
161
Stephen Warren6904b6e2011-10-18 11:11:49 +0000162 if (fit_image_get_comp(fit_hdr, noffset, &comp)) {
163 puts("Could not find script subimage "
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100164 "compression type\n");
165 return 1;
166 }
167
Bartlomiej Sieka3b8cc712008-03-20 19:38:45 +0100168 data = (ulong)fit_data;
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100169 len = (ulong)fit_len;
170 break;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100171#endif
172 default:
Stephen Warren6904b6e2011-10-18 11:11:49 +0000173 puts("Invalid image type for imxtract\n");
wdenk0359dde2004-06-09 10:15:00 +0000174 return 1;
175 }
wdenk0359dde2004-06-09 10:15:00 +0000176
177 if (argc > 3) {
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100178 switch (comp) {
179 case IH_COMP_NONE:
180#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
181 {
182 size_t l = len;
183 size_t tail;
184 void *to = (void *) dest;
185 void *from = (void *)data;
186
Stephen Warren6904b6e2011-10-18 11:11:49 +0000187 printf(" Loading part %d ... ", part);
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100188
189 while (l > 0) {
190 tail = (l > CHUNKSZ) ? CHUNKSZ : l;
191 WATCHDOG_RESET();
Stephen Warren6904b6e2011-10-18 11:11:49 +0000192 memmove(to, from, tail);
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100193 to += tail;
194 from += tail;
195 l -= tail;
196 }
197 }
198#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000199 printf(" Loading part %d ... ", part);
200 memmove((char *) dest, (char *)data, len);
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100201#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
202 break;
Matthew McClintockc93a7542011-05-24 05:48:26 +0000203#ifdef CONFIG_GZIP
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100204 case IH_COMP_GZIP:
Stephen Warren6904b6e2011-10-18 11:11:49 +0000205 printf(" Uncompressing part %d ... ", part);
206 if (gunzip((void *) dest, unc_len,
207 (uchar *) data, &len) != 0) {
208 puts("GUNZIP ERROR - image not loaded\n");
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100209 return 1;
210 }
211 break;
Matthew McClintockc93a7542011-05-24 05:48:26 +0000212#endif
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100213#if defined(CONFIG_BZIP2)
214 case IH_COMP_BZIP2:
Wolfgang Denk3207afd2010-01-31 21:51:43 +0100215 {
216 int i;
217
Stephen Warren6904b6e2011-10-18 11:11:49 +0000218 printf(" Uncompressing part %d ... ", part);
Wolfgang Denk3207afd2010-01-31 21:51:43 +0100219 /*
Wolfgang Denka2cfb242010-03-12 23:06:04 +0100220 * If we've got less than 4 MB of malloc()
Wolfgang Denk3207afd2010-01-31 21:51:43 +0100221 * space, use slower decompression algorithm
222 * which requires at most 2300 KB of memory.
223 */
224 i = BZ2_bzBuffToBuffDecompress(
Stephen Warren6904b6e2011-10-18 11:11:49 +0000225 (char *)ntohl(hdr->ih_load),
Wolfgang Denk3207afd2010-01-31 21:51:43 +0100226 &unc_len, (char *)data, len,
227 CONFIG_SYS_MALLOC_LEN < (4096 * 1024),
228 0);
229 if (i != BZ_OK) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000230 printf("BUNZIP2 ERROR %d - "
Wolfgang Denk3207afd2010-01-31 21:51:43 +0100231 "image not loaded\n", i);
232 return 1;
233 }
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100234 }
235 break;
236#endif /* CONFIG_BZIP2 */
237 default:
Stephen Warren6904b6e2011-10-18 11:11:49 +0000238 printf("Unimplemented compression type %d\n", comp);
Wolfgang Wegner781afa92009-12-10 10:11:21 +0100239 return 1;
240 }
Stephen Warren6904b6e2011-10-18 11:11:49 +0000241 puts("OK\n");
wdenk0359dde2004-06-09 10:15:00 +0000242 }
243
Simon Glass103789d2013-02-24 17:33:22 +0000244 setenv_hex("fileaddr", data);
245 setenv_hex("filesize", len);
wdenk0359dde2004-06-09 10:15:00 +0000246
247 return 0;
248}
249
Kim Phillipsdc00a682012-10-29 13:34:31 +0000250#ifdef CONFIG_SYS_LONGHELP
251static char imgextract_help_text[] =
Wolfgang Denkc54781c2009-05-24 17:06:54 +0200252 "addr part [dest]\n"
253 " - extract <part> from legacy image at <addr> and copy to <dest>"
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100254#if defined(CONFIG_FIT)
Wolfgang Denkc54781c2009-05-24 17:06:54 +0200255 "\n"
256 "addr uname [dest]\n"
257 " - extract <uname> subimage from FIT image at <addr> and copy to <dest>"
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100258#endif
Kim Phillipsdc00a682012-10-29 13:34:31 +0000259 "";
260#endif
261
262U_BOOT_CMD(
263 imxtract, 4, 1, do_imgextract,
264 "extract a part of a multi-image", imgextract_help_text
Marian Balakowicz2321ed02008-03-12 10:33:00 +0100265);