Commit 5a1235779ebbf089dea70098c5432749a919b150

Authored by aliguori
1 parent 265ca29a

uImage: implement gzip support (Hollis Blanchard)

Based on gzip uImage loading code from u-boot.

Signed-off-by: Jerone Young <jyoung5@us.ibm.com>
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5762 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 136 additions and 4 deletions
loader.c
... ... @@ -20,12 +20,37 @@
20 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 22 * THE SOFTWARE.
  23 + *
  24 + * Gunzip functionality in this file is derived from u-boot:
  25 + *
  26 + * (C) Copyright 2008 Semihalf
  27 + *
  28 + * (C) Copyright 2000-2005
  29 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  30 + *
  31 + * This program is free software; you can redistribute it and/or
  32 + * modify it under the terms of the GNU General Public License as
  33 + * published by the Free Software Foundation; either version 2 of
  34 + * the License, or (at your option) any later version.
  35 + *
  36 + * This program is distributed in the hope that it will be useful,
  37 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  38 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  39 + * GNU General Public License for more details.
  40 + *
  41 + * You should have received a copy of the GNU General Public License
  42 + * along with this program; if not, write to the Free Software
  43 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  44 + * MA 02111-1307 USA
23 45 */
  46 +
24 47 #include "qemu-common.h"
25 48 #include "disas.h"
26 49 #include "sysemu.h"
27 50 #include "uboot_image.h"
28 51  
  52 +#include <zlib.h>
  53 +
29 54 /* return the size or -1 if error */
30 55 int get_image_size(const char *filename)
31 56 {
... ... @@ -345,10 +370,94 @@ static void bswap_uboot_header(uboot_image_header_t *hdr)
345 370 #endif
346 371 }
347 372  
  373 +
  374 +#define ZALLOC_ALIGNMENT 16
  375 +
  376 +static void *zalloc(void *x, unsigned items, unsigned size)
  377 +{
  378 + void *p;
  379 +
  380 + size *= items;
  381 + size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
  382 +
  383 + p = qemu_malloc(size);
  384 +
  385 + return (p);
  386 +}
  387 +
  388 +static void zfree(void *x, void *addr, unsigned nb)
  389 +{
  390 + qemu_free(addr);
  391 +}
  392 +
  393 +
  394 +#define HEAD_CRC 2
  395 +#define EXTRA_FIELD 4
  396 +#define ORIG_NAME 8
  397 +#define COMMENT 0x10
  398 +#define RESERVED 0xe0
  399 +
  400 +#define DEFLATED 8
  401 +
  402 +/* This is the maximum in uboot, so if a uImage overflows this, it would
  403 + * overflow on real hardware too. */
  404 +#define UBOOT_MAX_GUNZIP_BYTES 0x800000
  405 +
  406 +static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
  407 + size_t srclen)
  408 +{
  409 + z_stream s;
  410 + ssize_t dstbytes;
  411 + int r, i, flags;
  412 +
  413 + /* skip header */
  414 + i = 10;
  415 + flags = src[3];
  416 + if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
  417 + puts ("Error: Bad gzipped data\n");
  418 + return -1;
  419 + }
  420 + if ((flags & EXTRA_FIELD) != 0)
  421 + i = 12 + src[10] + (src[11] << 8);
  422 + if ((flags & ORIG_NAME) != 0)
  423 + while (src[i++] != 0)
  424 + ;
  425 + if ((flags & COMMENT) != 0)
  426 + while (src[i++] != 0)
  427 + ;
  428 + if ((flags & HEAD_CRC) != 0)
  429 + i += 2;
  430 + if (i >= srclen) {
  431 + puts ("Error: gunzip out of data in header\n");
  432 + return -1;
  433 + }
  434 +
  435 + s.zalloc = zalloc;
  436 + s.zfree = (free_func)zfree;
  437 +
  438 + r = inflateInit2(&s, -MAX_WBITS);
  439 + if (r != Z_OK) {
  440 + printf ("Error: inflateInit2() returned %d\n", r);
  441 + return (-1);
  442 + }
  443 + s.next_in = src + i;
  444 + s.avail_in = srclen - i;
  445 + s.next_out = dst;
  446 + s.avail_out = dstlen;
  447 + r = inflate(&s, Z_FINISH);
  448 + if (r != Z_OK && r != Z_STREAM_END) {
  449 + printf ("Error: inflate() returned %d\n", r);
  450 + return -1;
  451 + }
  452 + dstbytes = s.next_out - (unsigned char *) dst;
  453 + inflateEnd(&s);
  454 +
  455 + return dstbytes;
  456 +}
  457 +
348 458 /* Load a U-Boot image. */
349 459 int load_uboot(const char *filename, target_ulong *ep, int *is_linux)
350 460 {
351   -
352 461 int fd;
353 462 int size;
354 463 uboot_image_header_t h;
... ... @@ -375,9 +484,14 @@ int load_uboot(const char *filename, target_ulong *ep, int *is_linux)
375 484 goto out;
376 485 }
377 486  
378   - /* TODO: Implement compressed images. */
379   - if (hdr->ih_comp != IH_COMP_NONE) {
380   - fprintf(stderr, "Unable to load compressed u-boot images\n");
  487 + switch (hdr->ih_comp) {
  488 + case IH_COMP_NONE:
  489 + case IH_COMP_GZIP:
  490 + break;
  491 + default:
  492 + fprintf(stderr,
  493 + "Unable to load u-boot images with compression type %d\n",
  494 + hdr->ih_comp);
381 495 goto out;
382 496 }
383 497  
... ... @@ -399,6 +513,24 @@ int load_uboot(const char *filename, target_ulong *ep, int *is_linux)
399 513 goto out;
400 514 }
401 515  
  516 + if (hdr->ih_comp == IH_COMP_GZIP) {
  517 + uint8_t *compressed_data;
  518 + size_t max_bytes;
  519 + ssize_t bytes;
  520 +
  521 + compressed_data = data;
  522 + max_bytes = UBOOT_MAX_GUNZIP_BYTES;
  523 + data = qemu_malloc(max_bytes);
  524 +
  525 + bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
  526 + qemu_free(compressed_data);
  527 + if (bytes < 0) {
  528 + fprintf(stderr, "Unable to decompress gzipped image!\n");
  529 + goto out;
  530 + }
  531 + hdr->ih_size = bytes;
  532 + }
  533 +
402 534 cpu_physical_memory_write_rom(hdr->ih_load, data, hdr->ih_size);
403 535  
404 536 ret = hdr->ih_size;
... ...