1
2
3
4
5
6
7
8
9
10
11
12#include "misc.h"
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98#define STATIC static
99
100#undef memset
101#undef memcpy
102#define memzero(s, n) memset((s), 0, (n))
103
104
105static void error(char *m);
106
107
108
109
110struct boot_params *real_mode;
111static int quiet;
112static int debug;
113
114void *memset(void *s, int c, size_t n);
115void *memcpy(void *dest, const void *src, size_t n);
116
117#ifdef CONFIG_X86_64
118#define memptr long
119#else
120#define memptr unsigned
121#endif
122
123static memptr free_mem_ptr;
124static memptr free_mem_end_ptr;
125
126static char *vidmem;
127static int vidport;
128static int lines, cols;
129
130#ifdef CONFIG_KERNEL_GZIP
131#include "../../../../lib/decompress_inflate.c"
132#endif
133
134#ifdef CONFIG_KERNEL_BZIP2
135#include "../../../../lib/decompress_bunzip2.c"
136#endif
137
138#ifdef CONFIG_KERNEL_LZMA
139#include "../../../../lib/decompress_unlzma.c"
140#endif
141
142#ifdef CONFIG_KERNEL_XZ
143#include "../../../../lib/decompress_unxz.c"
144#endif
145
146#ifdef CONFIG_KERNEL_LZO
147#include "../../../../lib/decompress_unlzo.c"
148#endif
149
150static void scroll(void)
151{
152 int i;
153
154 memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2);
155 for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2)
156 vidmem[i] = ' ';
157}
158
159#define XMTRDY 0x20
160
161#define TXR 0
162#define LSR 5
163static void serial_putchar(int ch)
164{
165 unsigned timeout = 0xffff;
166
167 while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
168 cpu_relax();
169
170 outb(ch, early_serial_base + TXR);
171}
172
173void __putstr(int error, const char *s)
174{
175 int x, y, pos;
176 char c;
177
178#ifndef CONFIG_X86_VERBOSE_BOOTUP
179 if (!error)
180 return;
181#endif
182 if (early_serial_base) {
183 const char *str = s;
184 while (*str) {
185 if (*str == '\n')
186 serial_putchar('\r');
187 serial_putchar(*str++);
188 }
189 }
190
191 if (real_mode->screen_info.orig_video_mode == 0 &&
192 lines == 0 && cols == 0)
193 return;
194
195 x = real_mode->screen_info.orig_x;
196 y = real_mode->screen_info.orig_y;
197
198 while ((c = *s++) != '\0') {
199 if (c == '\n') {
200 x = 0;
201 if (++y >= lines) {
202 scroll();
203 y--;
204 }
205 } else {
206 vidmem[(x + cols * y) * 2] = c;
207 if (++x >= cols) {
208 x = 0;
209 if (++y >= lines) {
210 scroll();
211 y--;
212 }
213 }
214 }
215 }
216
217 real_mode->screen_info.orig_x = x;
218 real_mode->screen_info.orig_y = y;
219
220 pos = (x + cols * y) * 2;
221 outb(14, vidport);
222 outb(0xff & (pos >> 9), vidport+1);
223 outb(15, vidport);
224 outb(0xff & (pos >> 1), vidport+1);
225}
226
227void *memset(void *s, int c, size_t n)
228{
229 int i;
230 char *ss = s;
231
232 for (i = 0; i < n; i++)
233 ss[i] = c;
234 return s;
235}
236#ifdef CONFIG_X86_32
237void *memcpy(void *dest, const void *src, size_t n)
238{
239 int d0, d1, d2;
240 asm volatile(
241 "rep ; movsl\n\t"
242 "movl %4,%%ecx\n\t"
243 "rep ; movsb\n\t"
244 : "=&c" (d0), "=&D" (d1), "=&S" (d2)
245 : "0" (n >> 2), "g" (n & 3), "1" (dest), "2" (src)
246 : "memory");
247
248 return dest;
249}
250#else
251void *memcpy(void *dest, const void *src, size_t n)
252{
253 long d0, d1, d2;
254 asm volatile(
255 "rep ; movsq\n\t"
256 "movq %4,%%rcx\n\t"
257 "rep ; movsb\n\t"
258 : "=&c" (d0), "=&D" (d1), "=&S" (d2)
259 : "0" (n >> 3), "g" (n & 7), "1" (dest), "2" (src)
260 : "memory");
261
262 return dest;
263}
264#endif
265
266static void error(char *x)
267{
268 __putstr(1, "\n\n");
269 __putstr(1, x);
270 __putstr(1, "\n\n -- System halted");
271
272 while (1)
273 asm("hlt");
274}
275
276static void parse_elf(void *output)
277{
278#ifdef CONFIG_X86_64
279 Elf64_Ehdr ehdr;
280 Elf64_Phdr *phdrs, *phdr;
281#else
282 Elf32_Ehdr ehdr;
283 Elf32_Phdr *phdrs, *phdr;
284#endif
285 void *dest;
286 int i;
287
288 memcpy(&ehdr, output, sizeof(ehdr));
289 if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
290 ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
291 ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
292 ehdr.e_ident[EI_MAG3] != ELFMAG3) {
293 error("Kernel is not a valid ELF file");
294 return;
295 }
296
297 if (!quiet)
298 putstr("Parsing ELF... ");
299
300 phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum);
301 if (!phdrs)
302 error("Failed to allocate space for phdrs");
303
304 memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum);
305
306 for (i = 0; i < ehdr.e_phnum; i++) {
307 phdr = &phdrs[i];
308
309 switch (phdr->p_type) {
310 case PT_LOAD:
311#ifdef CONFIG_RELOCATABLE
312 dest = output;
313 dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR);
314#else
315 dest = (void *)(phdr->p_paddr);
316#endif
317 memcpy(dest,
318 output + phdr->p_offset,
319 phdr->p_filesz);
320 break;
321 default: break;
322 }
323 }
324}
325
326asmlinkage void decompress_kernel(void *rmode, memptr heap,
327 unsigned char *input_data,
328 unsigned long input_len,
329 unsigned char *output)
330{
331 real_mode = rmode;
332
333 if (cmdline_find_option_bool("quiet"))
334 quiet = 1;
335 if (cmdline_find_option_bool("debug"))
336 debug = 1;
337
338 if (real_mode->screen_info.orig_video_mode == 7) {
339 vidmem = (char *) 0xb0000;
340 vidport = 0x3b4;
341 } else {
342 vidmem = (char *) 0xb8000;
343 vidport = 0x3d4;
344 }
345
346 lines = real_mode->screen_info.orig_video_lines;
347 cols = real_mode->screen_info.orig_video_cols;
348
349 console_init();
350 if (debug)
351 putstr("early console in decompress_kernel\n");
352
353 free_mem_ptr = heap;
354 free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
355
356 if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
357 error("Destination address inappropriately aligned");
358#ifdef CONFIG_X86_64
359 if (heap > 0x3fffffffffffUL)
360 error("Destination address too large");
361#else
362 if (heap > ((-__PAGE_OFFSET-(128<<20)-1) & 0x7fffffff))
363 error("Destination address too large");
364#endif
365#ifndef CONFIG_RELOCATABLE
366 if ((unsigned long)output != LOAD_PHYSICAL_ADDR)
367 error("Wrong destination address");
368#endif
369
370 if (!quiet)
371 putstr("\nDecompressing Linux... ");
372 decompress(input_data, input_len, NULL, NULL, output, NULL, error);
373 parse_elf(output);
374 if (!quiet)
375 putstr("done.\nBooting the kernel.\n");
376 return;
377}
378