1 /* $NetBSD: gzboot.c,v 1.13 2009/03/18 17:06:44 cegger Exp $ */
4 * Copyright (c) 2002 Wasabi Systems, Inc.
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
39 * The Gzip header parser and libz interface glue are derived from
40 * sys/lib/libsa/cread.c, which carries the following notice:
43 * Matthias Drochner. All rights reserved.
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions
48 * 1. Redistributions of source code must retain the above copyright
49 * notice, this list of conditions and the following disclaimer.
50 * 2. Redistributions in binary form must reproduce the above copyright
51 * notice, this list of conditions and the following disclaimer in the
52 * documentation and/or other materials provided with the distribution.
54 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
55 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
56 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
57 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
58 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
59 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
60 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
61 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
62 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
63 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
66 #include <sys/param.h>
67 #include <lib/libsa/stand.h>
68 #include <lib/libkern/libkern.h>
69 #include <lib/libz/libz.h>
76 #define EOF (-1) /* needed by compression code */
78 #define Z_BUFSIZE 1024
80 static const int gz_magic
[2] = { 0x1f, 0x8b }; /* gzip magic header */
83 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
84 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
85 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
86 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
87 #define COMMENT 0x10 /* bit 4 set: file comment present */
88 #define RESERVED 0xe0 /* bits 5..7: reserved */
92 int z_err
; /* error code for last stream operation */
93 int z_eof
; /* set of end of input file */
94 const unsigned char *srcbuf
;/* source buffer */
95 size_t srcoff
; /* source buffer offset */
96 size_t srcsize
;/* size of source buffer */
97 unsigned char *inbuf
; /* input buffer */
98 uint32_t crc
; /* crc32 of uncompressed data */
99 int spinny
; /* twiddle every N reads */
102 static uint32_t get_u8(struct state
*);
103 static uint32_t get_u32(struct state
*);
104 static int check_header(struct state
*);
106 /* XXX - find a suitable header for these: */
107 void zmemcpy(unsigned char *, unsigned char *, unsigned int);
109 /* end zlib glue defns */
112 void gzcopy(void *, const void *, size_t);
117 extern char bootprog_name
[], bootprog_rev
[],
118 bootprog_maker
[], bootprog_date
[];
119 void (*loadaddr
)(void) = (void *) md_root_loadaddr
;
124 printf(">> %s, Revision %s\n", bootprog_name
, bootprog_rev
);
125 printf(">> (%s, %s)\n", bootprog_maker
, bootprog_date
);
129 printf(">> Load address: 0x%x\n", md_root_loadaddr
);
132 * If md_root_size is 0, then it means that we are simply
133 * decompressing from an image which was concatenated onto
134 * the end of the gzboot binary.
136 if (md_root_size
!= 0)
137 printf(">> Image size: %u\n", md_root_size
);
139 printf("Uncompressing image...");
140 gzcopy((void *) loadaddr
, md_root_image
, md_root_size
);
143 printf("Jumping to image @ 0x%x...\n", md_root_loadaddr
);
167 /* internal utility routines */
170 readbuf(struct state
*s
, void *buf
, size_t len
)
173 if (s
->srcsize
!= 0 && len
> (s
->srcsize
- s
->srcoff
))
174 len
= s
->srcsize
- s
->srcoff
;
176 if ((s
->spinny
++ & 7) == 0)
178 memcpy(buf
, s
->srcbuf
+ s
->srcoff
, len
);
185 readgz(struct state
*s
, void *buf
, size_t len
)
187 unsigned char *start
= buf
; /* start for CRC computation */
189 if (s
->z_err
== Z_DATA_ERROR
|| s
->z_err
== Z_ERRNO
)
191 if (s
->z_err
== Z_STREAM_END
)
192 return (0); /* EOF */
194 s
->stream
.next_out
= buf
;
195 s
->stream
.avail_out
= len
;
197 while (s
->stream
.avail_out
!= 0) {
198 if (s
->stream
.avail_in
== 0 && s
->z_eof
== 0) {
200 got
= readbuf(s
, s
->inbuf
, Z_BUFSIZE
);
203 s
->stream
.avail_in
= got
;
204 s
->stream
.next_in
= s
->inbuf
;
207 s
->z_err
= inflate(&s
->stream
, Z_NO_FLUSH
);
209 if (s
->z_err
== Z_STREAM_END
) {
210 /* Check CRC and original size */
211 s
->crc
= crc32(s
->crc
, start
, (unsigned int)
212 (s
->stream
.next_out
- start
));
213 start
= s
->stream
.next_out
;
215 if (get_u32(s
) != s
->crc
) {
216 printf("FATAL: CRC checksum mismatch\n");
217 s
->z_err
= Z_DATA_ERROR
;
219 if (get_u32(s
) != s
->stream
.total_out
) {
220 printf("FATAL: total output mismatch\n");
221 s
->z_err
= Z_DATA_ERROR
;
225 if (s
->z_err
!= Z_OK
&& s
->z_err
!= Z_STREAM_END
) {
226 printf("FATAL: error %d from zlib\n",
230 if (s
->z_err
!= Z_OK
|| s
->z_eof
)
234 s
->crc
= crc32(s
->crc
, start
,
235 (unsigned int)(s
->stream
.next_out
- start
));
237 return ((ssize_t
) (len
- s
->stream
.avail_out
));
240 /* util routines for zlib */
243 zmemcpy(unsigned char *dst
, unsigned char *src
, unsigned int len
)
246 memcpy(dst
, src
, len
);
249 /* gzip utility routines */
252 get_u8(struct state
*s
)
258 if (s
->stream
.avail_in
== 0) {
261 got
= readbuf(s
, s
->inbuf
, Z_BUFSIZE
);
266 s
->stream
.avail_in
= got
;
267 s
->stream
.next_in
= s
->inbuf
;
269 s
->stream
.avail_in
--;
270 return (*(s
->stream
.next_in
)++);
274 get_u32(struct state
*s
)
280 x
|= get_u8(s
) << 16;
283 s
->z_err
= Z_DATA_ERROR
;
289 check_header(struct state
*s
)
291 int method
; /* method byte */
292 int flags
; /* flags byte */
296 /* Check the gzip magic header */
297 for (len
= 0; len
< 2; len
++) {
299 if (c
== gz_magic
[len
])
301 printf("FATAL: not a Gzip'd image\n");
307 if (method
!= Z_DEFLATED
|| (flags
& RESERVED
) != 0) {
308 printf("FATAL: invalid Gzip header\n");
312 /* Discard time, xflags, and OS code: */
313 for (len
= 0; len
< 6; len
++)
316 if (flags
& EXTRA_FIELD
) {
317 /* skip the extra field */
319 len
|= get_u8(s
) << 8;
320 /* len is garbage if EOF, but the loop below will quit anyway */
321 while (len
-- && get_u8(s
) != EOF
)
324 if (flags
& ORIG_NAME
) {
325 /* skip the original file name */
326 while ((c
= get_u8(s
)) != 0 && c
!= EOF
)
329 if (flags
& COMMENT
) {
330 /* skip the file comment */
331 while ((c
= get_u8(s
)) != 0 && c
!= EOF
)
334 if (flags
& HEAD_CRC
) {
335 /* skip header CRC */
336 for (len
= 0; len
< 2; len
++)
341 printf("FATAL: end of image encountered parsing Gzip header\n");
349 /* the actual gzcopy routine */
352 gzcopy(void *dst
, const void *src
, size_t srclen
)
355 unsigned char *cp
= dst
;
358 memset(&state
, 0, sizeof(state
));
362 state
.srcsize
= srclen
;
364 if (inflateInit2(&state
.stream
, -15) != Z_OK
) {
365 printf("FATAL: inflateInit2 failed\n");
369 state
.stream
.next_in
= state
.inbuf
= alloc(Z_BUFSIZE
);
370 if (state
.inbuf
== NULL
) {
371 inflateEnd(&state
.stream
);
372 printf("FATAL: unable to allocate Z buffer\n");
376 /* Skip the Gzip header. */
377 if (check_header(&state
)) {
378 inflateEnd(&state
.stream
);
379 dealloc(state
.inbuf
, Z_BUFSIZE
);
383 /* Uncompress the image! */
384 while ((len
= readgz(&state
, cp
, Z_BUFSIZE
)) > 0)
390 inflateEnd(&state
.stream
);
391 dealloc(state
.inbuf
, Z_BUFSIZE
);