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 99 #define TEST_BUFFER_SIZE 512 100 101 typedef int (*mutate_func)(void *, unsigned long, void *, unsigned long, 102 unsigned long *); 103 104 static int compress_using_gzip(void *in, unsigned long in_size, 105 void *out, unsigned long out_max, 106 unsigned long *out_size) 107 { 108 int ret; 109 unsigned long inout_size = out_max; 110 111 ret = gzip(out, &inout_size, in, in_size); 112 if (out_size) 113 *out_size = inout_size; 114 115 return ret; 116 } 117 118 static int uncompress_using_gzip(void *in, unsigned long in_size, 119 void *out, unsigned long out_max, 120 unsigned long *out_size) 121 { 122 int ret; 123 unsigned long inout_size = in_size; 124 125 ret = gunzip(out, out_max, in, &inout_size); 126 if (out_size) 127 *out_size = inout_size; 128 129 return ret; 130 } 131 132 static int compress_using_bzip2(void *in, unsigned long in_size, 133 void *out, unsigned long out_max, 134 unsigned long *out_size) 135 { 136 /* There is no bzip2 compression in u-boot, so fake it. */ 137 assert(in_size == strlen(plain)); 138 assert(memcmp(plain, in, in_size) == 0); 139 140 if (bzip2_compressed_size > out_max) 141 return -1; 142 143 memcpy(out, bzip2_compressed, bzip2_compressed_size); 144 if (out_size) 145 *out_size = bzip2_compressed_size; 146 147 return 0; 148 } 149 150 static int uncompress_using_bzip2(void *in, unsigned long in_size, 151 void *out, unsigned long out_max, 152 unsigned long *out_size) 153 { 154 int ret; 155 unsigned int inout_size = out_max; 156 157 ret = BZ2_bzBuffToBuffDecompress(out, &inout_size, in, in_size, 158 CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0); 159 if (out_size) 160 *out_size = inout_size; 161 162 return (ret != BZ_OK); 163 } 164 165 static int compress_using_lzma(void *in, unsigned long in_size, 166 void *out, unsigned long out_max, 167 unsigned long *out_size) 168 { 169 /* There is no lzma compression in u-boot, so fake it. */ 170 assert(in_size == strlen(plain)); 171 assert(memcmp(plain, in, in_size) == 0); 172 173 if (lzma_compressed_size > out_max) 174 return -1; 175 176 memcpy(out, lzma_compressed, lzma_compressed_size); 177 if (out_size) 178 *out_size = lzma_compressed_size; 179 180 return 0; 181 } 182 183 static int uncompress_using_lzma(void *in, unsigned long in_size, 184 void *out, unsigned long out_max, 185 unsigned long *out_size) 186 { 187 int ret; 188 SizeT inout_size = out_max; 189 190 ret = lzmaBuffToBuffDecompress(out, &inout_size, in, in_size); 191 if (out_size) 192 *out_size = inout_size; 193 194 return (ret != SZ_OK); 195 } 196 197 static int compress_using_lzo(void *in, unsigned long in_size, 198 void *out, unsigned long out_max, 199 unsigned long *out_size) 200 { 201 /* There is no lzo compression in u-boot, so fake it. */ 202 assert(in_size == strlen(plain)); 203 assert(memcmp(plain, in, in_size) == 0); 204 205 if (lzo_compressed_size > out_max) 206 return -1; 207 208 memcpy(out, lzo_compressed, lzo_compressed_size); 209 if (out_size) 210 *out_size = lzo_compressed_size; 211 212 return 0; 213 } 214 215 static int uncompress_using_lzo(void *in, unsigned long in_size, 216 void *out, unsigned long out_max, 217 unsigned long *out_size) 218 { 219 int ret; 220 size_t input_size = in_size; 221 size_t output_size = out_max; 222 223 ret = lzop_decompress(in, input_size, out, &output_size); 224 if (out_size) 225 *out_size = output_size; 226 227 return (ret != LZO_E_OK); 228 } 229 230 #define errcheck(statement) if (!(statement)) { \ 231 fprintf(stderr, "\tFailed: %s\n", #statement); \ 232 ret = 1; \ 233 goto out; \ 234 } 235 236 static int run_test(char *name, mutate_func compress, mutate_func uncompress) 237 { 238 ulong orig_size, compressed_size, uncompressed_size; 239 void *orig_buf; 240 void *compressed_buf = NULL; 241 void *uncompressed_buf = NULL; 242 void *compare_buf = NULL; 243 int ret; 244 245 printf(" testing %s ...\n", name); 246 247 orig_buf = (void *)plain; 248 orig_size = strlen(orig_buf); /* Trailing NULL not included. */ 249 errcheck(orig_size > 0); 250 251 compressed_size = uncompressed_size = TEST_BUFFER_SIZE; 252 compressed_buf = malloc(compressed_size); 253 errcheck(compressed_buf != NULL); 254 uncompressed_buf = malloc(uncompressed_size); 255 errcheck(uncompressed_buf != NULL); 256 compare_buf = malloc(uncompressed_size); 257 errcheck(compare_buf != NULL); 258 259 /* Compress works as expected. */ 260 printf("\torig_size:%lu\n", orig_size); 261 memset(compressed_buf, 'A', TEST_BUFFER_SIZE); 262 errcheck(compress(orig_buf, orig_size, 263 compressed_buf, compressed_size, 264 &compressed_size) == 0); 265 printf("\tcompressed_size:%lu\n", compressed_size); 266 errcheck(compressed_size > 0); 267 errcheck(compressed_size < orig_size); 268 errcheck(((char *)compressed_buf)[compressed_size-1] != 'A'); 269 errcheck(((char *)compressed_buf)[compressed_size] == 'A'); 270 271 /* Uncompresses with space remaining. */ 272 errcheck(uncompress(compressed_buf, compressed_size, 273 uncompressed_buf, uncompressed_size, 274 &uncompressed_size) == 0); 275 printf("\tuncompressed_size:%lu\n", uncompressed_size); 276 errcheck(uncompressed_size == orig_size); 277 errcheck(memcmp(orig_buf, uncompressed_buf, orig_size) == 0); 278 279 /* Uncompresses with exactly the right size output buffer. */ 280 memset(uncompressed_buf, 'A', TEST_BUFFER_SIZE); 281 errcheck(uncompress(compressed_buf, compressed_size, 282 uncompressed_buf, orig_size, 283 &uncompressed_size) == 0); 284 errcheck(uncompressed_size == orig_size); 285 errcheck(memcmp(orig_buf, uncompressed_buf, orig_size) == 0); 286 errcheck(((char *)uncompressed_buf)[orig_size] == 'A'); 287 288 /* Make sure compression does not over-run. */ 289 memset(compare_buf, 'A', TEST_BUFFER_SIZE); 290 ret = compress(orig_buf, orig_size, 291 compare_buf, compressed_size - 1, 292 NULL); 293 errcheck(((char *)compare_buf)[compressed_size] == 'A'); 294 errcheck(ret != 0); 295 printf("\tcompress does not overrun\n"); 296 297 /* Make sure decompression does not over-run. */ 298 memset(compare_buf, 'A', TEST_BUFFER_SIZE); 299 ret = uncompress(compressed_buf, compressed_size, 300 compare_buf, uncompressed_size - 1, 301 NULL); 302 errcheck(((char *)compare_buf)[uncompressed_size - 1] == 'A'); 303 errcheck(ret != 0); 304 printf("\tuncompress does not overrun\n"); 305 306 /* Got here, everything is fine. */ 307 ret = 0; 308 309 out: 310 printf(" %s: %s\n", name, ret == 0 ? "ok" : "FAILED"); 311 312 free(compare_buf); 313 free(uncompressed_buf); 314 free(compressed_buf); 315 316 return ret; 317 } 318 319 static int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc, 320 char *const argv[]) 321 { 322 int err = 0; 323 324 err += run_test("gzip", compress_using_gzip, uncompress_using_gzip); 325 err += run_test("bzip2", compress_using_bzip2, uncompress_using_bzip2); 326 err += run_test("lzma", compress_using_lzma, uncompress_using_lzma); 327 err += run_test("lzo", compress_using_lzo, uncompress_using_lzo); 328 329 printf("ut_compression %s\n", err == 0 ? "ok" : "FAILED"); 330 331 return err; 332 } 333 334 static int compress_using_none(void *in, unsigned long in_size, 335 void *out, unsigned long out_max, 336 unsigned long *out_size) 337 { 338 /* Here we just copy */ 339 memcpy(out, in, in_size); 340 *out_size = in_size; 341 342 return 0; 343 } 344 345 /** 346 * run_bootm_test() - Run tests on the bootm decopmression function 347 * 348 * @comp_type: Compression type to test 349 * @compress: Our function to compress data 350 * @return 0 if OK, non-zero on failure 351 */ 352 static int run_bootm_test(int comp_type, mutate_func compress) 353 { 354 ulong compress_size = 1024; 355 void *compress_buff; 356 int unc_len; 357 int err = 0; 358 const ulong image_start = 0; 359 const ulong load_addr = 0x1000; 360 ulong load_end; 361 362 printf("Testing: %s\n", genimg_get_comp_name(comp_type)); 363 compress_buff = map_sysmem(image_start, 0); 364 unc_len = strlen(plain); 365 compress((void *)plain, unc_len, compress_buff, compress_size, 366 &compress_size); 367 err = bootm_decomp_image(comp_type, load_addr, image_start, 368 IH_TYPE_KERNEL, map_sysmem(load_addr, 0), 369 compress_buff, compress_size, unc_len, 370 &load_end); 371 if (err) 372 return err; 373 err = bootm_decomp_image(comp_type, load_addr, image_start, 374 IH_TYPE_KERNEL, map_sysmem(load_addr, 0), 375 compress_buff, compress_size, unc_len - 1, 376 &load_end); 377 if (!err) 378 return -EINVAL; 379 380 /* We can't detect corruption when not decompressing */ 381 if (comp_type == IH_COMP_NONE) 382 return 0; 383 memset(compress_buff + compress_size / 2, '\x49', 384 compress_size / 2); 385 err = bootm_decomp_image(comp_type, load_addr, image_start, 386 IH_TYPE_KERNEL, map_sysmem(load_addr, 0), 387 compress_buff, compress_size, 0x10000, 388 &load_end); 389 if (!err) 390 return -EINVAL; 391 392 return 0; 393 } 394 395 static int do_ut_image_decomp(cmd_tbl_t *cmdtp, int flag, int argc, 396 char *const argv[]) 397 { 398 int err = 0; 399 400 err = run_bootm_test(IH_COMP_GZIP, compress_using_gzip); 401 err |= run_bootm_test(IH_COMP_BZIP2, compress_using_bzip2); 402 err |= run_bootm_test(IH_COMP_LZMA, compress_using_lzma); 403 err |= run_bootm_test(IH_COMP_LZO, compress_using_lzo); 404 err |= run_bootm_test(IH_COMP_NONE, compress_using_none); 405 406 printf("ut_image_decomp %s\n", err == 0 ? "ok" : "FAILED"); 407 408 return 0; 409 } 410 411 U_BOOT_CMD( 412 ut_compression, 5, 1, do_ut_compression, 413 "Basic test of compressors: gzip bzip2 lzma lzo", "" 414 ); 415 416 U_BOOT_CMD( 417 ut_image_decomp, 5, 1, do_ut_image_decomp, 418 "Basic test of bootm decompression", "" 419 ); 420