Upgraded GRUB2 to 2.00 release.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / loader / multiboot.c
blob11336dc7c09af11e03198aa6bf42aa7275a716c3
1 /* multiboot.c - boot a multiboot OS image. */
2 /*
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:
23 * - drives table
24 * - ROM configuration table
25 * - SMBIOS tables
26 * - Networking information
29 #include <grub/loader.h>
30 #include <grub/command.h>
31 #include <grub/multiboot.h>
32 #include <grub/cpu/multiboot.h>
33 #include <grub/elf.h>
34 #include <grub/aout.h>
35 #include <grub/file.h>
36 #include <grub/err.h>
37 #include <grub/dl.h>
38 #include <grub/mm.h>
39 #include <grub/misc.h>
40 #include <grub/env.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>
50 #endif
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"
56 #else
57 #define DEFAULT_VIDEO_MODE "auto"
58 #endif
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. */
68 grub_uint32_t
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)))
78 count++;
79 return 0;
82 grub_mmap_iterate (hook);
84 return count;
87 grub_err_t
88 grub_multiboot_set_video_mode (void)
90 grub_err_t err;
91 const char *modevar;
93 #if GRUB_MACHINE_HAS_VGA_TEXT
94 if (accepts_video)
95 #endif
97 modevar = grub_env_get ("gfxpayload");
98 if (! modevar || *modevar == 0)
99 err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0);
100 else
102 char *tmp;
103 tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
104 if (! tmp)
105 return grub_errno;
106 err = grub_video_set_mode (tmp, 0, 0);
107 grub_free (tmp);
110 #if GRUB_MACHINE_HAS_VGA_TEXT
111 else
112 err = grub_video_set_mode ("text", 0, 0);
113 #endif
115 return err;
118 static grub_err_t
119 grub_multiboot_boot (void)
121 grub_err_t err;
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);
128 if (err)
129 return err;
131 #ifdef GRUB_MACHINE_EFI
132 err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
133 if (err)
134 return err;
135 #endif
137 #if defined (__i386__) || defined (__x86_64__)
138 grub_relocator32_boot (grub_multiboot_relocator, state, 0);
139 #else
140 grub_relocator32_boot (grub_multiboot_relocator, state);
141 #endif
143 /* Not reached. */
144 return GRUB_ERR_NONE;
147 static grub_err_t
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. */
169 grub_err_t
170 grub_multiboot_load_elf (grub_file_t file, const char *filename,
171 void *buffer)
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"));
181 grub_err_t
182 grub_multiboot_set_console (int console_type, int accepted_consoles,
183 int width, int height, int depth,
184 int console_req)
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"));
195 accepts_video = 0;
196 accepts_ega_text = 0;
197 return GRUB_ERR_NONE;
200 if (console_type == GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER)
202 char *buf;
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);
208 else
209 buf = grub_strdup ("auto");
211 if (!buf)
212 return grub_errno;
213 grub_env_set ("gfxpayload", buf);
214 grub_free (buf);
216 else
219 * AROS FIX
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");
241 #else
242 grub_env_set ("gfxpayload", "640x200,auto");
243 #endif
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;
250 static grub_err_t
251 grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)),
252 int argc, char *argv[])
254 grub_file_t file = 0;
255 grub_err_t err;
257 grub_loader_unset ();
259 if (argc == 0)
260 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
262 file = grub_file_open (argv[0]);
263 if (! file)
264 return grub_errno;
266 grub_dl_ref (my_mod);
268 /* Skip filename. */
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)
275 goto fail;
277 err = grub_multiboot_load (file, argv[0]);
278 if (err)
279 goto fail;
281 grub_multiboot_set_bootdev ();
283 grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0);
285 fail:
286 if (file)
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);
296 return grub_errno;
299 static grub_err_t
300 grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
301 int argc, char *argv[])
303 grub_file_t file = 0;
304 grub_ssize_t size;
305 void *module = NULL;
306 grub_addr_t target;
307 grub_err_t err;
308 int nounzip = 0;
310 if (argc == 0)
311 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
313 if (grub_strcmp (argv[0], "--nounzip") == 0)
315 argv++;
316 argc--;
317 nounzip = 1;
320 if (argc == 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"));
327 if (nounzip)
328 grub_file_filter_disable_compression ();
330 file = grub_file_open (argv[0]);
331 if (! file)
332 return grub_errno;
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);
341 if (err)
343 grub_file_close (file);
344 return err;
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);
351 if (err)
353 grub_file_close (file);
354 return err;
357 if (grub_file_read (file, module, size) != size)
359 grub_file_close (file);
360 if (!grub_errno)
361 grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
362 argv[0]);
363 return grub_errno;
366 grub_file_close (file);
367 return GRUB_ERR_NONE;;
370 static grub_command_t cmd_multiboot, cmd_module;
372 GRUB_MOD_INIT(multiboot)
374 cmd_multiboot =
375 #ifdef GRUB_USE_MULTIBOOT2
376 grub_register_command ("multiboot2", grub_cmd_multiboot,
377 0, N_("Load a multiboot 2 kernel."));
378 cmd_module =
379 grub_register_command ("module2", grub_cmd_module,
380 0, N_("Load a multiboot 2 module."));
381 #else
382 grub_register_command ("multiboot", grub_cmd_multiboot,
383 0, N_("Load a multiboot kernel."));
384 cmd_module =
385 grub_register_command ("module", grub_cmd_module,
386 0, N_("Load a multiboot module."));
387 #endif
389 my_mod = mod;
392 GRUB_MOD_FINI(multiboot)
394 grub_unregister_command (cmd_multiboot);
395 grub_unregister_command (cmd_module);