/* Find the optimal number of pages for the memory map. Is it better to move this code to efi/mm.c? */ static void find_efi_mmap_size (void) { efi_mmap_size = (1 << 12); while (1) { int ret; grub_efi_memory_descriptor_t *mmap; grub_efi_uintn_t desc_size; grub_efi_uintn_t cur_mmap_size = efi_mmap_size; mmap = grub_malloc (cur_mmap_size); if (! mmap) return; ret = grub_efi_get_memory_map (&cur_mmap_size, mmap, 0, &desc_size, 0); grub_free (mmap); if (ret < 0) return; else if (ret > 0) break; if (efi_mmap_size < cur_mmap_size) efi_mmap_size = cur_mmap_size; efi_mmap_size += (1 << 12); } /* Increase the size a bit for safety, because GRUB allocates more on later, and EFI itself may allocate more. */ efi_mmap_size += (3 << 12); efi_mmap_size = ALIGN_UP (efi_mmap_size, 4096); }
int grub_efi_finish_boot_services (void) { grub_efi_uintn_t mmap_size = 0; grub_efi_uintn_t map_key; grub_efi_uintn_t desc_size; grub_efi_uint32_t desc_version; void *mmap_buf = 0; if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key, &desc_size, &desc_version) < 0) return 0; mmap_buf = grub_malloc (mmap_size); if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key, &desc_size, &desc_version) <= 0) return 0; return grub_efi_exit_boot_services (map_key); }
static void update_e820_map (struct e820_entry *e820_map, int *e820_nr_map) { grub_efi_uintn_t desc_size; if (grub_efi_get_memory_map (0, &desc_size, 0) < 0) { grub_printf ("cannot get memory map"); return; } e820_map_from_efi_map (e820_map, e820_nr_map, mmap_buf, desc_size, mmap_size); }
/* Find the optimal number of pages for the memory map. Is it better to move this code to efi/mm.c? */ static grub_efi_uintn_t find_efi_mmap_size (void) { static grub_efi_uintn_t mmap_size = 0; if (mmap_size != 0) return mmap_size; mmap_size = (1 << 12); while (1) { int ret; grub_efi_memory_descriptor_t *mmap; grub_efi_uintn_t desc_size; grub_efi_uintn_t cur_mmap_size = mmap_size; mmap = grub_malloc (cur_mmap_size); if (! mmap) return 0; ret = grub_efi_get_memory_map (&cur_mmap_size, mmap, 0, &desc_size, 0); grub_free (mmap); if (ret < 0) { grub_error (GRUB_ERR_IO, "cannot get memory map"); return 0; } else if (ret > 0) break; if (mmap_size < cur_mmap_size) mmap_size = cur_mmap_size; mmap_size += (1 << 12); } /* Increase the size a bit for safety, because GRUB allocates more on later, and EFI itself may allocate more. */ mmap_size += (3 << 12); mmap_size = page_align (mmap_size); return mmap_size; }
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_machine_mmap_iterate (grub_memory_hook_t hook) { grub_efi_uintn_t mmap_size = 0; grub_efi_memory_descriptor_t *map_buf = 0; grub_efi_uintn_t map_key = 0; grub_efi_uintn_t desc_size = 0; grub_efi_uint32_t desc_version = 0; grub_efi_memory_descriptor_t *desc; if (grub_efi_get_memory_map (&mmap_size, map_buf, &map_key, &desc_size, &desc_version) < 0) return grub_errno; map_buf = grub_malloc (mmap_size); if (! map_buf) return grub_errno; if (grub_efi_get_memory_map (&mmap_size, map_buf, &map_key, &desc_size, &desc_version) <= 0) { grub_free (map_buf); return grub_errno; } for (desc = map_buf; desc < NEXT_MEMORY_DESCRIPTOR (map_buf, mmap_size); desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) { grub_dprintf ("mmap", "EFI memory region 0x%llx-0x%llx: %d\n", (unsigned long long) desc->physical_start, (unsigned long long) desc->physical_start + desc->num_pages * 4096, desc->type); switch (desc->type) { case GRUB_EFI_RUNTIME_SERVICES_CODE: hook (desc->physical_start, desc->num_pages * 4096, GRUB_MEMORY_CODE); break; case GRUB_EFI_UNUSABLE_MEMORY: hook (desc->physical_start, desc->num_pages * 4096, GRUB_MEMORY_BADRAM); break; default: grub_printf ("Unknown memory type %d, considering reserved\n", desc->type); case GRUB_EFI_RESERVED_MEMORY_TYPE: case GRUB_EFI_RUNTIME_SERVICES_DATA: case GRUB_EFI_MEMORY_MAPPED_IO: case GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE: case GRUB_EFI_PAL_CODE: hook (desc->physical_start, desc->num_pages * 4096, GRUB_MEMORY_RESERVED); break; case GRUB_EFI_LOADER_CODE: case GRUB_EFI_LOADER_DATA: case GRUB_EFI_BOOT_SERVICES_CODE: case GRUB_EFI_BOOT_SERVICES_DATA: case GRUB_EFI_CONVENTIONAL_MEMORY: hook (desc->physical_start, desc->num_pages * 4096, GRUB_MEMORY_AVAILABLE); break; case GRUB_EFI_ACPI_RECLAIM_MEMORY: hook (desc->physical_start, desc->num_pages * 4096, GRUB_MEMORY_ACPI); break; case GRUB_EFI_ACPI_MEMORY_NVS: hook (desc->physical_start, desc->num_pages * 4096, GRUB_MEMORY_NVS); break; } } return GRUB_ERR_NONE; }