1 /* multiboot.c - boot a multiboot OS image. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
21 * FIXME: The following features from the Multiboot specification still
22 * need to be implemented:
24 * - ROM configuration table
26 * - Networking information
29 #include <grub/loader.h>
30 #include <grub/command.h>
31 #include <grub/multiboot.h>
32 #include <grub/cpu/multiboot.h>
34 #include <grub/aout.h>
35 #include <grub/file.h>
39 #include <grub/misc.h>
41 #include <grub/cpu/relocator.h>
42 #include <grub/video.h>
43 #include <grub/memory.h>
44 #include <grub/i18n.h>
46 GRUB_MOD_LICENSE ("GPLv3+");
48 #ifdef GRUB_MACHINE_EFI
49 #include <grub/efi/efi.h>
52 struct grub_relocator
*grub_multiboot_relocator
= NULL
;
53 grub_uint32_t grub_multiboot_payload_eip
;
54 #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
55 #define DEFAULT_VIDEO_MODE "text"
57 #define DEFAULT_VIDEO_MODE "auto"
60 static int accepts_video
;
61 static int accepts_ega_text
;
62 static int console_required
;
63 static grub_dl_t my_mod
;
66 /* Helper for grub_get_multiboot_mmap_count. */
68 count_hook (grub_uint64_t addr
__attribute__ ((unused
)),
69 grub_uint64_t size
__attribute__ ((unused
)),
70 grub_memory_type_t type
__attribute__ ((unused
)), void *data
)
72 grub_size_t
*count
= data
;
78 /* Return the length of the Multiboot mmap that will be needed to allocate
79 our platform's map. */
81 grub_get_multiboot_mmap_count (void)
83 grub_size_t count
= 0;
85 grub_mmap_iterate (count_hook
, &count
);
91 grub_multiboot_set_video_mode (void)
96 #if GRUB_MACHINE_HAS_VGA_TEXT
100 modevar
= grub_env_get ("gfxpayload");
101 if (! modevar
|| *modevar
== 0)
102 err
= grub_video_set_mode (DEFAULT_VIDEO_MODE
, 0, 0);
106 tmp
= grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE
, modevar
);
109 err
= grub_video_set_mode (tmp
, 0, 0);
113 #if GRUB_MACHINE_HAS_VGA_TEXT
115 err
= grub_video_set_mode ("text", 0, 0);
122 grub_multiboot_boot (void)
125 struct grub_relocator32_state state
= MULTIBOOT_INITIAL_STATE
;
127 state
.MULTIBOOT_ENTRY_REGISTER
= grub_multiboot_payload_eip
;
129 err
= grub_multiboot_make_mbi (&state
.MULTIBOOT_MBI_REGISTER
);
134 #if defined (__i386__) || defined (__x86_64__)
135 grub_relocator32_boot (grub_multiboot_relocator
, state
, 0);
137 grub_relocator32_boot (grub_multiboot_relocator
, state
);
141 return GRUB_ERR_NONE
;
145 grub_multiboot_unload (void)
147 grub_multiboot_free_mbi ();
149 grub_relocator_unload (grub_multiboot_relocator
);
150 grub_multiboot_relocator
= NULL
;
152 grub_dl_unref (my_mod
);
154 return GRUB_ERR_NONE
;
157 static grub_uint64_t highest_load
;
159 #define MULTIBOOT_LOAD_ELF64
160 #include "multiboot_elfxx.c"
161 #undef MULTIBOOT_LOAD_ELF64
163 #define MULTIBOOT_LOAD_ELF32
164 #include "multiboot_elfxx.c"
165 #undef MULTIBOOT_LOAD_ELF32
167 /* Load ELF32 or ELF64. */
169 grub_multiboot_load_elf (grub_file_t file
, const char *filename
,
172 if (grub_multiboot_is_elf32 (buffer
))
173 return grub_multiboot_load_elf32 (file
, filename
, buffer
);
174 else if (grub_multiboot_is_elf64 (buffer
))
175 return grub_multiboot_load_elf64 (file
, filename
, buffer
);
177 return grub_error (GRUB_ERR_UNKNOWN_OS
, N_("invalid arch-dependent ELF magic"));
181 grub_multiboot_set_console (int console_type
, int accepted_consoles
,
182 int width
, int height
, int depth
,
185 console_required
= console_req
;
186 if (!(accepted_consoles
187 & (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER
188 | (GRUB_MACHINE_HAS_VGA_TEXT
? GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
: 0))))
190 if (console_required
)
191 return grub_error (GRUB_ERR_BAD_OS
,
192 "OS requires a console but none is available");
193 grub_puts_ (N_("WARNING: no console will be available to OS"));
195 accepts_ega_text
= 0;
196 return GRUB_ERR_NONE
;
199 if (console_type
== GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER
)
202 if (depth
&& width
&& height
)
203 buf
= grub_xasprintf ("%dx%dx%d,%dx%d,auto", width
,
204 height
, depth
, width
, height
);
205 else if (width
&& height
)
206 buf
= grub_xasprintf ("%dx%d,auto", width
, height
);
208 buf
= grub_strdup ("auto");
212 grub_env_set ("gfxpayload", buf
);
217 #if GRUB_MACHINE_HAS_VGA_TEXT
218 grub_env_set ("gfxpayload", "text");
220 /* Always use video if no VGA text is available. */
221 grub_env_set ("gfxpayload", "auto");
225 accepts_video
= !!(accepted_consoles
& GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER
);
226 accepts_ega_text
= !!(accepted_consoles
& GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
);
227 return GRUB_ERR_NONE
;
231 grub_cmd_multiboot (grub_command_t cmd
__attribute__ ((unused
)),
232 int argc
, char *argv
[])
234 grub_file_t file
= 0;
237 grub_loader_unset ();
241 #ifndef GRUB_USE_MULTIBOOT2
242 grub_multiboot_quirks
= GRUB_MULTIBOOT_QUIRKS_NONE
;
244 if (argc
!= 0 && grub_strcmp (argv
[0], "--quirk-bad-kludge") == 0)
248 grub_multiboot_quirks
|= GRUB_MULTIBOOT_QUIRK_BAD_KLUDGE
;
251 if (argc
!= 0 && grub_strcmp (argv
[0], "--quirk-modules-after-kernel") == 0)
255 grub_multiboot_quirks
|= GRUB_MULTIBOOT_QUIRK_MODULES_AFTER_KERNEL
;
260 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("filename expected"));
262 file
= grub_file_open (argv
[0]);
266 grub_dl_ref (my_mod
);
269 grub_multiboot_init_mbi (argc
- 1, argv
+ 1);
271 grub_relocator_unload (grub_multiboot_relocator
);
272 grub_multiboot_relocator
= grub_relocator_new ();
274 if (!grub_multiboot_relocator
)
277 err
= grub_multiboot_load (file
, argv
[0]);
281 grub_multiboot_set_bootdev ();
283 grub_loader_set (grub_multiboot_boot
, grub_multiboot_unload
, 0);
287 grub_file_close (file
);
289 if (grub_errno
!= GRUB_ERR_NONE
)
291 grub_relocator_unload (grub_multiboot_relocator
);
292 grub_multiboot_relocator
= NULL
;
293 grub_dl_unref (my_mod
);
300 grub_cmd_module (grub_command_t cmd
__attribute__ ((unused
)),
301 int argc
, char *argv
[])
303 grub_file_t file
= 0;
309 grub_uint64_t lowest_addr
= 0;
312 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("filename expected"));
314 if (grub_strcmp (argv
[0], "--nounzip") == 0)
322 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("filename expected"));
324 if (!grub_multiboot_relocator
)
325 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
326 N_("you need to load the kernel first"));
329 grub_file_filter_disable_compression ();
331 file
= grub_file_open (argv
[0]);
335 #ifndef GRUB_USE_MULTIBOOT2
336 if (grub_multiboot_quirks
& GRUB_MULTIBOOT_QUIRK_MODULES_AFTER_KERNEL
)
337 lowest_addr
= ALIGN_UP (highest_load
+ 1048576, 4096);
340 size
= grub_file_size (file
);
343 grub_relocator_chunk_t ch
;
344 err
= grub_relocator_alloc_chunk_align (grub_multiboot_relocator
, &ch
,
345 lowest_addr
, (0xffffffff - size
) + 1,
346 size
, MULTIBOOT_MOD_ALIGN
,
347 GRUB_RELOCATOR_PREFERENCE_NONE
, 1);
350 grub_file_close (file
);
353 module
= get_virtual_current_address (ch
);
354 target
= get_physical_target_address (ch
);
362 err
= grub_multiboot_add_module (target
, size
, argc
- 1, argv
+ 1);
365 grub_file_close (file
);
369 if (size
&& grub_file_read (file
, module
, size
) != size
)
371 grub_file_close (file
);
373 grub_error (GRUB_ERR_FILE_READ_ERROR
, N_("premature end of file %s"),
378 grub_file_close (file
);
379 return GRUB_ERR_NONE
;
382 static grub_command_t cmd_multiboot
, cmd_module
;
384 GRUB_MOD_INIT(multiboot
)
387 #ifdef GRUB_USE_MULTIBOOT2
388 grub_register_command ("multiboot2", grub_cmd_multiboot
,
389 0, N_("Load a multiboot 2 kernel."));
391 grub_register_command ("module2", grub_cmd_module
,
392 0, N_("Load a multiboot 2 module."));
394 grub_register_command ("multiboot", grub_cmd_multiboot
,
395 0, N_("Load a multiboot kernel."));
397 grub_register_command ("module", grub_cmd_module
,
398 0, N_("Load a multiboot module."));
404 GRUB_MOD_FINI(multiboot
)
406 grub_unregister_command (cmd_multiboot
);
407 grub_unregister_command (cmd_module
);