diff --git a/ChangeLog b/ChangeLog index 62d5e7bea..4c7a1a08f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-10-28 Vladimir Serbinenko + + * grub-core/loader/multiboot_mbi2.c: Implement EFI memory map. + 2013-10-28 Vladimir Serbinenko * grub-core/loader/multiboot.c: Add support for multiboot kernels diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c index e78b482a7..bff03896b 100644 --- a/grub-core/loader/i386/multiboot_mbi.c +++ b/grub-core/loader/i386/multiboot_mbi.c @@ -36,6 +36,10 @@ #include #include +#ifdef GRUB_MACHINE_EFI +#include +#endif + /* The bits in the required part of flags field we don't support. */ #define UNSUPPORTED_FLAGS 0x0000fff8 @@ -587,6 +591,12 @@ grub_multiboot_make_mbi (grub_uint32_t *target) 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; } diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index 093717cde..54e4d2408 100644 --- a/grub-core/loader/multiboot.c +++ b/grub-core/loader/multiboot.c @@ -131,12 +131,6 @@ grub_multiboot_boot (void) if (err) return err; -#ifdef GRUB_MACHINE_EFI - err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); - if (err) - return err; -#endif - #if defined (__i386__) || defined (__x86_64__) grub_relocator32_boot (grub_multiboot_relocator, state, 0); #else diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c index 561c79157..dfd7b9292 100644 --- a/grub-core/loader/multiboot_mbi2.c +++ b/grub-core/loader/multiboot_mbi2.c @@ -295,9 +295,55 @@ acpiv2_size (void) #endif } +#ifdef GRUB_MACHINE_EFI + +static grub_efi_uintn_t efi_mmap_size = 0; + +/* 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); +} +#endif + static grub_size_t grub_multiboot_get_mbi_size (void) { +#ifdef GRUB_MACHINE_EFI + if (!efi_mmap_size) + find_efi_mmap_size (); +#endif return 2 * sizeof (grub_uint32_t) + sizeof (struct multiboot_tag) + (sizeof (struct multiboot_tag_string) + ALIGN_UP (cmdline_size, MULTIBOOT_TAG_ALIGN)) @@ -318,6 +364,10 @@ grub_multiboot_get_mbi_size (void) + ALIGN_UP (sizeof (struct multiboot_tag_old_acpi) + sizeof (struct grub_acpi_rsdp_v10), MULTIBOOT_TAG_ALIGN) + acpiv2_size () +#ifdef GRUB_MACHINE_EFI + + ALIGN_UP (sizeof (struct multiboot_tag_efi_mmap) + + efi_mmap_size, MULTIBOOT_TAG_ALIGN) +#endif + sizeof (struct multiboot_tag_vbe) + MULTIBOOT_TAG_ALIGN - 1 + sizeof (struct multiboot_tag_apm) + MULTIBOOT_TAG_ALIGN - 1; } @@ -760,6 +810,28 @@ grub_multiboot_make_mbi (grub_uint32_t *target) } #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; + + err = grub_efi_finish_boot_services (&efi_mmap_size, tag->efi_mmap, NULL, + &efi_desc_size, &efi_desc_version); + 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); + } +#endif + { struct multiboot_tag *tag = (struct multiboot_tag *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_END; diff --git a/include/multiboot2.h b/include/multiboot2.h index 0e26a8ec2..58f2f6845 100644 --- a/include/multiboot2.h +++ b/include/multiboot2.h @@ -58,6 +58,7 @@ #define MULTIBOOT_TAG_TYPE_ACPI_OLD 14 #define MULTIBOOT_TAG_TYPE_ACPI_NEW 15 #define MULTIBOOT_TAG_TYPE_NETWORK 16 +#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17 #define MULTIBOOT_HEADER_TAG_END 0 #define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1 @@ -361,6 +362,15 @@ struct multiboot_tag_network multiboot_uint8_t dhcpack[0]; }; +struct multiboot_tag_efi_mmap +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t descr_size; + multiboot_uint32_t descr_vers; + multiboot_uint8_t efi_mmap[0]; +}; + #endif /* ! ASM_FILE */ #endif /* ! MULTIBOOT_HEADER */