178acc472SPeter Tyser /* 278acc472SPeter Tyser * (C) Copyright 2000-2006 378acc472SPeter Tyser * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 478acc472SPeter Tyser * 51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 678acc472SPeter Tyser */ 778acc472SPeter Tyser 878acc472SPeter Tyser #include <common.h> 978acc472SPeter Tyser #include <watchdog.h> 1078acc472SPeter Tyser #include <command.h> 1178acc472SPeter Tyser #include <image.h> 1278acc472SPeter Tyser #include <malloc.h> 1378acc472SPeter Tyser #include <u-boot/zlib.h> 14*918e9ebbSEric Nelson #include <div64.h> 1578acc472SPeter Tyser 16*918e9ebbSEric Nelson #define HEADER0 '\x1f' 17*918e9ebbSEric Nelson #define HEADER1 '\x8b' 1878acc472SPeter Tyser #define ZALLOC_ALIGNMENT 16 1978acc472SPeter Tyser #define HEAD_CRC 2 2078acc472SPeter Tyser #define EXTRA_FIELD 4 2178acc472SPeter Tyser #define ORIG_NAME 8 2278acc472SPeter Tyser #define COMMENT 0x10 2378acc472SPeter Tyser #define RESERVED 0xe0 2478acc472SPeter Tyser #define DEFLATED 8 2578acc472SPeter Tyser 26e3ed0575SMike Frysinger void *gzalloc(void *x, unsigned items, unsigned size) 2778acc472SPeter Tyser { 2878acc472SPeter Tyser void *p; 2978acc472SPeter Tyser 3078acc472SPeter Tyser size *= items; 3178acc472SPeter Tyser size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1); 3278acc472SPeter Tyser 3378acc472SPeter Tyser p = malloc (size); 3478acc472SPeter Tyser 3578acc472SPeter Tyser return (p); 3678acc472SPeter Tyser } 3778acc472SPeter Tyser 38e3ed0575SMike Frysinger void gzfree(void *x, void *addr, unsigned nb) 3978acc472SPeter Tyser { 4078acc472SPeter Tyser free (addr); 4178acc472SPeter Tyser } 4278acc472SPeter Tyser 4378acc472SPeter Tyser int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp) 4478acc472SPeter Tyser { 4578acc472SPeter Tyser int i, flags; 4678acc472SPeter Tyser 4778acc472SPeter Tyser /* skip header */ 4878acc472SPeter Tyser i = 10; 4978acc472SPeter Tyser flags = src[3]; 5078acc472SPeter Tyser if (src[2] != DEFLATED || (flags & RESERVED) != 0) { 5178acc472SPeter Tyser puts ("Error: Bad gzipped data\n"); 5278acc472SPeter Tyser return (-1); 5378acc472SPeter Tyser } 5478acc472SPeter Tyser if ((flags & EXTRA_FIELD) != 0) 5578acc472SPeter Tyser i = 12 + src[10] + (src[11] << 8); 5678acc472SPeter Tyser if ((flags & ORIG_NAME) != 0) 5778acc472SPeter Tyser while (src[i++] != 0) 5878acc472SPeter Tyser ; 5978acc472SPeter Tyser if ((flags & COMMENT) != 0) 6078acc472SPeter Tyser while (src[i++] != 0) 6178acc472SPeter Tyser ; 6278acc472SPeter Tyser if ((flags & HEAD_CRC) != 0) 6378acc472SPeter Tyser i += 2; 6478acc472SPeter Tyser if (i >= *lenp) { 6578acc472SPeter Tyser puts ("Error: gunzip out of data in header\n"); 6678acc472SPeter Tyser return (-1); 6778acc472SPeter Tyser } 6878acc472SPeter Tyser 6978acc472SPeter Tyser return zunzip(dst, dstlen, src, lenp, 1, i); 7078acc472SPeter Tyser } 7178acc472SPeter Tyser 72*918e9ebbSEric Nelson __weak 73*918e9ebbSEric Nelson void gzwrite_progress_init(u64 expectedsize) 74*918e9ebbSEric Nelson { 75*918e9ebbSEric Nelson putc('\n'); 76*918e9ebbSEric Nelson } 77*918e9ebbSEric Nelson 78*918e9ebbSEric Nelson __weak 79*918e9ebbSEric Nelson void gzwrite_progress(int iteration, 80*918e9ebbSEric Nelson u64 bytes_written, 81*918e9ebbSEric Nelson u64 total_bytes) 82*918e9ebbSEric Nelson { 83*918e9ebbSEric Nelson if (0 == (iteration & 3)) 84*918e9ebbSEric Nelson printf("%llu/%llu\r", bytes_written, total_bytes); 85*918e9ebbSEric Nelson } 86*918e9ebbSEric Nelson 87*918e9ebbSEric Nelson __weak 88*918e9ebbSEric Nelson void gzwrite_progress_finish(int returnval, 89*918e9ebbSEric Nelson u64 bytes_written, 90*918e9ebbSEric Nelson u64 total_bytes, 91*918e9ebbSEric Nelson u32 expected_crc, 92*918e9ebbSEric Nelson u32 calculated_crc) 93*918e9ebbSEric Nelson { 94*918e9ebbSEric Nelson if (0 == returnval) { 95*918e9ebbSEric Nelson printf("\n\t%llu bytes, crc 0x%08x\n", 96*918e9ebbSEric Nelson total_bytes, calculated_crc); 97*918e9ebbSEric Nelson } else { 98*918e9ebbSEric Nelson printf("\n\tuncompressed %llu of %llu\n" 99*918e9ebbSEric Nelson "\tcrcs == 0x%08x/0x%08x\n", 100*918e9ebbSEric Nelson bytes_written, total_bytes, 101*918e9ebbSEric Nelson expected_crc, calculated_crc); 102*918e9ebbSEric Nelson } 103*918e9ebbSEric Nelson } 104*918e9ebbSEric Nelson 105*918e9ebbSEric Nelson int gzwrite(unsigned char *src, int len, 106*918e9ebbSEric Nelson struct block_dev_desc *dev, 107*918e9ebbSEric Nelson unsigned long szwritebuf, 108*918e9ebbSEric Nelson u64 startoffs, 109*918e9ebbSEric Nelson u64 szexpected) 110*918e9ebbSEric Nelson { 111*918e9ebbSEric Nelson int i, flags; 112*918e9ebbSEric Nelson z_stream s; 113*918e9ebbSEric Nelson int r = 0; 114*918e9ebbSEric Nelson unsigned char *writebuf; 115*918e9ebbSEric Nelson unsigned crc = 0; 116*918e9ebbSEric Nelson u64 totalfilled = 0; 117*918e9ebbSEric Nelson lbaint_t blksperbuf, outblock; 118*918e9ebbSEric Nelson u32 expected_crc; 119*918e9ebbSEric Nelson u32 payload_size; 120*918e9ebbSEric Nelson int iteration = 0; 121*918e9ebbSEric Nelson 122*918e9ebbSEric Nelson if (!szwritebuf || 123*918e9ebbSEric Nelson (szwritebuf % dev->blksz) || 124*918e9ebbSEric Nelson (szwritebuf < dev->blksz)) { 125*918e9ebbSEric Nelson printf("%s: size %lu not a multiple of %lu\n", 126*918e9ebbSEric Nelson __func__, szwritebuf, dev->blksz); 127*918e9ebbSEric Nelson return -1; 128*918e9ebbSEric Nelson } 129*918e9ebbSEric Nelson 130*918e9ebbSEric Nelson if (startoffs & (dev->blksz-1)) { 131*918e9ebbSEric Nelson printf("%s: start offset %llu not a multiple of %lu\n", 132*918e9ebbSEric Nelson __func__, startoffs, dev->blksz); 133*918e9ebbSEric Nelson return -1; 134*918e9ebbSEric Nelson } 135*918e9ebbSEric Nelson 136*918e9ebbSEric Nelson blksperbuf = szwritebuf / dev->blksz; 137*918e9ebbSEric Nelson outblock = lldiv(startoffs, dev->blksz); 138*918e9ebbSEric Nelson 139*918e9ebbSEric Nelson /* skip header */ 140*918e9ebbSEric Nelson i = 10; 141*918e9ebbSEric Nelson flags = src[3]; 142*918e9ebbSEric Nelson if (src[2] != DEFLATED || (flags & RESERVED) != 0) { 143*918e9ebbSEric Nelson puts("Error: Bad gzipped data\n"); 144*918e9ebbSEric Nelson return -1; 145*918e9ebbSEric Nelson } 146*918e9ebbSEric Nelson if ((flags & EXTRA_FIELD) != 0) 147*918e9ebbSEric Nelson i = 12 + src[10] + (src[11] << 8); 148*918e9ebbSEric Nelson if ((flags & ORIG_NAME) != 0) 149*918e9ebbSEric Nelson while (src[i++] != 0) 150*918e9ebbSEric Nelson ; 151*918e9ebbSEric Nelson if ((flags & COMMENT) != 0) 152*918e9ebbSEric Nelson while (src[i++] != 0) 153*918e9ebbSEric Nelson ; 154*918e9ebbSEric Nelson if ((flags & HEAD_CRC) != 0) 155*918e9ebbSEric Nelson i += 2; 156*918e9ebbSEric Nelson 157*918e9ebbSEric Nelson if (i >= len-8) { 158*918e9ebbSEric Nelson puts("Error: gunzip out of data in header"); 159*918e9ebbSEric Nelson return -1; 160*918e9ebbSEric Nelson } 161*918e9ebbSEric Nelson 162*918e9ebbSEric Nelson payload_size = len - i - 8; 163*918e9ebbSEric Nelson 164*918e9ebbSEric Nelson memcpy(&expected_crc, src + len - 8, sizeof(expected_crc)); 165*918e9ebbSEric Nelson expected_crc = le32_to_cpu(expected_crc); 166*918e9ebbSEric Nelson u32 szuncompressed; 167*918e9ebbSEric Nelson memcpy(&szuncompressed, src + len - 4, sizeof(szuncompressed)); 168*918e9ebbSEric Nelson if (szexpected == 0) { 169*918e9ebbSEric Nelson szexpected = le32_to_cpu(szuncompressed); 170*918e9ebbSEric Nelson } else if (szuncompressed != (u32)szexpected) { 171*918e9ebbSEric Nelson printf("size of %llx doesn't match trailer low bits %x\n", 172*918e9ebbSEric Nelson szexpected, szuncompressed); 173*918e9ebbSEric Nelson return -1; 174*918e9ebbSEric Nelson } 175*918e9ebbSEric Nelson if (lldiv(szexpected, dev->blksz) > (dev->lba - outblock)) { 176*918e9ebbSEric Nelson printf("%s: uncompressed size %llu exceeds device size\n", 177*918e9ebbSEric Nelson __func__, szexpected); 178*918e9ebbSEric Nelson return -1; 179*918e9ebbSEric Nelson } 180*918e9ebbSEric Nelson 181*918e9ebbSEric Nelson gzwrite_progress_init(szexpected); 182*918e9ebbSEric Nelson 183*918e9ebbSEric Nelson s.zalloc = gzalloc; 184*918e9ebbSEric Nelson s.zfree = gzfree; 185*918e9ebbSEric Nelson 186*918e9ebbSEric Nelson r = inflateInit2(&s, -MAX_WBITS); 187*918e9ebbSEric Nelson if (r != Z_OK) { 188*918e9ebbSEric Nelson printf("Error: inflateInit2() returned %d\n", r); 189*918e9ebbSEric Nelson return -1; 190*918e9ebbSEric Nelson } 191*918e9ebbSEric Nelson 192*918e9ebbSEric Nelson s.next_in = src + i; 193*918e9ebbSEric Nelson s.avail_in = payload_size+8; 194*918e9ebbSEric Nelson writebuf = (unsigned char *)malloc(szwritebuf); 195*918e9ebbSEric Nelson 196*918e9ebbSEric Nelson /* decompress until deflate stream ends or end of file */ 197*918e9ebbSEric Nelson do { 198*918e9ebbSEric Nelson if (s.avail_in == 0) { 199*918e9ebbSEric Nelson printf("%s: weird termination with result %d\n", 200*918e9ebbSEric Nelson __func__, r); 201*918e9ebbSEric Nelson break; 202*918e9ebbSEric Nelson } 203*918e9ebbSEric Nelson 204*918e9ebbSEric Nelson /* run inflate() on input until output buffer not full */ 205*918e9ebbSEric Nelson do { 206*918e9ebbSEric Nelson unsigned long blocks_written; 207*918e9ebbSEric Nelson int numfilled; 208*918e9ebbSEric Nelson lbaint_t writeblocks; 209*918e9ebbSEric Nelson 210*918e9ebbSEric Nelson s.avail_out = szwritebuf; 211*918e9ebbSEric Nelson s.next_out = writebuf; 212*918e9ebbSEric Nelson r = inflate(&s, Z_SYNC_FLUSH); 213*918e9ebbSEric Nelson if ((r != Z_OK) && 214*918e9ebbSEric Nelson (r != Z_STREAM_END)) { 215*918e9ebbSEric Nelson printf("Error: inflate() returned %d\n", r); 216*918e9ebbSEric Nelson goto out; 217*918e9ebbSEric Nelson } 218*918e9ebbSEric Nelson numfilled = szwritebuf - s.avail_out; 219*918e9ebbSEric Nelson crc = crc32(crc, writebuf, numfilled); 220*918e9ebbSEric Nelson totalfilled += numfilled; 221*918e9ebbSEric Nelson if (numfilled < szwritebuf) { 222*918e9ebbSEric Nelson writeblocks = (numfilled+dev->blksz-1) 223*918e9ebbSEric Nelson / dev->blksz; 224*918e9ebbSEric Nelson memset(writebuf+numfilled, 0, 225*918e9ebbSEric Nelson dev->blksz-(numfilled%dev->blksz)); 226*918e9ebbSEric Nelson } else { 227*918e9ebbSEric Nelson writeblocks = blksperbuf; 228*918e9ebbSEric Nelson } 229*918e9ebbSEric Nelson 230*918e9ebbSEric Nelson gzwrite_progress(iteration++, 231*918e9ebbSEric Nelson totalfilled, 232*918e9ebbSEric Nelson szexpected); 233*918e9ebbSEric Nelson blocks_written = dev->block_write(dev->dev, 234*918e9ebbSEric Nelson outblock, 235*918e9ebbSEric Nelson writeblocks, 236*918e9ebbSEric Nelson writebuf); 237*918e9ebbSEric Nelson outblock += blocks_written; 238*918e9ebbSEric Nelson if (ctrlc()) { 239*918e9ebbSEric Nelson puts("abort\n"); 240*918e9ebbSEric Nelson goto out; 241*918e9ebbSEric Nelson } 242*918e9ebbSEric Nelson WATCHDOG_RESET(); 243*918e9ebbSEric Nelson } while (s.avail_out == 0); 244*918e9ebbSEric Nelson /* done when inflate() says it's done */ 245*918e9ebbSEric Nelson } while (r != Z_STREAM_END); 246*918e9ebbSEric Nelson 247*918e9ebbSEric Nelson if ((szexpected != totalfilled) || 248*918e9ebbSEric Nelson (crc != expected_crc)) 249*918e9ebbSEric Nelson r = -1; 250*918e9ebbSEric Nelson else 251*918e9ebbSEric Nelson r = 0; 252*918e9ebbSEric Nelson 253*918e9ebbSEric Nelson out: 254*918e9ebbSEric Nelson gzwrite_progress_finish(r, totalfilled, szexpected, 255*918e9ebbSEric Nelson expected_crc, crc); 256*918e9ebbSEric Nelson free(writebuf); 257*918e9ebbSEric Nelson inflateEnd(&s); 258*918e9ebbSEric Nelson 259*918e9ebbSEric Nelson return r; 260*918e9ebbSEric Nelson } 261*918e9ebbSEric Nelson 26278acc472SPeter Tyser /* 26378acc472SPeter Tyser * Uncompress blocks compressed with zlib without headers 26478acc472SPeter Tyser */ 26578acc472SPeter Tyser int zunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp, 26678acc472SPeter Tyser int stoponerr, int offset) 26778acc472SPeter Tyser { 26878acc472SPeter Tyser z_stream s; 2699c55c54fSSimon Glass int err = 0; 27078acc472SPeter Tyser int r; 27178acc472SPeter Tyser 272e3ed0575SMike Frysinger s.zalloc = gzalloc; 273e3ed0575SMike Frysinger s.zfree = gzfree; 27478acc472SPeter Tyser 27578acc472SPeter Tyser r = inflateInit2(&s, -MAX_WBITS); 27678acc472SPeter Tyser if (r != Z_OK) { 27778acc472SPeter Tyser printf("Error: inflateInit2() returned %d\n", r); 27878acc472SPeter Tyser return -1; 27978acc472SPeter Tyser } 28078acc472SPeter Tyser s.next_in = src + offset; 28178acc472SPeter Tyser s.avail_in = *lenp - offset; 28278acc472SPeter Tyser s.next_out = dst; 28378acc472SPeter Tyser s.avail_out = dstlen; 284f039ada5SCatalin Radu do { 28578acc472SPeter Tyser r = inflate(&s, Z_FINISH); 286b75650d8SKees Cook if (stoponerr == 1 && r != Z_STREAM_END && 287b75650d8SKees Cook (s.avail_out == 0 || r != Z_BUF_ERROR)) { 28878acc472SPeter Tyser printf("Error: inflate() returned %d\n", r); 2899c55c54fSSimon Glass err = -1; 2909c55c54fSSimon Glass break; 29178acc472SPeter Tyser } 292f039ada5SCatalin Radu s.avail_in = *lenp - offset - (int)(s.next_out - (unsigned char*)dst); 293f039ada5SCatalin Radu } while (r == Z_BUF_ERROR); 29478acc472SPeter Tyser *lenp = s.next_out - (unsigned char *) dst; 29578acc472SPeter Tyser inflateEnd(&s); 29678acc472SPeter Tyser 2979c55c54fSSimon Glass return err; 29878acc472SPeter Tyser } 299