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>
27 #include <grub/misc.h>
28 #include <grub/types.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
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"
49 #define DEFAULT_VIDEO_MODE "text"
52 static grub_dl_t my_mod
;
54 static grub_size_t linux_mem_size
;
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))) =
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00,
72 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
79 } __attribute__ ((packed
));
81 static struct gdt_descriptor gdt_desc
=
91 } __attribute__ ((packed
));
93 static struct idt_descriptor idt_desc
=
99 #ifdef GRUB_MACHINE_PCBIOS
100 struct linux_vesafb_res
103 grub_uint16_t height
;
106 struct linux_vesafb_mode
108 grub_uint8_t res_index
;
128 static struct linux_vesafb_res linux_vesafb_res
[] =
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 */
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 */
182 { VGA_640_400
, 15 }, /* 0x321 */
183 { VGA_640_400
, 16 }, /* 0x322 */
184 { VGA_640_400
, 24 }, /* 0x323 */
185 { VGA_640_400
, 32 }, /* 0x324 */
190 { VGA_640_480
, 32 }, /* 0x329 */
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 */
215 { VGA_1600_1200
, 32 }, /* 0x342 */
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 */
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. */
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
)))
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
295 mmap_size
+= (1 << 12);
297 return page_align (mmap_size
);
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. */
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. */
329 /* FIXME: Should request low memory from the heap when this feature is
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
342 size
+= addr
- 0x10000;
346 if (addr
+ size
> 0x90000)
347 size
= 0x90000 - addr
;
349 if (real_size
+ mmap_size
> size
)
353 (void *) (grub_size_t
) ((addr
+ size
) - (real_size
+ mmap_size
));
359 grub_mmap_iterate (hook
);
362 grub_error (GRUB_ERR_OUT_OF_MEMORY
, "cannot allocate real mode pages");
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
);
381 grub_e820_add_region (struct grub_e820_mmap
*e820_map
, int *e820_num
,
382 grub_uint64_t start
, grub_uint64_t size
,
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
;
395 e820_map
[n
].addr
= start
;
396 e820_map
[n
].size
= size
;
397 e820_map
[n
].type
= type
;
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
;
409 ret
= grub_video_get_info (&mode_info
);
413 ret
= grub_video_get_active_render_target (&render_target
);
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
;
438 extern grub_uint8_t grub_linux_trampoline_start
[];
439 extern grub_uint8_t grub_linux_trampoline_end
[];
443 grub_linux_boot (void)
445 struct linux_kernel_params
*params
;
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);
462 grub_sprintf (tmp
, "%s;" DEFAULT_VIDEO_MODE
, modevar
);
463 err
= grub_video_set_mode (tmp
, 0);
466 #ifndef GRUB_ASSUME_LINUX_HAS_FB_SUPPORT
468 err
= grub_video_set_mode (DEFAULT_VIDEO_MODE
, 0);
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
;
482 params
->have_vga
= GRUB_VIDEO_TYPE_TEXT
;
483 params
->video_width
= 80;
484 params
->video_height
= 25;
487 grub_dprintf ("linux", "code32_start = %x, idt_desc = %lx, gdt_desc = %lx\n",
488 (unsigned) params
->code32_start
,
489 (unsigned long) &(idt_desc
.limit
),
490 (unsigned long) &(gdt_desc
.limit
));
491 grub_dprintf ("linux", "idt = %x:%lx, gdt = %x:%lx\n",
492 (unsigned) idt_desc
.limit
, (unsigned long) idt_desc
.base
,
493 (unsigned) gdt_desc
.limit
, (unsigned long) gdt_desc
.base
);
495 auto int NESTED_FUNC_ATTR
hook (grub_uint64_t
, grub_uint64_t
, grub_uint32_t
);
496 int NESTED_FUNC_ATTR
hook (grub_uint64_t addr
, grub_uint64_t size
, grub_uint32_t type
)
500 case GRUB_MACHINE_MEMORY_AVAILABLE
:
501 grub_e820_add_region (params
->e820_map
, &e820_num
,
502 addr
, size
, GRUB_E820_RAM
);
505 #ifdef GRUB_MACHINE_MEMORY_ACPI
506 case GRUB_MACHINE_MEMORY_ACPI
:
507 grub_e820_add_region (params
->e820_map
, &e820_num
,
508 addr
, size
, GRUB_E820_ACPI
);
512 #ifdef GRUB_MACHINE_MEMORY_NVS
513 case GRUB_MACHINE_MEMORY_NVS
:
514 grub_e820_add_region (params
->e820_map
, &e820_num
,
515 addr
, size
, GRUB_E820_NVS
);
519 #ifdef GRUB_MACHINE_MEMORY_CODE
520 case GRUB_MACHINE_MEMORY_CODE
:
521 grub_e820_add_region (params
->e820_map
, &e820_num
,
522 addr
, size
, GRUB_E820_EXEC_CODE
);
527 grub_e820_add_region (params
->e820_map
, &e820_num
,
528 addr
, size
, GRUB_E820_RESERVED
);
534 grub_mmap_iterate (hook
);
535 params
->mmap_size
= e820_num
;
537 /* Initialize these last, because terminal position could be affected by printfs above. */
538 if (params
->have_vga
== GRUB_VIDEO_TYPE_TEXT
)
540 params
->video_cursor_x
= grub_getxy () >> 8;
541 params
->video_cursor_y
= grub_getxy () & 0xff;
546 grub_memcpy ((char *) prot_mode_mem
+ (prot_mode_pages
<< 12),
547 grub_linux_trampoline_start
,
548 grub_linux_trampoline_end
- grub_linux_trampoline_start
);
550 ((void (*) (unsigned long, void *)) ((char *) prot_mode_mem
551 + (prot_mode_pages
<< 12)))
552 (params
->code32_start
, real_mode_mem
);
555 /* Hardware interrupts are not safe any longer. */
556 asm volatile ("cli" : : );
558 /* Load the IDT and the GDT for the bootstrap. */
559 asm volatile ("lidt %0" : : "m" (idt_desc
));
560 asm volatile ("lgdt %0" : : "m" (gdt_desc
));
563 asm volatile ("jmp *%2" : : "b" (0), "S" (real_mode_mem
), "g" (params
->code32_start
));
567 /* Never reach here. */
568 return GRUB_ERR_NONE
;
572 grub_linux_unload (void)
574 grub_dl_unref (my_mod
);
576 return GRUB_ERR_NONE
;
580 grub_cmd_linux (grub_command_t cmd
__attribute__ ((unused
)),
581 int argc
, char *argv
[])
583 grub_file_t file
= 0;
584 struct linux_kernel_header lh
;
585 struct linux_kernel_params
*params
;
586 grub_uint8_t setup_sects
;
587 grub_size_t real_size
, prot_size
;
592 grub_dl_ref (my_mod
);
596 grub_error (GRUB_ERR_BAD_ARGUMENT
, "no kernel specified");
600 file
= grub_file_open (argv
[0]);
604 if (grub_file_read (file
, &lh
, sizeof (lh
)) != sizeof (lh
))
606 grub_error (GRUB_ERR_READ_ERROR
, "cannot read the linux header");
610 if (lh
.boot_flag
!= grub_cpu_to_le16 (0xaa55))
612 grub_error (GRUB_ERR_BAD_OS
, "invalid magic number");
616 if (lh
.setup_sects
> GRUB_LINUX_MAX_SETUP_SECTS
)
618 grub_error (GRUB_ERR_BAD_OS
, "too many setup sectors");
622 if (! (lh
.loadflags
& GRUB_LINUX_FLAG_BIG_KERNEL
))
624 grub_error (GRUB_ERR_BAD_OS
, "zImage doesn't support 32-bit boot"
625 #ifdef GRUB_MACHINE_PCBIOS
626 " (try with `linux16')"
632 /* FIXME: 2.03 is not always good enough (Linux 2.4 can be 2.03 and
633 still not support 32-bit boot. */
634 if (lh
.header
!= grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE
)
635 || grub_le_to_cpu16 (lh
.version
) < 0x0203)
637 grub_error (GRUB_ERR_BAD_OS
, "version too old for 32-bit boot"
638 #ifdef GRUB_MACHINE_PCBIOS
639 " (try with `linux16')"
645 setup_sects
= lh
.setup_sects
;
647 /* If SETUP_SECTS is not set, set it to the default (4). */
649 setup_sects
= GRUB_LINUX_DEFAULT_SETUP_SECTS
;
651 real_size
= setup_sects
<< GRUB_DISK_SECTOR_BITS
;
652 prot_size
= grub_file_size (file
) - real_size
- GRUB_DISK_SECTOR_SIZE
;
654 if (! allocate_pages (prot_size
))
657 params
= (struct linux_kernel_params
*) real_mode_mem
;
658 grub_memset (params
, 0, GRUB_LINUX_CL_END_OFFSET
);
659 grub_memcpy (¶ms
->setup_sects
, &lh
.setup_sects
, sizeof (lh
) - 0x1F1);
661 params
->ps_mouse
= params
->padding10
= 0;
663 len
= 0x400 - sizeof (lh
);
664 if (grub_file_read (file
, (char *) real_mode_mem
+ sizeof (lh
), len
) != len
)
666 grub_error (GRUB_ERR_FILE_READ_ERROR
, "Couldn't read file");
670 params
->type_of_loader
= (LINUX_LOADER_ID_GRUB
<< 4);
672 /* These two are used (instead of cmd_line_ptr) by older versions of Linux,
673 and otherwise ignored. */
674 params
->cl_magic
= GRUB_LINUX_CL_MAGIC
;
675 params
->cl_offset
= 0x1000;
677 params
->cmd_line_ptr
= (unsigned long) real_mode_mem
+ 0x1000;
678 params
->ramdisk_image
= 0;
679 params
->ramdisk_size
= 0;
681 params
->heap_end_ptr
= GRUB_LINUX_HEAP_END_OFFSET
;
682 params
->loadflags
|= GRUB_LINUX_FLAG_CAN_USE_HEAP
;
684 /* These are not needed to be precise, because Linux uses these values
685 only to raise an error when the decompression code cannot find good
687 params
->ext_mem
= ((32 * 0x100000) >> 10);
688 params
->alt_mem
= ((32 * 0x100000) >> 10);
690 /* Ignored by Linux. */
691 params
->video_page
= 0;
693 /* Must be non-zero even in text mode, or Linux will think there's no VGA. */
694 params
->video_mode
= 0x3;
696 /* Only used when `video_mode == 0x7', otherwise ignored. */
697 params
->video_ega_bx
= 0;
699 params
->font_size
= 16; /* XXX */
701 /* The other parameters are filled when booting. */
703 grub_file_seek (file
, real_size
+ GRUB_DISK_SECTOR_SIZE
);
705 grub_printf (" [Linux-bzImage, setup=0x%x, size=0x%x]\n",
706 (unsigned) real_size
, (unsigned) prot_size
);
708 /* Look for memory size and video mode specified on the command line. */
710 for (i
= 1; i
< argc
; i
++)
711 #ifdef GRUB_MACHINE_PCBIOS
712 if (grub_memcmp (argv
[i
], "vga=", 4) == 0)
714 /* Video mode selection support. */
715 char *val
= argv
[i
] + 4;
716 unsigned vid_mode
= GRUB_LINUX_VID_MODE_NORMAL
;
717 struct linux_vesafb_mode
*linux_mode
;
721 if (grub_strcmp (val
, "normal") == 0)
722 vid_mode
= GRUB_LINUX_VID_MODE_NORMAL
;
723 else if (grub_strcmp (val
, "ext") == 0)
724 vid_mode
= GRUB_LINUX_VID_MODE_EXTENDED
;
725 else if (grub_strcmp (val
, "ask") == 0)
727 grub_printf ("Legacy `ask' parameter no longer supported.\n");
729 /* We usually would never do this in a loader, but "vga=ask" means user
730 requested interaction, so it can't hurt to request keyboard input. */
731 grub_wait_after_message ();
736 vid_mode
= (grub_uint16_t
) grub_strtoul (val
, 0, 0);
741 case GRUB_LINUX_VID_MODE_NORMAL
:
742 grub_env_set ("gfxpayload", "text");
743 grub_printf ("%s is deprecated. "
744 "Use set gfxpayload=text before "
745 "linux command instead.\n",
750 case GRUB_LINUX_VID_MODE_EXTENDED
:
751 /* FIXME: support 80x50 text. */
752 grub_env_set ("gfxpayload", "text");
753 grub_printf ("%s is deprecated. "
754 "Use set gfxpayload=text before "
755 "linux command instead.\n",
759 /* Ignore invalid values. */
760 if (vid_mode
< GRUB_LINUX_VID_MODE_VESA_START
||
761 vid_mode
>= GRUB_LINUX_VID_MODE_VESA_START
+
762 ARRAY_SIZE (linux_vesafb_modes
))
764 grub_env_set ("gfxpayload", "text");
765 grub_printf ("%s is deprecated. Mode %d isn't recognized. "
766 "Use set gfxpayload=WIDTHxHEIGHT[xDEPTH] before "
767 "linux command instead.\n",
772 buf
= grub_malloc (sizeof ("WWWWxHHHHxDD;WWWWxHHHH"));
777 = &linux_vesafb_modes
[vid_mode
- GRUB_LINUX_VID_MODE_VESA_START
];
779 grub_sprintf (buf
, "%ux%ux%u;%ux%u",
780 linux_vesafb_res
[linux_mode
->res_index
].width
,
781 linux_vesafb_res
[linux_mode
->res_index
].height
,
783 linux_vesafb_res
[linux_mode
->res_index
].width
,
784 linux_vesafb_res
[linux_mode
->res_index
].height
);
785 grub_printf ("%s is deprecated. "
786 "Use set gfxpayload=%s before "
787 "linux command instead.\n",
789 err
= grub_env_set ("gfxpayload", buf
);
796 #endif /* GRUB_MACHINE_PCBIOS */
797 if (grub_memcmp (argv
[i
], "mem=", 4) == 0)
799 char *val
= argv
[i
] + 4;
801 linux_mem_size
= grub_strtoul (val
, &val
, 0);
805 grub_errno
= GRUB_ERR_NONE
;
812 switch (grub_tolower (val
[0]))
824 /* Check an overflow. */
825 if (linux_mem_size
> (~0UL >> shift
))
828 linux_mem_size
<<= shift
;
831 else if (grub_memcmp (argv
[i
], "quiet", sizeof ("quiet") - 1) == 0)
833 params
->loadflags
|= GRUB_LINUX_FLAG_QUIET
;
837 /* Specify the boot file. */
838 dest
= grub_stpcpy ((char *) real_mode_mem
+ GRUB_LINUX_CL_OFFSET
,
840 dest
= grub_stpcpy (dest
, argv
[0]);
842 /* Copy kernel parameters. */
845 && dest
+ grub_strlen (argv
[i
]) + 1 < ((char *) real_mode_mem
846 + GRUB_LINUX_CL_END_OFFSET
);
850 dest
= grub_stpcpy (dest
, argv
[i
]);
854 if (grub_file_read (file
, (void *) GRUB_LINUX_BZIMAGE_ADDR
, len
) != len
)
855 grub_error (GRUB_ERR_FILE_READ_ERROR
, "Couldn't read file");
857 if (grub_errno
== GRUB_ERR_NONE
)
859 grub_loader_set (grub_linux_boot
, grub_linux_unload
,
860 0 /* set noreturn=0 in order to avoid grub_console_fini() */);
867 grub_file_close (file
);
869 if (grub_errno
!= GRUB_ERR_NONE
)
871 grub_dl_unref (my_mod
);
879 grub_cmd_initrd (grub_command_t cmd
__attribute__ ((unused
)),
880 int argc
, char *argv
[])
882 grub_file_t file
= 0;
884 grub_addr_t addr_min
, addr_max
;
886 struct linux_kernel_header
*lh
;
890 grub_error (GRUB_ERR_BAD_ARGUMENT
, "No module specified");
896 grub_error (GRUB_ERR_BAD_ARGUMENT
, "You need to load the kernel first.");
900 file
= grub_file_open (argv
[0]);
904 size
= grub_file_size (file
);
905 initrd_pages
= (page_align (size
) >> 12);
907 lh
= (struct linux_kernel_header
*) real_mode_mem
;
909 /* Get the highest address available for the initrd. */
910 if (grub_le_to_cpu16 (lh
->version
) >= 0x0203)
912 addr_max
= grub_cpu_to_le32 (lh
->initrd_addr_max
);
914 /* XXX in reality, Linux specifies a bogus value, so
915 it is necessary to make sure that ADDR_MAX does not exceed
917 if (addr_max
> GRUB_LINUX_INITRD_MAX_ADDRESS
)
918 addr_max
= GRUB_LINUX_INITRD_MAX_ADDRESS
;
921 addr_max
= GRUB_LINUX_INITRD_MAX_ADDRESS
;
923 if (linux_mem_size
!= 0 && linux_mem_size
< addr_max
)
924 addr_max
= linux_mem_size
;
926 /* Linux 2.3.xx has a bug in the memory range check, so avoid
928 Linux 2.2.xx has a bug in the memory range check, which is
929 worse than that of Linux 2.3.xx, so avoid the last 64kb. */
932 /* Usually, the compression ratio is about 50%. */
933 addr_min
= (grub_addr_t
) prot_mode_mem
+ ((prot_mode_pages
* 3) << 12)
936 if (addr_max
> grub_os_area_addr
+ grub_os_area_size
)
937 addr_max
= grub_os_area_addr
+ grub_os_area_size
;
939 /* Put the initrd as high as possible, 4KiB aligned. */
940 addr
= (addr_max
- size
) & ~0xFFF;
944 grub_error (GRUB_ERR_OUT_OF_RANGE
, "The initrd is too big");
948 initrd_mem
= (void *) addr
;
950 if (grub_file_read (file
, initrd_mem
, size
) != size
)
952 grub_error (GRUB_ERR_FILE_READ_ERROR
, "Couldn't read file");
956 grub_printf (" [Initrd, addr=0x%x, size=0x%x]\n",
957 (unsigned) addr
, (unsigned) size
);
959 lh
->ramdisk_image
= addr
;
960 lh
->ramdisk_size
= size
;
961 lh
->root_dev
= 0x0100; /* XXX */
965 grub_file_close (file
);
970 static grub_command_t cmd_linux
, cmd_initrd
;
974 cmd_linux
= grub_register_command ("linux", grub_cmd_linux
,
976 cmd_initrd
= grub_register_command ("initrd", grub_cmd_initrd
,
983 grub_unregister_command (cmd_linux
);
984 grub_unregister_command (cmd_initrd
);