multiboot: disentangle multiboot and multiboot2.
[grub.git] / grub-core / loader / i386 / multiboot_mbi.c
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
19 #include <grub/memory.h>
20 #ifdef GRUB_MACHINE_PCBIOS
21 #include <grub/machine/biosnum.h>
22 #include <grub/machine/apm.h>
23 #include <grub/machine/memory.h>
24 #endif
25 #include <grub/multiboot.h>
26 #include <grub/cpu/relocator.h>
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>
33 #include <grub/relocator.h>
34 #include <grub/video.h>
35 #include <grub/file.h>
36 #include <grub/net.h>
37 #include <grub/i18n.h>
38 #include <grub/lib/cmdline.h>
39
40 #ifdef GRUB_MACHINE_EFI
41 #include <grub/efi/efi.h>
42 #endif
43
44 /* The bits in the required part of flags field we don't support.  */
45 #define UNSUPPORTED_FLAGS                       0x0000fff8
46
47 struct 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
56 static struct module *modules, *modules_last;
57 static grub_size_t cmdline_size;
58 static grub_size_t total_modcmd;
59 static unsigned modcnt;
60 static char *cmdline = NULL;
61 static grub_uint32_t bootdev;
62 static int bootdev_set;
63 static grub_size_t elf_sec_num, elf_sec_entsize;
64 static unsigned elf_sec_shstrndx;
65 static void *elf_sections;
66 grub_multiboot_quirks_t grub_multiboot_quirks;
67
68 static grub_err_t
69 load_kernel (grub_file_t file, const char *filename,
70              char *buffer, struct multiboot_header *header)
71 {
72   grub_err_t err;
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
82   if (grub_multiboot_quirks & GRUB_MULTIBOOT_QUIRK_BAD_KLUDGE)
83     {
84       err = grub_multiboot_load_elf (&mld);
85       if (err == GRUB_ERR_NONE) {
86         return GRUB_ERR_NONE;
87       }
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
133   return grub_multiboot_load_elf (&mld);
134 }
135
136 static struct multiboot_header *
137 find_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
154 grub_err_t
155 grub_multiboot_load (grub_file_t file, const char *filename)
156 {
157   char *buffer;
158   grub_ssize_t len;
159   struct multiboot_header *header;
160   grub_err_t err;
161
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)
168     {
169       grub_free (buffer);
170       if (!grub_errno)
171         grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
172                     filename);
173       return grub_errno;
174     }
175
176   header = find_header (buffer, len);
177
178   if (header == 0)
179     {
180       grub_free (buffer);
181       return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found");
182     }
183
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
191   err = load_kernel (file, filename, buffer, header);
192   if (err)
193     {
194       grub_free (buffer);
195       return err;
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,
206                                             0, 0, 0, 0);
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,
213                                             header->depth, 0);
214           break;
215         default:
216           err = grub_error (GRUB_ERR_BAD_OS, 
217                             "unsupported graphical mode type %d",
218                             header->mode_type);
219           break;
220         }
221     }
222   else
223     err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, 
224                                       GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
225                                       0, 0, 0, 0);
226   return err;
227 }
228
229 #if GRUB_MACHINE_HAS_VBE || GRUB_MACHINE_HAS_VGA_TEXT
230 #include <grub/i386/pc/vbe.h>
231 #endif
232
233 static grub_size_t
234 grub_multiboot_get_mbi_size (void)
235 {
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)
240     + modcnt * sizeof (struct multiboot_mod_list) + total_modcmd
241     + ALIGN_UP (sizeof(PACKAGE_STRING), 4) 
242     + grub_multiboot_get_mmap_count () * sizeof (struct multiboot_mmap_entry)
243     + elf_sec_entsize * elf_sec_num
244     + 256 * sizeof (struct multiboot_color)
245 #if GRUB_MACHINE_HAS_VBE || GRUB_MACHINE_HAS_VGA_TEXT
246     + sizeof (struct grub_vbe_info_block)
247     + sizeof (struct grub_vbe_mode_info_block)
248 #endif
249     + ALIGN_UP (sizeof (struct multiboot_apm_info), 4);
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;
259 }
260
261 /* Helper for grub_fill_multiboot_mmap.  */
262 static int
263 grub_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;
270   (*mmap_entry)->type = type;
271   (*mmap_entry)->size = sizeof (struct multiboot_mmap_entry) - sizeof ((*mmap_entry)->size);
272   (*mmap_entry)++;
273
274   return 0;
275 }
276
277 /* Fill previously allocated Multiboot mmap.  */
278 static void
279 grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry)
280 {
281   struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry;
282
283   grub_mmap_iterate (grub_fill_multiboot_mmap_iter, &mmap_entry);
284 }
285
286 #if GRUB_MACHINE_HAS_VBE || GRUB_MACHINE_HAS_VGA_TEXT
287
288 static grub_err_t
289 fill_vbe_info (struct multiboot_info *mbi, grub_uint8_t *ptrorig,
290                grub_uint32_t ptrdest, int fill_generic)
291 {
292   grub_uint32_t vbe_mode;
293   struct grub_vbe_mode_info_block *mode_info;
294 #if GRUB_MACHINE_HAS_VBE
295   grub_vbe_status_t status;
296   void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
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);
306 #else
307   mbi->vbe_control_info = 0;
308 #endif
309
310 #if GRUB_MACHINE_HAS_VBE  
311   status = grub_vbe_bios_get_mode (scratch);
312   vbe_mode = *(grub_uint32_t *) scratch;
313   if (status != GRUB_VBE_STATUS_OK)
314     return grub_error (GRUB_ERR_IO, "can't get VBE mode");
315 #else
316   vbe_mode = 3;
317 #endif
318   mbi->vbe_mode = vbe_mode;
319
320   mode_info = (struct grub_vbe_mode_info_block *) ptrorig;
321   mbi->vbe_mode_info = ptrdest;
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     {
332 #if GRUB_MACHINE_HAS_VBE  
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));
338 #endif
339     }
340   ptrorig += sizeof (struct grub_vbe_mode_info_block);
341   ptrdest += sizeof (struct grub_vbe_mode_info_block);
342
343 #if GRUB_MACHINE_HAS_VBE        
344   grub_vbe_bios_get_pm_interface (&mbi->vbe_interface_seg,
345                                   &mbi->vbe_interface_off,
346                                   &mbi->vbe_interface_len);
347 #endif
348   
349   mbi->flags |= MULTIBOOT_INFO_VBE_INFO;
350
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
366   return GRUB_ERR_NONE;
367 }
368 #endif
369
370 static grub_err_t
371 retrieve_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
380   err = grub_multiboot_set_video_mode ();
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 ();
390 #if GRUB_MACHINE_HAS_VGA_TEXT
391   if (driv_id == GRUB_VIDEO_DRIVER_NONE)
392     return fill_vbe_info (mbi, ptrorig, ptrdest, 1);
393 #else
394   if (driv_id == GRUB_VIDEO_DRIVER_NONE)
395     return GRUB_ERR_NONE;
396 #endif
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;
434       mbi->framebuffer_red_field_position = mode_info.red_field_pos;
435       mbi->framebuffer_red_mask_size = mode_info.red_mask_size;
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
444 #if GRUB_MACHINE_HAS_VBE
445   if (driv_id == GRUB_VIDEO_DRIVER_VBE)
446     return fill_vbe_info (mbi, ptrorig, ptrdest, 0);
447 #endif
448
449   return GRUB_ERR_NONE;
450 }
451
452 grub_err_t
453 grub_multiboot_make_mbi (grub_uint32_t *target)
454 {
455   struct multiboot_info *mbi;
456   struct multiboot_mod_list *modlist;
457   unsigned i;
458   struct module *cur;
459   grub_size_t mmap_size;
460   grub_uint8_t *ptrorig; 
461   grub_addr_t ptrdest;
462
463   grub_err_t err;
464   grub_size_t bufsize;
465   grub_relocator_chunk_t ch;
466
467   bufsize = grub_multiboot_get_mbi_size ();
468
469   err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch,
470                                           0x10000, 0xa0000 - bufsize,
471                                           bufsize, 4,
472                                           GRUB_RELOCATOR_PREFERENCE_NONE, 0);
473   if (err)
474     return err;
475   ptrorig = get_virtual_current_address (ch);
476   ptrdest = get_physical_target_address (ch);
477
478   *target = ptrdest;
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
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
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
545   mmap_size = grub_multiboot_get_mmap_count () 
546     * sizeof (struct multiboot_mmap_entry);
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
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
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;
588
589       ptrorig += elf_sec_entsize * elf_sec_num;
590       ptrdest += elf_sec_entsize * elf_sec_num;
591     }
592
593   err = retrieve_video_parameters (mbi, ptrorig, ptrdest);
594   if (err)
595     {
596       grub_print_error ();
597       grub_errno = GRUB_ERR_NONE;
598     }
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
609 #if GRUB_MACHINE_HAS_VBE
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
615
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
622   return GRUB_ERR_NONE;
623 }
624
625 void
626 grub_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
635 void
636 grub_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;
655
656   grub_free (elf_sections);
657   elf_sections = NULL;
658   elf_sec_entsize = 0;
659   elf_sec_num = 0;
660 }
661
662 grub_err_t
663 grub_multiboot_init_mbi (int argc, char *argv[])
664 {
665   grub_ssize_t len = 0;
666
667   grub_multiboot_free_mbi ();
668
669   len = grub_loader_cmdline_size (argc, argv);
670
671   cmdline = grub_malloc (len);
672   if (! cmdline)
673     return grub_errno;
674   cmdline_size = len;
675
676   grub_create_loader_cmdline (argc, argv, cmdline,
677                               cmdline_size);
678
679   return GRUB_ERR_NONE;
680 }
681
682 grub_err_t
683 grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
684                            int argc, char *argv[])
685 {
686   struct module *newmod;
687   grub_size_t len = 0;
688
689   newmod = grub_malloc (sizeof (*newmod));
690   if (!newmod)
691     return grub_errno;
692   newmod->start = start;
693   newmod->size = size;
694   newmod->next = 0;
695
696   len = grub_loader_cmdline_size (argc, argv);
697
698   newmod->cmdline = grub_malloc (len);
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
707   grub_create_loader_cmdline (argc, argv, newmod->cmdline,
708                               newmod->cmdline_size);
709
710   if (modules_last)
711     modules_last->next = newmod;
712   else
713     modules = newmod;
714   modules_last = newmod;
715
716   modcnt++;
717
718   return GRUB_ERR_NONE;
719 }
720
721 void
722 grub_multiboot_set_bootdev (void)
723 {
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
733   if (biosdev == 0xffffffff)
734     return;
735
736   dev = grub_device_open (0);
737   if (dev && dev->disk && dev->disk->partition)
738     {
739       if (dev->disk->partition->parent)
740         {
741           part = dev->disk->partition->number;
742           slice = dev->disk->partition->parent->number;
743         }
744       else
745         slice = dev->disk->partition->number;
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 }