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