]> git.proxmox.com Git - grub2.git/blob - grub-core/loader/multiboot_mbi2.c
Import grub2_2.02+dfsg1.orig.tar.xz
[grub2.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 }