static grub_err_t grub_linux_boot (void) { grub_err_t err = 0; const char *modevar; char *tmp; struct grub_relocator32_state state; void *real_mode_mem; struct grub_linux_boot_ctx ctx = { .real_mode_target = 0 }; grub_size_t mmap_size; grub_size_t cl_offset; #ifdef GRUB_MACHINE_IEEE1275 { const char *bootpath; grub_ssize_t len; bootpath = grub_env_get ("root"); if (bootpath) grub_ieee1275_set_property (grub_ieee1275_chosen, "bootpath", bootpath, grub_strlen (bootpath) + 1, &len); linux_params.ofw_signature = GRUB_LINUX_OFW_SIGNATURE; linux_params.ofw_num_items = 1; linux_params.ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn; linux_params.ofw_idt = 0; } #endif modevar = grub_env_get ("gfxpayload"); /* Now all graphical modes are acceptable. May change in future if we have modes without framebuffer. */ if (modevar && *modevar != 0) { tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar); if (! tmp) return grub_errno; #if ACCEPTS_PURE_TEXT err = grub_video_set_mode (tmp, 0, 0); #else err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); #endif grub_free (tmp); } else /* We can't go back to text mode from coreboot fb. */ #ifdef GRUB_MACHINE_COREBOOT if (grub_video_get_driver_id () == GRUB_VIDEO_DRIVER_COREBOOT) err = GRUB_ERR_NONE; else #endif { #if ACCEPTS_PURE_TEXT err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0); #else err = grub_video_set_mode (DEFAULT_VIDEO_MODE, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); #endif } if (err) { grub_print_error (); grub_puts_ (N_("Booting in blind mode")); grub_errno = GRUB_ERR_NONE; } if (grub_linux_setup_video (&linux_params)) { #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) linux_params.have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT; linux_params.video_mode = 0x3; #else linux_params.have_vga = 0; linux_params.video_mode = 0; linux_params.video_width = 0; linux_params.video_height = 0; #endif } #ifndef GRUB_MACHINE_IEEE1275 if (linux_params.have_vga == GRUB_VIDEO_LINUX_TYPE_TEXT) #endif { grub_term_output_t term; int found = 0; FOR_ACTIVE_TERM_OUTPUTS(term) if (grub_strcmp (term->name, "vga_text") == 0 || grub_strcmp (term->name, "console") == 0 || grub_strcmp (term->name, "ofconsole") == 0) { struct grub_term_coordinate pos = grub_term_getxy (term); linux_params.video_cursor_x = pos.x; linux_params.video_cursor_y = pos.y; linux_params.video_width = grub_term_width (term); linux_params.video_height = grub_term_height (term); found = 1; break; } if (!found) { linux_params.video_cursor_x = 0; linux_params.video_cursor_y = 0; linux_params.video_width = 80; linux_params.video_height = 25; } } mmap_size = find_mmap_size (); /* Make sure that each size is aligned to a page boundary. */ cl_offset = ALIGN_UP (mmap_size + sizeof (linux_params), 4096); if (cl_offset < ((grub_size_t) linux_params.setup_sects << GRUB_DISK_SECTOR_BITS)) cl_offset = ALIGN_UP ((grub_size_t) (linux_params.setup_sects << GRUB_DISK_SECTOR_BITS), 4096); ctx.real_size = ALIGN_UP (cl_offset + maximal_cmdline_size, 4096); #ifdef GRUB_MACHINE_EFI efi_mmap_size = find_efi_mmap_size (); if (efi_mmap_size == 0) return grub_errno; #endif grub_dprintf ("linux", "real_size = %x, mmap_size = %x\n", (unsigned) ctx.real_size, (unsigned) mmap_size); #ifdef GRUB_MACHINE_EFI grub_efi_mmap_iterate (grub_linux_boot_mmap_find, &ctx, 1); if (! ctx.real_mode_target) grub_efi_mmap_iterate (grub_linux_boot_mmap_find, &ctx, 0); #else grub_mmap_iterate (grub_linux_boot_mmap_find, &ctx); #endif grub_dprintf ("linux", "real_mode_target = %lx, real_size = %x, efi_mmap_size = %x\n", (unsigned long) ctx.real_mode_target, (unsigned) ctx.real_size, (unsigned) efi_mmap_size); if (! ctx.real_mode_target) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages"); { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, ctx.real_mode_target, (ctx.real_size + efi_mmap_size)); if (err) return err; real_mode_mem = get_virtual_current_address (ch); } efi_mmap_buf = (grub_uint8_t *) real_mode_mem + ctx.real_size; grub_dprintf ("linux", "real_mode_mem = %p\n", real_mode_mem); ctx.params = real_mode_mem; *ctx.params = linux_params; ctx.params->cmd_line_ptr = ctx.real_mode_target + cl_offset; grub_memcpy ((char *) ctx.params + cl_offset, linux_cmdline, maximal_cmdline_size); grub_dprintf ("linux", "code32_start = %x\n", (unsigned) ctx.params->code32_start); ctx.e820_num = 0; if (grub_mmap_iterate (grub_linux_boot_mmap_fill, &ctx)) return grub_errno; ctx.params->mmap_size = ctx.e820_num; #ifdef GRUB_MACHINE_EFI { grub_efi_uintn_t efi_desc_size; grub_size_t efi_mmap_target; grub_efi_uint32_t efi_desc_version; err = grub_efi_finish_boot_services (&efi_mmap_size, efi_mmap_buf, NULL, &efi_desc_size, &efi_desc_version); if (err) return err; /* Note that no boot services are available from here. */ efi_mmap_target = ctx.real_mode_target + ((grub_uint8_t *) efi_mmap_buf - (grub_uint8_t *) real_mode_mem); /* Pass EFI parameters. */ if (grub_le_to_cpu16 (ctx.params->version) >= 0x0208) { ctx.params->v0208.efi_mem_desc_size = efi_desc_size; ctx.params->v0208.efi_mem_desc_version = efi_desc_version; ctx.params->v0208.efi_mmap = efi_mmap_target; ctx.params->v0208.efi_mmap_size = efi_mmap_size; #ifdef __x86_64__ ctx.params->v0208.efi_mmap_hi = (efi_mmap_target >> 32); #endif } else if (grub_le_to_cpu16 (ctx.params->version) >= 0x0206)
grub_err_t grub_multiboot_make_mbi (grub_uint32_t *target) { grub_properly_aligned_t *ptrorig; grub_properly_aligned_t *mbistart; grub_err_t err; grub_size_t bufsize; grub_relocator_chunk_t ch; bufsize = grub_multiboot_get_mbi_size (); COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN % sizeof (grub_properly_aligned_t) == 0); err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, 0, 0xffffffff - bufsize, bufsize, MULTIBOOT_TAG_ALIGN, GRUB_RELOCATOR_PREFERENCE_NONE, 1); if (err) return err; ptrorig = get_virtual_current_address (ch); #if defined (__i386__) || defined (__x86_64__) *target = get_physical_target_address (ch); #elif defined (__mips) *target = get_physical_target_address (ch) | 0x80000000; #else #error Please complete this #endif mbistart = ptrorig; COMPILE_TIME_ASSERT ((2 * sizeof (grub_uint32_t)) % sizeof (grub_properly_aligned_t) == 0); COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN % sizeof (grub_properly_aligned_t) == 0); ptrorig += (2 * sizeof (grub_uint32_t)) / sizeof (grub_properly_aligned_t); { struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_CMDLINE; tag->size = sizeof (struct multiboot_tag_string) + cmdline_size; grub_memcpy (tag->string, cmdline, cmdline_size); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } { struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME; tag->size = sizeof (struct multiboot_tag_string) + sizeof (PACKAGE_STRING); grub_memcpy (tag->string, PACKAGE_STRING, sizeof (PACKAGE_STRING)); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } #ifdef GRUB_MACHINE_PCBIOS { struct grub_apm_info info; if (grub_apm_get_info (&info)) { struct multiboot_tag_apm *tag = (struct multiboot_tag_apm *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_APM; tag->size = sizeof (struct multiboot_tag_apm); tag->cseg = info.cseg; tag->offset = info.offset; tag->cseg_16 = info.cseg_16; tag->dseg = info.dseg; tag->flags = info.flags; tag->cseg_len = info.cseg_len; tag->dseg_len = info.dseg_len; tag->cseg_16_len = info.cseg_16_len; tag->version = info.version; ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } } #endif { unsigned i; struct module *cur; for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next) { struct multiboot_tag_module *tag = (struct multiboot_tag_module *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_MODULE; tag->size = sizeof (struct multiboot_tag_module) + cur->cmdline_size; tag->mod_start = cur->start; tag->mod_end = tag->mod_start + cur->size; grub_memcpy (tag->cmdline, cur->cmdline, cur->cmdline_size); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } } { struct multiboot_tag_mmap *tag = (struct multiboot_tag_mmap *) ptrorig; grub_fill_multiboot_mmap (tag); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } { struct multiboot_tag_elf_sections *tag = (struct multiboot_tag_elf_sections *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_ELF_SECTIONS; tag->size = sizeof (struct multiboot_tag_elf_sections) + elf_sec_entsize * elf_sec_num; grub_memcpy (tag->sections, elf_sections, elf_sec_entsize * elf_sec_num); tag->num = elf_sec_num; tag->entsize = elf_sec_entsize; tag->shndx = elf_sec_shstrndx; ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } { struct multiboot_tag_basic_meminfo *tag = (struct multiboot_tag_basic_meminfo *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO; tag->size = sizeof (struct multiboot_tag_basic_meminfo); /* Convert from bytes to kilobytes. */ tag->mem_lower = grub_mmap_get_lower () / 1024; tag->mem_upper = grub_mmap_get_upper () / 1024; ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } { struct grub_net_network_level_interface *net; FOR_NET_NETWORK_LEVEL_INTERFACES(net) if (net->dhcp_ack) { struct multiboot_tag_network *tag = (struct multiboot_tag_network *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_NETWORK; tag->size = sizeof (struct multiboot_tag_network) + net->dhcp_acklen; grub_memcpy (tag->dhcpack, net->dhcp_ack, net->dhcp_acklen); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } } if (bootdev_set) { struct multiboot_tag_bootdev *tag = (struct multiboot_tag_bootdev *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_BOOTDEV; tag->size = sizeof (struct multiboot_tag_bootdev); tag->biosdev = biosdev; tag->slice = slice; tag->part = part; ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } { err = retrieve_video_parameters (&ptrorig); if (err) { grub_print_error (); grub_errno = GRUB_ERR_NONE; } } #if defined (GRUB_MACHINE_EFI) && defined (__x86_64__) { struct multiboot_tag_efi64 *tag = (struct multiboot_tag_efi64 *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_EFI64; tag->size = sizeof (*tag); tag->pointer = (grub_addr_t) grub_efi_system_table; ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } #endif #if defined (GRUB_MACHINE_EFI) && defined (__i386__) { struct multiboot_tag_efi32 *tag = (struct multiboot_tag_efi32 *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_EFI32; tag->size = sizeof (*tag); tag->pointer = (grub_addr_t) grub_efi_system_table; ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } #endif #if GRUB_MACHINE_HAS_ACPI { struct multiboot_tag_old_acpi *tag = (struct multiboot_tag_old_acpi *) ptrorig; struct grub_acpi_rsdp_v10 *a = grub_acpi_get_rsdpv1 (); if (a) { tag->type = MULTIBOOT_TAG_TYPE_ACPI_OLD; tag->size = sizeof (*tag) + sizeof (*a); grub_memcpy (tag->rsdp, a, sizeof (*a)); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } } { struct multiboot_tag_new_acpi *tag = (struct multiboot_tag_new_acpi *) ptrorig; struct grub_acpi_rsdp_v20 *a = grub_acpi_get_rsdpv2 (); if (a) { tag->type = MULTIBOOT_TAG_TYPE_ACPI_NEW; tag->size = sizeof (*tag) + a->length; grub_memcpy (tag->rsdp, a, a->length); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } } #endif #ifdef GRUB_MACHINE_EFI { struct multiboot_tag_efi_mmap *tag = (struct multiboot_tag_efi_mmap *) ptrorig; grub_efi_uintn_t efi_desc_size; grub_efi_uint32_t efi_desc_version; tag->type = MULTIBOOT_TAG_TYPE_EFI_MMAP; tag->size = sizeof (*tag) + efi_mmap_size; if (!keep_bs) err = grub_efi_finish_boot_services (&efi_mmap_size, tag->efi_mmap, NULL, &efi_desc_size, &efi_desc_version); else { if (grub_efi_get_memory_map (&efi_mmap_size, (void *) tag->efi_mmap, NULL, &efi_desc_size, &efi_desc_version) <= 0) err = grub_error (GRUB_ERR_IO, "couldn't retrieve memory map"); } if (err) return err; tag->descr_size = efi_desc_size; tag->descr_vers = efi_desc_version; tag->size = sizeof (*tag) + efi_mmap_size; ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } if (keep_bs) { struct multiboot_tag *tag = (struct multiboot_tag *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_EFI_BS; tag->size = sizeof (struct multiboot_tag); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } #endif { struct multiboot_tag *tag = (struct multiboot_tag *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_END; tag->size = sizeof (struct multiboot_tag); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } ((grub_uint32_t *) mbistart)[0] = (char *) ptrorig - (char *) mbistart; ((grub_uint32_t *) mbistart)[1] = 0; return GRUB_ERR_NONE; }
grub_err_t grub_multiboot_make_mbi (grub_uint32_t *target) { struct multiboot_info *mbi; struct multiboot_mod_list *modlist; unsigned i; struct module *cur; grub_size_t mmap_size; grub_uint8_t *ptrorig; grub_addr_t ptrdest; grub_err_t err; grub_size_t bufsize; grub_relocator_chunk_t ch; bufsize = grub_multiboot_get_mbi_size (); err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, 0x10000, 0xa0000 - bufsize, bufsize, 4, GRUB_RELOCATOR_PREFERENCE_NONE, 0); if (err) return err; ptrorig = get_virtual_current_address (ch); ptrdest = get_physical_target_address (ch); *target = ptrdest; mbi = (struct multiboot_info *) ptrorig; ptrorig += sizeof (*mbi); ptrdest += sizeof (*mbi); grub_memset (mbi, 0, sizeof (*mbi)); grub_memcpy (ptrorig, cmdline, cmdline_size); mbi->flags |= MULTIBOOT_INFO_CMDLINE; mbi->cmdline = ptrdest; ptrorig += ALIGN_UP (cmdline_size, 4); ptrdest += ALIGN_UP (cmdline_size, 4); grub_memcpy (ptrorig, PACKAGE_STRING, sizeof(PACKAGE_STRING)); mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME; mbi->boot_loader_name = ptrdest; ptrorig += ALIGN_UP (sizeof(PACKAGE_STRING), 4); ptrdest += ALIGN_UP (sizeof(PACKAGE_STRING), 4); #ifdef GRUB_MACHINE_PCBIOS { struct grub_apm_info info; if (grub_apm_get_info (&info)) { struct multiboot_apm_info *mbinfo = (void *) ptrorig; mbinfo->cseg = info.cseg; mbinfo->offset = info.offset; mbinfo->cseg_16 = info.cseg_16; mbinfo->dseg = info.dseg; mbinfo->flags = info.flags; mbinfo->cseg_len = info.cseg_len; mbinfo->dseg_len = info.dseg_len; mbinfo->cseg_16_len = info.cseg_16_len; mbinfo->version = info.version; ptrorig += ALIGN_UP (sizeof (struct multiboot_apm_info), 4); ptrdest += ALIGN_UP (sizeof (struct multiboot_apm_info), 4); } } #endif if (modcnt) { mbi->flags |= MULTIBOOT_INFO_MODS; mbi->mods_addr = ptrdest; mbi->mods_count = modcnt; modlist = (struct multiboot_mod_list *) ptrorig; ptrorig += modcnt * sizeof (struct multiboot_mod_list); ptrdest += modcnt * sizeof (struct multiboot_mod_list); for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next) { modlist[i].mod_start = cur->start; modlist[i].mod_end = modlist[i].mod_start + cur->size; modlist[i].cmdline = ptrdest; grub_memcpy (ptrorig, cur->cmdline, cur->cmdline_size); ptrorig += ALIGN_UP (cur->cmdline_size, 4); ptrdest += ALIGN_UP (cur->cmdline_size, 4); } } else { mbi->mods_addr = 0; mbi->mods_count = 0; } mmap_size = grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry); grub_fill_multiboot_mmap ((struct multiboot_mmap_entry *) ptrorig); mbi->mmap_length = mmap_size; mbi->mmap_addr = ptrdest; mbi->flags |= MULTIBOOT_INFO_MEM_MAP; ptrorig += mmap_size; ptrdest += mmap_size; /* Convert from bytes to kilobytes. */ mbi->mem_lower = grub_mmap_get_lower () / 1024; mbi->mem_upper = grub_mmap_get_upper () / 1024; mbi->flags |= MULTIBOOT_INFO_MEMORY; if (bootdev_set) { mbi->boot_device = bootdev; mbi->flags |= MULTIBOOT_INFO_BOOTDEV; } { struct grub_net_network_level_interface *net; FOR_NET_NETWORK_LEVEL_INTERFACES(net) if (net->dhcp_ack) { grub_memcpy (ptrorig, net->dhcp_ack, net->dhcp_acklen); mbi->drives_addr = ptrdest; mbi->drives_length = net->dhcp_acklen; ptrorig += net->dhcp_acklen; ptrdest += net->dhcp_acklen; break; } } if (elf_sec_num) { mbi->u.elf_sec.addr = ptrdest; grub_memcpy (ptrorig, elf_sections, elf_sec_entsize * elf_sec_num); mbi->u.elf_sec.num = elf_sec_num; mbi->u.elf_sec.size = elf_sec_entsize; mbi->u.elf_sec.shndx = elf_sec_shstrndx; mbi->flags |= MULTIBOOT_INFO_ELF_SHDR; ptrorig += elf_sec_entsize * elf_sec_num; ptrdest += elf_sec_entsize * elf_sec_num; } err = retrieve_video_parameters (mbi, ptrorig, ptrdest); if (err) { grub_print_error (); grub_errno = GRUB_ERR_NONE; } if ((mbi->flags & MULTIBOOT_INFO_FRAMEBUFFER_INFO) && mbi->framebuffer_type == MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) { ptrorig += mbi->framebuffer_palette_num_colors * sizeof (struct multiboot_color); ptrdest += mbi->framebuffer_palette_num_colors * sizeof (struct multiboot_color); } #if GRUB_MACHINE_HAS_VBE ptrorig += sizeof (struct grub_vbe_info_block); ptrdest += sizeof (struct grub_vbe_info_block); ptrorig += sizeof (struct grub_vbe_mode_info_block); ptrdest += sizeof (struct grub_vbe_mode_info_block); #endif #ifdef GRUB_MACHINE_EFI err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); if (err) return err; #endif return GRUB_ERR_NONE; }