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