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 /* Return the length of the Multiboot mmap that will be needed to allocate
67 our platform's map. */
69 grub_get_multiboot_mmap_count (void)
71 grub_size_t count
= 0;
73 auto int NESTED_FUNC_ATTR
hook (grub_uint64_t
, grub_uint64_t
, grub_uint32_t
);
74 int NESTED_FUNC_ATTR
hook (grub_uint64_t addr
__attribute__ ((unused
)),
75 grub_uint64_t size
__attribute__ ((unused
)),
76 grub_memory_type_t type
__attribute__ ((unused
)))
82 grub_mmap_iterate (hook
);
88 grub_multiboot_set_video_mode (void)
93 #if GRUB_MACHINE_HAS_VGA_TEXT
97 modevar
= grub_env_get ("gfxpayload");
98 if (! modevar
|| *modevar
== 0)
99 err
= grub_video_set_mode (DEFAULT_VIDEO_MODE
, 0, 0);
103 tmp
= grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE
, modevar
);
106 err
= grub_video_set_mode (tmp
, 0, 0);
110 #if GRUB_MACHINE_HAS_VGA_TEXT
112 err
= grub_video_set_mode ("text", 0, 0);
119 grub_multiboot_boot (void)
122 struct grub_relocator32_state state
= MULTIBOOT_INITIAL_STATE
;
124 state
.MULTIBOOT_ENTRY_REGISTER
= grub_multiboot_payload_eip
;
126 err
= grub_multiboot_make_mbi (&state
.MULTIBOOT_MBI_REGISTER
);
131 #ifdef GRUB_MACHINE_EFI
132 err
= grub_efi_finish_boot_services (NULL
, NULL
, NULL
, NULL
, NULL
);
137 #if defined (__i386__) || defined (__x86_64__)
138 grub_relocator32_boot (grub_multiboot_relocator
, state
, 0);
140 grub_relocator32_boot (grub_multiboot_relocator
, state
);
144 return GRUB_ERR_NONE
;
148 grub_multiboot_unload (void)
150 grub_multiboot_free_mbi ();
152 grub_relocator_unload (grub_multiboot_relocator
);
153 grub_multiboot_relocator
= NULL
;
155 grub_dl_unref (my_mod
);
157 return GRUB_ERR_NONE
;
160 #define MULTIBOOT_LOAD_ELF64
161 #include "multiboot_elfxx.c"
162 #undef MULTIBOOT_LOAD_ELF64
164 #define MULTIBOOT_LOAD_ELF32
165 #include "multiboot_elfxx.c"
166 #undef MULTIBOOT_LOAD_ELF32
168 /* Load ELF32 or ELF64. */
170 grub_multiboot_load_elf (grub_file_t file
, const char *filename
,
173 if (grub_multiboot_is_elf32 (buffer
))
174 return grub_multiboot_load_elf32 (file
, filename
, buffer
);
175 else if (grub_multiboot_is_elf64 (buffer
))
176 return grub_multiboot_load_elf64 (file
, filename
, buffer
);
178 return grub_error (GRUB_ERR_UNKNOWN_OS
, N_("invalid arch-dependent ELF magic"));
182 grub_multiboot_set_console (int console_type
, int accepted_consoles
,
183 int width
, int height
, int depth
,
186 console_required
= console_req
;
187 if (!(accepted_consoles
188 & (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER
189 | (GRUB_MACHINE_HAS_VGA_TEXT
? GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
: 0))))
191 if (console_required
)
192 return grub_error (GRUB_ERR_BAD_OS
,
193 "OS requires a console but none is available");
194 grub_puts_ (N_("WARNING: no console will be available to OS"));
196 accepts_ega_text
= 0;
197 return GRUB_ERR_NONE
;
200 if (console_type
== GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER
)
203 if (depth
&& width
&& height
)
204 buf
= grub_xasprintf ("%dx%dx%d,%dx%d,auto", width
,
205 height
, depth
, width
, height
);
206 else if (width
&& height
)
207 buf
= grub_xasprintf ("%dx%d,auto", width
, height
);
209 buf
= grub_strdup ("auto");
213 grub_env_set ("gfxpayload", buf
);
220 * Our kernel (secondary level bootstrap) supports both framebuffer and text.
221 * Its preferred mode is text (otherwise we will always run in VESA mode and
222 * will not be able to use VGA one.
223 * Intelmac (being a EFI machine) is considered to have no text mode at all
224 * (GRUB_MACHINE_HAS_VGA_TEXT == 0). Setting "text" here seems to actually
225 * leave GRUB in graphics mode whatever it is, but trick it into thinking that
226 * it's a real text mode (video.c line 561 is reached, grub_set_video_mode("text; auto", 0, 0)
227 * is called). As a result no framebuffer information is provided to the kernel
228 * (grub_video_get_driver_id() returns GRUB_VIDEO_DRIVER_NONE, actually leaving
229 * it with no display.
230 * An alternative is to teach GRUB to really switch EFI to text mode using
231 * grub_efi_set_text_mode(1) in such a case.
232 * Plain "auto" would be more logical here, but it does not work on my Mac.
233 * Perhaps GOP driver does not accept width == height == 0 as a signal to
234 * auto-select best available mode. I have to set some resolution manually,
235 * and the driver selects best match (1280x1024, which is the only available
236 * mode on my machine). I choose to set "640x200" here as graphical representation
237 * of 80x25 VGA text mode.
239 #if GRUB_MACHINE_HAS_VGA_TEXT
240 grub_env_set ("gfxpayload", "text");
242 grub_env_set ("gfxpayload", "640x200,auto");
245 accepts_video
= !!(accepted_consoles
& GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER
);
246 accepts_ega_text
= !!(accepted_consoles
& GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
);
247 return GRUB_ERR_NONE
;
251 grub_cmd_multiboot (grub_command_t cmd
__attribute__ ((unused
)),
252 int argc
, char *argv
[])
254 grub_file_t file
= 0;
257 grub_loader_unset ();
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;
311 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("filename expected"));
313 if (grub_strcmp (argv
[0], "--nounzip") == 0)
321 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("filename expected"));
323 if (!grub_multiboot_relocator
)
324 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
325 N_("you need to load the kernel first"));
328 grub_file_filter_disable_compression ();
330 file
= grub_file_open (argv
[0]);
334 size
= grub_file_size (file
);
336 grub_relocator_chunk_t ch
;
337 err
= grub_relocator_alloc_chunk_align (grub_multiboot_relocator
, &ch
,
338 0, (0xffffffff - size
) + 1,
339 size
, MULTIBOOT_MOD_ALIGN
,
340 GRUB_RELOCATOR_PREFERENCE_NONE
, 0);
343 grub_file_close (file
);
346 module
= get_virtual_current_address (ch
);
347 target
= get_physical_target_address (ch
);
350 err
= grub_multiboot_add_module (target
, size
, argc
- 1, argv
+ 1);
353 grub_file_close (file
);
357 if (grub_file_read (file
, module
, size
) != size
)
359 grub_file_close (file
);
361 grub_error (GRUB_ERR_FILE_READ_ERROR
, N_("premature end of file %s"),
366 grub_file_close (file
);
367 return GRUB_ERR_NONE
;;
370 static grub_command_t cmd_multiboot
, cmd_module
;
372 GRUB_MOD_INIT(multiboot
)
375 #ifdef GRUB_USE_MULTIBOOT2
376 grub_register_command ("multiboot2", grub_cmd_multiboot
,
377 0, N_("Load a multiboot 2 kernel."));
379 grub_register_command ("module2", grub_cmd_module
,
380 0, N_("Load a multiboot 2 module."));
382 grub_register_command ("multiboot", grub_cmd_multiboot
,
383 0, N_("Load a multiboot kernel."));
385 grub_register_command ("module", grub_cmd_module
,
386 0, N_("Load a multiboot module."));
392 GRUB_MOD_FINI(multiboot
)
394 grub_unregister_command (cmd_multiboot
);
395 grub_unregister_command (cmd_module
);