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; | ... | ... |