1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2013, The Chromium Authors
4  */
5 
6 #include <common.h>
7 #include <abuf.h>
8 #include <bootm.h>
9 #include <command.h>
10 #include <gzip.h>
11 #include <image.h>
12 #include <log.h>
13 #include <malloc.h>
14 #include <mapmem.h>
15 #include <asm/io.h>
16 
17 #include <u-boot/lz4.h>
18 #include <u-boot/zlib.h>
19 #include <bzlib.h>
20 
21 #include <lzma/LzmaTypes.h>
22 #include <lzma/LzmaDec.h>
23 #include <lzma/LzmaTools.h>
24 
25 #include <linux/lzo.h>
26 #include <linux/zstd.h>
27 #include <test/compression.h>
28 #include <test/suites.h>
29 #include <test/ut.h>
30 
31 static const char plain[] =
32 	"I am a highly compressable bit of text.\n"
33 	"I am a highly compressable bit of text.\n"
34 	"I am a highly compressable bit of text.\n"
35 	"There are many like me, but this one is mine.\n"
36 	"If I were any shorter, there wouldn't be much sense in\n"
37 	"compressing me in the first place. At least with lzo, anyway,\n"
38 	"which appears to behave poorly in the face of short text\n"
39 	"messages.\n";
40 
41 /* bzip2 -c /tmp/plain.txt > /tmp/plain.bz2 */
42 static const char bzip2_compressed[] =
43 	"\x42\x5a\x68\x39\x31\x41\x59\x26\x53\x59\xe5\x63\xdd\x09\x00\x00"
44 	"\x28\x57\x80\x00\x10\x40\x85\x20\x20\x04\x00\x3f\xef\xdf\xf0\x30"
45 	"\x00\xd6\xd0\x34\x91\x89\xa6\xf5\x4d\x19\x1a\x19\x0d\x02\x34\xd4"
46 	"\xc9\x00\x34\x34\x00\x02\x48\x41\x35\x4f\xd4\xc6\x88\xd3\x50\x3d"
47 	"\x4f\x51\x82\x4f\x88\xc3\x0d\x05\x62\x4f\x91\xa3\x52\x1b\xd0\x52"
48 	"\x41\x4a\xa3\x98\xc2\x6b\xca\xa3\x82\xa5\xac\x8b\x15\x99\x68\xad"
49 	"\xdf\x29\xd6\xf1\xf7\x5a\x10\xcd\x8c\x26\x61\x94\x95\xfe\x9e\x16"
50 	"\x18\x28\x69\xd4\x23\x64\xcc\x2b\xe5\xe8\x5f\x00\xa4\x70\x26\x2c"
51 	"\xee\xbd\x59\x6d\x6a\xec\xfc\x31\xda\x59\x0a\x14\x2a\x60\x1c\xf0"
52 	"\x04\x86\x73\x9a\xc5\x5b\x87\x3f\x5b\x4c\x93\xe6\xb5\x35\x0d\xa6"
53 	"\xb1\x2e\x62\x7b\xab\x67\xe7\x99\x2a\x14\x5e\x9f\x64\xcb\x96\xf4"
54 	"\x0d\x65\xd4\x39\xe6\x8b\x7e\xea\x1c\x03\x69\x97\x83\x58\x91\x96"
55 	"\xe1\xf0\x9d\xa4\x15\x8b\xb8\xc6\x93\xdc\x3d\xd9\x3c\x22\x55\xef"
56 	"\xfb\xbb\x2a\xd3\x87\xa2\x8b\x04\xd9\x19\xf8\xe2\xfd\x4f\xdb\x1a"
57 	"\x07\xc8\x60\xa3\x3f\xf8\xbb\x92\x29\xc2\x84\x87\x2b\x1e\xe8\x48";
58 static const unsigned long bzip2_compressed_size = sizeof(bzip2_compressed) - 1;
59 
60 /* lzma -z -c /tmp/plain.txt > /tmp/plain.lzma */
61 static const char lzma_compressed[] =
62 	"\x5d\x00\x00\x80\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x24\x88"
63 	"\x08\x26\xd8\x41\xff\x99\xc8\xcf\x66\x3d\x80\xac\xba\x17\xf1\xc8"
64 	"\xb9\xdf\x49\x37\xb1\x68\xa0\x2a\xdd\x63\xd1\xa7\xa3\x66\xf8\x15"
65 	"\xef\xa6\x67\x8a\x14\x18\x80\xcb\xc7\xb1\xcb\x84\x6a\xb2\x51\x16"
66 	"\xa1\x45\xa0\xd6\x3e\x55\x44\x8a\x5c\xa0\x7c\xe5\xa8\xbd\x04\x57"
67 	"\x8f\x24\xfd\xb9\x34\x50\x83\x2f\xf3\x46\x3e\xb9\xb0\x00\x1a\xf5"
68 	"\xd3\x86\x7e\x8f\x77\xd1\x5d\x0e\x7c\xe1\xac\xde\xf8\x65\x1f\x4d"
69 	"\xce\x7f\xa7\x3d\xaa\xcf\x26\xa7\x58\x69\x1e\x4c\xea\x68\x8a\xe5"
70 	"\x89\xd1\xdc\x4d\xc7\xe0\x07\x42\xbf\x0c\x9d\x06\xd7\x51\xa2\x0b"
71 	"\x7c\x83\x35\xe1\x85\xdf\xee\xfb\xa3\xee\x2f\x47\x5f\x8b\x70\x2b"
72 	"\xe1\x37\xf3\x16\xf6\x27\x54\x8a\x33\x72\x49\xea\x53\x7d\x60\x0b"
73 	"\x21\x90\x66\xe7\x9e\x56\x61\x5d\xd8\xdc\x59\xf0\xac\x2f\xd6\x49"
74 	"\x6b\x85\x40\x08\x1f\xdf\x26\x25\x3b\x72\x44\xb0\xb8\x21\x2f\xb3"
75 	"\xd7\x9b\x24\x30\x78\x26\x44\x07\xc3\x33\xd1\x4d\x03\x1b\xe1\xff"
76 	"\xfd\xf5\x50\x8d\xca";
77 static const unsigned long lzma_compressed_size = sizeof(lzma_compressed) - 1;
78 
79 /* lzop -c /tmp/plain.txt > /tmp/plain.lzo */
80 static const char lzo_compressed[] =
81 	"\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a\x10\x30\x20\x60\x09\x40\x01"
82 	"\x05\x03\x00\x00\x09\x00\x00\x81\xb4\x52\x09\x54\xf1\x00\x00\x00"
83 	"\x00\x09\x70\x6c\x61\x69\x6e\x2e\x74\x78\x74\x65\xb1\x07\x9c\x00"
84 	"\x00\x01\x5e\x00\x00\x01\x0f\xc3\xc7\x7a\xe0\x00\x16\x49\x20\x61"
85 	"\x6d\x20\x61\x20\x68\x69\x67\x68\x6c\x79\x20\x63\x6f\x6d\x70\x72"
86 	"\x65\x73\x73\x61\x62\x6c\x65\x20\x62\x69\x74\x20\x6f\x66\x20\x74"
87 	"\x65\x78\x74\x2e\x0a\x20\x2f\x9c\x00\x00\x22\x54\x68\x65\x72\x65"
88 	"\x20\x61\x72\x65\x20\x6d\x61\x6e\x79\x20\x6c\x69\x6b\x65\x20\x6d"
89 	"\x65\x2c\x20\x62\x75\x74\x20\x74\x68\x69\x73\x20\x6f\x6e\x65\x20"
90 	"\x69\x73\x20\x6d\x69\x6e\x65\x2e\x0a\x49\x66\x20\x49\x20\x77\x84"
91 	"\x06\x0a\x6e\x79\x20\x73\x68\x6f\x72\x74\x65\x72\x2c\x20\x74\x90"
92 	"\x08\x00\x08\x77\x6f\x75\x6c\x64\x6e\x27\x74\x20\x62\x65\x20\x6d"
93 	"\x75\x63\x68\x20\x73\x65\x6e\x73\x65\x20\x69\x6e\x0a\xf8\x19\x02"
94 	"\x69\x6e\x67\x20\x6d\x64\x02\x64\x06\x00\x5a\x20\x66\x69\x72\x73"
95 	"\x74\x20\x70\x6c\x61\x63\x65\x2e\x20\x41\x74\x20\x6c\x65\x61\x73"
96 	"\x74\x20\x77\x69\x74\x68\x20\x6c\x7a\x6f\x2c\x20\x61\x6e\x79\x77"
97 	"\x61\x79\x2c\x0a\x77\x68\x69\x63\x68\x20\x61\x70\x70\x65\x61\x72"
98 	"\x73\x20\x74\x6f\x20\x62\x65\x68\x61\x76\x65\x20\x70\x6f\x6f\x72"
99 	"\x6c\x79\x20\x69\x6e\x20\x74\x68\x65\x20\x66\x61\x63\x65\x20\x6f"
100 	"\x66\x20\x73\x68\x6f\x72\x74\x20\x74\x65\x78\x74\x0a\x6d\x65\x73"
101 	"\x73\x61\x67\x65\x73\x2e\x0a\x11\x00\x00\x00\x00\x00\x00";
102 static const unsigned long lzo_compressed_size = sizeof(lzo_compressed) - 1;
103 
104 /* lz4 -z /tmp/plain.txt > /tmp/plain.lz4 */
105 static const char lz4_compressed[] =
106 	"\x04\x22\x4d\x18\x64\x70\xb9\x01\x01\x00\x00\xff\x19\x49\x20\x61"
107 	"\x6d\x20\x61\x20\x68\x69\x67\x68\x6c\x79\x20\x63\x6f\x6d\x70\x72"
108 	"\x65\x73\x73\x61\x62\x6c\x65\x20\x62\x69\x74\x20\x6f\x66\x20\x74"
109 	"\x65\x78\x74\x2e\x0a\x28\x00\x3d\xf1\x25\x54\x68\x65\x72\x65\x20"
110 	"\x61\x72\x65\x20\x6d\x61\x6e\x79\x20\x6c\x69\x6b\x65\x20\x6d\x65"
111 	"\x2c\x20\x62\x75\x74\x20\x74\x68\x69\x73\x20\x6f\x6e\x65\x20\x69"
112 	"\x73\x20\x6d\x69\x6e\x65\x2e\x0a\x49\x66\x20\x49\x20\x77\x32\x00"
113 	"\xd1\x6e\x79\x20\x73\x68\x6f\x72\x74\x65\x72\x2c\x20\x74\x45\x00"
114 	"\xf4\x0b\x77\x6f\x75\x6c\x64\x6e\x27\x74\x20\x62\x65\x20\x6d\x75"
115 	"\x63\x68\x20\x73\x65\x6e\x73\x65\x20\x69\x6e\x0a\xcf\x00\x50\x69"
116 	"\x6e\x67\x20\x6d\x12\x00\x00\x32\x00\xf0\x11\x20\x66\x69\x72\x73"
117 	"\x74\x20\x70\x6c\x61\x63\x65\x2e\x20\x41\x74\x20\x6c\x65\x61\x73"
118 	"\x74\x20\x77\x69\x74\x68\x20\x6c\x7a\x6f\x2c\x63\x00\xf5\x14\x77"
119 	"\x61\x79\x2c\x0a\x77\x68\x69\x63\x68\x20\x61\x70\x70\x65\x61\x72"
120 	"\x73\x20\x74\x6f\x20\x62\x65\x68\x61\x76\x65\x20\x70\x6f\x6f\x72"
121 	"\x6c\x79\x4e\x00\x30\x61\x63\x65\x27\x01\x01\x95\x00\x01\x2d\x01"
122 	"\xb0\x0a\x6d\x65\x73\x73\x61\x67\x65\x73\x2e\x0a\x00\x00\x00\x00"
123 	"\x9d\x12\x8c\x9d";
124 static const unsigned long lz4_compressed_size = sizeof(lz4_compressed) - 1;
125 
126 /* zstd -19 -c /tmp/plain.txt > /tmp/plain.zst */
127 static const char zstd_compressed[] =
128 	"\x28\xb5\x2f\xfd\x64\x5e\x00\xbd\x05\x00\x02\x0e\x26\x1a\x70\x17"
129 	"\xb8\x0d\x0c\x53\x5c\x9d\x97\xee\xa0\x5d\x84\x89\x3f\x5c\x7a\x78"
130 	"\x00\x80\x80\x0f\xe8\xdf\xaf\x06\x66\xd0\x23\xa6\x7a\x64\x8e\xf4"
131 	"\x0d\x5b\x47\x65\x26\x7e\x81\xdd\x0b\xe7\x5a\x95\x3d\x49\xcc\x67"
132 	"\xe0\x2d\x46\x58\xb6\xac\x64\x16\xf2\xe0\xf8\x16\x17\xaf\xda\x8f"
133 	"\x37\xc0\xc3\x0d\x3b\x89\x57\x15\x1e\x46\x46\x12\x9a\x84\xbe\xa6"
134 	"\xab\xcf\x50\x90\x5f\x78\x01\xd2\xc0\x51\x72\x59\x0b\xea\xab\xf2"
135 	"\xd4\x2b\x2d\x26\x7c\x10\x66\x78\x42\x64\x45\x3f\xa5\x15\x6f\xbd"
136 	"\x4a\x61\xe1\xc8\x27\xc0\xe3\x95\x0c\xf9\xca\x7c\xf5\x13\x30\xc3"
137 	"\x1a\x7c\x7d\xa4\x17\x0b\xff\x14\xa6\x7a\x95\xa0\x34\xbc\xce\x21"
138 	"\x78\x36\x23\x33\x11\x09\x00\x60\x13\x00\x63\xa3\x8e\x28\x94\x55"
139 	"\x15\xb6\x26\x68\x05\x4f\x23\x12\xee\x53\x55\x2d\x44\x2f\x54\x95"
140 	"\x01\xe4\xf4\x6e\xfa";
141 static const unsigned long zstd_compressed_size = sizeof(zstd_compressed) - 1;
142 
143 
144 #define TEST_BUFFER_SIZE	512
145 
146 typedef int (*mutate_func)(struct unit_test_state *uts, void *, unsigned long,
147 			   void *, unsigned long, unsigned long *);
148 
compress_using_gzip(struct unit_test_state * uts,void * in,unsigned long in_size,void * out,unsigned long out_max,unsigned long * out_size)149 static int compress_using_gzip(struct unit_test_state *uts,
150 			       void *in, unsigned long in_size,
151 			       void *out, unsigned long out_max,
152 			       unsigned long *out_size)
153 {
154 	int ret;
155 	unsigned long inout_size = out_max;
156 
157 	ret = gzip(out, &inout_size, in, in_size);
158 	if (out_size)
159 		*out_size = inout_size;
160 
161 	return ret;
162 }
163 
uncompress_using_gzip(struct unit_test_state * uts,void * in,unsigned long in_size,void * out,unsigned long out_max,unsigned long * out_size)164 static int uncompress_using_gzip(struct unit_test_state *uts,
165 				 void *in, unsigned long in_size,
166 				 void *out, unsigned long out_max,
167 				 unsigned long *out_size)
168 {
169 	int ret;
170 	unsigned long inout_size = in_size;
171 
172 	ret = gunzip(out, out_max, in, &inout_size);
173 	if (out_size)
174 		*out_size = inout_size;
175 
176 	return ret;
177 }
178 
compress_using_bzip2(struct unit_test_state * uts,void * in,unsigned long in_size,void * out,unsigned long out_max,unsigned long * out_size)179 static int compress_using_bzip2(struct unit_test_state *uts,
180 				void *in, unsigned long in_size,
181 				void *out, unsigned long out_max,
182 				unsigned long *out_size)
183 {
184 	/* There is no bzip2 compression in u-boot, so fake it. */
185 	ut_asserteq(in_size, strlen(plain));
186 	ut_asserteq_mem(plain, in, in_size);
187 
188 	if (bzip2_compressed_size > out_max)
189 		return -1;
190 
191 	memcpy(out, bzip2_compressed, bzip2_compressed_size);
192 	if (out_size)
193 		*out_size = bzip2_compressed_size;
194 
195 	return 0;
196 }
197 
uncompress_using_bzip2(struct unit_test_state * uts,void * in,unsigned long in_size,void * out,unsigned long out_max,unsigned long * out_size)198 static int uncompress_using_bzip2(struct unit_test_state *uts,
199 				  void *in, unsigned long in_size,
200 				  void *out, unsigned long out_max,
201 				  unsigned long *out_size)
202 {
203 	int ret;
204 	unsigned int inout_size = out_max;
205 
206 	ret = BZ2_bzBuffToBuffDecompress(out, &inout_size, in, in_size,
207 			CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0);
208 	if (out_size)
209 		*out_size = inout_size;
210 
211 	return (ret != BZ_OK);
212 }
213 
compress_using_lzma(struct unit_test_state * uts,void * in,unsigned long in_size,void * out,unsigned long out_max,unsigned long * out_size)214 static int compress_using_lzma(struct unit_test_state *uts,
215 			       void *in, unsigned long in_size,
216 			       void *out, unsigned long out_max,
217 			       unsigned long *out_size)
218 {
219 	/* There is no lzma compression in u-boot, so fake it. */
220 	ut_asserteq(in_size,  strlen(plain));
221 	ut_asserteq_mem(plain, in, in_size);
222 
223 	if (lzma_compressed_size > out_max)
224 		return -1;
225 
226 	memcpy(out, lzma_compressed, lzma_compressed_size);
227 	if (out_size)
228 		*out_size = lzma_compressed_size;
229 
230 	return 0;
231 }
232 
uncompress_using_lzma(struct unit_test_state * uts,void * in,unsigned long in_size,void * out,unsigned long out_max,unsigned long * out_size)233 static int uncompress_using_lzma(struct unit_test_state *uts,
234 				 void *in, unsigned long in_size,
235 				 void *out, unsigned long out_max,
236 				 unsigned long *out_size)
237 {
238 	int ret;
239 	SizeT inout_size = out_max;
240 
241 	ret = lzmaBuffToBuffDecompress(out, &inout_size, in, in_size);
242 	if (out_size)
243 		*out_size = inout_size;
244 
245 	return (ret != SZ_OK);
246 }
247 
compress_using_lzo(struct unit_test_state * uts,void * in,unsigned long in_size,void * out,unsigned long out_max,unsigned long * out_size)248 static int compress_using_lzo(struct unit_test_state *uts,
249 			      void *in, unsigned long in_size,
250 			      void *out, unsigned long out_max,
251 			      unsigned long *out_size)
252 {
253 	/* There is no lzo compression in u-boot, so fake it. */
254 	ut_asserteq(in_size,  strlen(plain));
255 	ut_asserteq_mem(plain, in, in_size);
256 
257 	if (lzo_compressed_size > out_max)
258 		return -1;
259 
260 	memcpy(out, lzo_compressed, lzo_compressed_size);
261 	if (out_size)
262 		*out_size = lzo_compressed_size;
263 
264 	return 0;
265 }
266 
uncompress_using_lzo(struct unit_test_state * uts,void * in,unsigned long in_size,void * out,unsigned long out_max,unsigned long * out_size)267 static int uncompress_using_lzo(struct unit_test_state *uts,
268 				void *in, unsigned long in_size,
269 				void *out, unsigned long out_max,
270 				unsigned long *out_size)
271 {
272 	int ret;
273 	size_t input_size = in_size;
274 	size_t output_size = out_max;
275 
276 	ret = lzop_decompress(in, input_size, out, &output_size);
277 	if (out_size)
278 		*out_size = output_size;
279 
280 	return (ret != LZO_E_OK);
281 }
282 
compress_using_lz4(struct unit_test_state * uts,void * in,unsigned long in_size,void * out,unsigned long out_max,unsigned long * out_size)283 static int compress_using_lz4(struct unit_test_state *uts,
284 			      void *in, unsigned long in_size,
285 			      void *out, unsigned long out_max,
286 			      unsigned long *out_size)
287 {
288 	/* There is no lz4 compression in u-boot, so fake it. */
289 	ut_asserteq(in_size,  strlen(plain));
290 	ut_asserteq_mem(plain, in, in_size);
291 
292 	if (lz4_compressed_size > out_max)
293 		return -1;
294 
295 	memcpy(out, lz4_compressed, lz4_compressed_size);
296 	if (out_size)
297 		*out_size = lz4_compressed_size;
298 
299 	return 0;
300 }
301 
uncompress_using_lz4(struct unit_test_state * uts,void * in,unsigned long in_size,void * out,unsigned long out_max,unsigned long * out_size)302 static int uncompress_using_lz4(struct unit_test_state *uts,
303 				void *in, unsigned long in_size,
304 				void *out, unsigned long out_max,
305 				unsigned long *out_size)
306 {
307 	int ret;
308 	size_t input_size = in_size;
309 	size_t output_size = out_max;
310 
311 	ret = ulz4fn(in, input_size, out, &output_size);
312 	if (out_size)
313 		*out_size = output_size;
314 
315 	return (ret != 0);
316 }
317 
compress_using_zstd(struct unit_test_state * uts,void * in,unsigned long in_size,void * out,unsigned long out_max,unsigned long * out_size)318 static int compress_using_zstd(struct unit_test_state *uts,
319 			       void *in, unsigned long in_size,
320 			       void *out, unsigned long out_max,
321 			       unsigned long *out_size)
322 {
323 	/* There is no zstd compression in u-boot, so fake it. */
324 	ut_asserteq(in_size, strlen(plain));
325 	ut_asserteq_mem(plain, in, in_size);
326 
327 	if (zstd_compressed_size > out_max)
328 		return -1;
329 
330 	memcpy(out, zstd_compressed, zstd_compressed_size);
331 	if (out_size)
332 		*out_size = zstd_compressed_size;
333 
334 	return 0;
335 }
336 
uncompress_using_zstd(struct unit_test_state * uts,void * in,unsigned long in_size,void * out,unsigned long out_max,unsigned long * out_size)337 static int uncompress_using_zstd(struct unit_test_state *uts,
338 				 void *in, unsigned long in_size,
339 				 void *out, unsigned long out_max,
340 				 unsigned long *out_size)
341 {
342 	struct abuf in_buf, out_buf;
343 	int ret;
344 
345 	abuf_init_set(&in_buf, in, in_size);
346 	abuf_init_set(&out_buf, out, out_max);
347 
348 	ret = zstd_decompress(&in_buf, &out_buf);
349 	if (ret >= 0) {
350 		*out_size = ret;
351 		ret = 0;
352 	}
353 
354 	return ret;
355 }
356 
357 #define errcheck(statement) if (!(statement)) { \
358 	fprintf(stderr, "\tFailed: %s\n", #statement); \
359 	ret = 1; \
360 	goto out; \
361 }
362 
363 struct buf_state {
364 	ulong orig_size;
365 	ulong compressed_size;
366 	ulong uncompressed_size;
367 	void *orig_buf;
368 	void *compressed_buf;
369 	void *uncompressed_buf;
370 	void *compare_buf;
371 };
372 
run_test_internal(struct unit_test_state * uts,char * name,mutate_func compress,mutate_func uncompress,struct buf_state * buf)373 static int run_test_internal(struct unit_test_state *uts, char *name,
374 			     mutate_func compress, mutate_func uncompress,
375 			     struct buf_state *buf)
376 {
377 	int ret;
378 
379 	/* Compress works as expected. */
380 	printf("\torig_size:%lu\n", buf->orig_size);
381 	memset(buf->compressed_buf, 'A', TEST_BUFFER_SIZE);
382 	ut_assertok(compress(uts, buf->orig_buf, buf->orig_size,
383 			  buf->compressed_buf, buf->compressed_size,
384 			  &buf->compressed_size));
385 	printf("\tcompressed_size:%lu\n", buf->compressed_size);
386 	ut_assert(buf->compressed_size > 0);
387 	ut_assert(buf->compressed_size < buf->orig_size);
388 	ut_assert(((char *)buf->compressed_buf)[buf->compressed_size - 1]
389 			!= 'A');
390 	ut_asserteq(((char *)buf->compressed_buf)[buf->compressed_size], 'A');
391 
392 	/* Uncompresses with space remaining. */
393 	ut_assertok(uncompress(uts, buf->compressed_buf, buf->compressed_size,
394 			    buf->uncompressed_buf, buf->uncompressed_size,
395 			    &buf->uncompressed_size));
396 	printf("\tuncompressed_size:%lu\n", buf->uncompressed_size);
397 	ut_asserteq(buf->uncompressed_size, buf->orig_size);
398 	ut_asserteq_mem(buf->orig_buf, buf->uncompressed_buf, buf->orig_size);
399 
400 	/* Uncompresses with exactly the right size output buffer. */
401 	memset(buf->uncompressed_buf, 'A', TEST_BUFFER_SIZE);
402 	ut_assertok(uncompress(uts, buf->compressed_buf, buf->compressed_size,
403 			    buf->uncompressed_buf, buf->orig_size,
404 			    &buf->uncompressed_size));
405 	ut_asserteq(buf->uncompressed_size, buf->orig_size);
406 	ut_asserteq_mem(buf->orig_buf, buf->uncompressed_buf, buf->orig_size);
407 	ut_asserteq(((char *)buf->uncompressed_buf)[buf->orig_size], 'A');
408 
409 	/* Uncompresses with trailing garbage in input buffer. */
410 	memset(buf->uncompressed_buf, 'A', TEST_BUFFER_SIZE);
411 	ut_assertok(uncompress(uts, buf->compressed_buf, buf->compressed_size + 4,
412 			    buf->uncompressed_buf, buf->uncompressed_size,
413 			    &buf->uncompressed_size));
414 	ut_asserteq(buf->uncompressed_size, buf->orig_size);
415 	ut_asserteq_mem(buf->orig_buf, buf->uncompressed_buf, buf->orig_size);
416 
417 	/* Make sure compression does not over-run. */
418 	memset(buf->compare_buf, 'A', TEST_BUFFER_SIZE);
419 	ret = compress(uts, buf->orig_buf, buf->orig_size,
420 		       buf->compare_buf, buf->compressed_size - 1,
421 		       NULL);
422 	ut_asserteq(((char *)buf->compare_buf)[buf->compressed_size], 'A');
423 	ut_assert(ret != 0);
424 	printf("\tcompress does not overrun\n");
425 
426 	/* Make sure decompression does not over-run. */
427 	memset(buf->compare_buf, 'A', TEST_BUFFER_SIZE);
428 	ret = uncompress(uts, buf->compressed_buf, buf->compressed_size,
429 			 buf->compare_buf, buf->uncompressed_size - 1,
430 			 NULL);
431 	ut_asserteq(((char *)buf->compare_buf)[buf->uncompressed_size - 1], 'A');
432 	ut_assert(ret != 0);
433 	printf("\tuncompress does not overrun\n");
434 
435 	/* Got here, everything is fine. */
436 	return 0;
437 }
438 
run_test(struct unit_test_state * uts,char * name,mutate_func compress,mutate_func uncompress)439 static int run_test(struct unit_test_state *uts, char *name,
440 		    mutate_func compress, mutate_func uncompress)
441 {
442 	struct buf_state sbuf, *buf = &sbuf;
443 	int ret;
444 
445 	printf(" testing %s ...\n", name);
446 
447 	buf->orig_buf = (void *)plain;
448 	buf->orig_size = strlen(buf->orig_buf); /* Trailing NUL not included */
449 	errcheck(buf->orig_size > 0);
450 
451 	buf->compressed_size = TEST_BUFFER_SIZE;
452 	buf->uncompressed_size = TEST_BUFFER_SIZE;
453 	buf->compressed_buf = malloc(buf->compressed_size);
454 	errcheck(buf->compressed_buf);
455 	buf->uncompressed_buf = malloc(buf->uncompressed_size);
456 	errcheck(buf->uncompressed_buf);
457 	buf->compare_buf = malloc(buf->uncompressed_size);
458 	errcheck(buf->compare_buf);
459 
460 	ret = run_test_internal(uts, name, compress, uncompress, buf);
461 out:
462 	printf(" %s: %s\n", name, ret == 0 ? "ok" : "FAILED");
463 
464 	free(buf->compare_buf);
465 	free(buf->uncompressed_buf);
466 	free(buf->compressed_buf);
467 
468 	return ret;
469 }
470 
compression_test_gzip(struct unit_test_state * uts)471 static int compression_test_gzip(struct unit_test_state *uts)
472 {
473 	return run_test(uts, "gzip", compress_using_gzip,
474 			uncompress_using_gzip);
475 }
476 COMPRESSION_TEST(compression_test_gzip, 0);
477 
compression_test_bzip2(struct unit_test_state * uts)478 static int compression_test_bzip2(struct unit_test_state *uts)
479 {
480 	return run_test(uts, "bzip2", compress_using_bzip2,
481 			uncompress_using_bzip2);
482 }
483 COMPRESSION_TEST(compression_test_bzip2, 0);
484 
compression_test_lzma(struct unit_test_state * uts)485 static int compression_test_lzma(struct unit_test_state *uts)
486 {
487 	return run_test(uts, "lzma", compress_using_lzma,
488 			uncompress_using_lzma);
489 }
490 COMPRESSION_TEST(compression_test_lzma, 0);
491 
compression_test_lzo(struct unit_test_state * uts)492 static int compression_test_lzo(struct unit_test_state *uts)
493 {
494 	return run_test(uts, "lzo", compress_using_lzo, uncompress_using_lzo);
495 }
496 COMPRESSION_TEST(compression_test_lzo, 0);
497 
compression_test_lz4(struct unit_test_state * uts)498 static int compression_test_lz4(struct unit_test_state *uts)
499 {
500 	return run_test(uts, "lz4", compress_using_lz4, uncompress_using_lz4);
501 }
502 COMPRESSION_TEST(compression_test_lz4, 0);
503 
compression_test_zstd(struct unit_test_state * uts)504 static int compression_test_zstd(struct unit_test_state *uts)
505 {
506 	return run_test(uts, "zstd", compress_using_zstd,
507 			uncompress_using_zstd);
508 }
509 COMPRESSION_TEST(compression_test_zstd, 0);
510 
compress_using_none(struct unit_test_state * uts,void * in,unsigned long in_size,void * out,unsigned long out_max,unsigned long * out_size)511 static int compress_using_none(struct unit_test_state *uts,
512 			       void *in, unsigned long in_size,
513 			       void *out, unsigned long out_max,
514 			       unsigned long *out_size)
515 {
516 	/* Here we just copy */
517 	memcpy(out, in, in_size);
518 	*out_size = in_size;
519 
520 	return 0;
521 }
522 
523 /**
524  * run_bootm_test() - Run tests on the bootm decompression function
525  *
526  * @comp_type:	Compression type to test
527  * @compress:	Our function to compress data
528  * Return: 0 if OK, non-zero on failure
529  */
run_bootm_test(struct unit_test_state * uts,int comp_type,mutate_func compress)530 static int run_bootm_test(struct unit_test_state *uts, int comp_type,
531 			  mutate_func compress)
532 {
533 	ulong compress_size = 1024;
534 	void *compress_buff;
535 	int unc_len;
536 	int err = 0;
537 	const ulong image_start = 0;
538 	const ulong load_addr = 0x1000;
539 	ulong load_end;
540 
541 	printf("Testing: %s\n", genimg_get_comp_name(comp_type));
542 	compress_buff = map_sysmem(image_start, 0);
543 	unc_len = strlen(plain);
544 	compress(uts, (void *)plain, unc_len, compress_buff, compress_size,
545 		 &compress_size);
546 	err = image_decomp(comp_type, load_addr, image_start,
547 			   IH_TYPE_KERNEL, map_sysmem(load_addr, 0),
548 			   compress_buff, compress_size, unc_len,
549 			   &load_end);
550 	ut_assertok(err);
551 	err = image_decomp(comp_type, load_addr, image_start,
552 			   IH_TYPE_KERNEL, map_sysmem(load_addr, 0),
553 			   compress_buff, compress_size, unc_len - 1,
554 			   &load_end);
555 	ut_assert(err);
556 
557 	/* We can't detect corruption when not decompressing */
558 	if (comp_type == IH_COMP_NONE)
559 		return 0;
560 	memset(compress_buff + compress_size / 2, '\x49',
561 	       compress_size / 2);
562 	err = image_decomp(comp_type, load_addr, image_start,
563 			   IH_TYPE_KERNEL, map_sysmem(load_addr, 0),
564 			   compress_buff, compress_size, 0x10000,
565 			   &load_end);
566 	ut_assert(err);
567 
568 	return 0;
569 }
570 
compression_test_bootm_gzip(struct unit_test_state * uts)571 static int compression_test_bootm_gzip(struct unit_test_state *uts)
572 {
573 	return run_bootm_test(uts, IH_COMP_GZIP, compress_using_gzip);
574 }
575 COMPRESSION_TEST(compression_test_bootm_gzip, 0);
576 
compression_test_bootm_bzip2(struct unit_test_state * uts)577 static int compression_test_bootm_bzip2(struct unit_test_state *uts)
578 {
579 	return run_bootm_test(uts, IH_COMP_BZIP2, compress_using_bzip2);
580 }
581 COMPRESSION_TEST(compression_test_bootm_bzip2, 0);
582 
compression_test_bootm_lzma(struct unit_test_state * uts)583 static int compression_test_bootm_lzma(struct unit_test_state *uts)
584 {
585 	return run_bootm_test(uts, IH_COMP_LZMA, compress_using_lzma);
586 }
587 COMPRESSION_TEST(compression_test_bootm_lzma, 0);
588 
compression_test_bootm_lzo(struct unit_test_state * uts)589 static int compression_test_bootm_lzo(struct unit_test_state *uts)
590 {
591 	return run_bootm_test(uts, IH_COMP_LZO, compress_using_lzo);
592 }
593 COMPRESSION_TEST(compression_test_bootm_lzo, 0);
594 
compression_test_bootm_lz4(struct unit_test_state * uts)595 static int compression_test_bootm_lz4(struct unit_test_state *uts)
596 {
597 	return run_bootm_test(uts, IH_COMP_LZ4, compress_using_lz4);
598 }
599 COMPRESSION_TEST(compression_test_bootm_lz4, 0);
600 
compression_test_bootm_zstd(struct unit_test_state * uts)601 static int compression_test_bootm_zstd(struct unit_test_state *uts)
602 {
603 	return run_bootm_test(uts, IH_COMP_ZSTD, compress_using_zstd);
604 }
605 COMPRESSION_TEST(compression_test_bootm_zstd, 0);
606 
compression_test_bootm_none(struct unit_test_state * uts)607 static int compression_test_bootm_none(struct unit_test_state *uts)
608 {
609 	return run_bootm_test(uts, IH_COMP_NONE, compress_using_none);
610 }
611 COMPRESSION_TEST(compression_test_bootm_none, 0);
612 
do_ut_compression(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])613 int do_ut_compression(struct cmd_tbl *cmdtp, int flag, int argc,
614 		      char *const argv[])
615 {
616 	struct unit_test *tests = UNIT_TEST_SUITE_START(compression_test);
617 	const int n_ents = UNIT_TEST_SUITE_COUNT(compression_test);
618 
619 	return cmd_ut_category("compression", "compression_test_",
620 			       tests, n_ents, argc, argv);
621 }
622