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
= 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
)
502 case GRUB_MACHINE_MEMORY_AVAILABLE
:
503 grub_e820_add_region (params
->e820_map
, &e820_num
,
504 addr
, size
, GRUB_E820_RAM
);
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
);
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
);
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
);
529 grub_e820_add_region (params
->e820_map
, &e820_num
,
530 addr
, size
, GRUB_E820_RESERVED
);
536 grub_mmap_iterate (hook
);
537 params
->mmap_size
= e820_num
;
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
);
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" : : );
564 asm volatile ("jmp *%%ecx" : : );
568 /* Never reach here. */
569 return GRUB_ERR_NONE
;
573 grub_linux_unload (void)
575 grub_dl_unref (my_mod
);
577 return GRUB_ERR_NONE
;
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
;
593 grub_dl_ref (my_mod
);
597 grub_error (GRUB_ERR_BAD_ARGUMENT
, "no kernel specified");
601 file
= grub_file_open (argv
[0]);
605 if (grub_file_read (file
, (char *) &lh
, sizeof (lh
)) != sizeof (lh
))
607 grub_error (GRUB_ERR_READ_ERROR
, "cannot read the linux header");
611 if (lh
.boot_flag
!= grub_cpu_to_le16 (0xaa55))
613 grub_error (GRUB_ERR_BAD_OS
, "invalid magic number");
617 if (lh
.setup_sects
> GRUB_LINUX_MAX_SETUP_SECTS
)
619 grub_error (GRUB_ERR_BAD_OS
, "too many setup sectors");
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')"
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')"
646 setup_sects
= lh
.setup_sects
;
648 /* If SETUP_SECTS is not set, set it to the default (4). */
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
))
658 params
= (struct linux_kernel_params
*) real_mode_mem
;
659 grub_memset (params
, 0, GRUB_LINUX_CL_END_OFFSET
);
660 grub_memcpy (¶ms
->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");
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
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. */
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
;
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 ();
728 vid_mode
= (grub_uint16_t
) grub_strtoul (val
, 0, 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",
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",
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",
764 buf
= grub_malloc (sizeof ("WWWWxHHHHxDD;WWWWxHHHH"));
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
,
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",
781 err
= grub_env_set ("gfxpayload", buf
);
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);
797 grub_errno
= GRUB_ERR_NONE
;
804 switch (grub_tolower (val
[0]))
816 /* Check an overflow. */
817 if (linux_mem_size
> (~0UL >> shift
))
820 linux_mem_size
<<= shift
;
824 /* Specify the boot file. */
825 dest
= grub_stpcpy ((char *) real_mode_mem
+ GRUB_LINUX_CL_OFFSET
,
827 dest
= grub_stpcpy (dest
, argv
[0]);
829 /* Copy kernel parameters. */
832 && dest
+ grub_strlen (argv
[i
]) + 1 < ((char *) real_mode_mem
833 + GRUB_LINUX_CL_END_OFFSET
);
837 dest
= grub_stpcpy (dest
, argv
[i
]);
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() */);
854 grub_file_close (file
);
856 if (grub_errno
!= GRUB_ERR_NONE
)
858 grub_dl_unref (my_mod
);
866 grub_cmd_initrd (grub_command_t cmd
__attribute__ ((unused
)),
867 int argc
, char *argv
[])
869 grub_file_t file
= 0;
871 grub_addr_t addr_min
, addr_max
;
873 struct linux_kernel_header
*lh
;
877 grub_error (GRUB_ERR_BAD_ARGUMENT
, "No module specified");
883 grub_error (GRUB_ERR_BAD_ARGUMENT
, "You need to load the kernel first.");
887 file
= grub_file_open (argv
[0]);
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
904 if (addr_max
> GRUB_LINUX_INITRD_MAX_ADDRESS
)
905 addr_max
= GRUB_LINUX_INITRD_MAX_ADDRESS
;
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
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. */
919 /* Usually, the compression ratio is about 50%. */
920 addr_min
= (grub_addr_t
) prot_mode_mem
+ ((prot_mode_pages
* 3) << 12)
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;
931 grub_error (GRUB_ERR_OUT_OF_RANGE
, "The initrd is too big");
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");
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 */
952 grub_file_close (file
);
957 static grub_command_t cmd_linux
, cmd_initrd
;
961 cmd_linux
= grub_register_command ("linux", grub_cmd_linux
,
963 cmd_initrd
= grub_register_command ("initrd", grub_cmd_initrd
,
970 grub_unregister_command (cmd_linux
);
971 grub_unregister_command (cmd_initrd
);