]> git.proxmox.com Git - grub2.git/blob - loader/i386/linux.c
2010-02-10 Vladimir Serbinenko <phcoder@gmail.com>
[grub2.git] / loader / i386 / linux.c
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc.
4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <grub/loader.h>
20 #include <grub/machine/memory.h>
21 #include <grub/machine/loader.h>
22 #include <grub/normal.h>
23 #include <grub/file.h>
24 #include <grub/disk.h>
25 #include <grub/err.h>
26 #include <grub/misc.h>
27 #include <grub/types.h>
28 #include <grub/dl.h>
29 #include <grub/mm.h>
30 #include <grub/term.h>
31 #include <grub/cpu/linux.h>
32 #include <grub/video.h>
33 #include <grub/video_fb.h>
34 #include <grub/command.h>
35 #include <grub/i386/pc/vbe.h>
36 #include <grub/i386/pc/console.h>
37 #include <grub/i18n.h>
38
39 #define GRUB_LINUX_CL_OFFSET 0x1000
40 #define GRUB_LINUX_CL_END_OFFSET 0x2000
41
42 static grub_dl_t my_mod;
43
44 static grub_size_t linux_mem_size;
45 static int loaded;
46 static void *real_mode_mem;
47 static void *prot_mode_mem;
48 static void *initrd_mem;
49 static grub_uint32_t real_mode_pages;
50 static grub_uint32_t prot_mode_pages;
51 static grub_uint32_t initrd_pages;
52
53 static grub_uint8_t gdt[] __attribute__ ((aligned(16))) =
54 {
55 /* NULL. */
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 /* Reserved. */
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59 /* Code segment. */
60 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00,
61 /* Data segment. */
62 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
63 };
64
65 struct gdt_descriptor
66 {
67 grub_uint16_t limit;
68 void *base;
69 } __attribute__ ((packed));
70
71 static struct gdt_descriptor gdt_desc =
72 {
73 sizeof (gdt) - 1,
74 gdt
75 };
76
77 struct idt_descriptor
78 {
79 grub_uint16_t limit;
80 void *base;
81 } __attribute__ ((packed));
82
83 static struct idt_descriptor idt_desc =
84 {
85 0,
86 0
87 };
88
89 #ifdef GRUB_MACHINE_PCBIOS
90 struct linux_vesafb_res
91 {
92 grub_uint16_t width;
93 grub_uint16_t height;
94 };
95
96 struct linux_vesafb_mode
97 {
98 grub_uint8_t res_index;
99 grub_uint8_t depth;
100 };
101
102 enum vga_modes
103 {
104 VGA_320_200,
105 VGA_640_400,
106 VGA_640_480,
107 VGA_800_500,
108 VGA_800_600,
109 VGA_896_672,
110 VGA_1024_640,
111 VGA_1024_768,
112 VGA_1152_720,
113 VGA_1280_1024,
114 VGA_1440_900,
115 VGA_1600_1200,
116 };
117
118 static struct linux_vesafb_res linux_vesafb_res[] =
119 {
120 { 320, 200 },
121 { 640, 400 },
122 { 640, 480 },
123 { 800, 500 },
124 { 800, 600 },
125 { 896, 672 },
126 { 1024, 640 },
127 { 1024, 768 },
128 { 1152, 720 },
129 { 1280, 1024 },
130 { 1440, 900 },
131 { 1600, 1200 },
132 };
133
134 /* This is the reverse of the table in [linux]/Documentation/fb/vesafb.txt
135 plus a few more modes based on the table in
136 http://en.wikipedia.org/wiki/VESA_BIOS_Extensions */
137 struct linux_vesafb_mode linux_vesafb_modes[] =
138 {
139 { VGA_640_400, 8 }, /* 0x300 */
140 { VGA_640_480, 8 }, /* 0x301 */
141 { VGA_800_600, 4 }, /* 0x302 */
142 { VGA_800_600, 8 }, /* 0x303 */
143 { VGA_1024_768, 4 }, /* 0x304 */
144 { VGA_1024_768, 8 }, /* 0x305 */
145 { VGA_1280_1024, 4 }, /* 0x306 */
146 { VGA_1280_1024, 8 }, /* 0x307 */
147 { 0, 0 },
148 { 0, 0 },
149 { 0, 0 },
150 { 0, 0 },
151 { 0, 0 },
152 { VGA_320_200, 15 }, /* 0x30d */
153 { VGA_320_200, 16 }, /* 0x30e */
154 { VGA_320_200, 24 }, /* 0x30f */
155 { VGA_640_480, 15 }, /* 0x310 */
156 { VGA_640_480, 16 }, /* 0x311 */
157 { VGA_640_480, 24 }, /* 0x312 */
158 { VGA_800_600, 15 }, /* 0x313 */
159 { VGA_800_600, 16 }, /* 0x314 */
160 { VGA_800_600, 24 }, /* 0x315 */
161 { VGA_1024_768, 15 }, /* 0x316 */
162 { VGA_1024_768, 16 }, /* 0x317 */
163 { VGA_1024_768, 24 }, /* 0x318 */
164 { VGA_1280_1024, 15 }, /* 0x319 */
165 { VGA_1280_1024, 16 }, /* 0x31a */
166 { VGA_1280_1024, 24 }, /* 0x31b */
167 { VGA_1600_1200, 8 }, /* 0x31c */
168 { VGA_1600_1200, 15 }, /* 0x31d */
169 { VGA_1600_1200, 16 }, /* 0x31e */
170 { VGA_1600_1200, 24 }, /* 0x31f */
171 { 0, 0 },
172 { VGA_640_400, 15 }, /* 0x321 */
173 { VGA_640_400, 16 }, /* 0x322 */
174 { VGA_640_400, 24 }, /* 0x323 */
175 { VGA_640_400, 32 }, /* 0x324 */
176 { 0, 0 },
177 { 0, 0 },
178 { 0, 0 },
179 { 0, 0 },
180 { VGA_640_480, 32 }, /* 0x329 */
181 { 0, 0 },
182 { 0, 0 },
183 { 0, 0 },
184 { 0, 0 },
185 { 0, 0 },
186 { VGA_896_672, 8 }, /* 0x32f */
187 { VGA_896_672, 15 }, /* 0x330 */
188 { VGA_896_672, 16 }, /* 0x331 */
189 { VGA_896_672, 24 }, /* 0x332 */
190 { VGA_896_672, 32 }, /* 0x333 */
191 { 0, 0 },
192 { 0, 0 },
193 { 0, 0 },
194 { 0, 0 },
195 { 0, 0 },
196 { 0, 0 },
197 { 0, 0 },
198 { 0, 0 },
199 { 0, 0 },
200 { 0, 0 },
201 { 0, 0 },
202 { 0, 0 },
203 { 0, 0 },
204 { 0, 0 },
205 { VGA_1600_1200, 32 }, /* 0x342 */
206 { 0, 0 },
207 { 0, 0 },
208 { 0, 0 },
209 { 0, 0 },
210 { 0, 0 },
211 { 0, 0 },
212 { 0, 0 },
213 { 0, 0 },
214 { 0, 0 },
215 { 0, 0 },
216 { 0, 0 },
217 { 0, 0 },
218 { 0, 0 },
219 { 0, 0 },
220 { 0, 0 },
221 { 0, 0 },
222 { 0, 0 },
223 { 0, 0 },
224 { 0, 0 },
225 { 0, 0 },
226 { 0, 0 },
227 { 0, 0 },
228 { 0, 0 },
229 { 0, 0 },
230 { 0, 0 },
231 { 0, 0 },
232 { 0, 0 },
233 { 0, 0 },
234 { 0, 0 },
235 { VGA_1440_900, 8 }, /* 0x360 */
236 { VGA_1440_900, 15 }, /* 0x361 */
237 { VGA_1440_900, 16 }, /* 0x362 */
238 { VGA_1440_900, 24 }, /* 0x363 */
239 { VGA_1440_900, 32 }, /* 0x364 */
240 { VGA_1152_720, 8 }, /* 0x365 */
241 { VGA_1152_720, 15 }, /* 0x366 */
242 { VGA_1152_720, 16 }, /* 0x367 */
243 { VGA_1152_720, 24 }, /* 0x368 */
244 { VGA_1152_720, 32 }, /* 0x369 */
245 { VGA_1024_640, 8 }, /* 0x36a */
246 { VGA_1024_640, 15 }, /* 0x36b */
247 { VGA_1024_640, 16 }, /* 0x36c */
248 { VGA_1024_640, 24 }, /* 0x36d */
249 { VGA_1024_640, 32 }, /* 0x36e */
250 { VGA_800_500, 8 }, /* 0x36f */
251 { VGA_800_500, 15 }, /* 0x370 */
252 { VGA_800_500, 16 }, /* 0x371 */
253 { VGA_800_500, 24 }, /* 0x372 */
254 { VGA_800_500, 32 }, /* 0x373 */
255 };
256 #endif
257
258 static inline grub_size_t
259 page_align (grub_size_t size)
260 {
261 return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
262 }
263
264 /* Find the optimal number of pages for the memory map. */
265 static grub_size_t
266 find_mmap_size (void)
267 {
268 grub_size_t count = 0, mmap_size;
269
270 auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
271 int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)),
272 grub_uint64_t size __attribute__ ((unused)),
273 grub_uint32_t type __attribute__ ((unused)))
274 {
275 count++;
276 return 0;
277 }
278
279 grub_mmap_iterate (hook);
280
281 mmap_size = count * sizeof (struct grub_e820_mmap);
282
283 /* Increase the size a bit for safety, because GRUB allocates more on
284 later. */
285 mmap_size += (1 << 12);
286
287 return page_align (mmap_size);
288 }
289
290 static void
291 free_pages (void)
292 {
293 real_mode_mem = prot_mode_mem = initrd_mem = 0;
294 }
295
296 /* Allocate pages for the real mode code and the protected mode code
297 for linux as well as a memory map buffer. */
298 static int
299 allocate_pages (grub_size_t prot_size)
300 {
301 grub_size_t real_size, mmap_size;
302
303 /* Make sure that each size is aligned to a page boundary. */
304 real_size = GRUB_LINUX_CL_END_OFFSET;
305 prot_size = page_align (prot_size);
306 mmap_size = find_mmap_size ();
307
308 grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
309 (unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size);
310
311 /* Calculate the number of pages; Combine the real mode code with
312 the memory map buffer for simplicity. */
313 real_mode_pages = ((real_size + mmap_size) >> 12);
314 prot_mode_pages = (prot_size >> 12);
315
316 /* Initialize the memory pointers with NULL for convenience. */
317 free_pages ();
318
319 /* FIXME: Should request low memory from the heap when this feature is
320 implemented. */
321
322 auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
323 int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
324 {
325 /* We must put real mode code in the traditional space. */
326
327 if (type == GRUB_MACHINE_MEMORY_AVAILABLE
328 && addr <= 0x90000)
329 {
330 if (addr < 0x10000)
331 {
332 size += addr - 0x10000;
333 addr = 0x10000;
334 }
335
336 if (addr + size > 0x90000)
337 size = 0x90000 - addr;
338
339 if (real_size + mmap_size > size)
340 return 0;
341
342 real_mode_mem =
343 (void *) (grub_size_t) ((addr + size) - (real_size + mmap_size));
344 return 1;
345 }
346
347 return 0;
348 }
349 grub_mmap_iterate (hook);
350 if (! real_mode_mem)
351 {
352 grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
353 goto fail;
354 }
355
356 prot_mode_mem = (void *) 0x100000;
357
358 grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, "
359 "prot_mode_mem = %lx, prot_mode_pages = %x\n",
360 (unsigned long) real_mode_mem, (unsigned) real_mode_pages,
361 (unsigned long) prot_mode_mem, (unsigned) prot_mode_pages);
362
363 return 1;
364
365 fail:
366 free_pages ();
367 return 0;
368 }
369
370 static void
371 grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num,
372 grub_uint64_t start, grub_uint64_t size,
373 grub_uint32_t type)
374 {
375 int n = *e820_num;
376
377 if (n >= GRUB_E820_MAX_ENTRY)
378 grub_fatal ("Too many e820 memory map entries");
379
380 if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) &&
381 (e820_map[n - 1].type == type))
382 e820_map[n - 1].size += size;
383 else
384 {
385 e820_map[n].addr = start;
386 e820_map[n].size = size;
387 e820_map[n].type = type;
388 (*e820_num)++;
389 }
390 }
391
392 static int
393 grub_linux_setup_video (struct linux_kernel_params *params)
394 {
395 struct grub_video_mode_info mode_info;
396 void *framebuffer;
397 grub_err_t err;
398
399 err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
400
401 if (err)
402 {
403 grub_errno = GRUB_ERR_NONE;
404 return 1;
405 }
406
407 params->lfb_width = mode_info.width;
408 params->lfb_height = mode_info.height;
409 params->lfb_depth = mode_info.bpp;
410 params->lfb_line_len = mode_info.pitch;
411
412 params->lfb_base = (grub_size_t) framebuffer;
413 params->lfb_size = ALIGN_UP (params->lfb_line_len * params->lfb_height, 65536);
414
415 params->red_mask_size = mode_info.red_mask_size;
416 params->red_field_pos = mode_info.red_field_pos;
417 params->green_mask_size = mode_info.green_mask_size;
418 params->green_field_pos = mode_info.green_field_pos;
419 params->blue_mask_size = mode_info.blue_mask_size;
420 params->blue_field_pos = mode_info.blue_field_pos;
421 params->reserved_mask_size = mode_info.reserved_mask_size;
422 params->reserved_field_pos = mode_info.reserved_field_pos;
423
424
425 #ifdef GRUB_MACHINE_PCBIOS
426 /* VESA packed modes may come with zeroed mask sizes, which need
427 to be set here according to DAC Palette width. If we don't,
428 this results in Linux displaying a black screen. */
429 if (mode_info.bpp <= 8)
430 {
431 struct grub_vbe_info_block controller_info;
432 int status;
433 int width = 8;
434
435 status = grub_vbe_bios_get_controller_info (&controller_info);
436
437 if (status == GRUB_VBE_STATUS_OK &&
438 (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH))
439 status = grub_vbe_bios_set_dac_palette_width (&width);
440
441 if (status != GRUB_VBE_STATUS_OK)
442 /* 6 is default after mode reset. */
443 width = 6;
444
445 params->red_mask_size = params->green_mask_size
446 = params->blue_mask_size = width;
447 params->reserved_mask_size = 0;
448 }
449 #endif
450
451 return 0;
452 }
453
454 #ifdef __x86_64__
455 extern grub_uint8_t grub_linux_trampoline_start[];
456 extern grub_uint8_t grub_linux_trampoline_end[];
457 #endif
458
459 static grub_err_t
460 grub_linux_boot (void)
461 {
462 struct linux_kernel_params *params;
463 int e820_num;
464 grub_err_t err = 0;
465 char *modevar, *tmp;
466
467 params = real_mode_mem;
468
469 grub_dprintf ("linux", "code32_start = %x, idt_desc = %lx, gdt_desc = %lx\n",
470 (unsigned) params->code32_start,
471 (unsigned long) &(idt_desc.limit),
472 (unsigned long) &(gdt_desc.limit));
473 grub_dprintf ("linux", "idt = %x:%lx, gdt = %x:%lx\n",
474 (unsigned) idt_desc.limit, (unsigned long) idt_desc.base,
475 (unsigned) gdt_desc.limit, (unsigned long) gdt_desc.base);
476
477 auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
478 int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
479 {
480 switch (type)
481 {
482 case GRUB_MACHINE_MEMORY_AVAILABLE:
483 grub_e820_add_region (params->e820_map, &e820_num,
484 addr, size, GRUB_E820_RAM);
485 break;
486
487 #ifdef GRUB_MACHINE_MEMORY_ACPI
488 case GRUB_MACHINE_MEMORY_ACPI:
489 grub_e820_add_region (params->e820_map, &e820_num,
490 addr, size, GRUB_E820_ACPI);
491 break;
492 #endif
493
494 #ifdef GRUB_MACHINE_MEMORY_NVS
495 case GRUB_MACHINE_MEMORY_NVS:
496 grub_e820_add_region (params->e820_map, &e820_num,
497 addr, size, GRUB_E820_NVS);
498 break;
499 #endif
500
501 #ifdef GRUB_MACHINE_MEMORY_CODE
502 case GRUB_MACHINE_MEMORY_CODE:
503 grub_e820_add_region (params->e820_map, &e820_num,
504 addr, size, GRUB_E820_EXEC_CODE);
505 break;
506 #endif
507
508 default:
509 grub_e820_add_region (params->e820_map, &e820_num,
510 addr, size, GRUB_E820_RESERVED);
511 }
512 return 0;
513 }
514
515 e820_num = 0;
516 grub_mmap_iterate (hook);
517 params->mmap_size = e820_num;
518
519 modevar = grub_env_get ("gfxpayload");
520
521 /* Now all graphical modes are acceptable.
522 May change in future if we have modes without framebuffer. */
523 if (modevar && *modevar != 0)
524 {
525 tmp = grub_xasprintf ("%s;text", modevar);
526 if (! tmp)
527 return grub_errno;
528 err = grub_video_set_mode (tmp, 0, 0);
529 grub_free (tmp);
530 }
531 else
532 err = grub_video_set_mode ("text", 0, 0);
533
534 if (err)
535 {
536 grub_print_error ();
537 grub_printf ("Booting however\n");
538 grub_errno = GRUB_ERR_NONE;
539 }
540
541 if (! grub_linux_setup_video (params))
542 {
543 /* Use generic framebuffer unless VESA is known to be supported. */
544 if (params->have_vga != GRUB_VIDEO_LINUX_TYPE_VESA)
545 params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
546 else
547 params->lfb_size >>= 16;
548 }
549 else
550 {
551 params->have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT;
552 params->video_width = 80;
553 params->video_height = 25;
554 }
555
556 /* Initialize these last, because terminal position could be affected by printfs above. */
557 if (params->have_vga == GRUB_VIDEO_LINUX_TYPE_TEXT)
558 {
559 grub_term_output_t term;
560 int found = 0;
561 FOR_ACTIVE_TERM_OUTPUTS(term)
562 if (grub_strcmp (term->name, "vga_text") == 0
563 || grub_strcmp (term->name, "console") == 0)
564 {
565 grub_uint16_t pos = grub_term_getxy (term);
566 params->video_cursor_x = pos >> 8;
567 params->video_cursor_y = pos & 0xff;
568 found = 1;
569 break;
570 }
571 if (!found)
572 {
573 params->video_cursor_x = 0;
574 params->video_cursor_y = 0;
575 }
576 }
577
578 #ifdef __x86_64__
579
580 grub_memcpy ((char *) prot_mode_mem + (prot_mode_pages << 12),
581 grub_linux_trampoline_start,
582 grub_linux_trampoline_end - grub_linux_trampoline_start);
583
584 ((void (*) (unsigned long, void *)) ((char *) prot_mode_mem
585 + (prot_mode_pages << 12)))
586 (params->code32_start, real_mode_mem);
587 #else
588
589 /* Hardware interrupts are not safe any longer. */
590 asm volatile ("cli" : : );
591
592 /* Load the IDT and the GDT for the bootstrap. */
593 asm volatile ("lidt %0" : : "m" (idt_desc));
594 asm volatile ("lgdt %0" : : "m" (gdt_desc));
595
596 /* Enter Linux. */
597 asm volatile ("jmp *%2" : : "b" (0), "S" (real_mode_mem), "g" (params->code32_start));
598
599 #endif
600
601 /* Never reach here. */
602 return GRUB_ERR_NONE;
603 }
604
605 static grub_err_t
606 grub_linux_unload (void)
607 {
608 grub_dl_unref (my_mod);
609 loaded = 0;
610 return GRUB_ERR_NONE;
611 }
612
613 static grub_err_t
614 grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
615 int argc, char *argv[])
616 {
617 grub_file_t file = 0;
618 struct linux_kernel_header lh;
619 struct linux_kernel_params *params;
620 grub_uint8_t setup_sects;
621 grub_size_t real_size, prot_size;
622 grub_ssize_t len;
623 int i;
624 char *dest;
625
626 grub_dl_ref (my_mod);
627
628 if (argc == 0)
629 {
630 grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
631 goto fail;
632 }
633
634 file = grub_file_open (argv[0]);
635 if (! file)
636 goto fail;
637
638 if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
639 {
640 grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header");
641 goto fail;
642 }
643
644 if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
645 {
646 grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
647 goto fail;
648 }
649
650 if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
651 {
652 grub_error (GRUB_ERR_BAD_OS, "too many setup sectors");
653 goto fail;
654 }
655
656 if (! (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL))
657 {
658 grub_error (GRUB_ERR_BAD_OS, "zImage doesn't support 32-bit boot"
659 #ifdef GRUB_MACHINE_PCBIOS
660 " (try with `linux16')"
661 #endif
662 );
663 goto fail;
664 }
665
666 /* FIXME: 2.03 is not always good enough (Linux 2.4 can be 2.03 and
667 still not support 32-bit boot. */
668 if (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)
669 || grub_le_to_cpu16 (lh.version) < 0x0203)
670 {
671 grub_error (GRUB_ERR_BAD_OS, "version too old for 32-bit boot"
672 #ifdef GRUB_MACHINE_PCBIOS
673 " (try with `linux16')"
674 #endif
675 );
676 goto fail;
677 }
678
679 setup_sects = lh.setup_sects;
680
681 /* If SETUP_SECTS is not set, set it to the default (4). */
682 if (! setup_sects)
683 setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
684
685 real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
686 prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
687
688 if (! allocate_pages (prot_size))
689 goto fail;
690
691 params = (struct linux_kernel_params *) real_mode_mem;
692 grub_memset (params, 0, GRUB_LINUX_CL_END_OFFSET);
693 grub_memcpy (&params->setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
694
695 params->ps_mouse = params->padding10 = 0;
696
697 len = 0x400 - sizeof (lh);
698 if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len)
699 {
700 grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
701 goto fail;
702 }
703
704 params->type_of_loader = (LINUX_LOADER_ID_GRUB << 4);
705
706 /* These two are used (instead of cmd_line_ptr) by older versions of Linux,
707 and otherwise ignored. */
708 params->cl_magic = GRUB_LINUX_CL_MAGIC;
709 params->cl_offset = 0x1000;
710
711 params->cmd_line_ptr = (unsigned long) real_mode_mem + 0x1000;
712 params->ramdisk_image = 0;
713 params->ramdisk_size = 0;
714
715 params->heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET;
716 params->loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
717
718 /* These are not needed to be precise, because Linux uses these values
719 only to raise an error when the decompression code cannot find good
720 space. */
721 params->ext_mem = ((32 * 0x100000) >> 10);
722 params->alt_mem = ((32 * 0x100000) >> 10);
723
724 /* Ignored by Linux. */
725 params->video_page = 0;
726
727 /* Must be non-zero even in text mode, or Linux will think there's no VGA. */
728 params->video_mode = 0x3;
729
730 /* Only used when `video_mode == 0x7', otherwise ignored. */
731 params->video_ega_bx = 0;
732
733 params->font_size = 16; /* XXX */
734
735 /* The other parameters are filled when booting. */
736
737 grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
738
739 grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n",
740 (unsigned) real_size, (unsigned) prot_size);
741
742 /* Look for memory size and video mode specified on the command line. */
743 linux_mem_size = 0;
744 for (i = 1; i < argc; i++)
745 #ifdef GRUB_MACHINE_PCBIOS
746 if (grub_memcmp (argv[i], "vga=", 4) == 0)
747 {
748 /* Video mode selection support. */
749 char *val = argv[i] + 4;
750 unsigned vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
751 struct linux_vesafb_mode *linux_mode;
752 grub_err_t err;
753 char *buf;
754
755 if (grub_strcmp (val, "normal") == 0)
756 vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
757 else if (grub_strcmp (val, "ext") == 0)
758 vid_mode = GRUB_LINUX_VID_MODE_EXTENDED;
759 else if (grub_strcmp (val, "ask") == 0)
760 {
761 grub_printf ("Legacy `ask' parameter no longer supported.\n");
762
763 /* We usually would never do this in a loader, but "vga=ask" means user
764 requested interaction, so it can't hurt to request keyboard input. */
765 grub_wait_after_message ();
766
767 goto fail;
768 }
769 else
770 vid_mode = (grub_uint16_t) grub_strtoul (val, 0, 0);
771
772 switch (vid_mode)
773 {
774 case 0:
775 case GRUB_LINUX_VID_MODE_NORMAL:
776 grub_env_set ("gfxpayload", "text");
777 grub_printf ("%s is deprecated. "
778 "Use set gfxpayload=text before "
779 "linux command instead.\n",
780 argv[i]);
781 break;
782
783 case 1:
784 case GRUB_LINUX_VID_MODE_EXTENDED:
785 /* FIXME: support 80x50 text. */
786 grub_env_set ("gfxpayload", "text");
787 grub_printf ("%s is deprecated. "
788 "Use set gfxpayload=text before "
789 "linux command instead.\n",
790 argv[i]);
791 break;
792 default:
793 /* Ignore invalid values. */
794 if (vid_mode < GRUB_LINUX_VID_MODE_VESA_START ||
795 vid_mode >= GRUB_LINUX_VID_MODE_VESA_START +
796 ARRAY_SIZE (linux_vesafb_modes))
797 {
798 grub_env_set ("gfxpayload", "text");
799 grub_printf ("%s is deprecated. Mode %d isn't recognized. "
800 "Use set gfxpayload=WIDTHxHEIGHT[xDEPTH] before "
801 "linux command instead.\n",
802 argv[i], vid_mode);
803 break;
804 }
805
806 /* We can't detect VESA, but user is implicitly telling us that it
807 is built-in because `vga=' parameter was used. */
808 params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA;
809
810 linux_mode
811 = &linux_vesafb_modes[vid_mode - GRUB_LINUX_VID_MODE_VESA_START];
812
813 buf = grub_xasprintf ("%ux%ux%u,%ux%u",
814 linux_vesafb_res[linux_mode->res_index].width,
815 linux_vesafb_res[linux_mode->res_index].height,
816 linux_mode->depth,
817 linux_vesafb_res[linux_mode->res_index].width,
818 linux_vesafb_res[linux_mode->res_index].height);
819 if (! buf)
820 goto fail;
821
822 grub_printf ("%s is deprecated. "
823 "Use set gfxpayload=%s before "
824 "linux command instead.\n",
825 argv[i], buf);
826 err = grub_env_set ("gfxpayload", buf);
827 grub_free (buf);
828 if (err)
829 goto fail;
830 }
831 }
832 else
833 #endif /* GRUB_MACHINE_PCBIOS */
834 if (grub_memcmp (argv[i], "mem=", 4) == 0)
835 {
836 char *val = argv[i] + 4;
837
838 linux_mem_size = grub_strtoul (val, &val, 0);
839
840 if (grub_errno)
841 {
842 grub_errno = GRUB_ERR_NONE;
843 linux_mem_size = 0;
844 }
845 else
846 {
847 int shift = 0;
848
849 switch (grub_tolower (val[0]))
850 {
851 case 'g':
852 shift += 10;
853 case 'm':
854 shift += 10;
855 case 'k':
856 shift += 10;
857 default:
858 break;
859 }
860
861 /* Check an overflow. */
862 if (linux_mem_size > (~0UL >> shift))
863 linux_mem_size = 0;
864 else
865 linux_mem_size <<= shift;
866 }
867 }
868 else if (grub_memcmp (argv[i], "quiet", sizeof ("quiet") - 1) == 0)
869 {
870 params->loadflags |= GRUB_LINUX_FLAG_QUIET;
871 }
872
873
874 /* Specify the boot file. */
875 dest = grub_stpcpy ((char *) real_mode_mem + GRUB_LINUX_CL_OFFSET,
876 "BOOT_IMAGE=");
877 dest = grub_stpcpy (dest, argv[0]);
878
879 /* Copy kernel parameters. */
880 for (i = 1;
881 i < argc
882 && dest + grub_strlen (argv[i]) + 1 < ((char *) real_mode_mem
883 + GRUB_LINUX_CL_END_OFFSET);
884 i++)
885 {
886 *dest++ = ' ';
887 dest = grub_stpcpy (dest, argv[i]);
888 }
889
890 len = prot_size;
891 if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len)
892 grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
893
894 if (grub_errno == GRUB_ERR_NONE)
895 {
896 grub_loader_set (grub_linux_boot, grub_linux_unload,
897 0 /* set noreturn=0 in order to avoid grub_console_fini() */);
898 loaded = 1;
899 }
900
901 fail:
902
903 if (file)
904 grub_file_close (file);
905
906 if (grub_errno != GRUB_ERR_NONE)
907 {
908 grub_dl_unref (my_mod);
909 loaded = 0;
910 }
911
912 return grub_errno;
913 }
914
915 static grub_err_t
916 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
917 int argc, char *argv[])
918 {
919 grub_file_t file = 0;
920 grub_ssize_t size;
921 grub_addr_t addr_min, addr_max;
922 grub_addr_t addr;
923 struct linux_kernel_header *lh;
924
925 if (argc == 0)
926 {
927 grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
928 goto fail;
929 }
930
931 if (! loaded)
932 {
933 grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
934 goto fail;
935 }
936
937 file = grub_file_open (argv[0]);
938 if (! file)
939 goto fail;
940
941 size = grub_file_size (file);
942 initrd_pages = (page_align (size) >> 12);
943
944 lh = (struct linux_kernel_header *) real_mode_mem;
945
946 /* Get the highest address available for the initrd. */
947 if (grub_le_to_cpu16 (lh->version) >= 0x0203)
948 {
949 addr_max = grub_cpu_to_le32 (lh->initrd_addr_max);
950
951 /* XXX in reality, Linux specifies a bogus value, so
952 it is necessary to make sure that ADDR_MAX does not exceed
953 0x3fffffff. */
954 if (addr_max > GRUB_LINUX_INITRD_MAX_ADDRESS)
955 addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
956 }
957 else
958 addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
959
960 if (linux_mem_size != 0 && linux_mem_size < addr_max)
961 addr_max = linux_mem_size;
962
963 /* Linux 2.3.xx has a bug in the memory range check, so avoid
964 the last page.
965 Linux 2.2.xx has a bug in the memory range check, which is
966 worse than that of Linux 2.3.xx, so avoid the last 64kb. */
967 addr_max -= 0x10000;
968
969 /* Usually, the compression ratio is about 50%. */
970 addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12)
971 + page_align (size);
972
973 if (addr_max > grub_os_area_addr + grub_os_area_size)
974 addr_max = grub_os_area_addr + grub_os_area_size;
975
976 /* Put the initrd as high as possible, 4KiB aligned. */
977 addr = (addr_max - size) & ~0xFFF;
978
979 if (addr < addr_min)
980 {
981 grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big");
982 goto fail;
983 }
984
985 initrd_mem = (void *) addr;
986
987 if (grub_file_read (file, initrd_mem, size) != size)
988 {
989 grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
990 goto fail;
991 }
992
993 grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n",
994 (unsigned) addr, (unsigned) size);
995
996 lh->ramdisk_image = addr;
997 lh->ramdisk_size = size;
998 lh->root_dev = 0x0100; /* XXX */
999
1000 fail:
1001 if (file)
1002 grub_file_close (file);
1003
1004 return grub_errno;
1005 }
1006
1007 static grub_command_t cmd_linux, cmd_initrd;
1008
1009 GRUB_MOD_INIT(linux)
1010 {
1011 cmd_linux = grub_register_command ("linux", grub_cmd_linux,
1012 0, N_("Load Linux."));
1013 cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
1014 0, N_("Load initrd."));
1015 my_mod = mod;
1016 }
1017
1018 GRUB_MOD_FINI(linux)
1019 {
1020 grub_unregister_command (cmd_linux);
1021 grub_unregister_command (cmd_initrd);
1022 }