Merge branch 'master' of git://www.denx.de/git/u-boot-imx
[platform/kernel/u-boot.git] / test / compression.c
1 /*
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>
10 #include <bootm.h>
11 #include <command.h>
12 #include <malloc.h>
13 #include <mapmem.h>
14 #include <asm/io.h>
15
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
25 static 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 */
36 static 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";
52 static const unsigned long bzip2_compressed_size = 240;
53
54 /* lzma -z -c /tmp/plain.txt > /tmp/plain.lzma */
55 static 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";
71 static const unsigned long lzma_compressed_size = 229;
72
73 /* lzop -c /tmp/plain.txt > /tmp/plain.lzo */
74 static 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";
96 static const unsigned long lzo_compressed_size = 334;
97
98 /* lz4 -z /tmp/plain.txt > /tmp/plain.lz4 */
99 static const char lz4_compressed[] =
100         "\x04\x22\x4d\x18\x64\x70\xb9\x01\x01\x00\x00\xff\x19\x49\x20\x61"
101         "\x6d\x20\x61\x20\x68\x69\x67\x68\x6c\x79\x20\x63\x6f\x6d\x70\x72"
102         "\x65\x73\x73\x61\x62\x6c\x65\x20\x62\x69\x74\x20\x6f\x66\x20\x74"
103         "\x65\x78\x74\x2e\x0a\x28\x00\x3d\xf1\x25\x54\x68\x65\x72\x65\x20"
104         "\x61\x72\x65\x20\x6d\x61\x6e\x79\x20\x6c\x69\x6b\x65\x20\x6d\x65"
105         "\x2c\x20\x62\x75\x74\x20\x74\x68\x69\x73\x20\x6f\x6e\x65\x20\x69"
106         "\x73\x20\x6d\x69\x6e\x65\x2e\x0a\x49\x66\x20\x49\x20\x77\x32\x00"
107         "\xd1\x6e\x79\x20\x73\x68\x6f\x72\x74\x65\x72\x2c\x20\x74\x45\x00"
108         "\xf4\x0b\x77\x6f\x75\x6c\x64\x6e\x27\x74\x20\x62\x65\x20\x6d\x75"
109         "\x63\x68\x20\x73\x65\x6e\x73\x65\x20\x69\x6e\x0a\xcf\x00\x50\x69"
110         "\x6e\x67\x20\x6d\x12\x00\x00\x32\x00\xf0\x11\x20\x66\x69\x72\x73"
111         "\x74\x20\x70\x6c\x61\x63\x65\x2e\x20\x41\x74\x20\x6c\x65\x61\x73"
112         "\x74\x20\x77\x69\x74\x68\x20\x6c\x7a\x6f\x2c\x63\x00\xf5\x14\x77"
113         "\x61\x79\x2c\x0a\x77\x68\x69\x63\x68\x20\x61\x70\x70\x65\x61\x72"
114         "\x73\x20\x74\x6f\x20\x62\x65\x68\x61\x76\x65\x20\x70\x6f\x6f\x72"
115         "\x6c\x79\x4e\x00\x30\x61\x63\x65\x27\x01\x01\x95\x00\x01\x2d\x01"
116         "\xb0\x0a\x6d\x65\x73\x73\x61\x67\x65\x73\x2e\x0a\x00\x00\x00\x00"
117         "\x9d\x12\x8c\x9d";
118 static const unsigned long lz4_compressed_size = 276;
119
120
121 #define TEST_BUFFER_SIZE        512
122
123 typedef int (*mutate_func)(void *, unsigned long, void *, unsigned long,
124                            unsigned long *);
125
126 static int compress_using_gzip(void *in, unsigned long in_size,
127                                void *out, unsigned long out_max,
128                                unsigned long *out_size)
129 {
130         int ret;
131         unsigned long inout_size = out_max;
132
133         ret = gzip(out, &inout_size, in, in_size);
134         if (out_size)
135                 *out_size = inout_size;
136
137         return ret;
138 }
139
140 static int uncompress_using_gzip(void *in, unsigned long in_size,
141                                  void *out, unsigned long out_max,
142                                  unsigned long *out_size)
143 {
144         int ret;
145         unsigned long inout_size = in_size;
146
147         ret = gunzip(out, out_max, in, &inout_size);
148         if (out_size)
149                 *out_size = inout_size;
150
151         return ret;
152 }
153
154 static int compress_using_bzip2(void *in, unsigned long in_size,
155                                 void *out, unsigned long out_max,
156                                 unsigned long *out_size)
157 {
158         /* There is no bzip2 compression in u-boot, so fake it. */
159         assert(in_size == strlen(plain));
160         assert(memcmp(plain, in, in_size) == 0);
161
162         if (bzip2_compressed_size > out_max)
163                 return -1;
164
165         memcpy(out, bzip2_compressed, bzip2_compressed_size);
166         if (out_size)
167                 *out_size = bzip2_compressed_size;
168
169         return 0;
170 }
171
172 static int uncompress_using_bzip2(void *in, unsigned long in_size,
173                                   void *out, unsigned long out_max,
174                                   unsigned long *out_size)
175 {
176         int ret;
177         unsigned int inout_size = out_max;
178
179         ret = BZ2_bzBuffToBuffDecompress(out, &inout_size, in, in_size,
180                         CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0);
181         if (out_size)
182                 *out_size = inout_size;
183
184         return (ret != BZ_OK);
185 }
186
187 static int compress_using_lzma(void *in, unsigned long in_size,
188                                void *out, unsigned long out_max,
189                                unsigned long *out_size)
190 {
191         /* There is no lzma compression in u-boot, so fake it. */
192         assert(in_size == strlen(plain));
193         assert(memcmp(plain, in, in_size) == 0);
194
195         if (lzma_compressed_size > out_max)
196                 return -1;
197
198         memcpy(out, lzma_compressed, lzma_compressed_size);
199         if (out_size)
200                 *out_size = lzma_compressed_size;
201
202         return 0;
203 }
204
205 static int uncompress_using_lzma(void *in, unsigned long in_size,
206                                  void *out, unsigned long out_max,
207                                  unsigned long *out_size)
208 {
209         int ret;
210         SizeT inout_size = out_max;
211
212         ret = lzmaBuffToBuffDecompress(out, &inout_size, in, in_size);
213         if (out_size)
214                 *out_size = inout_size;
215
216         return (ret != SZ_OK);
217 }
218
219 static int compress_using_lzo(void *in, unsigned long in_size,
220                               void *out, unsigned long out_max,
221                               unsigned long *out_size)
222 {
223         /* There is no lzo compression in u-boot, so fake it. */
224         assert(in_size == strlen(plain));
225         assert(memcmp(plain, in, in_size) == 0);
226
227         if (lzo_compressed_size > out_max)
228                 return -1;
229
230         memcpy(out, lzo_compressed, lzo_compressed_size);
231         if (out_size)
232                 *out_size = lzo_compressed_size;
233
234         return 0;
235 }
236
237 static int uncompress_using_lzo(void *in, unsigned long in_size,
238                                 void *out, unsigned long out_max,
239                                 unsigned long *out_size)
240 {
241         int ret;
242         size_t input_size = in_size;
243         size_t output_size = out_max;
244
245         ret = lzop_decompress(in, input_size, out, &output_size);
246         if (out_size)
247                 *out_size = output_size;
248
249         return (ret != LZO_E_OK);
250 }
251
252 static int compress_using_lz4(void *in, unsigned long in_size,
253                               void *out, unsigned long out_max,
254                               unsigned long *out_size)
255 {
256         /* There is no lz4 compression in u-boot, so fake it. */
257         assert(in_size == strlen(plain));
258         assert(memcmp(plain, in, in_size) == 0);
259
260         if (lz4_compressed_size > out_max)
261                 return -1;
262
263         memcpy(out, lz4_compressed, lz4_compressed_size);
264         if (out_size)
265                 *out_size = lz4_compressed_size;
266
267         return 0;
268 }
269
270 static int uncompress_using_lz4(void *in, unsigned long in_size,
271                                 void *out, unsigned long out_max,
272                                 unsigned long *out_size)
273 {
274         int ret;
275         size_t input_size = in_size;
276         size_t output_size = out_max;
277
278         ret = ulz4fn(in, input_size, out, &output_size);
279         if (out_size)
280                 *out_size = output_size;
281
282         return (ret != 0);
283 }
284
285 #define errcheck(statement) if (!(statement)) { \
286         fprintf(stderr, "\tFailed: %s\n", #statement); \
287         ret = 1; \
288         goto out; \
289 }
290
291 static int run_test(char *name, mutate_func compress, mutate_func uncompress)
292 {
293         ulong orig_size, compressed_size, uncompressed_size;
294         void *orig_buf;
295         void *compressed_buf = NULL;
296         void *uncompressed_buf = NULL;
297         void *compare_buf = NULL;
298         int ret;
299
300         printf(" testing %s ...\n", name);
301
302         orig_buf = (void *)plain;
303         orig_size = strlen(orig_buf); /* Trailing NULL not included. */
304         errcheck(orig_size > 0);
305
306         compressed_size = uncompressed_size = TEST_BUFFER_SIZE;
307         compressed_buf = malloc(compressed_size);
308         errcheck(compressed_buf != NULL);
309         uncompressed_buf = malloc(uncompressed_size);
310         errcheck(uncompressed_buf != NULL);
311         compare_buf = malloc(uncompressed_size);
312         errcheck(compare_buf != NULL);
313
314         /* Compress works as expected. */
315         printf("\torig_size:%lu\n", orig_size);
316         memset(compressed_buf, 'A', TEST_BUFFER_SIZE);
317         errcheck(compress(orig_buf, orig_size,
318                         compressed_buf, compressed_size,
319                         &compressed_size) == 0);
320         printf("\tcompressed_size:%lu\n", compressed_size);
321         errcheck(compressed_size > 0);
322         errcheck(compressed_size < orig_size);
323         errcheck(((char *)compressed_buf)[compressed_size-1] != 'A');
324         errcheck(((char *)compressed_buf)[compressed_size] == 'A');
325
326         /* Uncompresses with space remaining. */
327         errcheck(uncompress(compressed_buf, compressed_size,
328                           uncompressed_buf, uncompressed_size,
329                           &uncompressed_size) == 0);
330         printf("\tuncompressed_size:%lu\n", uncompressed_size);
331         errcheck(uncompressed_size == orig_size);
332         errcheck(memcmp(orig_buf, uncompressed_buf, orig_size) == 0);
333
334         /* Uncompresses with exactly the right size output buffer. */
335         memset(uncompressed_buf, 'A', TEST_BUFFER_SIZE);
336         errcheck(uncompress(compressed_buf, compressed_size,
337                           uncompressed_buf, orig_size,
338                           &uncompressed_size) == 0);
339         errcheck(uncompressed_size == orig_size);
340         errcheck(memcmp(orig_buf, uncompressed_buf, orig_size) == 0);
341         errcheck(((char *)uncompressed_buf)[orig_size] == 'A');
342
343         /* Make sure compression does not over-run. */
344         memset(compare_buf, 'A', TEST_BUFFER_SIZE);
345         ret = compress(orig_buf, orig_size,
346                        compare_buf, compressed_size - 1,
347                        NULL);
348         errcheck(((char *)compare_buf)[compressed_size] == 'A');
349         errcheck(ret != 0);
350         printf("\tcompress does not overrun\n");
351
352         /* Make sure decompression does not over-run. */
353         memset(compare_buf, 'A', TEST_BUFFER_SIZE);
354         ret = uncompress(compressed_buf, compressed_size,
355                          compare_buf, uncompressed_size - 1,
356                          NULL);
357         errcheck(((char *)compare_buf)[uncompressed_size - 1] == 'A');
358         errcheck(ret != 0);
359         printf("\tuncompress does not overrun\n");
360
361         /* Got here, everything is fine. */
362         ret = 0;
363
364 out:
365         printf(" %s: %s\n", name, ret == 0 ? "ok" : "FAILED");
366
367         free(compare_buf);
368         free(uncompressed_buf);
369         free(compressed_buf);
370
371         return ret;
372 }
373
374 static int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc,
375                              char *const argv[])
376 {
377         int err = 0;
378
379         err += run_test("gzip", compress_using_gzip, uncompress_using_gzip);
380         err += run_test("bzip2", compress_using_bzip2, uncompress_using_bzip2);
381         err += run_test("lzma", compress_using_lzma, uncompress_using_lzma);
382         err += run_test("lzo", compress_using_lzo, uncompress_using_lzo);
383         err += run_test("lz4", compress_using_lz4, uncompress_using_lz4);
384
385         printf("ut_compression %s\n", err == 0 ? "ok" : "FAILED");
386
387         return err;
388 }
389
390 static int compress_using_none(void *in, unsigned long in_size,
391                                void *out, unsigned long out_max,
392                                unsigned long *out_size)
393 {
394         /* Here we just copy */
395         memcpy(out, in, in_size);
396         *out_size = in_size;
397
398         return 0;
399 }
400
401 /**
402  * run_bootm_test() - Run tests on the bootm decopmression function
403  *
404  * @comp_type:  Compression type to test
405  * @compress:   Our function to compress data
406  * @return 0 if OK, non-zero on failure
407  */
408 static int run_bootm_test(int comp_type, mutate_func compress)
409 {
410         ulong compress_size = 1024;
411         void *compress_buff;
412         int unc_len;
413         int err = 0;
414         const ulong image_start = 0;
415         const ulong load_addr = 0x1000;
416         ulong load_end;
417
418         printf("Testing: %s\n", genimg_get_comp_name(comp_type));
419         compress_buff = map_sysmem(image_start, 0);
420         unc_len = strlen(plain);
421         compress((void *)plain, unc_len, compress_buff, compress_size,
422                  &compress_size);
423         err = bootm_decomp_image(comp_type, load_addr, image_start,
424                                  IH_TYPE_KERNEL, map_sysmem(load_addr, 0),
425                                  compress_buff, compress_size, unc_len,
426                                  &load_end);
427         if (err)
428                 return err;
429         err = bootm_decomp_image(comp_type, load_addr, image_start,
430                                  IH_TYPE_KERNEL, map_sysmem(load_addr, 0),
431                                  compress_buff, compress_size, unc_len - 1,
432                                  &load_end);
433         if (!err)
434                 return -EINVAL;
435
436         /* We can't detect corruption when not decompressing */
437         if (comp_type == IH_COMP_NONE)
438                 return 0;
439         memset(compress_buff + compress_size / 2, '\x49',
440                compress_size / 2);
441         err = bootm_decomp_image(comp_type, load_addr, image_start,
442                                  IH_TYPE_KERNEL, map_sysmem(load_addr, 0),
443                                  compress_buff, compress_size, 0x10000,
444                                  &load_end);
445         if (!err)
446                 return -EINVAL;
447
448         return 0;
449 }
450
451 static int do_ut_image_decomp(cmd_tbl_t *cmdtp, int flag, int argc,
452                               char *const argv[])
453 {
454         int err = 0;
455
456         err = run_bootm_test(IH_COMP_GZIP, compress_using_gzip);
457         err |= run_bootm_test(IH_COMP_BZIP2, compress_using_bzip2);
458         err |= run_bootm_test(IH_COMP_LZMA, compress_using_lzma);
459         err |= run_bootm_test(IH_COMP_LZO, compress_using_lzo);
460         err |= run_bootm_test(IH_COMP_LZ4, compress_using_lz4);
461         err |= run_bootm_test(IH_COMP_NONE, compress_using_none);
462
463         printf("ut_image_decomp %s\n", err == 0 ? "ok" : "FAILED");
464
465         return 0;
466 }
467
468 U_BOOT_CMD(
469         ut_compression, 5,      1,      do_ut_compression,
470         "Basic test of compressors: gzip bzip2 lzma lzo", ""
471 );
472
473 U_BOOT_CMD(
474         ut_image_decomp,        5,      1, do_ut_image_decomp,
475         "Basic test of bootm decompression", ""
476 );