orphan
[debian/elilo] / gunzip.c
1 /*
2  *  Copyright (C) 2005 Hewlett-Packard Development Company, L.P.
3  *      Contributed by Alex Williamson <alex.williamson@hp.com>
4  *
5  *  Copyright (C) 2001-2003 Hewlett-Packard Co.
6  *      Contributed by Stephane Eranian <eranian@hpl.hp.com>
7  *
8  *  Copyright (C) 2001 Silicon Graphics, Inc.
9  *      Contributed by Brent Casavant <bcasavan@sgi.com>
10  *
11  * This file is part of the ELILO, the EFI Linux boot loader.
12  *
13  *  ELILO is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU General Public License as published by
15  *  the Free Software Foundation; either version 2, or (at your option)
16  *  any later version.
17  *
18  *  ELILO is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU General Public License for more details.
22  *
23  *  You should have received a copy of the GNU General Public License
24  *  along with ELILO; see the file COPYING.  If not, write to the Free
25  *  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
26  *  02111-1307, USA.
27  *
28  * Please check out the elilo.txt for complete documentation on how
29  * to use this program.
30  */
31
32 #include <efi.h>
33 #include <efilib.h>
34
35 #include "elilo.h"
36
37 #include "gzip.h"
38
39 #define LD_NAME L"gunzip"
40
41 #define memzero(s, n)   Memset((VOID *)(s), 0, (n))
42 #define memcpy(a,b,n)   Memcpy((VOID *)(a),(b),(n))
43
44 /* size of output buffer */
45 #define WSIZE 0x8000            /* Window size must be at least 32k, */
46                                 /* and a power of two */
47 /*
48  * gzip declarations
49  */
50 #define OF(args)  args
51 #define FUNC_STATIC static
52
53 typedef unsigned char  uch;
54 typedef unsigned short ush;
55 typedef unsigned long  ulg;
56
57 /*
58  * static parameters to gzip helper functions
59  * we cannot use paramters because API was not
60  * designed that way
61  */
62 static uch *inbuf;              /* input buffer (compressed data) */
63 static uch *window;             /* output buffer (uncompressed data) */
64
65 static VOID *outbuf;
66 unsigned char *outptr;
67 static unsigned long outsize;
68
69 static unsigned inptr  = 0;   /* index of next byte to be processed in inbuf */
70 static unsigned outcnt = 0;  /* bytes in output buffer */
71
72 #define get_byte()  inbuf[inptr++]
73
74 /* Diagnostic functions */
75 #ifdef INFLATE_DEBUG
76 #  define Assert(cond,msg) {if(!(cond)) error(msg);}
77 int stderr;
78 #  define Trace(x) Print(L"line %d:\n", __LINE__);
79 #  define Tracev(x) {if (verbose) Print(L"line %d:\n", __LINE__) ;}
80 #  define Tracevv(x) {if (verbose>1) Print(L"line %d:\n", __LINE__)  ;}
81 #  define Tracec(c,x) {if (verbose && (c))  Print(L"line %d:\n", __LINE__) ;}
82 #  define Tracecv(c,x) {if (verbose>1 && (c))  Print(L"line %d:\n", __LINE__) ;}
83 #else
84 #  define Assert(cond,msg)
85 #  define Trace(x)
86 #  define Tracev(x)
87 #  define Tracevv(x)
88 #  define Tracec(c,x)
89 #  define Tracecv(c,x)
90 #endif
91
92 static void flush_window(void);
93 static void error(char *m);
94 static long bytes_out;
95
96 static void error(char *m);
97
98 #define gzip_malloc(size) (void *)alloc(size, 0)
99 #define gzip_free(where) free(where)
100
101 #include "inflate.c"
102
103 /*
104  * Run a set of bytes through the crc shift register.  If s is a NULL
105  * pointer, then initialize the crc shift register contents instead.
106  * Return the current crc in either case.
107  *
108  * Input:
109  *      S       pointer to bytes to pump through.
110  *      N       number of bytes in S[].
111  */
112 static void
113 updcrc(unsigned char *s, unsigned n)
114 {
115         register unsigned long c;
116         /* crc is defined in inflate.c */
117
118         c = crc;
119         while (n--) {
120                 c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
121         }
122         crc = c;
123         return;
124 }
125
126 /*
127  * Clear input and output buffers
128  */
129 static void
130 clear_bufs(void)
131 {
132         outcnt = 0;
133         inptr = 0;
134 }
135
136 /*
137  * Write the output window window[0..outcnt-1] holding uncompressed
138  * data and update crc.
139  */
140 void
141 flush_window(void)
142 {
143         /*
144          * We'll end up relying on the CRC check and size check failing
145          * if there's actually more data than we expect.
146          */
147         if (!outcnt || bytes_out + outcnt > outsize)
148                 return;
149
150         updcrc(window, outcnt);
151
152         Memcpy(outptr, window, outcnt);
153         outptr += outcnt;
154         bytes_out += outcnt;
155
156         outcnt = 0;
157 }
158
159 static void
160 error(char *x)
161 {
162         ERR_PRT((L"%s : %a", LD_NAME, x));
163         /* will eventually exit with error from gunzip() */
164 }
165
166 static INT32
167 decompress(VOID)
168 {
169         INT32 ret;
170
171         clear_bufs();
172         makecrc();
173         Print(L"Uncompressing... ");
174         ret = gunzip();
175         if (ret == 0) Print(L"done\n");
176         return ret == 0 ? 0 : -1;
177 }
178
179 int
180 gunzip_image(memdesc_t *image)
181 {
182         UINTN pgcnt;
183
184         inbuf = image->start_addr;
185
186         /* 
187          * Last 4 bytes of gzip'd image indicates the uncompressed size
188          */
189         outsize = inbuf[image->size - 1] << 24 | inbuf[image->size - 2] << 16 |
190                   inbuf[image->size - 3] << 8 | inbuf[image->size - 4];
191
192         pgcnt = EFI_SIZE_TO_PAGES(outsize);
193
194         outbuf = alloc_pages(pgcnt, EfiLoaderData, AllocateAnyPages, 0);
195         if (outbuf == NULL) {
196                 ERR_PRT((L"%s : allocate output buffer failed\n", LD_NAME));
197                 return -1;
198         }
199         outptr = outbuf;
200
201         window = (void *)alloc(WSIZE, 0);
202         if (window == NULL) {
203                 ERR_PRT((L"%s : allocate output window failed\n", LD_NAME));
204                 free(outbuf);
205                 return -1;
206         }
207
208         bytes_out  = 0;
209
210         if (decompress() != 0) {
211                 free(window);
212                 free(outbuf);
213                 return ELILO_LOAD_ERROR;
214         }
215
216         free(window);
217         free(image->start_addr);
218
219         image->start_addr = outbuf;
220         image->size = outsize;
221         image->pgcnt = pgcnt;
222
223         return ELILO_LOAD_SUCCESS;
224 }