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