ARM: atmel: at91sam9n12ek: enable spl support
[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 <asm/io.h>
14
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
24 static 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 */
35 static 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";
51 static const unsigned long bzip2_compressed_size = 240;
52
53 /* lzma -z -c /tmp/plain.txt > /tmp/plain.lzma */
54 static 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";
70 static const unsigned long lzma_compressed_size = 229;
71
72 /* lzop -c /tmp/plain.txt > /tmp/plain.lzo */
73 static 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";
95 static const unsigned long lzo_compressed_size = 334;
96
97
98 #define TEST_BUFFER_SIZE        512
99
100 typedef int (*mutate_func)(void *, unsigned long, void *, unsigned long,
101                            unsigned long *);
102
103 static 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
117 static 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
131 static int compress_using_bzip2(void *in, unsigned long in_size,
132                                 void *out, unsigned long out_max,
133                                 unsigned long *out_size)
134 {
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
149 static 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
164 static 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
182 static 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
196 static 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
214 static 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
235 static 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
308 out:
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
318 static int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc,
319                              char *const argv[])
320 {
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
328         printf("ut_compression %s\n", err == 0 ? "ok" : "FAILED");
329
330         return err;
331 }
332
333 static 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  */
351 static 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
394 static 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
410 U_BOOT_CMD(
411         ut_compression, 5,      1,      do_ut_compression,
412         "Basic test of compressors: gzip bzip2 lzma lzo", ""
413 );
414
415 U_BOOT_CMD(
416         ut_image_decomp,        5,      1, do_ut_image_decomp,
417         "Basic test of bootm decompression", ""
418 );