diff options
Diffstat (limited to 'arch/x86_64/boot/compressed/misc.c')
-rw-r--r-- | arch/x86_64/boot/compressed/misc.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c new file mode 100644 index 000000000000..c8b9216f9e63 --- /dev/null +++ b/arch/x86_64/boot/compressed/misc.c | |||
@@ -0,0 +1,354 @@ | |||
1 | /* | ||
2 | * misc.c | ||
3 | * | ||
4 | * This is a collection of several routines from gzip-1.0.3 | ||
5 | * adapted for Linux. | ||
6 | * | ||
7 | * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 | ||
8 | * puts by Nick Holloway 1993, better puts by Martin Mares 1995 | ||
9 | * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 | ||
10 | */ | ||
11 | |||
12 | #include "miscsetup.h" | ||
13 | #include <asm/io.h> | ||
14 | |||
15 | /* | ||
16 | * gzip declarations | ||
17 | */ | ||
18 | |||
19 | #define OF(args) args | ||
20 | #define STATIC static | ||
21 | |||
22 | #undef memset | ||
23 | #undef memcpy | ||
24 | #define memzero(s, n) memset ((s), 0, (n)) | ||
25 | |||
26 | typedef unsigned char uch; | ||
27 | typedef unsigned short ush; | ||
28 | typedef unsigned long ulg; | ||
29 | |||
30 | #define WSIZE 0x8000 /* Window size must be at least 32k, */ | ||
31 | /* and a power of two */ | ||
32 | |||
33 | static uch *inbuf; /* input buffer */ | ||
34 | static uch window[WSIZE]; /* Sliding window buffer */ | ||
35 | |||
36 | static unsigned insize = 0; /* valid bytes in inbuf */ | ||
37 | static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ | ||
38 | static unsigned outcnt = 0; /* bytes in output buffer */ | ||
39 | |||
40 | /* gzip flag byte */ | ||
41 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ | ||
42 | #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ | ||
43 | #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ | ||
44 | #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ | ||
45 | #define COMMENT 0x10 /* bit 4 set: file comment present */ | ||
46 | #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ | ||
47 | #define RESERVED 0xC0 /* bit 6,7: reserved */ | ||
48 | |||
49 | #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) | ||
50 | |||
51 | /* Diagnostic functions */ | ||
52 | #ifdef DEBUG | ||
53 | # define Assert(cond,msg) {if(!(cond)) error(msg);} | ||
54 | # define Trace(x) fprintf x | ||
55 | # define Tracev(x) {if (verbose) fprintf x ;} | ||
56 | # define Tracevv(x) {if (verbose>1) fprintf x ;} | ||
57 | # define Tracec(c,x) {if (verbose && (c)) fprintf x ;} | ||
58 | # define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} | ||
59 | #else | ||
60 | # define Assert(cond,msg) | ||
61 | # define Trace(x) | ||
62 | # define Tracev(x) | ||
63 | # define Tracevv(x) | ||
64 | # define Tracec(c,x) | ||
65 | # define Tracecv(c,x) | ||
66 | #endif | ||
67 | |||
68 | static int fill_inbuf(void); | ||
69 | static void flush_window(void); | ||
70 | static void error(char *m); | ||
71 | static void gzip_mark(void **); | ||
72 | static void gzip_release(void **); | ||
73 | |||
74 | /* | ||
75 | * This is set up by the setup-routine at boot-time | ||
76 | */ | ||
77 | static unsigned char *real_mode; /* Pointer to real-mode data */ | ||
78 | |||
79 | #define EXT_MEM_K (*(unsigned short *)(real_mode + 0x2)) | ||
80 | #ifndef STANDARD_MEMORY_BIOS_CALL | ||
81 | #define ALT_MEM_K (*(unsigned long *)(real_mode + 0x1e0)) | ||
82 | #endif | ||
83 | #define SCREEN_INFO (*(struct screen_info *)(real_mode+0)) | ||
84 | |||
85 | extern char input_data[]; | ||
86 | extern int input_len; | ||
87 | |||
88 | static long bytes_out = 0; | ||
89 | static uch *output_data; | ||
90 | static unsigned long output_ptr = 0; | ||
91 | |||
92 | static void *malloc(int size); | ||
93 | static void free(void *where); | ||
94 | |||
95 | static void putstr(const char *); | ||
96 | |||
97 | extern int end; | ||
98 | static long free_mem_ptr = (long)&end; | ||
99 | static long free_mem_end_ptr; | ||
100 | |||
101 | #define INPLACE_MOVE_ROUTINE 0x1000 | ||
102 | #define LOW_BUFFER_START 0x2000 | ||
103 | #define LOW_BUFFER_MAX 0x90000 | ||
104 | #define HEAP_SIZE 0x3000 | ||
105 | static unsigned int low_buffer_end, low_buffer_size; | ||
106 | static int high_loaded =0; | ||
107 | static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/; | ||
108 | |||
109 | static char *vidmem = (char *)0xb8000; | ||
110 | static int vidport; | ||
111 | static int lines, cols; | ||
112 | |||
113 | #include "../../../../lib/inflate.c" | ||
114 | |||
115 | static void *malloc(int size) | ||
116 | { | ||
117 | void *p; | ||
118 | |||
119 | if (size <0) error("Malloc error"); | ||
120 | if (free_mem_ptr <= 0) error("Memory error"); | ||
121 | |||
122 | free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ | ||
123 | |||
124 | p = (void *)free_mem_ptr; | ||
125 | free_mem_ptr += size; | ||
126 | |||
127 | if (free_mem_ptr >= free_mem_end_ptr) | ||
128 | error("Out of memory"); | ||
129 | |||
130 | return p; | ||
131 | } | ||
132 | |||
133 | static void free(void *where) | ||
134 | { /* Don't care */ | ||
135 | } | ||
136 | |||
137 | static void gzip_mark(void **ptr) | ||
138 | { | ||
139 | *ptr = (void *) free_mem_ptr; | ||
140 | } | ||
141 | |||
142 | static void gzip_release(void **ptr) | ||
143 | { | ||
144 | free_mem_ptr = (long) *ptr; | ||
145 | } | ||
146 | |||
147 | static void scroll(void) | ||
148 | { | ||
149 | int i; | ||
150 | |||
151 | memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 ); | ||
152 | for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 ) | ||
153 | vidmem[i] = ' '; | ||
154 | } | ||
155 | |||
156 | static void putstr(const char *s) | ||
157 | { | ||
158 | int x,y,pos; | ||
159 | char c; | ||
160 | |||
161 | x = SCREEN_INFO.orig_x; | ||
162 | y = SCREEN_INFO.orig_y; | ||
163 | |||
164 | while ( ( c = *s++ ) != '\0' ) { | ||
165 | if ( c == '\n' ) { | ||
166 | x = 0; | ||
167 | if ( ++y >= lines ) { | ||
168 | scroll(); | ||
169 | y--; | ||
170 | } | ||
171 | } else { | ||
172 | vidmem [ ( x + cols * y ) * 2 ] = c; | ||
173 | if ( ++x >= cols ) { | ||
174 | x = 0; | ||
175 | if ( ++y >= lines ) { | ||
176 | scroll(); | ||
177 | y--; | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | |||
183 | SCREEN_INFO.orig_x = x; | ||
184 | SCREEN_INFO.orig_y = y; | ||
185 | |||
186 | pos = (x + cols * y) * 2; /* Update cursor position */ | ||
187 | outb_p(14, vidport); | ||
188 | outb_p(0xff & (pos >> 9), vidport+1); | ||
189 | outb_p(15, vidport); | ||
190 | outb_p(0xff & (pos >> 1), vidport+1); | ||
191 | } | ||
192 | |||
193 | void* memset(void* s, int c, unsigned n) | ||
194 | { | ||
195 | int i; | ||
196 | char *ss = (char*)s; | ||
197 | |||
198 | for (i=0;i<n;i++) ss[i] = c; | ||
199 | return s; | ||
200 | } | ||
201 | |||
202 | void* memcpy(void* dest, const void* src, unsigned n) | ||
203 | { | ||
204 | int i; | ||
205 | char *d = (char *)dest, *s = (char *)src; | ||
206 | |||
207 | for (i=0;i<n;i++) d[i] = s[i]; | ||
208 | return dest; | ||
209 | } | ||
210 | |||
211 | /* =========================================================================== | ||
212 | * Fill the input buffer. This is called only when the buffer is empty | ||
213 | * and at least one byte is really needed. | ||
214 | */ | ||
215 | static int fill_inbuf(void) | ||
216 | { | ||
217 | if (insize != 0) { | ||
218 | error("ran out of input data"); | ||
219 | } | ||
220 | |||
221 | inbuf = input_data; | ||
222 | insize = input_len; | ||
223 | inptr = 1; | ||
224 | return inbuf[0]; | ||
225 | } | ||
226 | |||
227 | /* =========================================================================== | ||
228 | * Write the output window window[0..outcnt-1] and update crc and bytes_out. | ||
229 | * (Used for the decompressed data only.) | ||
230 | */ | ||
231 | static void flush_window_low(void) | ||
232 | { | ||
233 | ulg c = crc; /* temporary variable */ | ||
234 | unsigned n; | ||
235 | uch *in, *out, ch; | ||
236 | |||
237 | in = window; | ||
238 | out = &output_data[output_ptr]; | ||
239 | for (n = 0; n < outcnt; n++) { | ||
240 | ch = *out++ = *in++; | ||
241 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
242 | } | ||
243 | crc = c; | ||
244 | bytes_out += (ulg)outcnt; | ||
245 | output_ptr += (ulg)outcnt; | ||
246 | outcnt = 0; | ||
247 | } | ||
248 | |||
249 | static void flush_window_high(void) | ||
250 | { | ||
251 | ulg c = crc; /* temporary variable */ | ||
252 | unsigned n; | ||
253 | uch *in, ch; | ||
254 | in = window; | ||
255 | for (n = 0; n < outcnt; n++) { | ||
256 | ch = *output_data++ = *in++; | ||
257 | if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start; | ||
258 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
259 | } | ||
260 | crc = c; | ||
261 | bytes_out += (ulg)outcnt; | ||
262 | outcnt = 0; | ||
263 | } | ||
264 | |||
265 | static void flush_window(void) | ||
266 | { | ||
267 | if (high_loaded) flush_window_high(); | ||
268 | else flush_window_low(); | ||
269 | } | ||
270 | |||
271 | static void error(char *x) | ||
272 | { | ||
273 | putstr("\n\n"); | ||
274 | putstr(x); | ||
275 | putstr("\n\n -- System halted"); | ||
276 | |||
277 | while(1); | ||
278 | } | ||
279 | |||
280 | void setup_normal_output_buffer(void) | ||
281 | { | ||
282 | #ifdef STANDARD_MEMORY_BIOS_CALL | ||
283 | if (EXT_MEM_K < 1024) error("Less than 2MB of memory"); | ||
284 | #else | ||
285 | if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory"); | ||
286 | #endif | ||
287 | output_data = (char *)0x100000; /* Points to 1M */ | ||
288 | free_mem_end_ptr = (long)real_mode; | ||
289 | } | ||
290 | |||
291 | struct moveparams { | ||
292 | uch *low_buffer_start; int lcount; | ||
293 | uch *high_buffer_start; int hcount; | ||
294 | }; | ||
295 | |||
296 | void setup_output_buffer_if_we_run_high(struct moveparams *mv) | ||
297 | { | ||
298 | high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE); | ||
299 | #ifdef STANDARD_MEMORY_BIOS_CALL | ||
300 | if (EXT_MEM_K < (3*1024)) error("Less than 4MB of memory"); | ||
301 | #else | ||
302 | if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory"); | ||
303 | #endif | ||
304 | mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START; | ||
305 | low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX | ||
306 | ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff; | ||
307 | low_buffer_size = low_buffer_end - LOW_BUFFER_START; | ||
308 | high_loaded = 1; | ||
309 | free_mem_end_ptr = (long)high_buffer_start; | ||
310 | if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) { | ||
311 | high_buffer_start = (uch *)(0x100000 + low_buffer_size); | ||
312 | mv->hcount = 0; /* say: we need not to move high_buffer */ | ||
313 | } | ||
314 | else mv->hcount = -1; | ||
315 | mv->high_buffer_start = high_buffer_start; | ||
316 | } | ||
317 | |||
318 | void close_output_buffer_if_we_run_high(struct moveparams *mv) | ||
319 | { | ||
320 | if (bytes_out > low_buffer_size) { | ||
321 | mv->lcount = low_buffer_size; | ||
322 | if (mv->hcount) | ||
323 | mv->hcount = bytes_out - low_buffer_size; | ||
324 | } else { | ||
325 | mv->lcount = bytes_out; | ||
326 | mv->hcount = 0; | ||
327 | } | ||
328 | } | ||
329 | |||
330 | int decompress_kernel(struct moveparams *mv, void *rmode) | ||
331 | { | ||
332 | real_mode = rmode; | ||
333 | |||
334 | if (SCREEN_INFO.orig_video_mode == 7) { | ||
335 | vidmem = (char *) 0xb0000; | ||
336 | vidport = 0x3b4; | ||
337 | } else { | ||
338 | vidmem = (char *) 0xb8000; | ||
339 | vidport = 0x3d4; | ||
340 | } | ||
341 | |||
342 | lines = SCREEN_INFO.orig_video_lines; | ||
343 | cols = SCREEN_INFO.orig_video_cols; | ||
344 | |||
345 | if (free_mem_ptr < 0x100000) setup_normal_output_buffer(); | ||
346 | else setup_output_buffer_if_we_run_high(mv); | ||
347 | |||
348 | makecrc(); | ||
349 | putstr(".\nDecompressing Linux..."); | ||
350 | gunzip(); | ||
351 | putstr("done.\nBooting the kernel.\n"); | ||
352 | if (high_loaded) close_output_buffer_if_we_run_high(mv); | ||
353 | return high_loaded; | ||
354 | } | ||