b0679a9f6c9848d81cb74cf799ad3a7b235d937c
[grub.git] / grub-core / loader / multiboot_mbi2.c
1 /*
2  *  GRUB  --  GRand Unified Bootloader
3  *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009,2010,2011,2012,2013  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/multiboot.h>
27 #include <grub/cpu/relocator.h>
28 #include <grub/disk.h>
29 #include <grub/device.h>
30 #include <grub/partition.h>
31 #include <grub/mm.h>
32 #include <grub/misc.h>
33 #include <grub/env.h>
34 #include <grub/video.h>
35 #include <grub/acpi.h>
36 #include <grub/i18n.h>
37 #include <grub/net.h>
38 #include <grub/lib/cmdline.h>
39
40 #if defined (GRUB_MACHINE_EFI)
41 #include <grub/efi/efi.h>
42 #endif
43
44 #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_QEMU)
45 #include <grub/i386/pc/vbe.h>
46 #define HAS_VGA_TEXT 1
47 #else
48 #define HAS_VGA_TEXT 0
49 #endif
50
51 struct module
52 {
53   struct module *next;
54   grub_addr_t start;
55   grub_size_t size;
56   char *cmdline;
57   int cmdline_size;
58 };
59
60 static struct module *modules, *modules_last;
61 static grub_size_t cmdline_size;
62 static grub_size_t total_modcmd;
63 static unsigned modcnt;
64 static char *cmdline = NULL;
65 static int bootdev_set;
66 static grub_uint32_t biosdev, slice, part;
67 static grub_size_t elf_sec_num, elf_sec_entsize;
68 static unsigned elf_sec_shstrndx;
69 static void *elf_sections;
70 static int keep_bs = 0;
71 static grub_uint32_t load_base_addr;
72
73 void
74 grub_multiboot_add_elfsyms (grub_size_t num, grub_size_t entsize,
75                             unsigned shndx, void *data)
76 {
77   elf_sec_num = num;
78   elf_sec_shstrndx = shndx;
79   elf_sec_entsize = entsize;
80   elf_sections = data;
81 }
82
83 static struct multiboot_header *
84 find_header (grub_properly_aligned_t *buffer, grub_ssize_t len)
85 {
86   struct multiboot_header *header;
87   /* Look for the multiboot header in the buffer.  The header should
88      be at least 12 bytes and aligned on a 4-byte boundary.  */
89   for (header = (struct multiboot_header *) buffer;
90        ((char *) header <= (char *) buffer + len - 12);
91        header = (struct multiboot_header *) ((grub_uint32_t *) header + MULTIBOOT_HEADER_ALIGN / 4))
92     {
93       if (header->magic == MULTIBOOT_HEADER_MAGIC
94           && !(header->magic + header->architecture
95                + header->header_length + header->checksum)
96           && header->architecture == MULTIBOOT_ARCHITECTURE_CURRENT)
97         return header;
98     }
99   return NULL;
100 }
101
102 grub_err_t
103 grub_multiboot_load (grub_file_t file, const char *filename)
104 {
105   grub_ssize_t len;
106   struct multiboot_header *header;
107   grub_err_t err;
108   struct multiboot_header_tag *tag;
109   struct multiboot_header_tag_address *addr_tag = NULL;
110   struct multiboot_header_tag_relocatable *rel_tag;
111   int entry_specified = 0, efi_entry_specified = 0;
112   grub_addr_t entry = 0, efi_entry = 0;
113   grub_uint32_t console_required = 0;
114   struct multiboot_header_tag_framebuffer *fbtag = NULL;
115   int accepted_consoles = GRUB_MULTIBOOT_CONSOLE_EGA_TEXT;
116   mbi_load_data_t mld;
117
118   mld.mbi_ver = 2;
119   mld.relocatable = 0;
120
121   mld.buffer = grub_malloc (MULTIBOOT_SEARCH);
122   if (!mld.buffer)
123     return grub_errno;
124
125   len = grub_file_read (file, mld.buffer, MULTIBOOT_SEARCH);
126   if (len < 32)
127     {
128       grub_free (mld.buffer);
129       return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), filename);
130     }
131
132   COMPILE_TIME_ASSERT (MULTIBOOT_HEADER_ALIGN % 4 == 0);
133
134   header = find_header (mld.buffer, len);
135
136   if (header == 0)
137     {
138       grub_free (mld.buffer);
139       return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found");
140     }
141
142   COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN % 4 == 0);
143
144   keep_bs = 0;
145
146   for (tag = (struct multiboot_header_tag *) (header + 1);
147        tag->type != MULTIBOOT_TAG_TYPE_END;
148        tag = (struct multiboot_header_tag *) ((grub_uint32_t *) tag + ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / 4))
149     switch (tag->type)
150       {
151       case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST:
152         {
153           unsigned i;
154           struct multiboot_header_tag_information_request *request_tag
155             = (struct multiboot_header_tag_information_request *) tag;
156           if (request_tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL)
157             break;
158           for (i = 0; i < (request_tag->size - sizeof (*request_tag))
159                  / sizeof (request_tag->requests[0]); i++)
160             switch (request_tag->requests[i])
161               {
162               case MULTIBOOT_TAG_TYPE_END:
163               case MULTIBOOT_TAG_TYPE_CMDLINE:
164               case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
165               case MULTIBOOT_TAG_TYPE_MODULE:
166               case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
167               case MULTIBOOT_TAG_TYPE_BOOTDEV:
168               case MULTIBOOT_TAG_TYPE_MMAP:
169               case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
170               case MULTIBOOT_TAG_TYPE_VBE:
171               case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
172               case MULTIBOOT_TAG_TYPE_APM:
173               case MULTIBOOT_TAG_TYPE_EFI32:
174               case MULTIBOOT_TAG_TYPE_EFI64:
175               case MULTIBOOT_TAG_TYPE_ACPI_OLD:
176               case MULTIBOOT_TAG_TYPE_ACPI_NEW:
177               case MULTIBOOT_TAG_TYPE_NETWORK:
178               case MULTIBOOT_TAG_TYPE_EFI_MMAP:
179               case MULTIBOOT_TAG_TYPE_EFI_BS:
180               case MULTIBOOT_TAG_TYPE_EFI32_IH:
181               case MULTIBOOT_TAG_TYPE_EFI64_IH:
182               case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
183                 break;
184
185               default:
186                 grub_free (mld.buffer);
187                 return grub_error (GRUB_ERR_UNKNOWN_OS,
188                                    "unsupported information tag: 0x%x",
189                                    request_tag->requests[i]);
190               }
191           break;
192         }
193                
194       case MULTIBOOT_HEADER_TAG_ADDRESS:
195         addr_tag = (struct multiboot_header_tag_address *) tag;
196         break;
197
198       case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS:
199         entry_specified = 1;
200         entry = ((struct multiboot_header_tag_entry_address *) tag)->entry_addr;
201         break;
202
203       case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64:
204 #if defined (GRUB_MACHINE_EFI) && defined (__x86_64__)
205         efi_entry_specified = 1;
206         efi_entry = ((struct multiboot_header_tag_entry_address *) tag)->entry_addr;
207 #endif
208         break;
209
210       case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS:
211         if (!(((struct multiboot_header_tag_console_flags *) tag)->console_flags
212             & MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED))
213           accepted_consoles &= ~GRUB_MULTIBOOT_CONSOLE_EGA_TEXT;
214         if (((struct multiboot_header_tag_console_flags *) tag)->console_flags
215             & MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED)
216           console_required = 1;
217         break;
218
219       case MULTIBOOT_HEADER_TAG_FRAMEBUFFER:
220         fbtag = (struct multiboot_header_tag_framebuffer *) tag;
221         accepted_consoles |= GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER;
222         break;
223
224       case MULTIBOOT_HEADER_TAG_RELOCATABLE:
225         mld.relocatable = 1;
226         rel_tag = (struct multiboot_header_tag_relocatable *) tag;
227         mld.min_addr = rel_tag->min_addr;
228         mld.max_addr = rel_tag->max_addr;
229         mld.align = rel_tag->align;
230         switch (rel_tag->preference)
231           {
232           case MULTIBOOT_LOAD_PREFERENCE_LOW:
233             mld.preference = GRUB_RELOCATOR_PREFERENCE_LOW;
234             break;
235
236           case MULTIBOOT_LOAD_PREFERENCE_HIGH:
237             mld.preference = GRUB_RELOCATOR_PREFERENCE_HIGH;
238             break;
239
240           default:
241             mld.preference = GRUB_RELOCATOR_PREFERENCE_NONE;
242           }
243         break;
244
245         /* GRUB always page-aligns modules.  */
246       case MULTIBOOT_HEADER_TAG_MODULE_ALIGN:
247         break;
248
249       case MULTIBOOT_HEADER_TAG_EFI_BS:
250 #ifdef GRUB_MACHINE_EFI
251         keep_bs = 1;
252 #endif
253         break;
254
255       default:
256         if (! (tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL))
257           {
258             grub_free (mld.buffer);
259             return grub_error (GRUB_ERR_UNKNOWN_OS,
260                                "unsupported tag: 0x%x", tag->type);
261           }
262         break;
263       }
264
265   if (addr_tag && !entry_specified && !(keep_bs && efi_entry_specified))
266     {
267       grub_free (mld.buffer);
268       return grub_error (GRUB_ERR_UNKNOWN_OS,
269                          "load address tag without entry address tag");
270     }
271  
272   if (addr_tag)
273     {
274       grub_uint64_t load_addr = (addr_tag->load_addr + 1)
275         ? addr_tag->load_addr : (addr_tag->header_addr
276                                  - ((char *) header - (char *) mld.buffer));
277       int offset = ((char *) header - (char *) mld.buffer -
278            (addr_tag->header_addr - load_addr));
279       int load_size = ((addr_tag->load_end_addr == 0) ? file->size - offset :
280                        addr_tag->load_end_addr - addr_tag->load_addr);
281       grub_size_t code_size;
282       void *source;
283       grub_relocator_chunk_t ch;
284
285       if (addr_tag->bss_end_addr)
286         code_size = (addr_tag->bss_end_addr - load_addr);
287       else
288         code_size = load_size;
289
290       if (mld.relocatable)
291         {
292           if (code_size > mld.max_addr || mld.min_addr > mld.max_addr - code_size)
293             {
294               grub_free (mld.buffer);
295               return grub_error (GRUB_ERR_BAD_OS, "invalid min/max address and/or load size");
296             }
297
298           err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch,
299                                                   mld.min_addr, mld.max_addr - code_size,
300                                                   code_size, mld.align ? mld.align : 1,
301                                                   mld.preference, keep_bs);
302         }
303       else
304         err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator,
305                                                &ch, load_addr, code_size);
306       if (err)
307         {
308           grub_dprintf ("multiboot_loader", "Error loading aout kludge\n");
309           grub_free (mld.buffer);
310           return err;
311         }
312       mld.link_base_addr = load_addr;
313       mld.load_base_addr = get_physical_target_address (ch);
314       source = get_virtual_current_address (ch);
315
316       grub_dprintf ("multiboot_loader", "link_base_addr=0x%x, load_base_addr=0x%x, "
317                     "load_size=0x%lx, relocatable=%d\n", mld.link_base_addr,
318                     mld.load_base_addr, (long) code_size, mld.relocatable);
319
320       if (mld.relocatable)
321         grub_dprintf ("multiboot_loader", "align=0x%lx, preference=0x%x, avoid_efi_boot_services=%d\n",
322                       (long) mld.align, mld.preference, keep_bs);
323
324       if ((grub_file_seek (file, offset)) == (grub_off_t) -1)
325         {
326           grub_free (mld.buffer);
327           return grub_errno;
328         }
329
330       grub_file_read (file, source, load_size);
331       if (grub_errno)
332         {
333           grub_free (mld.buffer);
334           return grub_errno;
335         }
336
337       if (addr_tag->bss_end_addr)
338         grub_memset ((grub_uint8_t *) source + load_size, 0,
339                      addr_tag->bss_end_addr - load_addr - load_size);
340     }
341   else
342     {
343       mld.file = file;
344       mld.filename = filename;
345       mld.avoid_efi_boot_services = keep_bs;
346       err = grub_multiboot_load_elf (&mld);
347       if (err)
348         {
349           grub_free (mld.buffer);
350           return err;
351         }
352     }
353
354   load_base_addr = mld.load_base_addr;
355
356   if (keep_bs && efi_entry_specified)
357     grub_multiboot_payload_eip = efi_entry;
358   else if (entry_specified)
359     grub_multiboot_payload_eip = entry;
360
361   if (mld.relocatable)
362     {
363       /*
364        * Both branches are mathematically equivalent. However, it looks
365        * that real life (C?) is more complicated. I am trying to avoid
366        * wrap around here if mld.load_base_addr < mld.link_base_addr.
367        * If you look at C operator precedence then everything should work.
368        * However, I am not 100% sure that a given compiler will not
369        * optimize/break this stuff. So, maybe we should use signed
370        * 64-bit int here.
371        */
372       if (mld.load_base_addr >= mld.link_base_addr)
373         grub_multiboot_payload_eip += mld.load_base_addr - mld.link_base_addr;
374       else
375         grub_multiboot_payload_eip -= mld.link_base_addr - mld.load_base_addr;
376     }
377
378   if (fbtag)
379     err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
380                                       accepted_consoles,
381                                       fbtag->width, fbtag->height,
382                                       fbtag->depth, console_required);
383   else
384     err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
385                                       accepted_consoles,
386                                       0, 0, 0, console_required);
387   return err;
388 }
389
390 static grub_size_t
391 acpiv2_size (void)
392 {
393 #if GRUB_MACHINE_HAS_ACPI
394   struct grub_acpi_rsdp_v20 *p = grub_acpi_get_rsdpv2 ();
395
396   if (!p)
397     return 0;
398
399   return ALIGN_UP (sizeof (struct multiboot_tag_old_acpi)
400                    + p->length, MULTIBOOT_TAG_ALIGN);
401 #else
402   return 0;
403 #endif
404 }
405
406 #ifdef GRUB_MACHINE_EFI
407
408 static grub_efi_uintn_t efi_mmap_size = 0;
409
410 /* Find the optimal number of pages for the memory map. Is it better to
411    move this code to efi/mm.c?  */
412 static void
413 find_efi_mmap_size (void)
414 {
415   efi_mmap_size = (1 << 12);
416   while (1)
417     {
418       int ret;
419       grub_efi_memory_descriptor_t *mmap;
420       grub_efi_uintn_t desc_size;
421       grub_efi_uintn_t cur_mmap_size = efi_mmap_size;
422
423       mmap = grub_malloc (cur_mmap_size);
424       if (! mmap)
425         return;
426
427       ret = grub_efi_get_memory_map (&cur_mmap_size, mmap, 0, &desc_size, 0);
428       grub_free (mmap);
429
430       if (ret < 0)
431         return;
432       else if (ret > 0)
433         break;
434
435       if (efi_mmap_size < cur_mmap_size)
436         efi_mmap_size = cur_mmap_size;
437       efi_mmap_size += (1 << 12);
438     }
439
440   /* Increase the size a bit for safety, because GRUB allocates more on
441      later, and EFI itself may allocate more.  */
442   efi_mmap_size += (3 << 12);
443
444   efi_mmap_size = ALIGN_UP (efi_mmap_size, 4096);
445 }
446 #endif
447
448 static grub_size_t
449 net_size (void)
450 {
451   struct grub_net_network_level_interface *net;
452   grub_size_t ret = 0;
453
454   FOR_NET_NETWORK_LEVEL_INTERFACES(net)
455     if (net->dhcp_ack)
456       ret += ALIGN_UP (sizeof (struct multiboot_tag_network) + net->dhcp_acklen,
457                        MULTIBOOT_TAG_ALIGN);
458   return ret;
459 }
460
461 static grub_size_t
462 grub_multiboot_get_mbi_size (void)
463 {
464 #ifdef GRUB_MACHINE_EFI
465   if (!keep_bs && !efi_mmap_size)
466     find_efi_mmap_size ();    
467 #endif
468   return 2 * sizeof (grub_uint32_t) + sizeof (struct multiboot_tag)
469     + sizeof (struct multiboot_tag)
470     + (sizeof (struct multiboot_tag_string)
471        + ALIGN_UP (cmdline_size, MULTIBOOT_TAG_ALIGN))
472     + (sizeof (struct multiboot_tag_string)
473        + ALIGN_UP (sizeof (PACKAGE_STRING), MULTIBOOT_TAG_ALIGN))
474     + (modcnt * sizeof (struct multiboot_tag_module) + total_modcmd)
475     + ALIGN_UP (sizeof (struct multiboot_tag_basic_meminfo),
476                 MULTIBOOT_TAG_ALIGN)
477     + ALIGN_UP (sizeof (struct multiboot_tag_bootdev), MULTIBOOT_TAG_ALIGN)
478     + ALIGN_UP (sizeof (struct multiboot_tag_elf_sections), MULTIBOOT_TAG_ALIGN)
479     + ALIGN_UP (elf_sec_entsize * elf_sec_num, MULTIBOOT_TAG_ALIGN)
480     + ALIGN_UP ((sizeof (struct multiboot_tag_mmap)
481                  + grub_get_multiboot_mmap_count ()
482                  * sizeof (struct multiboot_mmap_entry)), MULTIBOOT_TAG_ALIGN)
483     + ALIGN_UP (sizeof (struct multiboot_tag_framebuffer), MULTIBOOT_TAG_ALIGN)
484     + ALIGN_UP (sizeof (struct multiboot_tag_old_acpi)
485                 + sizeof (struct grub_acpi_rsdp_v10), MULTIBOOT_TAG_ALIGN)
486     + ALIGN_UP (sizeof (struct multiboot_tag_load_base_addr), MULTIBOOT_TAG_ALIGN)
487     + acpiv2_size ()
488     + net_size ()
489 #ifdef GRUB_MACHINE_EFI
490     + ALIGN_UP (sizeof (struct multiboot_tag_efi32), MULTIBOOT_TAG_ALIGN)
491     + ALIGN_UP (sizeof (struct multiboot_tag_efi32_ih), MULTIBOOT_TAG_ALIGN)
492     + ALIGN_UP (sizeof (struct multiboot_tag_efi64), MULTIBOOT_TAG_ALIGN)
493     + ALIGN_UP (sizeof (struct multiboot_tag_efi64_ih), MULTIBOOT_TAG_ALIGN)
494     + ALIGN_UP (sizeof (struct multiboot_tag_efi_mmap)
495                 + efi_mmap_size, MULTIBOOT_TAG_ALIGN)
496 #endif
497     + sizeof (struct multiboot_tag_vbe) + MULTIBOOT_TAG_ALIGN - 1
498     + sizeof (struct multiboot_tag_apm) + MULTIBOOT_TAG_ALIGN - 1;
499 }
500
501 /* Helper for grub_fill_multiboot_mmap.  */
502 static int
503 grub_fill_multiboot_mmap_iter (grub_uint64_t addr, grub_uint64_t size,
504                                grub_memory_type_t type, void *data)
505 {
506   struct multiboot_mmap_entry **mmap_entry = data;
507
508   (*mmap_entry)->addr = addr;
509   (*mmap_entry)->len = size;
510   (*mmap_entry)->type = type;
511   (*mmap_entry)->zero = 0;
512   (*mmap_entry)++;
513
514   return 0;
515 }
516
517 /* Fill previously allocated Multiboot mmap.  */
518 static void
519 grub_fill_multiboot_mmap (struct multiboot_tag_mmap *tag)
520 {
521   struct multiboot_mmap_entry *mmap_entry = tag->entries;
522
523   tag->type = MULTIBOOT_TAG_TYPE_MMAP;
524   tag->size = sizeof (struct multiboot_tag_mmap)
525     + sizeof (struct multiboot_mmap_entry) * grub_get_multiboot_mmap_count (); 
526   tag->entry_size = sizeof (struct multiboot_mmap_entry);
527   tag->entry_version = 0;
528
529   grub_mmap_iterate (grub_fill_multiboot_mmap_iter, &mmap_entry);
530 }
531
532 #if defined (GRUB_MACHINE_PCBIOS)
533 static void
534 fill_vbe_tag (struct multiboot_tag_vbe *tag)
535 {
536   grub_vbe_status_t status;
537   void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
538
539   tag->type = MULTIBOOT_TAG_TYPE_VBE;
540   tag->size = 0;
541     
542   status = grub_vbe_bios_get_controller_info (scratch);
543   if (status != GRUB_VBE_STATUS_OK)
544     return;
545   
546   grub_memcpy (&tag->vbe_control_info, scratch,
547                sizeof (struct grub_vbe_info_block));
548   
549   status = grub_vbe_bios_get_mode (scratch);
550   tag->vbe_mode = *(grub_uint32_t *) scratch;
551   if (status != GRUB_VBE_STATUS_OK)
552     return;
553
554   /* get_mode_info isn't available for mode 3.  */
555   if (tag->vbe_mode == 3)
556     {
557       struct grub_vbe_mode_info_block *mode_info = (void *) &tag->vbe_mode_info;
558       grub_memset (mode_info, 0,
559                    sizeof (struct grub_vbe_mode_info_block));
560       mode_info->memory_model = GRUB_VBE_MEMORY_MODEL_TEXT;
561       mode_info->x_resolution = 80;
562       mode_info->y_resolution = 25;
563     }
564   else
565     {
566       status = grub_vbe_bios_get_mode_info (tag->vbe_mode, scratch);
567       if (status != GRUB_VBE_STATUS_OK)
568         return;
569       grub_memcpy (&tag->vbe_mode_info, scratch,
570                    sizeof (struct grub_vbe_mode_info_block));
571     }      
572   grub_vbe_bios_get_pm_interface (&tag->vbe_interface_seg,
573                                   &tag->vbe_interface_off,
574                                   &tag->vbe_interface_len);
575
576   tag->size = sizeof (*tag);
577 }
578 #endif
579
580 static grub_err_t
581 retrieve_video_parameters (grub_properly_aligned_t **ptrorig)
582 {
583   grub_err_t err;
584   struct grub_video_mode_info mode_info;
585   void *framebuffer;
586   grub_video_driver_id_t driv_id;
587   struct grub_video_palette_data palette[256];
588   struct multiboot_tag_framebuffer *tag
589     = (struct multiboot_tag_framebuffer *) *ptrorig;
590
591   err = grub_multiboot_set_video_mode ();
592   if (err)
593     {
594       grub_print_error ();
595       grub_errno = GRUB_ERR_NONE;
596     }
597
598   grub_video_get_palette (0, ARRAY_SIZE (palette), palette);
599
600   driv_id = grub_video_get_driver_id ();
601 #if HAS_VGA_TEXT
602   if (driv_id == GRUB_VIDEO_DRIVER_NONE)
603     {
604       struct grub_vbe_mode_info_block vbe_mode_info;
605       grub_uint32_t vbe_mode;
606
607 #if defined (GRUB_MACHINE_PCBIOS)
608       {
609         grub_vbe_status_t status;
610         void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
611         status = grub_vbe_bios_get_mode (scratch);
612         vbe_mode = *(grub_uint32_t *) scratch;
613         if (status != GRUB_VBE_STATUS_OK)
614           return GRUB_ERR_NONE;
615       }
616 #else
617       vbe_mode = 3;
618 #endif
619
620       /* get_mode_info isn't available for mode 3.  */
621       if (vbe_mode == 3)
622         {
623           grub_memset (&vbe_mode_info, 0,
624                        sizeof (struct grub_vbe_mode_info_block));
625           vbe_mode_info.memory_model = GRUB_VBE_MEMORY_MODEL_TEXT;
626           vbe_mode_info.x_resolution = 80;
627           vbe_mode_info.y_resolution = 25;
628         }
629 #if defined (GRUB_MACHINE_PCBIOS)
630       else
631         {
632           grub_vbe_status_t status;
633           void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
634           status = grub_vbe_bios_get_mode_info (vbe_mode, scratch);
635           if (status != GRUB_VBE_STATUS_OK)
636             return GRUB_ERR_NONE;
637           grub_memcpy (&vbe_mode_info, scratch,
638                        sizeof (struct grub_vbe_mode_info_block));
639         }
640 #endif
641
642       if (vbe_mode_info.memory_model == GRUB_VBE_MEMORY_MODEL_TEXT)
643         {
644           tag = (struct multiboot_tag_framebuffer *) *ptrorig;
645           tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
646           tag->common.size = 0;
647
648           tag->common.framebuffer_addr = 0xb8000;
649           
650           tag->common.framebuffer_pitch = 2 * vbe_mode_info.x_resolution;       
651           tag->common.framebuffer_width = vbe_mode_info.x_resolution;
652           tag->common.framebuffer_height = vbe_mode_info.y_resolution;
653
654           tag->common.framebuffer_bpp = 16;
655           
656           tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT;
657           tag->common.size = sizeof (tag->common);
658           tag->common.reserved = 0;
659           *ptrorig += ALIGN_UP (tag->common.size, MULTIBOOT_TAG_ALIGN)
660             / sizeof (grub_properly_aligned_t);
661         }
662       return GRUB_ERR_NONE;
663     }
664 #else
665   if (driv_id == GRUB_VIDEO_DRIVER_NONE)
666     return GRUB_ERR_NONE;
667 #endif
668
669 #if GRUB_MACHINE_HAS_VBE
670   {
671     struct multiboot_tag_vbe *tag_vbe = (struct multiboot_tag_vbe *) *ptrorig;
672
673     fill_vbe_tag (tag_vbe);
674
675     *ptrorig += ALIGN_UP (tag_vbe->size, MULTIBOOT_TAG_ALIGN)
676       / sizeof (grub_properly_aligned_t);
677   }
678 #endif
679
680   err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
681   if (err)
682     return err;
683
684   tag = (struct multiboot_tag_framebuffer *) *ptrorig;
685   tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
686   tag->common.size = 0;
687
688   tag->common.framebuffer_addr = (grub_addr_t) framebuffer;
689   tag->common.framebuffer_pitch = mode_info.pitch;
690
691   tag->common.framebuffer_width = mode_info.width;
692   tag->common.framebuffer_height = mode_info.height;
693
694   tag->common.framebuffer_bpp = mode_info.bpp;
695
696   tag->common.reserved = 0;
697       
698   if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)
699     {
700       unsigned i;
701       tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED;
702       tag->framebuffer_palette_num_colors = mode_info.number_of_colors;
703       if (tag->framebuffer_palette_num_colors > ARRAY_SIZE (palette))
704         tag->framebuffer_palette_num_colors = ARRAY_SIZE (palette);
705       tag->common.size = sizeof (struct multiboot_tag_framebuffer_common)
706         + sizeof (multiboot_uint16_t) + tag->framebuffer_palette_num_colors
707         * sizeof (struct multiboot_color);
708       for (i = 0; i < tag->framebuffer_palette_num_colors; i++)
709         {
710           tag->framebuffer_palette[i].red = palette[i].r;
711           tag->framebuffer_palette[i].green = palette[i].g;
712           tag->framebuffer_palette[i].blue = palette[i].b;
713         }
714     }
715   else
716     {
717       tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB;
718       tag->framebuffer_red_field_position = mode_info.red_field_pos;
719       tag->framebuffer_red_mask_size = mode_info.red_mask_size;
720       tag->framebuffer_green_field_position = mode_info.green_field_pos;
721       tag->framebuffer_green_mask_size = mode_info.green_mask_size;
722       tag->framebuffer_blue_field_position = mode_info.blue_field_pos;
723       tag->framebuffer_blue_mask_size = mode_info.blue_mask_size;
724
725       tag->common.size = sizeof (struct multiboot_tag_framebuffer_common) + 6;
726     }
727   *ptrorig += ALIGN_UP (tag->common.size, MULTIBOOT_TAG_ALIGN)
728     / sizeof (grub_properly_aligned_t);
729
730   return GRUB_ERR_NONE;
731 }
732
733 grub_err_t
734 grub_multiboot_make_mbi (grub_uint32_t *target)
735 {
736   grub_properly_aligned_t *ptrorig;
737   grub_properly_aligned_t *mbistart;
738   grub_err_t err;
739   grub_size_t bufsize;
740   grub_relocator_chunk_t ch;
741
742   bufsize = grub_multiboot_get_mbi_size ();
743
744   COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN % sizeof (grub_properly_aligned_t) == 0);
745
746   err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch,
747                                           0, 0xffffffff - bufsize,
748                                           bufsize, MULTIBOOT_TAG_ALIGN,
749                                           GRUB_RELOCATOR_PREFERENCE_NONE, 1);
750   if (err)
751     return err;
752
753   ptrorig = get_virtual_current_address (ch);
754 #if defined (__i386__) || defined (__x86_64__)
755   *target = get_physical_target_address (ch);
756 #elif defined (__mips)
757   *target = get_physical_target_address (ch) | 0x80000000;
758 #else
759 #error Please complete this
760 #endif
761
762   mbistart = ptrorig;
763   COMPILE_TIME_ASSERT ((2 * sizeof (grub_uint32_t))
764                        % sizeof (grub_properly_aligned_t) == 0);
765   COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN
766                        % sizeof (grub_properly_aligned_t) == 0);
767   ptrorig += (2 * sizeof (grub_uint32_t)) / sizeof (grub_properly_aligned_t);
768
769   {
770     struct multiboot_tag_load_base_addr *tag = (struct multiboot_tag_load_base_addr *) ptrorig;
771     tag->type = MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR;
772     tag->size = sizeof (struct multiboot_tag_load_base_addr);
773     tag->load_base_addr = load_base_addr;
774     ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
775        / sizeof (grub_properly_aligned_t);
776   }
777
778   {
779     struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig;
780     tag->type = MULTIBOOT_TAG_TYPE_CMDLINE;
781     tag->size = sizeof (struct multiboot_tag_string) + cmdline_size; 
782     grub_memcpy (tag->string, cmdline, cmdline_size);
783     ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
784        / sizeof (grub_properly_aligned_t);
785   }
786
787   {
788     struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig;
789     tag->type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME;
790     tag->size = sizeof (struct multiboot_tag_string) + sizeof (PACKAGE_STRING); 
791     grub_memcpy (tag->string, PACKAGE_STRING, sizeof (PACKAGE_STRING));
792     ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
793       / sizeof (grub_properly_aligned_t);
794   }
795
796 #ifdef GRUB_MACHINE_PCBIOS
797   {
798     struct grub_apm_info info;
799     if (grub_apm_get_info (&info))
800       {
801         struct multiboot_tag_apm *tag = (struct multiboot_tag_apm *) ptrorig;
802
803         tag->type = MULTIBOOT_TAG_TYPE_APM;
804         tag->size = sizeof (struct multiboot_tag_apm); 
805
806         tag->cseg = info.cseg;
807         tag->offset = info.offset;
808         tag->cseg_16 = info.cseg_16;
809         tag->dseg = info.dseg;
810         tag->flags = info.flags;
811         tag->cseg_len = info.cseg_len;
812         tag->dseg_len = info.dseg_len;
813         tag->cseg_16_len = info.cseg_16_len;
814         tag->version = info.version;
815
816         ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
817           / sizeof (grub_properly_aligned_t);
818       }
819   }
820 #endif
821
822   {
823     unsigned i;
824     struct module *cur;
825
826     for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next)
827       {
828         struct multiboot_tag_module *tag
829           = (struct multiboot_tag_module *) ptrorig;
830         tag->type = MULTIBOOT_TAG_TYPE_MODULE;
831         tag->size = sizeof (struct multiboot_tag_module) + cur->cmdline_size;
832         tag->mod_start = cur->start;
833         tag->mod_end = tag->mod_start + cur->size;
834         grub_memcpy (tag->cmdline, cur->cmdline, cur->cmdline_size);
835         ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
836           / sizeof (grub_properly_aligned_t);
837       }
838   }
839
840   if (!keep_bs)
841     {
842       struct multiboot_tag_mmap *tag = (struct multiboot_tag_mmap *) ptrorig;
843       grub_fill_multiboot_mmap (tag);
844       ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
845         / sizeof (grub_properly_aligned_t);
846     }
847
848   {
849     struct multiboot_tag_elf_sections *tag
850       = (struct multiboot_tag_elf_sections *) ptrorig;
851     tag->type = MULTIBOOT_TAG_TYPE_ELF_SECTIONS;
852     tag->size = sizeof (struct multiboot_tag_elf_sections)
853       + elf_sec_entsize * elf_sec_num;
854     grub_memcpy (tag->sections, elf_sections, elf_sec_entsize * elf_sec_num);
855     tag->num = elf_sec_num;
856     tag->entsize = elf_sec_entsize;
857     tag->shndx = elf_sec_shstrndx;
858     ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
859       / sizeof (grub_properly_aligned_t);
860   }
861
862   if (!keep_bs)
863     {
864       struct multiboot_tag_basic_meminfo *tag
865         = (struct multiboot_tag_basic_meminfo *) ptrorig;
866       tag->type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO;
867       tag->size = sizeof (struct multiboot_tag_basic_meminfo);
868
869       /* Convert from bytes to kilobytes.  */
870       tag->mem_lower = grub_mmap_get_lower () / 1024;
871       tag->mem_upper = grub_mmap_get_upper () / 1024;
872       ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
873         / sizeof (grub_properly_aligned_t);
874     }
875
876   {
877     struct grub_net_network_level_interface *net;
878
879     FOR_NET_NETWORK_LEVEL_INTERFACES(net)
880       if (net->dhcp_ack)
881         {
882           struct multiboot_tag_network *tag
883             = (struct multiboot_tag_network *) ptrorig;
884           tag->type = MULTIBOOT_TAG_TYPE_NETWORK;
885           tag->size = sizeof (struct multiboot_tag_network) + net->dhcp_acklen;
886           grub_memcpy (tag->dhcpack, net->dhcp_ack, net->dhcp_acklen);
887           ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
888             / sizeof (grub_properly_aligned_t);
889         }
890   }
891
892   if (bootdev_set)
893     {
894       struct multiboot_tag_bootdev *tag
895         = (struct multiboot_tag_bootdev *) ptrorig;
896       tag->type = MULTIBOOT_TAG_TYPE_BOOTDEV;
897       tag->size = sizeof (struct multiboot_tag_bootdev); 
898
899       tag->biosdev = biosdev;
900       tag->slice = slice;
901       tag->part = part;
902       ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
903         / sizeof (grub_properly_aligned_t);
904     }
905
906   {
907     err = retrieve_video_parameters (&ptrorig);
908     if (err)
909       {
910         grub_print_error ();
911         grub_errno = GRUB_ERR_NONE;
912       }
913   }
914
915 #if defined (GRUB_MACHINE_EFI) && defined (__x86_64__)
916   {
917     struct multiboot_tag_efi64 *tag = (struct multiboot_tag_efi64 *) ptrorig;
918     tag->type = MULTIBOOT_TAG_TYPE_EFI64;
919     tag->size = sizeof (*tag);
920     tag->pointer = (grub_addr_t) grub_efi_system_table;
921     ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
922       / sizeof (grub_properly_aligned_t);
923   }
924 #endif
925
926 #if defined (GRUB_MACHINE_EFI) && defined (__i386__)
927   {
928     struct multiboot_tag_efi32 *tag = (struct multiboot_tag_efi32 *) ptrorig;
929     tag->type = MULTIBOOT_TAG_TYPE_EFI32;
930     tag->size = sizeof (*tag);
931     tag->pointer = (grub_addr_t) grub_efi_system_table;
932     ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
933       / sizeof (grub_properly_aligned_t);
934   }
935 #endif
936
937 #if GRUB_MACHINE_HAS_ACPI
938   {
939     struct multiboot_tag_old_acpi *tag = (struct multiboot_tag_old_acpi *)
940       ptrorig;
941     struct grub_acpi_rsdp_v10 *a = grub_acpi_get_rsdpv1 ();
942     if (a)
943       {
944         tag->type = MULTIBOOT_TAG_TYPE_ACPI_OLD;
945         tag->size = sizeof (*tag) + sizeof (*a);
946         grub_memcpy (tag->rsdp, a, sizeof (*a));
947         ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
948           / sizeof (grub_properly_aligned_t);
949       }
950   }
951
952   {
953     struct multiboot_tag_new_acpi *tag = (struct multiboot_tag_new_acpi *)
954       ptrorig;
955     struct grub_acpi_rsdp_v20 *a = grub_acpi_get_rsdpv2 ();
956     if (a)
957       {
958         tag->type = MULTIBOOT_TAG_TYPE_ACPI_NEW;
959         tag->size = sizeof (*tag) + a->length;
960         grub_memcpy (tag->rsdp, a, a->length);
961         ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
962           / sizeof (grub_properly_aligned_t);
963       }
964   }
965 #endif
966
967 #ifdef GRUB_MACHINE_EFI
968   {
969     struct multiboot_tag_efi_mmap *tag = (struct multiboot_tag_efi_mmap *) ptrorig;
970     grub_efi_uintn_t efi_desc_size;
971     grub_efi_uint32_t efi_desc_version;
972
973     if (!keep_bs)
974       {
975         tag->type = MULTIBOOT_TAG_TYPE_EFI_MMAP;
976         tag->size = sizeof (*tag) + efi_mmap_size;
977
978         err = grub_efi_finish_boot_services (&efi_mmap_size, tag->efi_mmap, NULL,
979                                              &efi_desc_size, &efi_desc_version);
980
981         if (err)
982           return err;
983
984         tag->descr_size = efi_desc_size;
985         tag->descr_vers = efi_desc_version;
986         tag->size = sizeof (*tag) + efi_mmap_size;
987
988         ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
989           / sizeof (grub_properly_aligned_t);
990       }
991   }
992
993   if (keep_bs)
994     {
995       {
996         struct multiboot_tag *tag = (struct multiboot_tag *) ptrorig;
997         tag->type = MULTIBOOT_TAG_TYPE_EFI_BS;
998         tag->size = sizeof (struct multiboot_tag);
999         ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
1000           / sizeof (grub_properly_aligned_t);
1001       }
1002
1003 #ifdef __i386__
1004       {
1005         struct multiboot_tag_efi32_ih *tag = (struct multiboot_tag_efi32_ih *) ptrorig;
1006         tag->type = MULTIBOOT_TAG_TYPE_EFI32_IH;
1007         tag->size = sizeof (struct multiboot_tag_efi32_ih);
1008         tag->pointer = (grub_addr_t) grub_efi_image_handle;
1009         ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
1010           / sizeof (grub_properly_aligned_t);
1011       }
1012 #endif
1013
1014 #ifdef __x86_64__
1015       {
1016         struct multiboot_tag_efi64_ih *tag = (struct multiboot_tag_efi64_ih *) ptrorig;
1017         tag->type = MULTIBOOT_TAG_TYPE_EFI64_IH;
1018         tag->size = sizeof (struct multiboot_tag_efi64_ih);
1019         tag->pointer = (grub_addr_t) grub_efi_image_handle;
1020         ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
1021           / sizeof (grub_properly_aligned_t);
1022       }
1023 #endif
1024     }
1025 #endif
1026
1027   {
1028     struct multiboot_tag *tag = (struct multiboot_tag *) ptrorig;
1029     tag->type = MULTIBOOT_TAG_TYPE_END;
1030     tag->size = sizeof (struct multiboot_tag);
1031     ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
1032       / sizeof (grub_properly_aligned_t);
1033   }
1034
1035   ((grub_uint32_t *) mbistart)[0] = (char *) ptrorig - (char *) mbistart;
1036   ((grub_uint32_t *) mbistart)[1] = 0;
1037
1038   return GRUB_ERR_NONE;
1039 }
1040
1041 void
1042 grub_multiboot_free_mbi (void)
1043 {
1044   struct module *cur, *next;
1045
1046   cmdline_size = 0;
1047   total_modcmd = 0;
1048   modcnt = 0;
1049   grub_free (cmdline);
1050   cmdline = NULL;
1051   bootdev_set = 0;
1052
1053   for (cur = modules; cur; cur = next)
1054     {
1055       next = cur->next;
1056       grub_free (cur->cmdline);
1057       grub_free (cur);
1058     }
1059   modules = NULL;
1060   modules_last = NULL;
1061 }
1062
1063 grub_err_t
1064 grub_multiboot_init_mbi (int argc, char *argv[])
1065 {
1066   grub_ssize_t len = 0;
1067
1068   grub_multiboot_free_mbi ();
1069
1070   len = grub_loader_cmdline_size (argc, argv);
1071
1072   cmdline = grub_malloc (len);
1073   if (! cmdline)
1074     return grub_errno;
1075   cmdline_size = len;
1076
1077   grub_create_loader_cmdline (argc, argv, cmdline,
1078                               cmdline_size);
1079
1080   return GRUB_ERR_NONE;
1081 }
1082
1083 grub_err_t
1084 grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
1085                            int argc, char *argv[])
1086 {
1087   struct module *newmod;
1088   grub_size_t len = 0;
1089
1090   newmod = grub_malloc (sizeof (*newmod));
1091   if (!newmod)
1092     return grub_errno;
1093   newmod->start = start;
1094   newmod->size = size;
1095
1096   len = grub_loader_cmdline_size (argc, argv);
1097
1098   newmod->cmdline = grub_malloc (len);
1099   if (! newmod->cmdline)
1100     {
1101       grub_free (newmod);
1102       return grub_errno;
1103     }
1104   newmod->cmdline_size = len;
1105   total_modcmd += ALIGN_UP (len, MULTIBOOT_TAG_ALIGN);
1106
1107   grub_create_loader_cmdline (argc, argv, newmod->cmdline,
1108                               newmod->cmdline_size);
1109
1110   if (modules_last)
1111     modules_last->next = newmod;
1112   else
1113     modules = newmod;
1114   modules_last = newmod;
1115
1116   modcnt++;
1117
1118   return GRUB_ERR_NONE;
1119 }
1120
1121 void
1122 grub_multiboot_set_bootdev (void)
1123 {
1124   grub_device_t dev;
1125
1126   slice = ~0;
1127   part = ~0;
1128
1129 #ifdef GRUB_MACHINE_PCBIOS
1130   biosdev = grub_get_root_biosnumber ();
1131 #else
1132   biosdev = 0xffffffff;
1133 #endif
1134
1135   if (biosdev == 0xffffffff)
1136     return;
1137
1138   dev = grub_device_open (0);
1139   if (dev && dev->disk && dev->disk->partition)
1140     {
1141       if (dev->disk->partition->parent)
1142         {
1143           part = dev->disk->partition->number;
1144           slice = dev->disk->partition->parent->number;
1145         }
1146       else
1147         slice = dev->disk->partition->number;
1148     }
1149   if (dev)
1150     grub_device_close (dev);
1151
1152   bootdev_set = 1;
1153 }