remove all trailing whitespace
[grub2/phcoder/solaris.git] / loader / i386 / linux.c
blob4ef88cb8fea4f8ec405940db8ee578cf40b77157
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc.
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.
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.
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/>.
19 #include <grub/loader.h>
20 #include <grub/machine/machine.h>
21 #include <grub/machine/memory.h>
22 #include <grub/machine/loader.h>
23 #include <grub/normal.h>
24 #include <grub/file.h>
25 #include <grub/disk.h>
26 #include <grub/err.h>
27 #include <grub/misc.h>
28 #include <grub/types.h>
29 #include <grub/dl.h>
30 #include <grub/mm.h>
31 #include <grub/term.h>
32 #include <grub/cpu/linux.h>
33 #include <grub/video.h>
34 /* FIXME: the definition of `struct grub_video_render_target' is
35 VBE-specific. */
36 #include <grub/i386/pc/vbe.h>
37 #include <grub/command.h>
39 #define GRUB_LINUX_CL_OFFSET 0x1000
40 #define GRUB_LINUX_CL_END_OFFSET 0x2000
42 /* This macro is useful for distributors, who can be certain they built FB support
43 into Linux, and therefore can benefit from seamless mode transition between
44 GRUB and Linux (saving boot time and visual glitches). Official GRUB, OTOH,
45 needs to be conservative. */
46 #ifdef GRUB_ASSUME_LINUX_HAS_FB_SUPPORT
47 #define DEFAULT_VIDEO_MODE "keep,1024x768,800x600,640x480"
48 #else
49 #define DEFAULT_VIDEO_MODE "text"
50 #endif
52 static grub_dl_t my_mod;
54 static grub_size_t linux_mem_size;
55 static int loaded;
56 static void *real_mode_mem;
57 static void *prot_mode_mem;
58 static void *initrd_mem;
59 static grub_uint32_t real_mode_pages;
60 static grub_uint32_t prot_mode_pages;
61 static grub_uint32_t initrd_pages;
63 static grub_uint8_t gdt[] __attribute__ ((aligned(16))) =
65 /* NULL. */
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 /* Reserved. */
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 /* Code segment. */
70 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00,
71 /* Data segment. */
72 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
75 struct gdt_descriptor
77 grub_uint16_t limit;
78 void *base;
79 } __attribute__ ((packed));
81 static struct gdt_descriptor gdt_desc =
83 sizeof (gdt) - 1,
84 gdt
87 struct idt_descriptor
89 grub_uint16_t limit;
90 void *base;
91 } __attribute__ ((packed));
93 static struct idt_descriptor idt_desc =
99 #ifdef GRUB_MACHINE_PCBIOS
100 struct linux_vesafb_res
102 grub_uint16_t width;
103 grub_uint16_t height;
106 struct linux_vesafb_mode
108 grub_uint8_t res_index;
109 grub_uint8_t depth;
112 enum vga_modes
114 VGA_320_200,
115 VGA_640_400,
116 VGA_640_480,
117 VGA_800_500,
118 VGA_800_600,
119 VGA_896_672,
120 VGA_1024_640,
121 VGA_1024_768,
122 VGA_1152_720,
123 VGA_1280_1024,
124 VGA_1440_900,
125 VGA_1600_1200,
128 static struct linux_vesafb_res linux_vesafb_res[] =
130 { 320, 200 },
131 { 640, 400 },
132 { 640, 480 },
133 { 800, 500 },
134 { 800, 600 },
135 { 896, 672 },
136 { 1024, 640 },
137 { 1024, 768 },
138 { 1152, 720 },
139 { 1280, 1024 },
140 { 1440, 900 },
141 { 1600, 1200 },
144 /* This is the reverse of the table in [linux]/Documentation/fb/vesafb.txt
145 plus a few more modes based on the table in
146 http://en.wikipedia.org/wiki/VESA_BIOS_Extensions */
147 struct linux_vesafb_mode linux_vesafb_modes[] =
149 { VGA_640_400, 8 }, /* 0x300 */
150 { VGA_640_480, 8 }, /* 0x301 */
151 { VGA_800_600, 4 }, /* 0x302 */
152 { VGA_800_600, 8 }, /* 0x303 */
153 { VGA_1024_768, 4 }, /* 0x304 */
154 { VGA_1024_768, 8 }, /* 0x305 */
155 { VGA_1280_1024, 4 }, /* 0x306 */
156 { VGA_1280_1024, 8 }, /* 0x307 */
157 { 0, 0 },
158 { 0, 0 },
159 { 0, 0 },
160 { 0, 0 },
161 { 0, 0 },
162 { VGA_320_200, 15 }, /* 0x30d */
163 { VGA_320_200, 16 }, /* 0x30e */
164 { VGA_320_200, 24 }, /* 0x30f */
165 { VGA_640_480, 15 }, /* 0x310 */
166 { VGA_640_480, 16 }, /* 0x311 */
167 { VGA_640_480, 24 }, /* 0x312 */
168 { VGA_800_600, 15 }, /* 0x313 */
169 { VGA_800_600, 16 }, /* 0x314 */
170 { VGA_800_600, 24 }, /* 0x315 */
171 { VGA_1024_768, 15 }, /* 0x316 */
172 { VGA_1024_768, 16 }, /* 0x317 */
173 { VGA_1024_768, 24 }, /* 0x318 */
174 { VGA_1280_1024, 15 }, /* 0x319 */
175 { VGA_1280_1024, 16 }, /* 0x31a */
176 { VGA_1280_1024, 24 }, /* 0x31b */
177 { VGA_1600_1200, 8 }, /* 0x31c */
178 { VGA_1600_1200, 15 }, /* 0x31d */
179 { VGA_1600_1200, 16 }, /* 0x31e */
180 { VGA_1600_1200, 24 }, /* 0x31f */
181 { 0, 0 },
182 { VGA_640_400, 15 }, /* 0x321 */
183 { VGA_640_400, 16 }, /* 0x322 */
184 { VGA_640_400, 24 }, /* 0x323 */
185 { VGA_640_400, 32 }, /* 0x324 */
186 { 0, 0 },
187 { 0, 0 },
188 { 0, 0 },
189 { 0, 0 },
190 { VGA_640_480, 32 }, /* 0x329 */
191 { 0, 0 },
192 { 0, 0 },
193 { 0, 0 },
194 { 0, 0 },
195 { 0, 0 },
196 { VGA_896_672, 8 }, /* 0x32f */
197 { VGA_896_672, 15 }, /* 0x330 */
198 { VGA_896_672, 16 }, /* 0x331 */
199 { VGA_896_672, 24 }, /* 0x332 */
200 { VGA_896_672, 32 }, /* 0x333 */
201 { 0, 0 },
202 { 0, 0 },
203 { 0, 0 },
204 { 0, 0 },
205 { 0, 0 },
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 { VGA_1600_1200, 32 }, /* 0x342 */
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 { 0, 0 },
236 { 0, 0 },
237 { 0, 0 },
238 { 0, 0 },
239 { 0, 0 },
240 { 0, 0 },
241 { 0, 0 },
242 { 0, 0 },
243 { 0, 0 },
244 { 0, 0 },
245 { VGA_1440_900, 8 }, /* 0x360 */
246 { VGA_1440_900, 15 }, /* 0x361 */
247 { VGA_1440_900, 16 }, /* 0x362 */
248 { VGA_1440_900, 24 }, /* 0x363 */
249 { VGA_1440_900, 32 }, /* 0x364 */
250 { VGA_1152_720, 8 }, /* 0x365 */
251 { VGA_1152_720, 15 }, /* 0x366 */
252 { VGA_1152_720, 16 }, /* 0x367 */
253 { VGA_1152_720, 24 }, /* 0x368 */
254 { VGA_1152_720, 32 }, /* 0x369 */
255 { VGA_1024_640, 8 }, /* 0x36a */
256 { VGA_1024_640, 15 }, /* 0x36b */
257 { VGA_1024_640, 16 }, /* 0x36c */
258 { VGA_1024_640, 24 }, /* 0x36d */
259 { VGA_1024_640, 32 }, /* 0x36e */
260 { VGA_800_500, 8 }, /* 0x36f */
261 { VGA_800_500, 15 }, /* 0x370 */
262 { VGA_800_500, 16 }, /* 0x371 */
263 { VGA_800_500, 24 }, /* 0x372 */
264 { VGA_800_500, 32 }, /* 0x373 */
266 #endif
268 static inline grub_size_t
269 page_align (grub_size_t size)
271 return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
274 /* Find the optimal number of pages for the memory map. */
275 static grub_size_t
276 find_mmap_size (void)
278 grub_size_t count = 0, mmap_size;
280 auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
281 int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)),
282 grub_uint64_t size __attribute__ ((unused)),
283 grub_uint32_t type __attribute__ ((unused)))
285 count++;
286 return 0;
289 grub_mmap_iterate (hook);
291 mmap_size = count * sizeof (struct grub_e820_mmap);
293 /* Increase the size a bit for safety, because GRUB allocates more on
294 later. */
295 mmap_size += (1 << 12);
297 return page_align (mmap_size);
300 static void
301 free_pages (void)
303 real_mode_mem = prot_mode_mem = initrd_mem = 0;
306 /* Allocate pages for the real mode code and the protected mode code
307 for linux as well as a memory map buffer. */
308 static int
309 allocate_pages (grub_size_t prot_size)
311 grub_size_t real_size, mmap_size;
313 /* Make sure that each size is aligned to a page boundary. */
314 real_size = GRUB_LINUX_CL_END_OFFSET;
315 prot_size = page_align (prot_size);
316 mmap_size = find_mmap_size ();
318 grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
319 (unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size);
321 /* Calculate the number of pages; Combine the real mode code with
322 the memory map buffer for simplicity. */
323 real_mode_pages = ((real_size + mmap_size) >> 12);
324 prot_mode_pages = (prot_size >> 12);
326 /* Initialize the memory pointers with NULL for convenience. */
327 free_pages ();
329 /* FIXME: Should request low memory from the heap when this feature is
330 implemented. */
332 auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
333 int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
335 /* We must put real mode code in the traditional space. */
337 if (type == GRUB_MACHINE_MEMORY_AVAILABLE
338 && addr <= 0x90000)
340 if (addr < 0x10000)
342 size += addr - 0x10000;
343 addr = 0x10000;
346 if (addr + size > 0x90000)
347 size = 0x90000 - addr;
349 if (real_size + mmap_size > size)
350 return 0;
352 real_mode_mem =
353 (void *) (grub_size_t) ((addr + size) - (real_size + mmap_size));
354 return 1;
357 return 0;
359 grub_mmap_iterate (hook);
360 if (! real_mode_mem)
362 grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
363 goto fail;
366 prot_mode_mem = (void *) 0x100000;
368 grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, "
369 "prot_mode_mem = %lx, prot_mode_pages = %x\n",
370 (unsigned long) real_mode_mem, (unsigned) real_mode_pages,
371 (unsigned long) prot_mode_mem, (unsigned) prot_mode_pages);
373 return 1;
375 fail:
376 free_pages ();
377 return 0;
380 static void
381 grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num,
382 grub_uint64_t start, grub_uint64_t size,
383 grub_uint32_t type)
385 int n = *e820_num;
387 if (n >= GRUB_E820_MAX_ENTRY)
388 grub_fatal ("Too many e820 memory map entries");
390 if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) &&
391 (e820_map[n - 1].type == type))
392 e820_map[n - 1].size += size;
393 else
395 e820_map[n].addr = start;
396 e820_map[n].size = size;
397 e820_map[n].type = type;
398 (*e820_num)++;
402 static int
403 grub_linux_setup_video (struct linux_kernel_params *params)
405 struct grub_video_mode_info mode_info;
406 struct grub_video_render_target *render_target;
407 int ret;
409 ret = grub_video_get_info (&mode_info);
410 if (ret)
411 return 1;
413 ret = grub_video_get_active_render_target (&render_target);
414 if (ret)
415 return 1;
417 params->lfb_width = mode_info.width;
418 params->lfb_height = mode_info.height;
419 params->lfb_depth = mode_info.bpp;
420 params->lfb_line_len = mode_info.pitch;
422 params->lfb_base = (grub_size_t) render_target->data;
423 params->lfb_size = (params->lfb_line_len * params->lfb_height + 65535) >> 16;
425 params->red_mask_size = mode_info.red_mask_size;
426 params->red_field_pos = mode_info.red_field_pos;
427 params->green_mask_size = mode_info.green_mask_size;
428 params->green_field_pos = mode_info.green_field_pos;
429 params->blue_mask_size = mode_info.blue_mask_size;
430 params->blue_field_pos = mode_info.blue_field_pos;
431 params->reserved_mask_size = mode_info.reserved_mask_size;
432 params->reserved_field_pos = mode_info.reserved_field_pos;
434 return 0;
437 #ifdef __x86_64__
438 extern grub_uint8_t grub_linux_trampoline_start[];
439 extern grub_uint8_t grub_linux_trampoline_end[];
440 #endif
442 static grub_err_t
443 grub_linux_boot (void)
445 struct linux_kernel_params *params;
446 int e820_num;
447 grub_err_t err;
448 char *modevar, *tmp;
450 params = real_mode_mem;
452 modevar = grub_env_get ("gfxpayload");
454 /* Now all graphical modes are acceptable.
455 May change in future if we have modes without framebuffer. */
456 if (modevar && *modevar != 0)
458 tmp = grub_malloc (grub_strlen (modevar)
459 + sizeof (DEFAULT_VIDEO_MODE) + 1);
460 if (! tmp)
461 return grub_errno;
462 grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar);
463 err = grub_video_set_mode (tmp, 0);
464 grub_free (tmp);
466 #ifndef GRUB_ASSUME_LINUX_HAS_FB_SUPPORT
467 else
468 err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0);
469 #endif
471 if (err)
473 grub_print_error ();
474 grub_printf ("Booting however\n");
475 grub_errno = GRUB_ERR_NONE;
478 if (! grub_linux_setup_video (params))
479 params->have_vga = GRUB_VIDEO_TYPE_VLFB;
480 else
482 params->have_vga = 0;
483 params->video_cursor_x = grub_getxy () >> 8;
484 params->video_cursor_y = grub_getxy () & 0xff;
485 params->video_width = 80;
486 params->video_height = 25;
489 grub_dprintf ("linux", "code32_start = %x, idt_desc = %lx, gdt_desc = %lx\n",
490 (unsigned) params->code32_start,
491 (unsigned long) &(idt_desc.limit),
492 (unsigned long) &(gdt_desc.limit));
493 grub_dprintf ("linux", "idt = %x:%lx, gdt = %x:%lx\n",
494 (unsigned) idt_desc.limit, (unsigned long) idt_desc.base,
495 (unsigned) gdt_desc.limit, (unsigned long) gdt_desc.base);
497 auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
498 int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
500 switch (type)
502 case GRUB_MACHINE_MEMORY_AVAILABLE:
503 grub_e820_add_region (params->e820_map, &e820_num,
504 addr, size, GRUB_E820_RAM);
505 break;
507 #ifdef GRUB_MACHINE_MEMORY_ACPI
508 case GRUB_MACHINE_MEMORY_ACPI:
509 grub_e820_add_region (params->e820_map, &e820_num,
510 addr, size, GRUB_E820_ACPI);
511 break;
512 #endif
514 #ifdef GRUB_MACHINE_MEMORY_NVS
515 case GRUB_MACHINE_MEMORY_NVS:
516 grub_e820_add_region (params->e820_map, &e820_num,
517 addr, size, GRUB_E820_NVS);
518 break;
519 #endif
521 #ifdef GRUB_MACHINE_MEMORY_CODE
522 case GRUB_MACHINE_MEMORY_CODE:
523 grub_e820_add_region (params->e820_map, &e820_num,
524 addr, size, GRUB_E820_EXEC_CODE);
525 break;
526 #endif
528 default:
529 grub_e820_add_region (params->e820_map, &e820_num,
530 addr, size, GRUB_E820_RESERVED);
532 return 0;
535 e820_num = 0;
536 grub_mmap_iterate (hook);
537 params->mmap_size = e820_num;
539 #ifdef __x86_64__
541 grub_memcpy ((char *) prot_mode_mem + (prot_mode_pages << 12),
542 grub_linux_trampoline_start,
543 grub_linux_trampoline_end - grub_linux_trampoline_start);
545 ((void (*) (unsigned long, void *)) ((char *) prot_mode_mem
546 + (prot_mode_pages << 12)))
547 (params->code32_start, real_mode_mem);
548 #else
550 /* Hardware interrupts are not safe any longer. */
551 asm volatile ("cli" : : );
553 /* Load the IDT and the GDT for the bootstrap. */
554 asm volatile ("lidt %0" : : "m" (idt_desc));
555 asm volatile ("lgdt %0" : : "m" (gdt_desc));
557 /* Pass parameters. */
558 asm volatile ("movl %0, %%ecx" : : "m" (params->code32_start));
559 asm volatile ("movl %0, %%esi" : : "m" (real_mode_mem));
561 asm volatile ("xorl %%ebx, %%ebx" : : );
563 /* Enter Linux. */
564 asm volatile ("jmp *%%ecx" : : );
566 #endif
568 /* Never reach here. */
569 return GRUB_ERR_NONE;
572 static grub_err_t
573 grub_linux_unload (void)
575 grub_dl_unref (my_mod);
576 loaded = 0;
577 return GRUB_ERR_NONE;
580 static grub_err_t
581 grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
582 int argc, char *argv[])
584 grub_file_t file = 0;
585 struct linux_kernel_header lh;
586 struct linux_kernel_params *params;
587 grub_uint8_t setup_sects;
588 grub_size_t real_size, prot_size;
589 grub_ssize_t len;
590 int i;
591 char *dest;
593 grub_dl_ref (my_mod);
595 if (argc == 0)
597 grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
598 goto fail;
601 file = grub_file_open (argv[0]);
602 if (! file)
603 goto fail;
605 if (grub_file_read (file, (char *) &lh, sizeof (lh)) != sizeof (lh))
607 grub_error (GRUB_ERR_READ_ERROR, "cannot read the linux header");
608 goto fail;
611 if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
613 grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
614 goto fail;
617 if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
619 grub_error (GRUB_ERR_BAD_OS, "too many setup sectors");
620 goto fail;
623 if (! (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL))
625 grub_error (GRUB_ERR_BAD_OS, "zImage doesn't support 32-bit boot"
626 #ifdef GRUB_MACHINE_PCBIOS
627 " (try with `linux16')"
628 #endif
630 goto fail;
633 /* FIXME: 2.03 is not always good enough (Linux 2.4 can be 2.03 and
634 still not support 32-bit boot. */
635 if (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)
636 || grub_le_to_cpu16 (lh.version) < 0x0203)
638 grub_error (GRUB_ERR_BAD_OS, "version too old for 32-bit boot"
639 #ifdef GRUB_MACHINE_PCBIOS
640 " (try with `linux16')"
641 #endif
643 goto fail;
646 setup_sects = lh.setup_sects;
648 /* If SETUP_SECTS is not set, set it to the default (4). */
649 if (! setup_sects)
650 setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
652 real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
653 prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
655 if (! allocate_pages (prot_size))
656 goto fail;
658 params = (struct linux_kernel_params *) real_mode_mem;
659 grub_memset (params, 0, GRUB_LINUX_CL_END_OFFSET);
660 grub_memcpy (&params->setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
662 params->ps_mouse = params->padding10 = 0;
664 len = 0x400 - sizeof (lh);
665 if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len)
667 grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
668 goto fail;
671 params->type_of_loader = (LINUX_LOADER_ID_GRUB << 4);
673 params->cl_magic = GRUB_LINUX_CL_MAGIC;
674 params->cl_offset = 0x1000;
675 params->cmd_line_ptr = (unsigned long) real_mode_mem + 0x1000;
676 params->ramdisk_image = 0;
677 params->ramdisk_size = 0;
679 params->heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET;
680 params->loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
682 /* These are not needed to be precise, because Linux uses these values
683 only to raise an error when the decompression code cannot find good
684 space. */
685 params->ext_mem = ((32 * 0x100000) >> 10);
686 params->alt_mem = ((32 * 0x100000) >> 10);
688 params->video_page = 0; /* ??? */
689 params->video_mode = 0;
690 params->video_ega_bx = 0;
691 params->font_size = 16; /* XXX */
693 /* The other parameters are filled when booting. */
695 grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
697 grub_printf (" [Linux-bzImage, setup=0x%x, size=0x%x]\n",
698 (unsigned) real_size, (unsigned) prot_size);
700 /* Look for memory size and video mode specified on the command line. */
701 linux_mem_size = 0;
702 for (i = 1; i < argc; i++)
703 #ifdef GRUB_MACHINE_PCBIOS
704 if (grub_memcmp (argv[i], "vga=", 4) == 0)
706 /* Video mode selection support. */
707 char *val = argv[i] + 4;
708 unsigned vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
709 struct linux_vesafb_mode *linux_mode;
710 grub_err_t err;
711 char *buf;
713 if (grub_strcmp (val, "normal") == 0)
714 vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
715 else if (grub_strcmp (val, "ext") == 0)
716 vid_mode = GRUB_LINUX_VID_MODE_EXTENDED;
717 else if (grub_strcmp (val, "ask") == 0)
719 grub_printf ("Legacy `ask' parameter no longer supported.\n");
721 /* We usually would never do this in a loader, but "vga=ask" means user
722 requested interaction, so it can't hurt to request keyboard input. */
723 grub_wait_after_message ();
725 goto fail;
727 else
728 vid_mode = (grub_uint16_t) grub_strtoul (val, 0, 0);
730 switch (vid_mode)
732 case 0:
733 case GRUB_LINUX_VID_MODE_NORMAL:
734 grub_env_set ("gfxpayload", "text");
735 grub_printf ("%s is deprecated. "
736 "Use set gfxpayload=text before "
737 "linux command instead.\n",
738 argv[i]);
739 break;
741 case 1:
742 case GRUB_LINUX_VID_MODE_EXTENDED:
743 /* FIXME: support 80x50 text. */
744 grub_env_set ("gfxpayload", "text");
745 grub_printf ("%s is deprecated. "
746 "Use set gfxpayload=text before "
747 "linux command instead.\n",
748 argv[i]);
749 break;
750 default:
751 /* Ignore invalid values. */
752 if (vid_mode < GRUB_LINUX_VID_MODE_VESA_START ||
753 vid_mode >= GRUB_LINUX_VID_MODE_VESA_START +
754 ARRAY_SIZE (linux_vesafb_modes))
756 grub_env_set ("gfxpayload", "text");
757 grub_printf ("%s is deprecated. Mode %d isn't recognized. "
758 "Use set gfxpayload=WIDTHxHEIGHT[xDEPTH] before "
759 "linux command instead.\n",
760 argv[i], vid_mode);
761 break;
764 buf = grub_malloc (sizeof ("WWWWxHHHHxDD;WWWWxHHHH"));
765 if (! buf)
766 goto fail;
768 linux_mode
769 = &linux_vesafb_modes[vid_mode - GRUB_LINUX_VID_MODE_VESA_START];
771 grub_sprintf (buf, "%ux%ux%u;%ux%u",
772 linux_vesafb_res[linux_mode->res_index].width,
773 linux_vesafb_res[linux_mode->res_index].height,
774 linux_mode->depth,
775 linux_vesafb_res[linux_mode->res_index].width,
776 linux_vesafb_res[linux_mode->res_index].height);
777 grub_printf ("%s is deprecated. "
778 "Use set gfxpayload=%s before "
779 "linux command instead.\n",
780 argv[i], buf);
781 err = grub_env_set ("gfxpayload", buf);
782 grub_free (buf);
783 if (err)
784 goto fail;
787 else
788 #endif /* GRUB_MACHINE_PCBIOS */
789 if (grub_memcmp (argv[i], "mem=", 4) == 0)
791 char *val = argv[i] + 4;
793 linux_mem_size = grub_strtoul (val, &val, 0);
795 if (grub_errno)
797 grub_errno = GRUB_ERR_NONE;
798 linux_mem_size = 0;
800 else
802 int shift = 0;
804 switch (grub_tolower (val[0]))
806 case 'g':
807 shift += 10;
808 case 'm':
809 shift += 10;
810 case 'k':
811 shift += 10;
812 default:
813 break;
816 /* Check an overflow. */
817 if (linux_mem_size > (~0UL >> shift))
818 linux_mem_size = 0;
819 else
820 linux_mem_size <<= shift;
824 /* Specify the boot file. */
825 dest = grub_stpcpy ((char *) real_mode_mem + GRUB_LINUX_CL_OFFSET,
826 "BOOT_IMAGE=");
827 dest = grub_stpcpy (dest, argv[0]);
829 /* Copy kernel parameters. */
830 for (i = 1;
831 i < argc
832 && dest + grub_strlen (argv[i]) + 1 < ((char *) real_mode_mem
833 + GRUB_LINUX_CL_END_OFFSET);
834 i++)
836 *dest++ = ' ';
837 dest = grub_stpcpy (dest, argv[i]);
840 len = prot_size;
841 if (grub_file_read (file, (char *) GRUB_LINUX_BZIMAGE_ADDR, len) != len)
842 grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
844 if (grub_errno == GRUB_ERR_NONE)
846 grub_loader_set (grub_linux_boot, grub_linux_unload,
847 0 /* set noreturn=0 in order to avoid grub_console_fini() */);
848 loaded = 1;
851 fail:
853 if (file)
854 grub_file_close (file);
856 if (grub_errno != GRUB_ERR_NONE)
858 grub_dl_unref (my_mod);
859 loaded = 0;
862 return grub_errno;
865 static grub_err_t
866 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
867 int argc, char *argv[])
869 grub_file_t file = 0;
870 grub_ssize_t size;
871 grub_addr_t addr_min, addr_max;
872 grub_addr_t addr;
873 struct linux_kernel_header *lh;
875 if (argc == 0)
877 grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified");
878 goto fail;
881 if (! loaded)
883 grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first.");
884 goto fail;
887 file = grub_file_open (argv[0]);
888 if (! file)
889 goto fail;
891 size = grub_file_size (file);
892 initrd_pages = (page_align (size) >> 12);
894 lh = (struct linux_kernel_header *) real_mode_mem;
896 /* Get the highest address available for the initrd. */
897 if (grub_le_to_cpu16 (lh->version) >= 0x0203)
899 addr_max = grub_cpu_to_le32 (lh->initrd_addr_max);
901 /* XXX in reality, Linux specifies a bogus value, so
902 it is necessary to make sure that ADDR_MAX does not exceed
903 0x3fffffff. */
904 if (addr_max > GRUB_LINUX_INITRD_MAX_ADDRESS)
905 addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
907 else
908 addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
910 if (linux_mem_size != 0 && linux_mem_size < addr_max)
911 addr_max = linux_mem_size;
913 /* Linux 2.3.xx has a bug in the memory range check, so avoid
914 the last page.
915 Linux 2.2.xx has a bug in the memory range check, which is
916 worse than that of Linux 2.3.xx, so avoid the last 64kb. */
917 addr_max -= 0x10000;
919 /* Usually, the compression ratio is about 50%. */
920 addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12)
921 + page_align (size);
923 if (addr_max > grub_os_area_addr + grub_os_area_size)
924 addr_max = grub_os_area_addr + grub_os_area_size;
926 /* Put the initrd as high as possible, 4KiB aligned. */
927 addr = (addr_max - size) & ~0xFFF;
929 if (addr < addr_min)
931 grub_error (GRUB_ERR_OUT_OF_RANGE, "The initrd is too big");
932 goto fail;
935 initrd_mem = (void *) addr;
937 if (grub_file_read (file, initrd_mem, size) != size)
939 grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
940 goto fail;
943 grub_printf (" [Initrd, addr=0x%x, size=0x%x]\n",
944 (unsigned) addr, (unsigned) size);
946 lh->ramdisk_image = addr;
947 lh->ramdisk_size = size;
948 lh->root_dev = 0x0100; /* XXX */
950 fail:
951 if (file)
952 grub_file_close (file);
954 return grub_errno;
957 static grub_command_t cmd_linux, cmd_initrd;
959 GRUB_MOD_INIT(linux)
961 cmd_linux = grub_register_command ("linux", grub_cmd_linux,
962 0, "load linux");
963 cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
964 0, "load initrd");
965 my_mod = mod;
968 GRUB_MOD_FINI(linux)
970 grub_unregister_command (cmd_linux);
971 grub_unregister_command (cmd_initrd);