]> git.proxmox.com Git - grub2.git/blame - grub-core/loader/i386/multiboot_mbi.c
multiboot2: Add support for relocatable images
[grub2.git] / grub-core / loader / i386 / multiboot_mbi.c
CommitLineData
cd051479
VS
1/*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
4 *
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.
9 *
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.
14 *
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/>.
17 */
18
cd051479
VS
19#include <grub/memory.h>
20#ifdef GRUB_MACHINE_PCBIOS
21#include <grub/machine/biosnum.h>
890c9fa5 22#include <grub/machine/apm.h>
f218b09c 23#include <grub/machine/memory.h>
cd051479
VS
24#endif
25#include <grub/multiboot.h>
b1f6f35a 26#include <grub/cpu/relocator.h>
cd051479
VS
27#include <grub/disk.h>
28#include <grub/device.h>
29#include <grub/partition.h>
30#include <grub/mm.h>
31#include <grub/misc.h>
32#include <grub/env.h>
5c8e58b0 33#include <grub/relocator.h>
884ade56 34#include <grub/video.h>
b1f6f35a 35#include <grub/file.h>
779e9dc4 36#include <grub/net.h>
9c4b5c13 37#include <grub/i18n.h>
1a46a3a4 38#include <grub/lib/cmdline.h>
884ade56 39
329550c4
VS
40#ifdef GRUB_MACHINE_EFI
41#include <grub/efi/efi.h>
42#endif
43
b1f6f35a
VS
44/* The bits in the required part of flags field we don't support. */
45#define UNSUPPORTED_FLAGS 0x0000fff8
cd051479
VS
46
47struct module
48{
49 struct module *next;
50 grub_addr_t start;
51 grub_size_t size;
52 char *cmdline;
53 int cmdline_size;
54};
55
7d4e39d6 56static struct module *modules, *modules_last;
cd051479
VS
57static grub_size_t cmdline_size;
58static grub_size_t total_modcmd;
59static unsigned modcnt;
60static char *cmdline = NULL;
61static grub_uint32_t bootdev;
62static int bootdev_set;
865a0f8a
VS
63static grub_size_t elf_sec_num, elf_sec_entsize;
64static unsigned elf_sec_shstrndx;
65static void *elf_sections;
00bfa988 66grub_multiboot_quirks_t grub_multiboot_quirks;
884ade56 67
00bfa988
VS
68static grub_err_t
69load_kernel (grub_file_t file, const char *filename,
70 char *buffer, struct multiboot_header *header)
71{
72 grub_err_t err;
a620876e
DK
73 mbi_load_data_t mld;
74
75 mld.file = file;
76 mld.filename = filename;
77 mld.buffer = buffer;
78 mld.mbi_ver = 1;
79 mld.relocatable = 0;
80 mld.avoid_efi_boot_services = 0;
81
00bfa988
VS
82 if (grub_multiboot_quirks & GRUB_MULTIBOOT_QUIRK_BAD_KLUDGE)
83 {
a620876e 84 err = grub_multiboot_load_elf (&mld);
95ba0460
VS
85 if (err == GRUB_ERR_NONE) {
86 return GRUB_ERR_NONE;
87 }
00bfa988
VS
88 if (err == GRUB_ERR_UNKNOWN_OS && (header->flags & MULTIBOOT_AOUT_KLUDGE))
89 grub_errno = err = GRUB_ERR_NONE;
90 }
91 if (header->flags & MULTIBOOT_AOUT_KLUDGE)
92 {
93 int offset = ((char *) header - buffer -
94 (header->header_addr - header->load_addr));
95 int load_size = ((header->load_end_addr == 0) ? file->size - offset :
96 header->load_end_addr - header->load_addr);
97 grub_size_t code_size;
98 void *source;
99 grub_relocator_chunk_t ch;
100
101 if (header->bss_end_addr)
102 code_size = (header->bss_end_addr - header->load_addr);
103 else
104 code_size = load_size;
105
106 err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator,
107 &ch, header->load_addr,
108 code_size);
109 if (err)
110 {
111 grub_dprintf ("multiboot_loader", "Error loading aout kludge\n");
112 return err;
113 }
114 source = get_virtual_current_address (ch);
115
116 if ((grub_file_seek (file, offset)) == (grub_off_t) -1)
117 {
118 return grub_errno;
119 }
120
121 grub_file_read (file, source, load_size);
122 if (grub_errno)
123 return grub_errno;
124
125 if (header->bss_end_addr)
126 grub_memset ((grub_uint8_t *) source + load_size, 0,
127 header->bss_end_addr - header->load_addr - load_size);
128
129 grub_multiboot_payload_eip = header->entry_addr;
130 return GRUB_ERR_NONE;
131 }
132
a620876e 133 return grub_multiboot_load_elf (&mld);
00bfa988 134}
cd051479 135
ef02b4ca
VS
136static struct multiboot_header *
137find_header (char *buffer, grub_ssize_t len)
138{
139 struct multiboot_header *header;
140
141 /* Look for the multiboot header in the buffer. The header should
142 be at least 12 bytes and aligned on a 4-byte boundary. */
143 for (header = (struct multiboot_header *) buffer;
144 ((char *) header <= buffer + len - 12);
145 header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN))
146 {
147 if (header->magic == MULTIBOOT_HEADER_MAGIC
148 && !(header->magic + header->flags + header->checksum))
149 return header;
150 }
151 return NULL;
152}
153
b1f6f35a 154grub_err_t
9c4b5c13 155grub_multiboot_load (grub_file_t file, const char *filename)
cd051479 156{
b1f6f35a
VS
157 char *buffer;
158 grub_ssize_t len;
159 struct multiboot_header *header;
160 grub_err_t err;
cd051479 161
b1f6f35a
VS
162 buffer = grub_malloc (MULTIBOOT_SEARCH);
163 if (!buffer)
164 return grub_errno;
165
166 len = grub_file_read (file, buffer, MULTIBOOT_SEARCH);
167 if (len < 32)
cd051479 168 {
b1f6f35a 169 grub_free (buffer);
9c4b5c13
VS
170 if (!grub_errno)
171 grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
172 filename);
173 return grub_errno;
cd051479
VS
174 }
175
ef02b4ca 176 header = find_header (buffer, len);
b1f6f35a
VS
177
178 if (header == 0)
179 {
180 grub_free (buffer);
181 return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found");
182 }
cd051479 183
b1f6f35a
VS
184 if (header->flags & UNSUPPORTED_FLAGS)
185 {
186 grub_free (buffer);
187 return grub_error (GRUB_ERR_UNKNOWN_OS,
188 "unsupported flag: 0x%x", header->flags);
189 }
190
00bfa988
VS
191 err = load_kernel (file, filename, buffer, header);
192 if (err)
b1f6f35a 193 {
00bfa988
VS
194 grub_free (buffer);
195 return err;
b1f6f35a
VS
196 }
197
198 if (header->flags & MULTIBOOT_VIDEO_MODE)
199 {
200 switch (header->mode_type)
201 {
202 case 1:
203 err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
204 GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
205 | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
c3a8dfc8 206 0, 0, 0, 0);
b1f6f35a
VS
207 break;
208 case 0:
209 err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
210 GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
211 | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
212 header->width, header->height,
c3a8dfc8 213 header->depth, 0);
b1f6f35a 214 break;
974ac4f7
VS
215 default:
216 err = grub_error (GRUB_ERR_BAD_OS,
217 "unsupported graphical mode type %d",
218 header->mode_type);
219 break;
b1f6f35a
VS
220 }
221 }
222 else
223 err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
224 GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
c3a8dfc8 225 0, 0, 0, 0);
b1f6f35a 226 return err;
cd051479
VS
227}
228
57994012
VS
229#if GRUB_MACHINE_HAS_VBE || GRUB_MACHINE_HAS_VGA_TEXT
230#include <grub/i386/pc/vbe.h>
231#endif
232
5c8e58b0 233static grub_size_t
cd051479
VS
234grub_multiboot_get_mbi_size (void)
235{
779e9dc4
VS
236 grub_size_t ret;
237 struct grub_net_network_level_interface *net;
238
239 ret = sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4)
cd051479 240 + modcnt * sizeof (struct multiboot_mod_list) + total_modcmd
8eb567e6
VS
241 + ALIGN_UP (sizeof(PACKAGE_STRING), 4)
242 + grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry)
26235524 243 + elf_sec_entsize * elf_sec_num
890c9fa5 244 + 256 * sizeof (struct multiboot_color)
57994012 245#if GRUB_MACHINE_HAS_VBE || GRUB_MACHINE_HAS_VGA_TEXT
57e41c71
VS
246 + sizeof (struct grub_vbe_info_block)
247 + sizeof (struct grub_vbe_mode_info_block)
248#endif
890c9fa5 249 + ALIGN_UP (sizeof (struct multiboot_apm_info), 4);
779e9dc4
VS
250
251 FOR_NET_NETWORK_LEVEL_INTERFACES(net)
252 if (net->dhcp_ack)
253 {
254 ret += net->dhcp_acklen;
255 break;
256 }
257
258 return ret;
cd051479
VS
259}
260
d0d4b8a0
CW
261/* Helper for grub_fill_multiboot_mmap. */
262static int
263grub_fill_multiboot_mmap_iter (grub_uint64_t addr, grub_uint64_t size,
264 grub_memory_type_t type, void *data)
265{
266 struct multiboot_mmap_entry **mmap_entry = data;
267
268 (*mmap_entry)->addr = addr;
269 (*mmap_entry)->len = size;
6de9ee86 270 (*mmap_entry)->type = type;
d0d4b8a0
CW
271 (*mmap_entry)->size = sizeof (struct multiboot_mmap_entry) - sizeof ((*mmap_entry)->size);
272 (*mmap_entry)++;
273
274 return 0;
275}
276
cd051479
VS
277/* Fill previously allocated Multiboot mmap. */
278static void
279grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry)
280{
281 struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry;
282
d0d4b8a0 283 grub_mmap_iterate (grub_fill_multiboot_mmap_iter, &mmap_entry);
cd051479
VS
284}
285
57994012
VS
286#if GRUB_MACHINE_HAS_VBE || GRUB_MACHINE_HAS_VGA_TEXT
287
57e41c71
VS
288static grub_err_t
289fill_vbe_info (struct multiboot_info *mbi, grub_uint8_t *ptrorig,
01740292 290 grub_uint32_t ptrdest, int fill_generic)
57e41c71 291{
57e41c71 292 grub_uint32_t vbe_mode;
01740292 293 struct grub_vbe_mode_info_block *mode_info;
57994012
VS
294#if GRUB_MACHINE_HAS_VBE
295 grub_vbe_status_t status;
296 void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
57e41c71
VS
297
298 status = grub_vbe_bios_get_controller_info (scratch);
299 if (status != GRUB_VBE_STATUS_OK)
300 return grub_error (GRUB_ERR_IO, "Can't get controller info.");
301
302 mbi->vbe_control_info = ptrdest;
303 grub_memcpy (ptrorig, scratch, sizeof (struct grub_vbe_info_block));
304 ptrorig += sizeof (struct grub_vbe_info_block);
305 ptrdest += sizeof (struct grub_vbe_info_block);
57994012
VS
306#else
307 mbi->vbe_control_info = 0;
308#endif
309
310#if GRUB_MACHINE_HAS_VBE
57e41c71
VS
311 status = grub_vbe_bios_get_mode (scratch);
312 vbe_mode = *(grub_uint32_t *) scratch;
313 if (status != GRUB_VBE_STATUS_OK)
01740292 314 return grub_error (GRUB_ERR_IO, "can't get VBE mode");
57994012
VS
315#else
316 vbe_mode = 3;
317#endif
57e41c71
VS
318 mbi->vbe_mode = vbe_mode;
319
01740292 320 mode_info = (struct grub_vbe_mode_info_block *) ptrorig;
57e41c71 321 mbi->vbe_mode_info = ptrdest;
01740292
VS
322 /* get_mode_info isn't available for mode 3. */
323 if (vbe_mode == 3)
324 {
325 grub_memset (mode_info, 0, sizeof (struct grub_vbe_mode_info_block));
326 mode_info->memory_model = GRUB_VBE_MEMORY_MODEL_TEXT;
327 mode_info->x_resolution = 80;
328 mode_info->y_resolution = 25;
329 }
330 else
331 {
57994012 332#if GRUB_MACHINE_HAS_VBE
01740292
VS
333 status = grub_vbe_bios_get_mode_info (vbe_mode, scratch);
334 if (status != GRUB_VBE_STATUS_OK)
335 return grub_error (GRUB_ERR_IO, "can't get mode info");
336 grub_memcpy (mode_info, scratch,
337 sizeof (struct grub_vbe_mode_info_block));
57994012 338#endif
01740292 339 }
57e41c71
VS
340 ptrorig += sizeof (struct grub_vbe_mode_info_block);
341 ptrdest += sizeof (struct grub_vbe_mode_info_block);
57994012
VS
342
343#if GRUB_MACHINE_HAS_VBE
0b37526a
VS
344 grub_vbe_bios_get_pm_interface (&mbi->vbe_interface_seg,
345 &mbi->vbe_interface_off,
346 &mbi->vbe_interface_len);
57994012 347#endif
57e41c71
VS
348
349 mbi->flags |= MULTIBOOT_INFO_VBE_INFO;
350
01740292
VS
351 if (fill_generic && mode_info->memory_model == GRUB_VBE_MEMORY_MODEL_TEXT)
352 {
353 mbi->framebuffer_addr = 0xb8000;
354
355 mbi->framebuffer_pitch = 2 * mode_info->x_resolution;
356 mbi->framebuffer_width = mode_info->x_resolution;
357 mbi->framebuffer_height = mode_info->y_resolution;
358
359 mbi->framebuffer_bpp = 16;
360
361 mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT;
362
363 mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO;
364 }
365
57e41c71
VS
366 return GRUB_ERR_NONE;
367}
368#endif
369
884ade56
VS
370static grub_err_t
371retrieve_video_parameters (struct multiboot_info *mbi,
372 grub_uint8_t *ptrorig, grub_uint32_t ptrdest)
373{
374 grub_err_t err;
375 struct grub_video_mode_info mode_info;
376 void *framebuffer;
377 grub_video_driver_id_t driv_id;
378 struct grub_video_palette_data palette[256];
379
5408044f 380 err = grub_multiboot_set_video_mode ();
884ade56
VS
381 if (err)
382 {
383 grub_print_error ();
384 grub_errno = GRUB_ERR_NONE;
385 }
386
387 grub_video_get_palette (0, ARRAY_SIZE (palette), palette);
388
389 driv_id = grub_video_get_driver_id ();
9ba27423 390#if GRUB_MACHINE_HAS_VGA_TEXT
01740292
VS
391 if (driv_id == GRUB_VIDEO_DRIVER_NONE)
392 return fill_vbe_info (mbi, ptrorig, ptrdest, 1);
393#else
884ade56
VS
394 if (driv_id == GRUB_VIDEO_DRIVER_NONE)
395 return GRUB_ERR_NONE;
57e41c71 396#endif
884ade56
VS
397
398 err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
399 if (err)
400 return err;
401
402 mbi->framebuffer_addr = (grub_addr_t) framebuffer;
403 mbi->framebuffer_pitch = mode_info.pitch;
404
405 mbi->framebuffer_width = mode_info.width;
406 mbi->framebuffer_height = mode_info.height;
407
408 mbi->framebuffer_bpp = mode_info.bpp;
409
410 if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)
411 {
412 struct multiboot_color *mb_palette;
413 unsigned i;
414 mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED;
415 mbi->framebuffer_palette_addr = ptrdest;
416 mbi->framebuffer_palette_num_colors = mode_info.number_of_colors;
417 if (mbi->framebuffer_palette_num_colors > ARRAY_SIZE (palette))
418 mbi->framebuffer_palette_num_colors = ARRAY_SIZE (palette);
419 mb_palette = (struct multiboot_color *) ptrorig;
420 for (i = 0; i < mbi->framebuffer_palette_num_colors; i++)
421 {
422 mb_palette[i].red = palette[i].r;
423 mb_palette[i].green = palette[i].g;
424 mb_palette[i].blue = palette[i].b;
425 }
426 ptrorig += mbi->framebuffer_palette_num_colors
427 * sizeof (struct multiboot_color);
428 ptrdest += mbi->framebuffer_palette_num_colors
429 * sizeof (struct multiboot_color);
430 }
431 else
432 {
433 mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB;
e9b29642
CW
434 mbi->framebuffer_red_field_position = mode_info.red_field_pos;
435 mbi->framebuffer_red_mask_size = mode_info.red_mask_size;
884ade56
VS
436 mbi->framebuffer_green_field_position = mode_info.green_field_pos;
437 mbi->framebuffer_green_mask_size = mode_info.green_mask_size;
438 mbi->framebuffer_blue_field_position = mode_info.blue_field_pos;
439 mbi->framebuffer_blue_mask_size = mode_info.blue_mask_size;
440 }
441
442 mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO;
443
9ba27423 444#if GRUB_MACHINE_HAS_VBE
01740292
VS
445 if (driv_id == GRUB_VIDEO_DRIVER_VBE)
446 return fill_vbe_info (mbi, ptrorig, ptrdest, 0);
57e41c71
VS
447#endif
448
884ade56
VS
449 return GRUB_ERR_NONE;
450}
451
cd051479 452grub_err_t
5c8e58b0 453grub_multiboot_make_mbi (grub_uint32_t *target)
cd051479 454{
cd051479
VS
455 struct multiboot_info *mbi;
456 struct multiboot_mod_list *modlist;
457 unsigned i;
458 struct module *cur;
459 grub_size_t mmap_size;
5c8e58b0
VS
460 grub_uint8_t *ptrorig;
461 grub_addr_t ptrdest;
88d2919b 462
5c8e58b0
VS
463 grub_err_t err;
464 grub_size_t bufsize;
4b2ec20b 465 grub_relocator_chunk_t ch;
cd051479 466
5c8e58b0
VS
467 bufsize = grub_multiboot_get_mbi_size ();
468
4b2ec20b 469 err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch,
4a70fed8 470 0x10000, 0xa0000 - bufsize,
49a716be 471 bufsize, 4,
9be4c45d 472 GRUB_RELOCATOR_PREFERENCE_NONE, 0);
5c8e58b0
VS
473 if (err)
474 return err;
4b2ec20b 475 ptrorig = get_virtual_current_address (ch);
e1dffcf2 476 ptrdest = get_physical_target_address (ch);
5c8e58b0
VS
477
478 *target = ptrdest;
cd051479
VS
479
480 mbi = (struct multiboot_info *) ptrorig;
481 ptrorig += sizeof (*mbi);
482 ptrdest += sizeof (*mbi);
483 grub_memset (mbi, 0, sizeof (*mbi));
484
485 grub_memcpy (ptrorig, cmdline, cmdline_size);
486 mbi->flags |= MULTIBOOT_INFO_CMDLINE;
487 mbi->cmdline = ptrdest;
488 ptrorig += ALIGN_UP (cmdline_size, 4);
489 ptrdest += ALIGN_UP (cmdline_size, 4);
490
491 grub_memcpy (ptrorig, PACKAGE_STRING, sizeof(PACKAGE_STRING));
492 mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME;
493 mbi->boot_loader_name = ptrdest;
494 ptrorig += ALIGN_UP (sizeof(PACKAGE_STRING), 4);
495 ptrdest += ALIGN_UP (sizeof(PACKAGE_STRING), 4);
496
890c9fa5
VS
497#ifdef GRUB_MACHINE_PCBIOS
498 {
499 struct grub_apm_info info;
500 if (grub_apm_get_info (&info))
501 {
502 struct multiboot_apm_info *mbinfo = (void *) ptrorig;
503
504 mbinfo->cseg = info.cseg;
505 mbinfo->offset = info.offset;
506 mbinfo->cseg_16 = info.cseg_16;
507 mbinfo->dseg = info.dseg;
508 mbinfo->flags = info.flags;
509 mbinfo->cseg_len = info.cseg_len;
510 mbinfo->dseg_len = info.dseg_len;
511 mbinfo->cseg_16_len = info.cseg_16_len;
512 mbinfo->version = info.version;
513
514 ptrorig += ALIGN_UP (sizeof (struct multiboot_apm_info), 4);
515 ptrdest += ALIGN_UP (sizeof (struct multiboot_apm_info), 4);
516 }
517 }
518#endif
519
cd051479
VS
520 if (modcnt)
521 {
522 mbi->flags |= MULTIBOOT_INFO_MODS;
523 mbi->mods_addr = ptrdest;
524 mbi->mods_count = modcnt;
525 modlist = (struct multiboot_mod_list *) ptrorig;
526 ptrorig += modcnt * sizeof (struct multiboot_mod_list);
527 ptrdest += modcnt * sizeof (struct multiboot_mod_list);
528
529 for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next)
530 {
531 modlist[i].mod_start = cur->start;
532 modlist[i].mod_end = modlist[i].mod_start + cur->size;
533 modlist[i].cmdline = ptrdest;
534 grub_memcpy (ptrorig, cur->cmdline, cur->cmdline_size);
535 ptrorig += ALIGN_UP (cur->cmdline_size, 4);
536 ptrdest += ALIGN_UP (cur->cmdline_size, 4);
537 }
538 }
539 else
540 {
541 mbi->mods_addr = 0;
542 mbi->mods_count = 0;
543 }
544
8eb567e6
VS
545 mmap_size = grub_get_multiboot_mmap_count ()
546 * sizeof (struct multiboot_mmap_entry);
cd051479
VS
547 grub_fill_multiboot_mmap ((struct multiboot_mmap_entry *) ptrorig);
548 mbi->mmap_length = mmap_size;
549 mbi->mmap_addr = ptrdest;
550 mbi->flags |= MULTIBOOT_INFO_MEM_MAP;
551 ptrorig += mmap_size;
552 ptrdest += mmap_size;
553
554 /* Convert from bytes to kilobytes. */
555 mbi->mem_lower = grub_mmap_get_lower () / 1024;
556 mbi->mem_upper = grub_mmap_get_upper () / 1024;
557 mbi->flags |= MULTIBOOT_INFO_MEMORY;
558
559 if (bootdev_set)
560 {
561 mbi->boot_device = bootdev;
562 mbi->flags |= MULTIBOOT_INFO_BOOTDEV;
563 }
564
779e9dc4
VS
565 {
566 struct grub_net_network_level_interface *net;
567 FOR_NET_NETWORK_LEVEL_INTERFACES(net)
568 if (net->dhcp_ack)
569 {
570 grub_memcpy (ptrorig, net->dhcp_ack, net->dhcp_acklen);
571 mbi->drives_addr = ptrdest;
572 mbi->drives_length = net->dhcp_acklen;
573 ptrorig += net->dhcp_acklen;
574 ptrdest += net->dhcp_acklen;
575 break;
576 }
577 }
578
865a0f8a
VS
579 if (elf_sec_num)
580 {
581 mbi->u.elf_sec.addr = ptrdest;
582 grub_memcpy (ptrorig, elf_sections, elf_sec_entsize * elf_sec_num);
583 mbi->u.elf_sec.num = elf_sec_num;
584 mbi->u.elf_sec.size = elf_sec_entsize;
585 mbi->u.elf_sec.shndx = elf_sec_shstrndx;
586
587 mbi->flags |= MULTIBOOT_INFO_ELF_SHDR;
45146057
VS
588
589 ptrorig += elf_sec_entsize * elf_sec_num;
590 ptrdest += elf_sec_entsize * elf_sec_num;
865a0f8a
VS
591 }
592
884ade56
VS
593 err = retrieve_video_parameters (mbi, ptrorig, ptrdest);
594 if (err)
595 {
596 grub_print_error ();
597 grub_errno = GRUB_ERR_NONE;
598 }
45146057
VS
599
600 if ((mbi->flags & MULTIBOOT_INFO_FRAMEBUFFER_INFO)
601 && mbi->framebuffer_type == MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED)
602 {
603 ptrorig += mbi->framebuffer_palette_num_colors
604 * sizeof (struct multiboot_color);
605 ptrdest += mbi->framebuffer_palette_num_colors
606 * sizeof (struct multiboot_color);
607 }
608
9ba27423 609#if GRUB_MACHINE_HAS_VBE
57e41c71
VS
610 ptrorig += sizeof (struct grub_vbe_info_block);
611 ptrdest += sizeof (struct grub_vbe_info_block);
612 ptrorig += sizeof (struct grub_vbe_mode_info_block);
613 ptrdest += sizeof (struct grub_vbe_mode_info_block);
614#endif
884ade56 615
329550c4
VS
616#ifdef GRUB_MACHINE_EFI
617 err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
618 if (err)
619 return err;
620#endif
621
cd051479
VS
622 return GRUB_ERR_NONE;
623}
624
865a0f8a
VS
625void
626grub_multiboot_add_elfsyms (grub_size_t num, grub_size_t entsize,
627 unsigned shndx, void *data)
628{
629 elf_sec_num = num;
630 elf_sec_shstrndx = shndx;
631 elf_sec_entsize = entsize;
632 elf_sections = data;
633}
634
cd051479
VS
635void
636grub_multiboot_free_mbi (void)
637{
638 struct module *cur, *next;
639
640 cmdline_size = 0;
641 total_modcmd = 0;
642 modcnt = 0;
643 grub_free (cmdline);
644 cmdline = NULL;
645 bootdev_set = 0;
646
647 for (cur = modules; cur; cur = next)
648 {
649 next = cur->next;
650 grub_free (cur->cmdline);
651 grub_free (cur);
652 }
653 modules = NULL;
654 modules_last = NULL;
865a0f8a
VS
655
656 grub_free (elf_sections);
657 elf_sections = NULL;
658 elf_sec_entsize = 0;
659 elf_sec_num = 0;
cd051479
VS
660}
661
662grub_err_t
663grub_multiboot_init_mbi (int argc, char *argv[])
664{
665 grub_ssize_t len = 0;
cd051479
VS
666
667 grub_multiboot_free_mbi ();
668
1a46a3a4 669 len = grub_loader_cmdline_size (argc, argv);
cd051479 670
1a46a3a4 671 cmdline = grub_malloc (len);
cd051479
VS
672 if (! cmdline)
673 return grub_errno;
674 cmdline_size = len;
675
1a46a3a4
VS
676 grub_create_loader_cmdline (argc, argv, cmdline,
677 cmdline_size);
cd051479
VS
678
679 return GRUB_ERR_NONE;
680}
681
682grub_err_t
683grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
684 int argc, char *argv[])
685{
686 struct module *newmod;
1a46a3a4 687 grub_size_t len = 0;
cd051479
VS
688
689 newmod = grub_malloc (sizeof (*newmod));
690 if (!newmod)
691 return grub_errno;
692 newmod->start = start;
693 newmod->size = size;
5318fe98 694 newmod->next = 0;
cd051479 695
1a46a3a4 696 len = grub_loader_cmdline_size (argc, argv);
cd051479 697
1a46a3a4 698 newmod->cmdline = grub_malloc (len);
cd051479
VS
699 if (! newmod->cmdline)
700 {
701 grub_free (newmod);
702 return grub_errno;
703 }
704 newmod->cmdline_size = len;
705 total_modcmd += ALIGN_UP (len, 4);
706
1a46a3a4
VS
707 grub_create_loader_cmdline (argc, argv, newmod->cmdline,
708 newmod->cmdline_size);
cd051479
VS
709
710 if (modules_last)
711 modules_last->next = newmod;
712 else
1a46a3a4 713 modules = newmod;
cd051479
VS
714 modules_last = newmod;
715
716 modcnt++;
717
718 return GRUB_ERR_NONE;
719}
720
721void
722grub_multiboot_set_bootdev (void)
723{
cd051479
VS
724 grub_uint32_t biosdev, slice = ~0, part = ~0;
725 grub_device_t dev;
726
727#ifdef GRUB_MACHINE_PCBIOS
728 biosdev = grub_get_root_biosnumber ();
729#else
730 biosdev = 0xffffffff;
731#endif
732
23432855
VS
733 if (biosdev == 0xffffffff)
734 return;
735
cd051479
VS
736 dev = grub_device_open (0);
737 if (dev && dev->disk && dev->disk->partition)
738 {
15cb7d43
VS
739 if (dev->disk->partition->parent)
740 {
741 part = dev->disk->partition->number;
742 slice = dev->disk->partition->parent->number;
cd051479 743 }
15cb7d43
VS
744 else
745 slice = dev->disk->partition->number;
cd051479
VS
746 }
747 if (dev)
748 grub_device_close (dev);
749
750 bootdev = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16)
751 | ((part & 0xff) << 8) | 0xff;
752 bootdev_set = 1;
753}