Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel'
[palacios.git] / kitten / arch / x86_64 / boot / compressed / misc.c
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 #define _LWK_STRING_H 1
13 #define _LWK_BITMAP_H 1
14
15 #include <lwk/linkage.h>
16 #include <lwk/screen_info.h>
17 #include <arch/page.h>
18 #include <arch/io.h>
19
20 /* WARNING!!
21  * This code is compiled with -fPIC and it is relocated dynamically
22  * at run time, but no relocation processing is performed.
23  * This means that it is not safe to place pointers in static structures.
24  */
25
26 /*
27  * Getting to provable safe in place decompression is hard.
28  * Worst case behaviours need to be analized.
29  * Background information:
30  *
31  * The file layout is:
32  *    magic[2]
33  *    method[1]
34  *    flags[1]
35  *    timestamp[4]
36  *    extraflags[1]
37  *    os[1]
38  *    compressed data blocks[N]
39  *    crc[4] orig_len[4]
40  *
41  * resulting in 18 bytes of non compressed data overhead.
42  *
43  * Files divided into blocks
44  * 1 bit (last block flag)
45  * 2 bits (block type)
46  *
47  * 1 block occurs every 32K -1 bytes or when there 50% compression has been achieved.
48  * The smallest block type encoding is always used.
49  *
50  * stored:
51  *    32 bits length in bytes.
52  *
53  * fixed:
54  *    magic fixed tree.
55  *    symbols.
56  *
57  * dynamic:
58  *    dynamic tree encoding.
59  *    symbols.
60  *
61  *
62  * The buffer for decompression in place is the length of the
63  * uncompressed data, plus a small amount extra to keep the algorithm safe.
64  * The compressed data is placed at the end of the buffer.  The output
65  * pointer is placed at the start of the buffer and the input pointer
66  * is placed where the compressed data starts.  Problems will occur
67  * when the output pointer overruns the input pointer.
68  *
69  * The output pointer can only overrun the input pointer if the input
70  * pointer is moving faster than the output pointer.  A condition only
71  * triggered by data whose compressed form is larger than the uncompressed
72  * form.
73  *
74  * The worst case at the block level is a growth of the compressed data
75  * of 5 bytes per 32767 bytes.
76  *
77  * The worst case internal to a compressed block is very hard to figure.
78  * The worst case can at least be boundined by having one bit that represents
79  * 32764 bytes and then all of the rest of the bytes representing the very
80  * very last byte.
81  *
82  * All of which is enough to compute an amount of extra data that is required
83  * to be safe.  To avoid problems at the block level allocating 5 extra bytes
84  * per 32767 bytes of data is sufficient.  To avoind problems internal to a block
85  * adding an extra 32767 bytes (the worst case uncompressed block size) is
86  * sufficient, to ensure that in the worst case the decompressed data for
87  * block will stop the byte before the compressed data for a block begins.
88  * To avoid problems with the compressed data's meta information an extra 18
89  * bytes are needed.  Leading to the formula:
90  *
91  * extra_bytes = (uncompressed_size >> 12) + 32768 + 18 + decompressor_size.
92  *
93  * Adding 8 bytes per 32K is a bit excessive but much easier to calculate.
94  * Adding 32768 instead of 32767 just makes for round numbers.
95  * Adding the decompressor_size is necessary as it musht live after all
96  * of the data as well.  Last I measured the decompressor is about 14K.
97  * 10K of actuall data and 4K of bss.
98  *
99  */
100
101 /*
102  * gzip declarations
103  */
104
105 #define OF(args)  args
106 #define STATIC static
107
108 #undef memset
109 #undef memcpy
110 #define memzero(s, n)     memset ((s), 0, (n))
111
112 typedef unsigned char  uch;
113 typedef unsigned short ush;
114 typedef unsigned long  ulg;
115
116 #define WSIZE 0x80000000        /* Window size must be at least 32k,
117                                  * and a power of two
118                                  * We don't actually have a window just
119                                  * a huge output buffer so I report
120                                  * a 2G windows size, as that should
121                                  * always be larger than our output buffer.
122                                  */
123
124 static uch *inbuf;      /* input buffer */
125 static uch *window;     /* Sliding window buffer, (and final output buffer) */
126
127 static unsigned insize;  /* valid bytes in inbuf */
128 static unsigned inptr;   /* index of next byte to be processed in inbuf */
129 static unsigned outcnt;  /* bytes in output buffer */
130
131 /* gzip flag byte */
132 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
133 #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
134 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
135 #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
136 #define COMMENT      0x10 /* bit 4 set: file comment present */
137 #define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
138 #define RESERVED     0xC0 /* bit 6,7:   reserved */
139
140 #define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
141                 
142 /* Diagnostic functions */
143 #ifdef DEBUG
144 #  define Assert(cond,msg) {if(!(cond)) error(msg);}
145 #  define Trace(x) fprintf x
146 #  define Tracev(x) {if (verbose) fprintf x ;}
147 #  define Tracevv(x) {if (verbose>1) fprintf x ;}
148 #  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
149 #  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
150 #else
151 #  define Assert(cond,msg)
152 #  define Trace(x)
153 #  define Tracev(x)
154 #  define Tracevv(x)
155 #  define Tracec(c,x)
156 #  define Tracecv(c,x)
157 #endif
158
159 static int  fill_inbuf(void);
160 static void flush_window(void);
161 static void error(char *m);
162 static void gzip_mark(void **);
163 static void gzip_release(void **);
164   
165 /*
166  * This is set up by the setup-routine at boot-time
167  */
168 static unsigned char *real_mode; /* Pointer to real-mode data */
169
170 #define RM_EXT_MEM_K   (*(unsigned short *)(real_mode + 0x2))
171 #ifndef STANDARD_MEMORY_BIOS_CALL
172 #define RM_ALT_MEM_K   (*(unsigned long *)(real_mode + 0x1e0))
173 #endif
174 #define RM_SCREEN_INFO (*(struct screen_info *)(real_mode+0))
175
176 extern unsigned char input_data[];
177 extern int input_len;
178
179 static long bytes_out = 0;
180
181 static void *malloc(int size);
182 static void free(void *where);
183
184 static void *memset(void *s, int c, unsigned n);
185 static void *memcpy(void *dest, const void *src, unsigned n);
186
187 static void putstr(const char *);
188
189 static long free_mem_ptr;
190 static long free_mem_end_ptr;
191
192 #define HEAP_SIZE             0x7000
193
194 static char *vidmem = (char *)0xb8000;
195 static int vidport;
196 static int lines, cols;
197
198 #include "../../../../lib/inflate.c"
199
200 static void *malloc(int size)
201 {
202         void *p;
203
204         if (size <0) error("Malloc error");
205         if (free_mem_ptr <= 0) error("Memory error");
206
207         free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
208
209         p = (void *)free_mem_ptr;
210         free_mem_ptr += size;
211
212         if (free_mem_ptr >= free_mem_end_ptr)
213                 error("Out of memory");
214
215         return p;
216 }
217
218 static void free(void *where)
219 {       /* Don't care */
220 }
221
222 static void gzip_mark(void **ptr)
223 {
224         *ptr = (void *) free_mem_ptr;
225 }
226
227 static void gzip_release(void **ptr)
228 {
229         free_mem_ptr = (long) *ptr;
230 }
231  
232 static void scroll(void)
233 {
234         int i;
235
236         memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
237         for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
238                 vidmem[i] = ' ';
239 }
240
241 static void putstr(const char *s)
242 {
243         int x,y,pos;
244         char c;
245
246         x = RM_SCREEN_INFO.orig_x;
247         y = RM_SCREEN_INFO.orig_y;
248
249         while ( ( c = *s++ ) != '\0' ) {
250                 if ( c == '\n' ) {
251                         x = 0;
252                         if ( ++y >= lines ) {
253                                 scroll();
254                                 y--;
255                         }
256                 } else {
257                         vidmem [ ( x + cols * y ) * 2 ] = c; 
258                         if ( ++x >= cols ) {
259                                 x = 0;
260                                 if ( ++y >= lines ) {
261                                         scroll();
262                                         y--;
263                                 }
264                         }
265                 }
266         }
267
268         RM_SCREEN_INFO.orig_x = x;
269         RM_SCREEN_INFO.orig_y = y;
270
271         pos = (x + cols * y) * 2;       /* Update cursor position */
272         outb_p(14, vidport);
273         outb_p(0xff & (pos >> 9), vidport+1);
274         outb_p(15, vidport);
275         outb_p(0xff & (pos >> 1), vidport+1);
276 }
277
278 static void* memset(void* s, int c, unsigned n)
279 {
280         int i;
281         char *ss = (char*)s;
282
283         for (i=0;i<n;i++) ss[i] = c;
284         return s;
285 }
286
287 static void* memcpy(void* dest, const void* src, unsigned n)
288 {
289         int i;
290         char *d = (char *)dest, *s = (char *)src;
291
292         for (i=0;i<n;i++) d[i] = s[i];
293         return dest;
294 }
295
296 /* ===========================================================================
297  * Fill the input buffer. This is called only when the buffer is empty
298  * and at least one byte is really needed.
299  */
300 static int fill_inbuf(void)
301 {
302         error("ran out of input data");
303         return 0;
304 }
305
306 /* ===========================================================================
307  * Write the output window window[0..outcnt-1] and update crc and bytes_out.
308  * (Used for the decompressed data only.)
309  */
310 static void flush_window(void)
311 {
312         /* With my window equal to my output buffer
313          * I only need to compute the crc here.
314          */
315         ulg c = crc;         /* temporary variable */
316         unsigned n;
317         uch *in, ch;
318
319         in = window;
320         for (n = 0; n < outcnt; n++) {
321                 ch = *in++;
322                 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
323         }
324         crc = c;
325         bytes_out += (ulg)outcnt;
326         outcnt = 0;
327 }
328
329 static void error(char *x)
330 {
331         putstr("\n\n");
332         putstr(x);
333         putstr("\n\n -- System halted");
334
335         while(1);       /* Halt */
336 }
337
338 asmlinkage void decompress_kernel(void *rmode, unsigned long heap,
339         uch *input_data, unsigned long input_len, uch *output)
340 {
341         real_mode = rmode;
342
343         if (RM_SCREEN_INFO.orig_video_mode == 7) {
344                 vidmem = (char *) 0xb0000;
345                 vidport = 0x3b4;
346         } else {
347                 vidmem = (char *) 0xb8000;
348                 vidport = 0x3d4;
349         }
350
351         lines = RM_SCREEN_INFO.orig_video_lines;
352         cols = RM_SCREEN_INFO.orig_video_cols;
353
354         window = output;                /* Output buffer (Normally at 1M) */
355         free_mem_ptr     = heap;        /* Heap  */
356         free_mem_end_ptr = heap + HEAP_SIZE;
357         inbuf  = input_data;            /* Input buffer */
358         insize = input_len;
359         inptr  = 0;
360
361         if ((ulg)output & (__KERNEL_ALIGN - 1))
362                 error("Destination address not 2M aligned");
363         if ((ulg)output >= 0xffffffffffUL)
364                 error("Destination address too large");
365
366         makecrc();
367         putstr(".\nDecompressing LWK...");
368         gunzip();
369         putstr("done.\nBooting the kernel.\n");
370         return;
371 }