aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/boot/gunzip_util.c
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2007-03-04 22:24:52 -0500
committerPaul Mackerras <paulus@samba.org>2007-03-12 22:35:01 -0400
commitad9d2716cfc1cda5a7e0d7bc0db45e3af8a4adbb (patch)
treed91ea074bd35c61c86b3c012a41622d5016fc919 /arch/powerpc/boot/gunzip_util.c
parentcfbff8a3802542c4d8b2290c49b1a59128c4a380 (diff)
[POWERPC] zImage: Add more flexible gunzip convenience functions
At present, arch/powerpc/boot/main.c includes a gunzip() function which is a convenient wrapper around zlib. However, it doesn't conveniently allow decompressing part of an image to one location, then the remainder to a different address. This patch adds a new set of more flexible convenience wrappers around zlib, moving them to their own file, gunzip_util.c, in the process. These wrappers allow decompressing sections of the compressed image to different locations. In addition, they transparently handle uncompressed data, avoiding special case code to handle uncompressed vmlinux images. The patch also converts main.c to use the new wrappers, using the new flexibility to avoid decompressing the vmlinux's ELF header twice as we did previously. That in turn means we avoid extending our allocations for the vmlinux to allow space for the extra copy of the ELF header. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/boot/gunzip_util.c')
-rw-r--r--arch/powerpc/boot/gunzip_util.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/arch/powerpc/boot/gunzip_util.c b/arch/powerpc/boot/gunzip_util.c
new file mode 100644
index 000000000000..3d9ff8f081c6
--- /dev/null
+++ b/arch/powerpc/boot/gunzip_util.c
@@ -0,0 +1,140 @@
1/*
2 * Copyright 2007 David Gibson, IBM Corporation.
3 * Based on earlier work, Copyright (C) Paul Mackerras 1997.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 */
10
11#include <stddef.h>
12#include "string.h"
13#include "stdio.h"
14#include "ops.h"
15#include "gunzip_util.h"
16
17struct gunzip_state state;
18
19#define HEAD_CRC 2
20#define EXTRA_FIELD 4
21#define ORIG_NAME 8
22#define COMMENT 0x10
23#define RESERVED 0xe0
24
25void gunzip_start(struct gunzip_state *state, void *src, int srclen)
26{
27 char *hdr = src;
28 int hdrlen = 0;
29
30 memset(state, 0, sizeof(*state));
31
32 /* Check for gzip magic number */
33 if ((hdr[0] == 0x1f) && (hdr[1] == 0x8b)) {
34 /* gzip data, initialize zlib parameters */
35 int r, flags;
36
37 state->s.workspace = state->scratch;
38 if (zlib_inflate_workspacesize() > sizeof(state->scratch)) {
39 printf("insufficient scratch space for gunzip\n\r");
40 exit();
41 }
42
43 /* skip header */
44 hdrlen = 10;
45 flags = hdr[3];
46 if (hdr[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
47 printf("bad gzipped data\n\r");
48 exit();
49 }
50 if ((flags & EXTRA_FIELD) != 0)
51 hdrlen = 12 + hdr[10] + (hdr[11] << 8);
52 if ((flags & ORIG_NAME) != 0)
53 while (hdr[hdrlen++] != 0)
54 ;
55 if ((flags & COMMENT) != 0)
56 while (hdr[hdrlen++] != 0)
57 ;
58 if ((flags & HEAD_CRC) != 0)
59 hdrlen += 2;
60 if (hdrlen >= srclen) {
61 printf("gunzip_start: ran out of data in header\n\r");
62 exit();
63 }
64
65 r = zlib_inflateInit2(&state->s, -MAX_WBITS);
66 if (r != Z_OK) {
67 printf("inflateInit2 returned %d\n\r", r);
68 exit();
69 }
70 }
71
72 state->s.next_in = src + hdrlen;
73 state->s.avail_in = srclen - hdrlen;
74}
75
76int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen)
77{
78 int len;
79
80 if (state->s.workspace) {
81 /* gunzipping */
82 int r;
83
84 state->s.next_out = dst;
85 state->s.avail_out = dstlen;
86 r = zlib_inflate(&state->s, Z_FULL_FLUSH);
87 if (r != Z_OK && r != Z_STREAM_END) {
88 printf("inflate returned %d msg: %s\n\r", r, state->s.msg);
89 exit();
90 }
91 len = state->s.next_out - (unsigned char *)dst;
92 } else {
93 /* uncompressed image */
94 len = min(state->s.avail_in, (unsigned)dstlen);
95 memcpy(dst, state->s.next_in, len);
96 state->s.next_in += len;
97 state->s.avail_in -= len;
98 }
99 return len;
100}
101
102void gunzip_exactly(struct gunzip_state *state, void *dst, int dstlen)
103{
104 int len;
105
106 len = gunzip_partial(state, dst, dstlen);
107 if (len < dstlen) {
108 printf("gunzip_block: ran out of data\n\r");
109 exit();
110 }
111}
112
113void gunzip_discard(struct gunzip_state *state, int len)
114{
115 static char discard_buf[128];
116
117 while (len > sizeof(discard_buf)) {
118 gunzip_exactly(state, discard_buf, sizeof(discard_buf));
119 len -= sizeof(discard_buf);
120 }
121
122 if (len > 0)
123 gunzip_exactly(state, discard_buf, len);
124}
125
126int gunzip_finish(struct gunzip_state *state, void *dst, int dstlen)
127{
128 int len;
129
130 if (state->s.workspace) {
131 len = gunzip_partial(state, dst, dstlen);
132 zlib_inflateEnd(&state->s);
133 } else {
134 /* uncompressed image */
135 len = min(state->s.avail_in, (unsigned)dstlen);
136 memcpy(dst, state->s.next_in, len);
137 }
138
139 return len;
140}