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 ); 477