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