1 /* 2 * (C) Copyright 2000-2006 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <watchdog.h> 10 #include <command.h> 11 #include <console.h> 12 #include <image.h> 13 #include <malloc.h> 14 #include <memalign.h> 15 #include <misc.h> 16 #include <u-boot/zlib.h> 17 #include <div64.h> 18 19 #define HEADER0 '\x1f' 20 #define HEADER1 '\x8b' 21 #define ZALLOC_ALIGNMENT 16 22 #define HEAD_CRC 2 23 #define EXTRA_FIELD 4 24 #define ORIG_NAME 8 25 #define COMMENT 0x10 26 #define RESERVED 0xe0 27 #define DEFLATED 8 28 29 void *gzalloc(void *x, unsigned items, unsigned size) 30 { 31 void *p; 32 33 size *= items; 34 size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1); 35 36 p = malloc (size); 37 38 return (p); 39 } 40 41 void gzfree(void *x, void *addr, unsigned nb) 42 { 43 free (addr); 44 } 45 46 int gzip_parse_header(const unsigned char *src, unsigned long len) 47 { 48 int i, flags; 49 50 /* skip header */ 51 i = 10; 52 flags = src[3]; 53 if (src[2] != DEFLATED || (flags & RESERVED) != 0) { 54 debug("Error: Bad gzipped data\n"); 55 return (-1); 56 } 57 if ((flags & EXTRA_FIELD) != 0) 58 i = 12 + src[10] + (src[11] << 8); 59 if ((flags & ORIG_NAME) != 0) 60 while (src[i++] != 0) 61 ; 62 if ((flags & COMMENT) != 0) 63 while (src[i++] != 0) 64 ; 65 if ((flags & HEAD_CRC) != 0) 66 i += 2; 67 if (i >= len) { 68 puts ("Error: gunzip out of data in header\n"); 69 return (-1); 70 } 71 return i; 72 } 73 74 int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp) 75 { 76 int offset = gzip_parse_header(src, *lenp); 77 78 if (offset < 0) 79 return offset; 80 81 #if defined(CONFIG_MISC_DECOMPRESS) && !defined(CONFIG_SPL_BUILD) 82 int ret; 83 84 ret = misc_decompress_process((ulong)dst, (ulong)src, *lenp, 85 DECOM_GZIP, true, (u64 *)lenp, 0); 86 if (!ret) 87 return 0; 88 89 printf("hw gunzip failed(%d), fallback to soft gunzip\n", ret); 90 #endif 91 return zunzip(dst, dstlen, src, lenp, 1, offset); 92 } 93 94 #ifdef CONFIG_CMD_UNZIP 95 __weak 96 void gzwrite_progress_init(u64 expectedsize) 97 { 98 putc('\n'); 99 } 100 101 __weak 102 void gzwrite_progress(int iteration, 103 u64 bytes_written, 104 u64 total_bytes) 105 { 106 if (0 == (iteration & 3)) 107 printf("%llu/%llu\r", bytes_written, total_bytes); 108 } 109 110 __weak 111 void gzwrite_progress_finish(int returnval, 112 u64 bytes_written, 113 u64 total_bytes, 114 u32 expected_crc, 115 u32 calculated_crc) 116 { 117 if (0 == returnval) { 118 printf("\n\t%llu bytes, crc 0x%08x\n", 119 total_bytes, calculated_crc); 120 } else { 121 printf("\n\tuncompressed %llu of %llu\n" 122 "\tcrcs == 0x%08x/0x%08x\n", 123 bytes_written, total_bytes, 124 expected_crc, calculated_crc); 125 } 126 } 127 128 int gzwrite(unsigned char *src, int len, 129 struct blk_desc *dev, 130 unsigned long szwritebuf, 131 u64 startoffs, 132 u64 szexpected) 133 { 134 int i, flags; 135 z_stream s; 136 int r = 0; 137 unsigned char *writebuf; 138 unsigned crc = 0; 139 u64 totalfilled = 0; 140 lbaint_t blksperbuf, outblock; 141 u32 expected_crc; 142 u32 payload_size; 143 int iteration = 0; 144 145 if (!szwritebuf || 146 (szwritebuf % dev->blksz) || 147 (szwritebuf < dev->blksz)) { 148 printf("%s: size %lu not a multiple of %lu\n", 149 __func__, szwritebuf, dev->blksz); 150 return -1; 151 } 152 153 if (startoffs & (dev->blksz-1)) { 154 printf("%s: start offset %llu not a multiple of %lu\n", 155 __func__, startoffs, dev->blksz); 156 return -1; 157 } 158 159 blksperbuf = szwritebuf / dev->blksz; 160 outblock = lldiv(startoffs, dev->blksz); 161 162 /* skip header */ 163 i = 10; 164 flags = src[3]; 165 if (src[2] != DEFLATED || (flags & RESERVED) != 0) { 166 puts("Error: Bad gzipped data\n"); 167 return -1; 168 } 169 if ((flags & EXTRA_FIELD) != 0) 170 i = 12 + src[10] + (src[11] << 8); 171 if ((flags & ORIG_NAME) != 0) 172 while (src[i++] != 0) 173 ; 174 if ((flags & COMMENT) != 0) 175 while (src[i++] != 0) 176 ; 177 if ((flags & HEAD_CRC) != 0) 178 i += 2; 179 180 if (i >= len-8) { 181 puts("Error: gunzip out of data in header"); 182 return -1; 183 } 184 185 payload_size = len - i - 8; 186 187 memcpy(&expected_crc, src + len - 8, sizeof(expected_crc)); 188 expected_crc = le32_to_cpu(expected_crc); 189 u32 szuncompressed; 190 memcpy(&szuncompressed, src + len - 4, sizeof(szuncompressed)); 191 if (szexpected == 0) { 192 szexpected = le32_to_cpu(szuncompressed); 193 } else if (szuncompressed != (u32)szexpected) { 194 printf("size of %llx doesn't match trailer low bits %x\n", 195 szexpected, szuncompressed); 196 return -1; 197 } 198 if (lldiv(szexpected, dev->blksz) > (dev->lba - outblock)) { 199 printf("%s: uncompressed size %llu exceeds device size\n", 200 __func__, szexpected); 201 return -1; 202 } 203 204 gzwrite_progress_init(szexpected); 205 206 s.zalloc = gzalloc; 207 s.zfree = gzfree; 208 209 r = inflateInit2(&s, -MAX_WBITS); 210 if (r != Z_OK) { 211 printf("Error: inflateInit2() returned %d\n", r); 212 return -1; 213 } 214 215 s.next_in = src + i; 216 s.avail_in = payload_size+8; 217 writebuf = (unsigned char *)malloc_cache_aligned(szwritebuf); 218 219 /* decompress until deflate stream ends or end of file */ 220 do { 221 if (s.avail_in == 0) { 222 printf("%s: weird termination with result %d\n", 223 __func__, r); 224 break; 225 } 226 227 /* run inflate() on input until output buffer not full */ 228 do { 229 unsigned long blocks_written; 230 int numfilled; 231 lbaint_t writeblocks; 232 233 s.avail_out = szwritebuf; 234 s.next_out = writebuf; 235 r = inflate(&s, Z_SYNC_FLUSH); 236 if ((r != Z_OK) && 237 (r != Z_STREAM_END)) { 238 printf("Error: inflate() returned %d\n", r); 239 goto out; 240 } 241 numfilled = szwritebuf - s.avail_out; 242 crc = crc32(crc, writebuf, numfilled); 243 totalfilled += numfilled; 244 if (numfilled < szwritebuf) { 245 writeblocks = (numfilled+dev->blksz-1) 246 / dev->blksz; 247 memset(writebuf+numfilled, 0, 248 dev->blksz-(numfilled%dev->blksz)); 249 } else { 250 writeblocks = blksperbuf; 251 } 252 253 gzwrite_progress(iteration++, 254 totalfilled, 255 szexpected); 256 blocks_written = blk_dwrite(dev, outblock, 257 writeblocks, writebuf); 258 outblock += blocks_written; 259 if (ctrlc()) { 260 puts("abort\n"); 261 goto out; 262 } 263 WATCHDOG_RESET(); 264 } while (s.avail_out == 0); 265 /* done when inflate() says it's done */ 266 } while (r != Z_STREAM_END); 267 268 if ((szexpected != totalfilled) || 269 (crc != expected_crc)) 270 r = -1; 271 else 272 r = 0; 273 274 out: 275 gzwrite_progress_finish(r, totalfilled, szexpected, 276 expected_crc, crc); 277 free(writebuf); 278 inflateEnd(&s); 279 280 return r; 281 } 282 #endif 283 284 /* 285 * Uncompress blocks compressed with zlib without headers 286 */ 287 int zunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp, 288 int stoponerr, int offset) 289 { 290 z_stream s; 291 int err = 0; 292 int r; 293 294 s.zalloc = gzalloc; 295 s.zfree = gzfree; 296 297 r = inflateInit2(&s, -MAX_WBITS); 298 if (r != Z_OK) { 299 printf("Error: inflateInit2() returned %d\n", r); 300 return -1; 301 } 302 s.next_in = src + offset; 303 s.avail_in = *lenp - offset; 304 s.next_out = dst; 305 s.avail_out = dstlen; 306 do { 307 r = inflate(&s, Z_FINISH); 308 if (stoponerr == 1 && r != Z_STREAM_END && 309 (s.avail_in == 0 || s.avail_out == 0 || r != Z_BUF_ERROR)) { 310 printf("Error: inflate() returned %d\n", r); 311 err = -1; 312 break; 313 } 314 } while (r == Z_BUF_ERROR); 315 *lenp = s.next_out - (unsigned char *) dst; 316 inflateEnd(&s); 317 318 return err; 319 } 320