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 #include <grub/video_fb.h>
35 #include <grub/command.h>
37 #define GRUB_LINUX_CL_OFFSET 0x1000
38 #define GRUB_LINUX_CL_END_OFFSET 0x2000
40 static grub_dl_t my_mod
;
42 static grub_size_t linux_mem_size
;
44 static void *real_mode_mem
;
45 static void *prot_mode_mem
;
46 static void *initrd_mem
;
47 static grub_uint32_t real_mode_pages
;
48 static grub_uint32_t prot_mode_pages
;
49 static grub_uint32_t initrd_pages
;
51 static grub_uint8_t gdt
[] __attribute__ ((aligned(16))) =
54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00,
60 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
67 } __attribute__ ((packed
));
69 static struct gdt_descriptor gdt_desc
=
79 } __attribute__ ((packed
));
81 static struct idt_descriptor idt_desc
=
87 #ifdef GRUB_MACHINE_PCBIOS
88 struct linux_vesafb_res
94 struct linux_vesafb_mode
96 grub_uint8_t res_index
;
116 static struct linux_vesafb_res linux_vesafb_res
[] =
132 /* This is the reverse of the table in [linux]/Documentation/fb/vesafb.txt
133 plus a few more modes based on the table in
134 http://en.wikipedia.org/wiki/VESA_BIOS_Extensions */
135 struct linux_vesafb_mode linux_vesafb_modes
[] =
137 { VGA_640_400
, 8 }, /* 0x300 */
138 { VGA_640_480
, 8 }, /* 0x301 */
139 { VGA_800_600
, 4 }, /* 0x302 */
140 { VGA_800_600
, 8 }, /* 0x303 */
141 { VGA_1024_768
, 4 }, /* 0x304 */
142 { VGA_1024_768
, 8 }, /* 0x305 */
143 { VGA_1280_1024
, 4 }, /* 0x306 */
144 { VGA_1280_1024
, 8 }, /* 0x307 */
150 { VGA_320_200
, 15 }, /* 0x30d */
151 { VGA_320_200
, 16 }, /* 0x30e */
152 { VGA_320_200
, 24 }, /* 0x30f */
153 { VGA_640_480
, 15 }, /* 0x310 */
154 { VGA_640_480
, 16 }, /* 0x311 */
155 { VGA_640_480
, 24 }, /* 0x312 */
156 { VGA_800_600
, 15 }, /* 0x313 */
157 { VGA_800_600
, 16 }, /* 0x314 */
158 { VGA_800_600
, 24 }, /* 0x315 */
159 { VGA_1024_768
, 15 }, /* 0x316 */
160 { VGA_1024_768
, 16 }, /* 0x317 */
161 { VGA_1024_768
, 24 }, /* 0x318 */
162 { VGA_1280_1024
, 15 }, /* 0x319 */
163 { VGA_1280_1024
, 16 }, /* 0x31a */
164 { VGA_1280_1024
, 24 }, /* 0x31b */
165 { VGA_1600_1200
, 8 }, /* 0x31c */
166 { VGA_1600_1200
, 15 }, /* 0x31d */
167 { VGA_1600_1200
, 16 }, /* 0x31e */
168 { VGA_1600_1200
, 24 }, /* 0x31f */
170 { VGA_640_400
, 15 }, /* 0x321 */
171 { VGA_640_400
, 16 }, /* 0x322 */
172 { VGA_640_400
, 24 }, /* 0x323 */
173 { VGA_640_400
, 32 }, /* 0x324 */
178 { VGA_640_480
, 32 }, /* 0x329 */
184 { VGA_896_672
, 8 }, /* 0x32f */
185 { VGA_896_672
, 15 }, /* 0x330 */
186 { VGA_896_672
, 16 }, /* 0x331 */
187 { VGA_896_672
, 24 }, /* 0x332 */
188 { VGA_896_672
, 32 }, /* 0x333 */
203 { VGA_1600_1200
, 32 }, /* 0x342 */
233 { VGA_1440_900
, 8 }, /* 0x360 */
234 { VGA_1440_900
, 15 }, /* 0x361 */
235 { VGA_1440_900
, 16 }, /* 0x362 */
236 { VGA_1440_900
, 24 }, /* 0x363 */
237 { VGA_1440_900
, 32 }, /* 0x364 */
238 { VGA_1152_720
, 8 }, /* 0x365 */
239 { VGA_1152_720
, 15 }, /* 0x366 */
240 { VGA_1152_720
, 16 }, /* 0x367 */
241 { VGA_1152_720
, 24 }, /* 0x368 */
242 { VGA_1152_720
, 32 }, /* 0x369 */
243 { VGA_1024_640
, 8 }, /* 0x36a */
244 { VGA_1024_640
, 15 }, /* 0x36b */
245 { VGA_1024_640
, 16 }, /* 0x36c */
246 { VGA_1024_640
, 24 }, /* 0x36d */
247 { VGA_1024_640
, 32 }, /* 0x36e */
248 { VGA_800_500
, 8 }, /* 0x36f */
249 { VGA_800_500
, 15 }, /* 0x370 */
250 { VGA_800_500
, 16 }, /* 0x371 */
251 { VGA_800_500
, 24 }, /* 0x372 */
252 { VGA_800_500
, 32 }, /* 0x373 */
256 static inline grub_size_t
257 page_align (grub_size_t size
)
259 return (size
+ (1 << 12) - 1) & (~((1 << 12) - 1));
262 /* Find the optimal number of pages for the memory map. */
264 find_mmap_size (void)
266 grub_size_t count
= 0, mmap_size
;
268 auto int NESTED_FUNC_ATTR
hook (grub_uint64_t
, grub_uint64_t
, grub_uint32_t
);
269 int NESTED_FUNC_ATTR
hook (grub_uint64_t addr
__attribute__ ((unused
)),
270 grub_uint64_t size
__attribute__ ((unused
)),
271 grub_uint32_t type
__attribute__ ((unused
)))
277 grub_mmap_iterate (hook
);
279 mmap_size
= count
* sizeof (struct grub_e820_mmap
);
281 /* Increase the size a bit for safety, because GRUB allocates more on
283 mmap_size
+= (1 << 12);
285 return page_align (mmap_size
);
291 real_mode_mem
= prot_mode_mem
= initrd_mem
= 0;
294 /* Allocate pages for the real mode code and the protected mode code
295 for linux as well as a memory map buffer. */
297 allocate_pages (grub_size_t prot_size
)
299 grub_size_t real_size
, mmap_size
;
301 /* Make sure that each size is aligned to a page boundary. */
302 real_size
= GRUB_LINUX_CL_END_OFFSET
;
303 prot_size
= page_align (prot_size
);
304 mmap_size
= find_mmap_size ();
306 grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
307 (unsigned) real_size
, (unsigned) prot_size
, (unsigned) mmap_size
);
309 /* Calculate the number of pages; Combine the real mode code with
310 the memory map buffer for simplicity. */
311 real_mode_pages
= ((real_size
+ mmap_size
) >> 12);
312 prot_mode_pages
= (prot_size
>> 12);
314 /* Initialize the memory pointers with NULL for convenience. */
317 /* FIXME: Should request low memory from the heap when this feature is
320 auto int NESTED_FUNC_ATTR
hook (grub_uint64_t
, grub_uint64_t
, grub_uint32_t
);
321 int NESTED_FUNC_ATTR
hook (grub_uint64_t addr
, grub_uint64_t size
, grub_uint32_t type
)
323 /* We must put real mode code in the traditional space. */
325 if (type
== GRUB_MACHINE_MEMORY_AVAILABLE
330 size
+= addr
- 0x10000;
334 if (addr
+ size
> 0x90000)
335 size
= 0x90000 - addr
;
337 if (real_size
+ mmap_size
> size
)
341 (void *) (grub_size_t
) ((addr
+ size
) - (real_size
+ mmap_size
));
347 grub_mmap_iterate (hook
);
350 grub_error (GRUB_ERR_OUT_OF_MEMORY
, "cannot allocate real mode pages");
354 prot_mode_mem
= (void *) 0x100000;
356 grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, "
357 "prot_mode_mem = %lx, prot_mode_pages = %x\n",
358 (unsigned long) real_mode_mem
, (unsigned) real_mode_pages
,
359 (unsigned long) prot_mode_mem
, (unsigned) prot_mode_pages
);
369 grub_e820_add_region (struct grub_e820_mmap
*e820_map
, int *e820_num
,
370 grub_uint64_t start
, grub_uint64_t size
,
375 if (n
>= GRUB_E820_MAX_ENTRY
)
376 grub_fatal ("Too many e820 memory map entries");
378 if ((n
> 0) && (e820_map
[n
- 1].addr
+ e820_map
[n
- 1].size
== start
) &&
379 (e820_map
[n
- 1].type
== type
))
380 e820_map
[n
- 1].size
+= size
;
383 e820_map
[n
].addr
= start
;
384 e820_map
[n
].size
= size
;
385 e820_map
[n
].type
= type
;
391 grub_linux_setup_video (struct linux_kernel_params
*params
)
393 struct grub_video_mode_info mode_info
;
397 ret
= grub_video_get_info_and_fini (&mode_info
, &framebuffer
);
402 params
->lfb_width
= mode_info
.width
;
403 params
->lfb_height
= mode_info
.height
;
404 params
->lfb_depth
= mode_info
.bpp
;
405 params
->lfb_line_len
= mode_info
.pitch
;
407 params
->lfb_base
= (grub_size_t
) framebuffer
;
408 params
->lfb_size
= (params
->lfb_line_len
* params
->lfb_height
+ 65535) >> 16;
410 params
->red_mask_size
= mode_info
.red_mask_size
;
411 params
->red_field_pos
= mode_info
.red_field_pos
;
412 params
->green_mask_size
= mode_info
.green_mask_size
;
413 params
->green_field_pos
= mode_info
.green_field_pos
;
414 params
->blue_mask_size
= mode_info
.blue_mask_size
;
415 params
->blue_field_pos
= mode_info
.blue_field_pos
;
416 params
->reserved_mask_size
= mode_info
.reserved_mask_size
;
417 params
->reserved_field_pos
= mode_info
.reserved_field_pos
;
423 extern grub_uint8_t grub_linux_trampoline_start
[];
424 extern grub_uint8_t grub_linux_trampoline_end
[];
428 grub_linux_boot (void)
430 struct linux_kernel_params
*params
;
435 params
= real_mode_mem
;
437 grub_dprintf ("linux", "code32_start = %x, idt_desc = %lx, gdt_desc = %lx\n",
438 (unsigned) params
->code32_start
,
439 (unsigned long) &(idt_desc
.limit
),
440 (unsigned long) &(gdt_desc
.limit
));
441 grub_dprintf ("linux", "idt = %x:%lx, gdt = %x:%lx\n",
442 (unsigned) idt_desc
.limit
, (unsigned long) idt_desc
.base
,
443 (unsigned) gdt_desc
.limit
, (unsigned long) gdt_desc
.base
);
445 auto int NESTED_FUNC_ATTR
hook (grub_uint64_t
, grub_uint64_t
, grub_uint32_t
);
446 int NESTED_FUNC_ATTR
hook (grub_uint64_t addr
, grub_uint64_t size
, grub_uint32_t type
)
450 case GRUB_MACHINE_MEMORY_AVAILABLE
:
451 grub_e820_add_region (params
->e820_map
, &e820_num
,
452 addr
, size
, GRUB_E820_RAM
);
455 #ifdef GRUB_MACHINE_MEMORY_ACPI
456 case GRUB_MACHINE_MEMORY_ACPI
:
457 grub_e820_add_region (params
->e820_map
, &e820_num
,
458 addr
, size
, GRUB_E820_ACPI
);
462 #ifdef GRUB_MACHINE_MEMORY_NVS
463 case GRUB_MACHINE_MEMORY_NVS
:
464 grub_e820_add_region (params
->e820_map
, &e820_num
,
465 addr
, size
, GRUB_E820_NVS
);
469 #ifdef GRUB_MACHINE_MEMORY_CODE
470 case GRUB_MACHINE_MEMORY_CODE
:
471 grub_e820_add_region (params
->e820_map
, &e820_num
,
472 addr
, size
, GRUB_E820_EXEC_CODE
);
477 grub_e820_add_region (params
->e820_map
, &e820_num
,
478 addr
, size
, GRUB_E820_RESERVED
);
484 grub_mmap_iterate (hook
);
485 params
->mmap_size
= e820_num
;
487 modevar
= grub_env_get ("gfxpayload");
489 /* Now all graphical modes are acceptable.
490 May change in future if we have modes without framebuffer. */
491 if (modevar
&& *modevar
!= 0)
493 tmp
= grub_malloc (grub_strlen (modevar
)
497 grub_sprintf (tmp
, "%s;text", modevar
);
498 err
= grub_video_set_mode (tmp
, 0);
502 err
= grub_video_set_mode ("text", 0);
507 grub_printf ("Booting however\n");
508 grub_errno
= GRUB_ERR_NONE
;
511 if (! grub_linux_setup_video (params
))
512 params
->have_vga
= GRUB_VIDEO_TYPE_VLFB
;
515 params
->have_vga
= GRUB_VIDEO_TYPE_TEXT
;
516 params
->video_width
= 80;
517 params
->video_height
= 25;
520 /* Initialize these last, because terminal position could be affected by printfs above. */
521 if (params
->have_vga
== GRUB_VIDEO_TYPE_TEXT
)
523 params
->video_cursor_x
= grub_getxy () >> 8;
524 params
->video_cursor_y
= grub_getxy () & 0xff;
529 grub_memcpy ((char *) prot_mode_mem
+ (prot_mode_pages
<< 12),
530 grub_linux_trampoline_start
,
531 grub_linux_trampoline_end
- grub_linux_trampoline_start
);
533 ((void (*) (unsigned long, void *)) ((char *) prot_mode_mem
534 + (prot_mode_pages
<< 12)))
535 (params
->code32_start
, real_mode_mem
);
538 /* Hardware interrupts are not safe any longer. */
539 asm volatile ("cli" : : );
541 /* Load the IDT and the GDT for the bootstrap. */
542 asm volatile ("lidt %0" : : "m" (idt_desc
));
543 asm volatile ("lgdt %0" : : "m" (gdt_desc
));
546 asm volatile ("jmp *%2" : : "b" (0), "S" (real_mode_mem
), "g" (params
->code32_start
));
550 /* Never reach here. */
551 return GRUB_ERR_NONE
;
555 grub_linux_unload (void)
557 grub_dl_unref (my_mod
);
559 return GRUB_ERR_NONE
;
563 grub_cmd_linux (grub_command_t cmd
__attribute__ ((unused
)),
564 int argc
, char *argv
[])
566 grub_file_t file
= 0;
567 struct linux_kernel_header lh
;
568 struct linux_kernel_params
*params
;
569 grub_uint8_t setup_sects
;
570 grub_size_t real_size
, prot_size
;
575 grub_dl_ref (my_mod
);
579 grub_error (GRUB_ERR_BAD_ARGUMENT
, "no kernel specified");
583 file
= grub_file_open (argv
[0]);
587 if (grub_file_read (file
, &lh
, sizeof (lh
)) != sizeof (lh
))
589 grub_error (GRUB_ERR_READ_ERROR
, "cannot read the linux header");
593 if (lh
.boot_flag
!= grub_cpu_to_le16 (0xaa55))
595 grub_error (GRUB_ERR_BAD_OS
, "invalid magic number");
599 if (lh
.setup_sects
> GRUB_LINUX_MAX_SETUP_SECTS
)
601 grub_error (GRUB_ERR_BAD_OS
, "too many setup sectors");
605 if (! (lh
.loadflags
& GRUB_LINUX_FLAG_BIG_KERNEL
))
607 grub_error (GRUB_ERR_BAD_OS
, "zImage doesn't support 32-bit boot"
608 #ifdef GRUB_MACHINE_PCBIOS
609 " (try with `linux16')"
615 /* FIXME: 2.03 is not always good enough (Linux 2.4 can be 2.03 and
616 still not support 32-bit boot. */
617 if (lh
.header
!= grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE
)
618 || grub_le_to_cpu16 (lh
.version
) < 0x0203)
620 grub_error (GRUB_ERR_BAD_OS
, "version too old for 32-bit boot"
621 #ifdef GRUB_MACHINE_PCBIOS
622 " (try with `linux16')"
628 setup_sects
= lh
.setup_sects
;
630 /* If SETUP_SECTS is not set, set it to the default (4). */
632 setup_sects
= GRUB_LINUX_DEFAULT_SETUP_SECTS
;
634 real_size
= setup_sects
<< GRUB_DISK_SECTOR_BITS
;
635 prot_size
= grub_file_size (file
) - real_size
- GRUB_DISK_SECTOR_SIZE
;
637 if (! allocate_pages (prot_size
))
640 params
= (struct linux_kernel_params
*) real_mode_mem
;
641 grub_memset (params
, 0, GRUB_LINUX_CL_END_OFFSET
);
642 grub_memcpy (¶ms
->setup_sects
, &lh
.setup_sects
, sizeof (lh
) - 0x1F1);
644 params
->ps_mouse
= params
->padding10
= 0;
646 len
= 0x400 - sizeof (lh
);
647 if (grub_file_read (file
, (char *) real_mode_mem
+ sizeof (lh
), len
) != len
)
649 grub_error (GRUB_ERR_FILE_READ_ERROR
, "Couldn't read file");
653 params
->type_of_loader
= (LINUX_LOADER_ID_GRUB
<< 4);
655 /* These two are used (instead of cmd_line_ptr) by older versions of Linux,
656 and otherwise ignored. */
657 params
->cl_magic
= GRUB_LINUX_CL_MAGIC
;
658 params
->cl_offset
= 0x1000;
660 params
->cmd_line_ptr
= (unsigned long) real_mode_mem
+ 0x1000;
661 params
->ramdisk_image
= 0;
662 params
->ramdisk_size
= 0;
664 params
->heap_end_ptr
= GRUB_LINUX_HEAP_END_OFFSET
;
665 params
->loadflags
|= GRUB_LINUX_FLAG_CAN_USE_HEAP
;
667 /* These are not needed to be precise, because Linux uses these values
668 only to raise an error when the decompression code cannot find good
670 params
->ext_mem
= ((32 * 0x100000) >> 10);
671 params
->alt_mem
= ((32 * 0x100000) >> 10);
673 /* Ignored by Linux. */
674 params
->video_page
= 0;
676 /* Must be non-zero even in text mode, or Linux will think there's no VGA. */
677 params
->video_mode
= 0x3;
679 /* Only used when `video_mode == 0x7', otherwise ignored. */
680 params
->video_ega_bx
= 0;
682 params
->font_size
= 16; /* XXX */
684 /* The other parameters are filled when booting. */
686 grub_file_seek (file
, real_size
+ GRUB_DISK_SECTOR_SIZE
);
688 grub_printf (" [Linux-bzImage, setup=0x%x, size=0x%x]\n",
689 (unsigned) real_size
, (unsigned) prot_size
);
691 /* Look for memory size and video mode specified on the command line. */
693 for (i
= 1; i
< argc
; i
++)
694 #ifdef GRUB_MACHINE_PCBIOS
695 if (grub_memcmp (argv
[i
], "vga=", 4) == 0)
697 /* Video mode selection support. */
698 char *val
= argv
[i
] + 4;
699 unsigned vid_mode
= GRUB_LINUX_VID_MODE_NORMAL
;
700 struct linux_vesafb_mode
*linux_mode
;
704 if (grub_strcmp (val
, "normal") == 0)
705 vid_mode
= GRUB_LINUX_VID_MODE_NORMAL
;
706 else if (grub_strcmp (val
, "ext") == 0)
707 vid_mode
= GRUB_LINUX_VID_MODE_EXTENDED
;
708 else if (grub_strcmp (val
, "ask") == 0)
710 grub_printf ("Legacy `ask' parameter no longer supported.\n");
712 /* We usually would never do this in a loader, but "vga=ask" means user
713 requested interaction, so it can't hurt to request keyboard input. */
714 grub_wait_after_message ();
719 vid_mode
= (grub_uint16_t
) grub_strtoul (val
, 0, 0);
724 case GRUB_LINUX_VID_MODE_NORMAL
:
725 grub_env_set ("gfxpayload", "text");
726 grub_printf ("%s is deprecated. "
727 "Use set gfxpayload=text before "
728 "linux command instead.\n",
733 case GRUB_LINUX_VID_MODE_EXTENDED
:
734 /* FIXME: support 80x50 text. */
735 grub_env_set ("gfxpayload", "text");
736 grub_printf ("%s is deprecated. "
737 "Use set gfxpayload=text before "
738 "linux command instead.\n",
742 /* Ignore invalid values. */
743 if (vid_mode
< GRUB_LINUX_VID_MODE_VESA_START
||
744 vid_mode
>= GRUB_LINUX_VID_MODE_VESA_START
+
745 ARRAY_SIZE (linux_vesafb_modes
))
747 grub_env_set ("gfxpayload", "text");
748 grub_printf ("%s is deprecated. Mode %d isn't recognized. "
749 "Use set gfxpayload=WIDTHxHEIGHT[xDEPTH] before "
750 "linux command instead.\n",
755 buf
= grub_malloc (sizeof ("WWWWxHHHHxDD;WWWWxHHHH"));
760 = &linux_vesafb_modes
[vid_mode
- GRUB_LINUX_VID_MODE_VESA_START
];
762 grub_sprintf (buf
, "%ux%ux%u,%ux%u",
763 linux_vesafb_res
[linux_mode
->res_index
].width
,
764 linux_vesafb_res
[linux_mode
->res_index
].height
,
766 linux_vesafb_res
[linux_mode
->res_index
].width
,
767 linux_vesafb_res
[linux_mode
->res_index
].height
);
768 grub_printf ("%s is deprecated. "
769 "Use set gfxpayload=%s before "
770 "linux command instead.\n",
772 err
= grub_env_set ("gfxpayload", buf
);
779 #endif /* GRUB_MACHINE_PCBIOS */
780 if (grub_memcmp (argv
[i
], "mem=", 4) == 0)
782 char *val
= argv
[i
] + 4;
784 linux_mem_size
= grub_strtoul (val
, &val
, 0);
788 grub_errno
= GRUB_ERR_NONE
;
795 switch (grub_tolower (val
[0]))
807 /* Check an overflow. */
808 if (linux_mem_size
> (~0UL >> shift
))
811 linux_mem_size
<<= shift
;
814 else if (grub_memcmp (argv
[i
], "quiet", sizeof ("quiet") - 1) == 0)
816 params
->loadflags
|= GRUB_LINUX_FLAG_QUIET
;
820 /* Specify the boot file. */
821 dest
= grub_stpcpy ((char *) real_mode_mem
+ GRUB_LINUX_CL_OFFSET
,
823 dest
= grub_stpcpy (dest
, argv
[0]);
825 /* Copy kernel parameters. */
828 && dest
+ grub_strlen (argv
[i
]) + 1 < ((char *) real_mode_mem
829 + GRUB_LINUX_CL_END_OFFSET
);
833 dest
= grub_stpcpy (dest
, argv
[i
]);
837 if (grub_file_read (file
, (void *) GRUB_LINUX_BZIMAGE_ADDR
, len
) != len
)
838 grub_error (GRUB_ERR_FILE_READ_ERROR
, "Couldn't read file");
840 if (grub_errno
== GRUB_ERR_NONE
)
842 grub_loader_set (grub_linux_boot
, grub_linux_unload
,
843 0 /* set noreturn=0 in order to avoid grub_console_fini() */);
850 grub_file_close (file
);
852 if (grub_errno
!= GRUB_ERR_NONE
)
854 grub_dl_unref (my_mod
);
862 grub_cmd_initrd (grub_command_t cmd
__attribute__ ((unused
)),
863 int argc
, char *argv
[])
865 grub_file_t file
= 0;
867 grub_addr_t addr_min
, addr_max
;
869 struct linux_kernel_header
*lh
;
873 grub_error (GRUB_ERR_BAD_ARGUMENT
, "No module specified");
879 grub_error (GRUB_ERR_BAD_ARGUMENT
, "You need to load the kernel first.");
883 file
= grub_file_open (argv
[0]);
887 size
= grub_file_size (file
);
888 initrd_pages
= (page_align (size
) >> 12);
890 lh
= (struct linux_kernel_header
*) real_mode_mem
;
892 /* Get the highest address available for the initrd. */
893 if (grub_le_to_cpu16 (lh
->version
) >= 0x0203)
895 addr_max
= grub_cpu_to_le32 (lh
->initrd_addr_max
);
897 /* XXX in reality, Linux specifies a bogus value, so
898 it is necessary to make sure that ADDR_MAX does not exceed
900 if (addr_max
> GRUB_LINUX_INITRD_MAX_ADDRESS
)
901 addr_max
= GRUB_LINUX_INITRD_MAX_ADDRESS
;
904 addr_max
= GRUB_LINUX_INITRD_MAX_ADDRESS
;
906 if (linux_mem_size
!= 0 && linux_mem_size
< addr_max
)
907 addr_max
= linux_mem_size
;
909 /* Linux 2.3.xx has a bug in the memory range check, so avoid
911 Linux 2.2.xx has a bug in the memory range check, which is
912 worse than that of Linux 2.3.xx, so avoid the last 64kb. */
915 /* Usually, the compression ratio is about 50%. */
916 addr_min
= (grub_addr_t
) prot_mode_mem
+ ((prot_mode_pages
* 3) << 12)
919 if (addr_max
> grub_os_area_addr
+ grub_os_area_size
)
920 addr_max
= grub_os_area_addr
+ grub_os_area_size
;
922 /* Put the initrd as high as possible, 4KiB aligned. */
923 addr
= (addr_max
- size
) & ~0xFFF;
927 grub_error (GRUB_ERR_OUT_OF_RANGE
, "The initrd is too big");
931 initrd_mem
= (void *) addr
;
933 if (grub_file_read (file
, initrd_mem
, size
) != size
)
935 grub_error (GRUB_ERR_FILE_READ_ERROR
, "Couldn't read file");
939 grub_printf (" [Initrd, addr=0x%x, size=0x%x]\n",
940 (unsigned) addr
, (unsigned) size
);
942 lh
->ramdisk_image
= addr
;
943 lh
->ramdisk_size
= size
;
944 lh
->root_dev
= 0x0100; /* XXX */
948 grub_file_close (file
);
953 static grub_command_t cmd_linux
, cmd_initrd
;
957 cmd_linux
= grub_register_command ("linux", grub_cmd_linux
,
959 cmd_initrd
= grub_register_command ("initrd", grub_cmd_initrd
,
966 grub_unregister_command (cmd_linux
);
967 grub_unregister_command (cmd_initrd
);