]> git.proxmox.com Git - grub2.git/blame - grub-core/loader/multiboot.c
bump version to 2.06-13+pmx2
[grub2.git] / grub-core / loader / multiboot.c
CommitLineData
9a5c1ade 1/* multiboot.c - boot a multiboot OS image. */
2/*
4b13b216 3 * GRUB -- GRand Unified Bootloader
0a46429a 4 * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc.
9a5c1ade 5 *
5a79f472 6 * GRUB is free software: you can redistribute it and/or modify
9a5c1ade 7 * it under the terms of the GNU General Public License as published by
5a79f472 8 * the Free Software Foundation, either version 3 of the License, or
9a5c1ade 9 * (at your option) any later version.
10 *
5a79f472 11 * GRUB is distributed in the hope that it will be useful,
9a5c1ade 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.
15 *
16 * You should have received a copy of the GNU General Public License
5a79f472 17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
9a5c1ade 18 */
19
d38e24c2 20/*
9a5c1ade 21 * FIXME: The following features from the Multiboot specification still
22 * need to be implemented:
9a5c1ade 23 * - drives table
24 * - ROM configuration table
4519e259
VS
25 * - SMBIOS tables
26 * - Networking information
9a5c1ade 27 */
28
4b13b216 29#include <grub/loader.h>
b1f6f35a 30#include <grub/command.h>
21e4a6fa
VS
31#ifdef GRUB_USE_MULTIBOOT2
32#include <grub/multiboot2.h>
33#define GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER GRUB_MULTIBOOT2_CONSOLE_FRAMEBUFFER
34#define GRUB_MULTIBOOT_CONSOLE_EGA_TEXT GRUB_MULTIBOOT2_CONSOLE_EGA_TEXT
35#define GRUB_MULTIBOOT(x) grub_multiboot2_ ## x
36#else
e5dfe777 37#include <grub/multiboot.h>
21e4a6fa
VS
38#define GRUB_MULTIBOOT(x) grub_multiboot_ ## x
39#endif
c04d6e05 40#include <grub/cpu/multiboot.h>
4b13b216 41#include <grub/elf.h>
d38e24c2 42#include <grub/aout.h>
4b13b216 43#include <grub/file.h>
44#include <grub/err.h>
4b13b216 45#include <grub/dl.h>
46#include <grub/mm.h>
47#include <grub/misc.h>
38ad2cf5 48#include <grub/env.h>
8c46a785 49#include <grub/cpu/relocator.h>
0a46429a 50#include <grub/video.h>
5408044f 51#include <grub/memory.h>
b1f6f35a 52#include <grub/i18n.h>
4b13b216 53
e745cf0c
VS
54GRUB_MOD_LICENSE ("GPLv3+");
55
a0b766fc
VS
56#ifdef GRUB_MACHINE_EFI
57#include <grub/efi/efi.h>
58#endif
4b13b216 59
21e4a6fa
VS
60struct grub_relocator *GRUB_MULTIBOOT (relocator) = NULL;
61grub_uint32_t GRUB_MULTIBOOT (payload_eip);
7210dca9 62#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
5408044f
VS
63#define DEFAULT_VIDEO_MODE "text"
64#else
65#define DEFAULT_VIDEO_MODE "auto"
66#endif
67
5408044f 68static int accepts_video;
c3a8dfc8
VS
69static int accepts_ega_text;
70static int console_required;
b1f6f35a
VS
71static grub_dl_t my_mod;
72
5408044f 73
d0d4b8a0
CW
74/* Helper for grub_get_multiboot_mmap_count. */
75static int
76count_hook (grub_uint64_t addr __attribute__ ((unused)),
77 grub_uint64_t size __attribute__ ((unused)),
78 grub_memory_type_t type __attribute__ ((unused)), void *data)
79{
80 grub_size_t *count = data;
81
82 (*count)++;
83 return 0;
84}
85
5408044f
VS
86/* Return the length of the Multiboot mmap that will be needed to allocate
87 our platform's map. */
88grub_uint32_t
21e4a6fa 89GRUB_MULTIBOOT (get_mmap_count) (void)
5408044f
VS
90{
91 grub_size_t count = 0;
92
d0d4b8a0 93 grub_mmap_iterate (count_hook, &count);
5408044f 94
8eb567e6 95 return count;
5408044f
VS
96}
97
5408044f 98grub_err_t
21e4a6fa 99GRUB_MULTIBOOT (set_video_mode) (void)
5408044f
VS
100{
101 grub_err_t err;
102 const char *modevar;
103
a4ea2dff
VS
104#if GRUB_MACHINE_HAS_VGA_TEXT
105 if (accepts_video)
106#endif
5408044f
VS
107 {
108 modevar = grub_env_get ("gfxpayload");
109 if (! modevar || *modevar == 0)
3f5a90c6 110 err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0);
5408044f
VS
111 else
112 {
113 char *tmp;
3f5a90c6 114 tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
5408044f
VS
115 if (! tmp)
116 return grub_errno;
3f5a90c6 117 err = grub_video_set_mode (tmp, 0, 0);
5408044f
VS
118 grub_free (tmp);
119 }
120 }
a4ea2dff 121#if GRUB_MACHINE_HAS_VGA_TEXT
5408044f 122 else
3f5a90c6 123 err = grub_video_set_mode ("text", 0, 0);
a4ea2dff 124#endif
5408044f
VS
125
126 return err;
127}
636813f7 128
9862b241
DK
129#ifdef GRUB_MACHINE_EFI
130#ifdef __x86_64__
131#define grub_relocator_efi_boot grub_relocator64_efi_boot
132#define grub_relocator_efi_state grub_relocator64_efi_state
133#endif
134#endif
135
136#ifdef grub_relocator_efi_boot
137static void
138efi_boot (struct grub_relocator *rel,
139 grub_uint32_t target)
140{
4bfd2662
VS
141#ifdef GRUB_USE_MULTIBOOT2
142 struct grub_relocator_efi_state state_efi = MULTIBOOT2_EFI_INITIAL_STATE;
143#else
9862b241 144 struct grub_relocator_efi_state state_efi = MULTIBOOT_EFI_INITIAL_STATE;
4bfd2662 145#endif
78d2b81b 146 state_efi.MULTIBOOT_EFI_ENTRY_REGISTER = GRUB_MULTIBOOT (payload_eip);
9862b241
DK
147 state_efi.MULTIBOOT_EFI_MBI_REGISTER = target;
148
149 grub_relocator_efi_boot (rel, state_efi);
150}
151#else
152#define grub_efi_is_finished 1
153static void
154efi_boot (struct grub_relocator *rel __attribute__ ((unused)),
155 grub_uint32_t target __attribute__ ((unused)))
156{
157}
158#endif
159
160#if defined (__i386__) || defined (__x86_64__)
161static void
162normal_boot (struct grub_relocator *rel, struct grub_relocator32_state state)
163{
164 grub_relocator32_boot (rel, state, 0);
165}
166#else
167static void
168normal_boot (struct grub_relocator *rel, struct grub_relocator32_state state)
169{
170 grub_relocator32_boot (rel, state);
171}
172#endif
173
4b13b216 174static grub_err_t
175grub_multiboot_boot (void)
9a5c1ade 176{
cd051479 177 grub_err_t err;
8c46a785 178
21e4a6fa
VS
179#ifdef GRUB_USE_MULTIBOOT2
180 struct grub_relocator32_state state = MULTIBOOT2_INITIAL_STATE;
181#else
182 struct grub_relocator32_state state = MULTIBOOT_INITIAL_STATE;
183#endif
184 state.MULTIBOOT_ENTRY_REGISTER = GRUB_MULTIBOOT (payload_eip);
636813f7 185
21e4a6fa 186 err = GRUB_MULTIBOOT (make_mbi) (&state.MULTIBOOT_MBI_REGISTER);
cd051479 187
cd051479
VS
188 if (err)
189 return err;
190
9862b241 191 if (grub_efi_is_finished)
21e4a6fa 192 normal_boot (GRUB_MULTIBOOT (relocator), state);
9862b241 193 else
21e4a6fa 194 efi_boot (GRUB_MULTIBOOT (relocator), state.MULTIBOOT_MBI_REGISTER);
9a5c1ade 195
196 /* Not reached. */
4b13b216 197 return GRUB_ERR_NONE;
9a5c1ade 198}
199
4b13b216 200static grub_err_t
201grub_multiboot_unload (void)
9a5c1ade 202{
21e4a6fa 203 GRUB_MULTIBOOT (free_mbi) ();
cd051479 204
21e4a6fa
VS
205 grub_relocator_unload (GRUB_MULTIBOOT (relocator));
206 GRUB_MULTIBOOT (relocator) = NULL;
b39f9d20 207
4b13b216 208 grub_dl_unref (my_mod);
9a5c1ade 209
4b13b216 210 return GRUB_ERR_NONE;
9a5c1ade 211}
212
00bfa988
VS
213static grub_uint64_t highest_load;
214
8a31787f 215#define MULTIBOOT_LOAD_ELF64
216#include "multiboot_elfxx.c"
217#undef MULTIBOOT_LOAD_ELF64
ea409713 218
8a31787f 219#define MULTIBOOT_LOAD_ELF32
220#include "multiboot_elfxx.c"
221#undef MULTIBOOT_LOAD_ELF32
ea409713 222
223/* Load ELF32 or ELF64. */
b1f6f35a 224grub_err_t
21e4a6fa 225GRUB_MULTIBOOT (load_elf) (mbi_load_data_t *mld)
ea409713 226{
a620876e
DK
227 if (grub_multiboot_is_elf32 (mld->buffer))
228 return grub_multiboot_load_elf32 (mld);
229 else if (grub_multiboot_is_elf64 (mld->buffer))
230 return grub_multiboot_load_elf64 (mld);
d38e24c2 231
67093bc0 232 return grub_error (GRUB_ERR_UNKNOWN_OS, N_("invalid arch-dependent ELF magic"));
ea409713 233}
234
b1f6f35a 235grub_err_t
21e4a6fa
VS
236GRUB_MULTIBOOT (set_console) (int console_type, int accepted_consoles,
237 int width, int height, int depth,
238 int console_req)
9a5c1ade 239{
c3a8dfc8
VS
240 console_required = console_req;
241 if (!(accepted_consoles
242 & (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER
243 | (GRUB_MACHINE_HAS_VGA_TEXT ? GRUB_MULTIBOOT_CONSOLE_EGA_TEXT : 0))))
9a5c1ade 244 {
c3a8dfc8
VS
245 if (console_required)
246 return grub_error (GRUB_ERR_BAD_OS,
247 "OS requires a console but none is available");
6e0632e2 248 grub_puts_ (N_("WARNING: no console will be available to OS"));
c3a8dfc8
VS
249 accepts_video = 0;
250 accepts_ega_text = 0;
251 return GRUB_ERR_NONE;
9a5c1ade 252 }
253
b1f6f35a 254 if (console_type == GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER)
9a5c1ade 255 {
b1f6f35a
VS
256 char *buf;
257 if (depth && width && height)
258 buf = grub_xasprintf ("%dx%dx%d,%dx%d,auto", width,
259 height, depth, width, height);
260 else if (width && height)
261 buf = grub_xasprintf ("%dx%d,auto", width, height);
262 else
263 buf = grub_strdup ("auto");
9a5c1ade 264
b1f6f35a
VS
265 if (!buf)
266 return grub_errno;
267 grub_env_set ("gfxpayload", buf);
268 grub_free (buf);
9a5c1ade 269 }
71764dc8 270 else
271 {
272#if GRUB_MACHINE_HAS_VGA_TEXT
273 grub_env_set ("gfxpayload", "text");
274#else
275 /* Always use video if no VGA text is available. */
276 grub_env_set ("gfxpayload", "auto");
277#endif
278 }
9a5c1ade 279
b1f6f35a 280 accepts_video = !!(accepted_consoles & GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER);
c3a8dfc8 281 accepts_ega_text = !!(accepted_consoles & GRUB_MULTIBOOT_CONSOLE_EGA_TEXT);
b1f6f35a
VS
282 return GRUB_ERR_NONE;
283}
d38e24c2 284
b1f6f35a
VS
285static grub_err_t
286grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)),
287 int argc, char *argv[])
9a5c1ade 288{
4b13b216 289 grub_file_t file = 0;
b1f6f35a 290 grub_err_t err;
9a5c1ade 291
ea409713 292 grub_loader_unset ();
c642636f 293
00bfa988
VS
294 highest_load = 0;
295
296#ifndef GRUB_USE_MULTIBOOT2
297 grub_multiboot_quirks = GRUB_MULTIBOOT_QUIRKS_NONE;
e0bd66c3 298 int option_found = 0;
00bfa988 299
e0bd66c3 300 do
00bfa988 301 {
e0bd66c3
VS
302 option_found = 0;
303 if (argc != 0 && grub_strcmp (argv[0], "--quirk-bad-kludge") == 0)
304 {
305 argc--;
306 argv++;
307 option_found = 1;
308 grub_multiboot_quirks |= GRUB_MULTIBOOT_QUIRK_BAD_KLUDGE;
309 }
00bfa988 310
e0bd66c3
VS
311 if (argc != 0 && grub_strcmp (argv[0], "--quirk-modules-after-kernel") == 0)
312 {
313 argc--;
314 argv++;
315 option_found = 1;
316 grub_multiboot_quirks |= GRUB_MULTIBOOT_QUIRK_MODULES_AFTER_KERNEL;
317 }
318 } while (option_found);
00bfa988
VS
319#endif
320
9a5c1ade 321 if (argc == 0)
9c4b5c13 322 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
9a5c1ade 323
ca0a4f68 324 file = grub_file_open (argv[0], GRUB_FILE_TYPE_MULTIBOOT_KERNEL);
ea409713 325 if (! file)
7a45a539 326 return grub_errno;
9a5c1ade 327
b1f6f35a 328 grub_dl_ref (my_mod);
371458b5 329
e1f39873 330 /* Skip filename. */
21e4a6fa 331 GRUB_MULTIBOOT (init_mbi) (argc - 1, argv + 1);
deceb3ec 332
21e4a6fa
VS
333 grub_relocator_unload (GRUB_MULTIBOOT (relocator));
334 GRUB_MULTIBOOT (relocator) = grub_relocator_new ();
14e43c6e 335
21e4a6fa 336 if (!GRUB_MULTIBOOT (relocator))
14e43c6e
VS
337 goto fail;
338
21e4a6fa 339 err = GRUB_MULTIBOOT (load) (file, argv[0]);
b1f6f35a 340 if (err)
ea409713 341 goto fail;
d38e24c2 342
21e4a6fa 343 GRUB_MULTIBOOT (set_bootdev) ();
38ad2cf5 344
14e43c6e 345 grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0);
9a5c1ade 346
347 fail:
348 if (file)
4b13b216 349 grub_file_close (file);
9a5c1ade 350
4b13b216 351 if (grub_errno != GRUB_ERR_NONE)
9a5c1ade 352 {
21e4a6fa
VS
353 grub_relocator_unload (GRUB_MULTIBOOT (relocator));
354 GRUB_MULTIBOOT (relocator) = NULL;
4b13b216 355 grub_dl_unref (my_mod);
9a5c1ade 356 }
b1f6f35a
VS
357
358 return grub_errno;
9a5c1ade 359}
360
b1f6f35a
VS
361static grub_err_t
362grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
363 int argc, char *argv[])
9a5c1ade 364{
4b13b216 365 grub_file_t file = 0;
cd051479 366 grub_ssize_t size;
5c8e58b0
VS
367 void *module = NULL;
368 grub_addr_t target;
cd051479 369 grub_err_t err;
dee50575 370 int nounzip = 0;
00bfa988 371 grub_uint64_t lowest_addr = 0;
dee50575
VS
372
373 if (argc == 0)
9c4b5c13 374 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
dee50575
VS
375
376 if (grub_strcmp (argv[0], "--nounzip") == 0)
377 {
378 argv++;
379 argc--;
380 nounzip = 1;
381 }
9a5c1ade 382
383 if (argc == 0)
9c4b5c13 384 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
9a5c1ade 385
21e4a6fa 386 if (!GRUB_MULTIBOOT (relocator))
b1f6f35a 387 return grub_error (GRUB_ERR_BAD_ARGUMENT,
9c4b5c13 388 N_("you need to load the kernel first"));
9a5c1ade 389
ca0a4f68
VS
390 file = grub_file_open (argv[0], GRUB_FILE_TYPE_MULTIBOOT_MODULE
391 | (nounzip ? GRUB_FILE_TYPE_NO_DECOMPRESS : GRUB_FILE_TYPE_NONE));
ea409713 392 if (! file)
b1f6f35a 393 return grub_errno;
9a5c1ade 394
00bfa988 395#ifndef GRUB_USE_MULTIBOOT2
c856be6b 396 lowest_addr = 0x100000;
00bfa988
VS
397 if (grub_multiboot_quirks & GRUB_MULTIBOOT_QUIRK_MODULES_AFTER_KERNEL)
398 lowest_addr = ALIGN_UP (highest_load + 1048576, 4096);
399#endif
400
4b13b216 401 size = grub_file_size (file);
cb3c4a47 402 if (size)
4b2ec20b
VS
403 {
404 grub_relocator_chunk_t ch;
21e4a6fa 405 err = grub_relocator_alloc_chunk_align (GRUB_MULTIBOOT (relocator), &ch,
e39786ab 406 lowest_addr, UP_TO_TOP32 (size),
4b2ec20b 407 size, MULTIBOOT_MOD_ALIGN,
0df77d79 408 GRUB_RELOCATOR_PREFERENCE_NONE, 1);
4b2ec20b
VS
409 if (err)
410 {
411 grub_file_close (file);
412 return err;
413 }
414 module = get_virtual_current_address (ch);
813c0a2b 415 target = get_physical_target_address (ch);
4b2ec20b 416 }
cb3c4a47
VS
417 else
418 {
419 module = 0;
420 target = 0;
421 }
9a5c1ade 422
21e4a6fa 423 err = GRUB_MULTIBOOT (add_module) (target, size, argc - 1, argv + 1);
cd051479 424 if (err)
b1f6f35a
VS
425 {
426 grub_file_close (file);
427 return err;
428 }
9a5c1ade 429
cb3c4a47 430 if (size && grub_file_read (file, module, size) != size)
9a5c1ade 431 {
b1f6f35a 432 grub_file_close (file);
7a45a539
VS
433 if (!grub_errno)
434 grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
435 argv[0]);
436 return grub_errno;
9a5c1ade 437 }
d38e24c2 438
b1f6f35a 439 grub_file_close (file);
cb3c4a47 440 return GRUB_ERR_NONE;
9a5c1ade 441}
cd051479 442
b1f6f35a
VS
443static grub_command_t cmd_multiboot, cmd_module;
444
445GRUB_MOD_INIT(multiboot)
446{
447 cmd_multiboot =
448#ifdef GRUB_USE_MULTIBOOT2
449 grub_register_command ("multiboot2", grub_cmd_multiboot,
450 0, N_("Load a multiboot 2 kernel."));
daea6abd
VS
451 cmd_module =
452 grub_register_command ("module2", grub_cmd_module,
453 0, N_("Load a multiboot 2 module."));
b1f6f35a
VS
454#else
455 grub_register_command ("multiboot", grub_cmd_multiboot,
456 0, N_("Load a multiboot kernel."));
b1f6f35a
VS
457 cmd_module =
458 grub_register_command ("module", grub_cmd_module,
459 0, N_("Load a multiboot module."));
daea6abd 460#endif
b1f6f35a
VS
461
462 my_mod = mod;
9a5c1ade 463}
cd051479 464
b1f6f35a
VS
465GRUB_MOD_FINI(multiboot)
466{
467 grub_unregister_command (cmd_multiboot);
468 grub_unregister_command (cmd_module);
469}