Commit 5a1235779ebbf089dea70098c5432749a919b150
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; | ... | ... |