blob: 7ef3a8c9f571e8fbcf7ae46b83da3f1ae369b448 [file] [log] [blame]
Kees Cook5d3bca82013-08-16 07:59:11 -07001/*
2 * Copyright (c) 2013, The Chromium Authors
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7#define DEBUG
8
9#include <common.h>
Simon Glass6d084ce2014-12-02 13:17:35 -070010#include <bootm.h>
Kees Cook5d3bca82013-08-16 07:59:11 -070011#include <command.h>
12#include <malloc.h>
Joe Hershberger65b905b2015-03-22 17:08:59 -050013#include <mapmem.h>
Simon Glass6d084ce2014-12-02 13:17:35 -070014#include <asm/io.h>
Kees Cook5d3bca82013-08-16 07:59:11 -070015
16#include <u-boot/zlib.h>
17#include <bzlib.h>
18
19#include <lzma/LzmaTypes.h>
20#include <lzma/LzmaDec.h>
21#include <lzma/LzmaTools.h>
22
23#include <linux/lzo.h>
24
25static const char plain[] =
26 "I am a highly compressable bit of text.\n"
27 "I am a highly compressable bit of text.\n"
28 "I am a highly compressable bit of text.\n"
29 "There are many like me, but this one is mine.\n"
30 "If I were any shorter, there wouldn't be much sense in\n"
31 "compressing me in the first place. At least with lzo, anyway,\n"
32 "which appears to behave poorly in the face of short text\n"
33 "messages.\n";
34
35/* bzip2 -c /tmp/plain.txt > /tmp/plain.bz2 */
36static const char bzip2_compressed[] =
37 "\x42\x5a\x68\x39\x31\x41\x59\x26\x53\x59\xe5\x63\xdd\x09\x00\x00"
38 "\x28\x57\x80\x00\x10\x40\x85\x20\x20\x04\x00\x3f\xef\xdf\xf0\x30"
39 "\x00\xd6\xd0\x34\x91\x89\xa6\xf5\x4d\x19\x1a\x19\x0d\x02\x34\xd4"
40 "\xc9\x00\x34\x34\x00\x02\x48\x41\x35\x4f\xd4\xc6\x88\xd3\x50\x3d"
41 "\x4f\x51\x82\x4f\x88\xc3\x0d\x05\x62\x4f\x91\xa3\x52\x1b\xd0\x52"
42 "\x41\x4a\xa3\x98\xc2\x6b\xca\xa3\x82\xa5\xac\x8b\x15\x99\x68\xad"
43 "\xdf\x29\xd6\xf1\xf7\x5a\x10\xcd\x8c\x26\x61\x94\x95\xfe\x9e\x16"
44 "\x18\x28\x69\xd4\x23\x64\xcc\x2b\xe5\xe8\x5f\x00\xa4\x70\x26\x2c"
45 "\xee\xbd\x59\x6d\x6a\xec\xfc\x31\xda\x59\x0a\x14\x2a\x60\x1c\xf0"
46 "\x04\x86\x73\x9a\xc5\x5b\x87\x3f\x5b\x4c\x93\xe6\xb5\x35\x0d\xa6"
47 "\xb1\x2e\x62\x7b\xab\x67\xe7\x99\x2a\x14\x5e\x9f\x64\xcb\x96\xf4"
48 "\x0d\x65\xd4\x39\xe6\x8b\x7e\xea\x1c\x03\x69\x97\x83\x58\x91\x96"
49 "\xe1\xf0\x9d\xa4\x15\x8b\xb8\xc6\x93\xdc\x3d\xd9\x3c\x22\x55\xef"
50 "\xfb\xbb\x2a\xd3\x87\xa2\x8b\x04\xd9\x19\xf8\xe2\xfd\x4f\xdb\x1a"
51 "\x07\xc8\x60\xa3\x3f\xf8\xbb\x92\x29\xc2\x84\x87\x2b\x1e\xe8\x48";
52static const unsigned long bzip2_compressed_size = 240;
53
54/* lzma -z -c /tmp/plain.txt > /tmp/plain.lzma */
55static const char lzma_compressed[] =
56 "\x5d\x00\x00\x80\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x24\x88"
57 "\x08\x26\xd8\x41\xff\x99\xc8\xcf\x66\x3d\x80\xac\xba\x17\xf1\xc8"
58 "\xb9\xdf\x49\x37\xb1\x68\xa0\x2a\xdd\x63\xd1\xa7\xa3\x66\xf8\x15"
59 "\xef\xa6\x67\x8a\x14\x18\x80\xcb\xc7\xb1\xcb\x84\x6a\xb2\x51\x16"
60 "\xa1\x45\xa0\xd6\x3e\x55\x44\x8a\x5c\xa0\x7c\xe5\xa8\xbd\x04\x57"
61 "\x8f\x24\xfd\xb9\x34\x50\x83\x2f\xf3\x46\x3e\xb9\xb0\x00\x1a\xf5"
62 "\xd3\x86\x7e\x8f\x77\xd1\x5d\x0e\x7c\xe1\xac\xde\xf8\x65\x1f\x4d"
63 "\xce\x7f\xa7\x3d\xaa\xcf\x26\xa7\x58\x69\x1e\x4c\xea\x68\x8a\xe5"
64 "\x89\xd1\xdc\x4d\xc7\xe0\x07\x42\xbf\x0c\x9d\x06\xd7\x51\xa2\x0b"
65 "\x7c\x83\x35\xe1\x85\xdf\xee\xfb\xa3\xee\x2f\x47\x5f\x8b\x70\x2b"
66 "\xe1\x37\xf3\x16\xf6\x27\x54\x8a\x33\x72\x49\xea\x53\x7d\x60\x0b"
67 "\x21\x90\x66\xe7\x9e\x56\x61\x5d\xd8\xdc\x59\xf0\xac\x2f\xd6\x49"
68 "\x6b\x85\x40\x08\x1f\xdf\x26\x25\x3b\x72\x44\xb0\xb8\x21\x2f\xb3"
69 "\xd7\x9b\x24\x30\x78\x26\x44\x07\xc3\x33\xd1\x4d\x03\x1b\xe1\xff"
70 "\xfd\xf5\x50\x8d\xca";
71static const unsigned long lzma_compressed_size = 229;
72
73/* lzop -c /tmp/plain.txt > /tmp/plain.lzo */
74static const char lzo_compressed[] =
75 "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a\x10\x30\x20\x60\x09\x40\x01"
76 "\x05\x03\x00\x00\x09\x00\x00\x81\xb4\x52\x09\x54\xf1\x00\x00\x00"
77 "\x00\x09\x70\x6c\x61\x69\x6e\x2e\x74\x78\x74\x65\xb1\x07\x9c\x00"
78 "\x00\x01\x5e\x00\x00\x01\x0f\xc3\xc7\x7a\xe0\x00\x16\x49\x20\x61"
79 "\x6d\x20\x61\x20\x68\x69\x67\x68\x6c\x79\x20\x63\x6f\x6d\x70\x72"
80 "\x65\x73\x73\x61\x62\x6c\x65\x20\x62\x69\x74\x20\x6f\x66\x20\x74"
81 "\x65\x78\x74\x2e\x0a\x20\x2f\x9c\x00\x00\x22\x54\x68\x65\x72\x65"
82 "\x20\x61\x72\x65\x20\x6d\x61\x6e\x79\x20\x6c\x69\x6b\x65\x20\x6d"
83 "\x65\x2c\x20\x62\x75\x74\x20\x74\x68\x69\x73\x20\x6f\x6e\x65\x20"
84 "\x69\x73\x20\x6d\x69\x6e\x65\x2e\x0a\x49\x66\x20\x49\x20\x77\x84"
85 "\x06\x0a\x6e\x79\x20\x73\x68\x6f\x72\x74\x65\x72\x2c\x20\x74\x90"
86 "\x08\x00\x08\x77\x6f\x75\x6c\x64\x6e\x27\x74\x20\x62\x65\x20\x6d"
87 "\x75\x63\x68\x20\x73\x65\x6e\x73\x65\x20\x69\x6e\x0a\xf8\x19\x02"
88 "\x69\x6e\x67\x20\x6d\x64\x02\x64\x06\x00\x5a\x20\x66\x69\x72\x73"
89 "\x74\x20\x70\x6c\x61\x63\x65\x2e\x20\x41\x74\x20\x6c\x65\x61\x73"
90 "\x74\x20\x77\x69\x74\x68\x20\x6c\x7a\x6f\x2c\x20\x61\x6e\x79\x77"
91 "\x61\x79\x2c\x0a\x77\x68\x69\x63\x68\x20\x61\x70\x70\x65\x61\x72"
92 "\x73\x20\x74\x6f\x20\x62\x65\x68\x61\x76\x65\x20\x70\x6f\x6f\x72"
93 "\x6c\x79\x20\x69\x6e\x20\x74\x68\x65\x20\x66\x61\x63\x65\x20\x6f"
94 "\x66\x20\x73\x68\x6f\x72\x74\x20\x74\x65\x78\x74\x0a\x6d\x65\x73"
95 "\x73\x61\x67\x65\x73\x2e\x0a\x11\x00\x00\x00\x00\x00\x00";
96static const unsigned long lzo_compressed_size = 334;
97
98
99#define TEST_BUFFER_SIZE 512
100
101typedef int (*mutate_func)(void *, unsigned long, void *, unsigned long,
102 unsigned long *);
103
104static int compress_using_gzip(void *in, unsigned long in_size,
105 void *out, unsigned long out_max,
106 unsigned long *out_size)
107{
108 int ret;
109 unsigned long inout_size = out_max;
110
111 ret = gzip(out, &inout_size, in, in_size);
112 if (out_size)
113 *out_size = inout_size;
114
115 return ret;
116}
117
118static int uncompress_using_gzip(void *in, unsigned long in_size,
119 void *out, unsigned long out_max,
120 unsigned long *out_size)
121{
122 int ret;
123 unsigned long inout_size = in_size;
124
125 ret = gunzip(out, out_max, in, &inout_size);
126 if (out_size)
127 *out_size = inout_size;
128
129 return ret;
130}
131
132static int compress_using_bzip2(void *in, unsigned long in_size,
Wolfgang Denkec7fbf52013-10-04 17:43:24 +0200133 void *out, unsigned long out_max,
134 unsigned long *out_size)
Kees Cook5d3bca82013-08-16 07:59:11 -0700135{
136 /* There is no bzip2 compression in u-boot, so fake it. */
137 assert(in_size == strlen(plain));
138 assert(memcmp(plain, in, in_size) == 0);
139
140 if (bzip2_compressed_size > out_max)
141 return -1;
142
143 memcpy(out, bzip2_compressed, bzip2_compressed_size);
144 if (out_size)
145 *out_size = bzip2_compressed_size;
146
147 return 0;
148}
149
150static int uncompress_using_bzip2(void *in, unsigned long in_size,
151 void *out, unsigned long out_max,
152 unsigned long *out_size)
153{
154 int ret;
155 unsigned int inout_size = out_max;
156
157 ret = BZ2_bzBuffToBuffDecompress(out, &inout_size, in, in_size,
158 CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0);
159 if (out_size)
160 *out_size = inout_size;
161
162 return (ret != BZ_OK);
163}
164
165static int compress_using_lzma(void *in, unsigned long in_size,
166 void *out, unsigned long out_max,
167 unsigned long *out_size)
168{
169 /* There is no lzma compression in u-boot, so fake it. */
170 assert(in_size == strlen(plain));
171 assert(memcmp(plain, in, in_size) == 0);
172
173 if (lzma_compressed_size > out_max)
174 return -1;
175
176 memcpy(out, lzma_compressed, lzma_compressed_size);
177 if (out_size)
178 *out_size = lzma_compressed_size;
179
180 return 0;
181}
182
183static int uncompress_using_lzma(void *in, unsigned long in_size,
184 void *out, unsigned long out_max,
185 unsigned long *out_size)
186{
187 int ret;
188 SizeT inout_size = out_max;
189
190 ret = lzmaBuffToBuffDecompress(out, &inout_size, in, in_size);
191 if (out_size)
192 *out_size = inout_size;
193
194 return (ret != SZ_OK);
195}
196
197static int compress_using_lzo(void *in, unsigned long in_size,
198 void *out, unsigned long out_max,
199 unsigned long *out_size)
200{
201 /* There is no lzo compression in u-boot, so fake it. */
202 assert(in_size == strlen(plain));
203 assert(memcmp(plain, in, in_size) == 0);
204
205 if (lzo_compressed_size > out_max)
206 return -1;
207
208 memcpy(out, lzo_compressed, lzo_compressed_size);
209 if (out_size)
210 *out_size = lzo_compressed_size;
211
212 return 0;
213}
214
215static int uncompress_using_lzo(void *in, unsigned long in_size,
216 void *out, unsigned long out_max,
217 unsigned long *out_size)
218{
219 int ret;
220 size_t input_size = in_size;
221 size_t output_size = out_max;
222
223 ret = lzop_decompress(in, input_size, out, &output_size);
224 if (out_size)
225 *out_size = output_size;
226
227 return (ret != LZO_E_OK);
228}
229
230#define errcheck(statement) if (!(statement)) { \
231 fprintf(stderr, "\tFailed: %s\n", #statement); \
232 ret = 1; \
233 goto out; \
234}
235
236static int run_test(char *name, mutate_func compress, mutate_func uncompress)
237{
238 ulong orig_size, compressed_size, uncompressed_size;
239 void *orig_buf;
240 void *compressed_buf = NULL;
241 void *uncompressed_buf = NULL;
242 void *compare_buf = NULL;
243 int ret;
244
245 printf(" testing %s ...\n", name);
246
247 orig_buf = (void *)plain;
248 orig_size = strlen(orig_buf); /* Trailing NULL not included. */
249 errcheck(orig_size > 0);
250
251 compressed_size = uncompressed_size = TEST_BUFFER_SIZE;
252 compressed_buf = malloc(compressed_size);
253 errcheck(compressed_buf != NULL);
254 uncompressed_buf = malloc(uncompressed_size);
255 errcheck(uncompressed_buf != NULL);
256 compare_buf = malloc(uncompressed_size);
257 errcheck(compare_buf != NULL);
258
259 /* Compress works as expected. */
260 printf("\torig_size:%lu\n", orig_size);
261 memset(compressed_buf, 'A', TEST_BUFFER_SIZE);
262 errcheck(compress(orig_buf, orig_size,
263 compressed_buf, compressed_size,
264 &compressed_size) == 0);
265 printf("\tcompressed_size:%lu\n", compressed_size);
266 errcheck(compressed_size > 0);
267 errcheck(compressed_size < orig_size);
268 errcheck(((char *)compressed_buf)[compressed_size-1] != 'A');
269 errcheck(((char *)compressed_buf)[compressed_size] == 'A');
270
271 /* Uncompresses with space remaining. */
272 errcheck(uncompress(compressed_buf, compressed_size,
273 uncompressed_buf, uncompressed_size,
274 &uncompressed_size) == 0);
275 printf("\tuncompressed_size:%lu\n", uncompressed_size);
276 errcheck(uncompressed_size == orig_size);
277 errcheck(memcmp(orig_buf, uncompressed_buf, orig_size) == 0);
278
279 /* Uncompresses with exactly the right size output buffer. */
280 memset(uncompressed_buf, 'A', TEST_BUFFER_SIZE);
281 errcheck(uncompress(compressed_buf, compressed_size,
282 uncompressed_buf, orig_size,
283 &uncompressed_size) == 0);
284 errcheck(uncompressed_size == orig_size);
285 errcheck(memcmp(orig_buf, uncompressed_buf, orig_size) == 0);
286 errcheck(((char *)uncompressed_buf)[orig_size] == 'A');
287
288 /* Make sure compression does not over-run. */
289 memset(compare_buf, 'A', TEST_BUFFER_SIZE);
290 ret = compress(orig_buf, orig_size,
291 compare_buf, compressed_size - 1,
292 NULL);
293 errcheck(((char *)compare_buf)[compressed_size] == 'A');
294 errcheck(ret != 0);
295 printf("\tcompress does not overrun\n");
296
297 /* Make sure decompression does not over-run. */
298 memset(compare_buf, 'A', TEST_BUFFER_SIZE);
299 ret = uncompress(compressed_buf, compressed_size,
300 compare_buf, uncompressed_size - 1,
301 NULL);
302 errcheck(((char *)compare_buf)[uncompressed_size - 1] == 'A');
303 errcheck(ret != 0);
304 printf("\tuncompress does not overrun\n");
305
306 /* Got here, everything is fine. */
307 ret = 0;
308
309out:
310 printf(" %s: %s\n", name, ret == 0 ? "ok" : "FAILED");
311
312 free(compare_buf);
313 free(uncompressed_buf);
314 free(compressed_buf);
315
316 return ret;
317}
318
Simon Glassa36b1902014-12-02 13:17:34 -0700319static int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc,
320 char *const argv[])
Kees Cook5d3bca82013-08-16 07:59:11 -0700321{
322 int err = 0;
323
324 err += run_test("gzip", compress_using_gzip, uncompress_using_gzip);
325 err += run_test("bzip2", compress_using_bzip2, uncompress_using_bzip2);
326 err += run_test("lzma", compress_using_lzma, uncompress_using_lzma);
327 err += run_test("lzo", compress_using_lzo, uncompress_using_lzo);
328
Simon Glassa36b1902014-12-02 13:17:34 -0700329 printf("ut_compression %s\n", err == 0 ? "ok" : "FAILED");
Kees Cook5d3bca82013-08-16 07:59:11 -0700330
331 return err;
332}
333
Simon Glass6d084ce2014-12-02 13:17:35 -0700334static int compress_using_none(void *in, unsigned long in_size,
335 void *out, unsigned long out_max,
336 unsigned long *out_size)
337{
338 /* Here we just copy */
339 memcpy(out, in, in_size);
340 *out_size = in_size;
341
342 return 0;
343}
344
345/**
346 * run_bootm_test() - Run tests on the bootm decopmression function
347 *
348 * @comp_type: Compression type to test
349 * @compress: Our function to compress data
350 * @return 0 if OK, non-zero on failure
351 */
352static int run_bootm_test(int comp_type, mutate_func compress)
353{
354 ulong compress_size = 1024;
355 void *compress_buff;
356 int unc_len;
357 int err = 0;
358 const ulong image_start = 0;
359 const ulong load_addr = 0x1000;
360 ulong load_end;
361
362 printf("Testing: %s\n", genimg_get_comp_name(comp_type));
363 compress_buff = map_sysmem(image_start, 0);
364 unc_len = strlen(plain);
365 compress((void *)plain, unc_len, compress_buff, compress_size,
366 &compress_size);
367 err = bootm_decomp_image(comp_type, load_addr, image_start,
368 IH_TYPE_KERNEL, map_sysmem(load_addr, 0),
369 compress_buff, compress_size, unc_len,
370 &load_end);
371 if (err)
372 return err;
373 err = bootm_decomp_image(comp_type, load_addr, image_start,
374 IH_TYPE_KERNEL, map_sysmem(load_addr, 0),
375 compress_buff, compress_size, unc_len - 1,
376 &load_end);
377 if (!err)
378 return -EINVAL;
379
380 /* We can't detect corruption when not decompressing */
381 if (comp_type == IH_COMP_NONE)
382 return 0;
383 memset(compress_buff + compress_size / 2, '\x49',
384 compress_size / 2);
385 err = bootm_decomp_image(comp_type, load_addr, image_start,
386 IH_TYPE_KERNEL, map_sysmem(load_addr, 0),
387 compress_buff, compress_size, 0x10000,
388 &load_end);
389 if (!err)
390 return -EINVAL;
391
392 return 0;
393}
394
395static int do_ut_image_decomp(cmd_tbl_t *cmdtp, int flag, int argc,
396 char *const argv[])
397{
398 int err = 0;
399
400 err = run_bootm_test(IH_COMP_GZIP, compress_using_gzip);
401 err |= run_bootm_test(IH_COMP_BZIP2, compress_using_bzip2);
402 err |= run_bootm_test(IH_COMP_LZMA, compress_using_lzma);
403 err |= run_bootm_test(IH_COMP_LZO, compress_using_lzo);
404 err |= run_bootm_test(IH_COMP_NONE, compress_using_none);
405
406 printf("ut_image_decomp %s\n", err == 0 ? "ok" : "FAILED");
407
408 return 0;
409}
410
Kees Cook5d3bca82013-08-16 07:59:11 -0700411U_BOOT_CMD(
Simon Glassa36b1902014-12-02 13:17:34 -0700412 ut_compression, 5, 1, do_ut_compression,
Kees Cook5d3bca82013-08-16 07:59:11 -0700413 "Basic test of compressors: gzip bzip2 lzma lzo", ""
414);
Simon Glass6d084ce2014-12-02 13:17:35 -0700415
416U_BOOT_CMD(
417 ut_image_decomp, 5, 1, do_ut_image_decomp,
418 "Basic test of bootm decompression", ""
419);