diff --git a/ChangeLog b/ChangeLog index 8fed46ab7..ffd3cdf63 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,26 @@ 2006-04-20 Yoshinori K. Okuji + Add support for pre-loaded modules into the EFI port. + + * util/i386/efi/grub-mkimage.c (make_mods_section): Rewritten + completely. Accept one more argument DIR. The caller has changed. + + * kern/i386/efi/init.c (grub_arch_modules_addr): Removed. + + * kern/efi/efi.c: Include grub/efi/pe32.h and grub/kernel.h. + (grub_efi_loaded_image_guid): New variable. + (grub_efi_get_loaded_image): New function. + (grub_arch_modules_addr): Likewise. + + * include/grub/efi/efi.h (grub_efi_get_loaded_image): New + prototype. + + * include/grub/efi/api.h (GRUB_EFI_LOADED_IMAGE_GUID): New macro. + (struct grub_efi_loaded_image): New structure. + (grub_efi_loaded_image_t): New type. + +2006-04-20 Yoshinori K. Okuji + * loader/i386/pc/linux.c (grub_rescue_cmd_linux): Compare the file size with GRUB_OS_AREA_SIZE as grub_size_t instead of grub_ssize_t. Reported by Jeff Chua . diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h index 6de22329e..d8ca9a1fe 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -69,6 +69,9 @@ #define GRUB_EFI_OPTIONAL_PTR 0x00000001 +#define GRUB_EFI_LOADED_IMAGE_GUID \ + { 0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } + /* Enumerations. */ enum grub_efi_timer_delay { @@ -343,7 +346,6 @@ struct grub_efi_boot_services grub_efi_event_t *event); grub_efi_status_t - (*set_timer) (grub_efi_event_t event, grub_efi_timer_delay_t type, grub_efi_uint64_t trigger_time); @@ -682,4 +684,26 @@ struct grub_efi_system_table }; typedef struct grub_efi_system_table grub_efi_system_table_t; +struct grub_efi_loaded_image +{ + grub_efi_uint32_t revision; + grub_efi_handle_t parent_handle; + grub_efi_system_table_t *system_table; + + grub_efi_handle_t device_handle; + grub_efi_device_path_t *file_path; + void *reserved; + + grub_efi_uint32_t load_options_size; + void *load_options; + + void *image_base; + grub_efi_uint64_t image_size; + grub_efi_memory_type_t image_code_type; + grub_efi_memory_type_t image_data_type; + + grub_efi_status_t (*unload) (grub_efi_handle_t image_handle); +}; +typedef struct grub_efi_loaded_image grub_efi_loaded_image_t; + #endif /* ! GRUB_EFI_API_HEADER */ diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h index 1d28f1fd4..046bfda93 100644 --- a/include/grub/efi/efi.h +++ b/include/grub/efi/efi.h @@ -40,6 +40,7 @@ int EXPORT_FUNC(grub_efi_get_memory_map) (grub_efi_uintn_t *memory_map_size, grub_efi_uintn_t *map_key, grub_efi_uintn_t *descriptor_size, grub_efi_uint32_t *descriptor_version); +grub_efi_loaded_image_t *EXPORT_FUNC(grub_efi_get_loaded_image) (void); void grub_efi_mm_init (void); void grub_efi_mm_fini (void); diff --git a/kern/efi/efi.c b/kern/efi/efi.c index 299de11c6..842067d9a 100644 --- a/kern/efi/efi.c +++ b/kern/efi/efi.c @@ -22,8 +22,10 @@ #include #include #include +#include #include #include +#include /* The handle of GRUB itself. Filled in by the startup code. */ grub_efi_handle_t grub_efi_image_handle; @@ -32,6 +34,7 @@ grub_efi_handle_t grub_efi_image_handle; grub_efi_system_table_t *grub_efi_system_table; static grub_efi_guid_t grub_efi_console_control_guid = GRUB_EFI_CONSOLE_CONTROL_GUID; +static grub_efi_guid_t grub_efi_loaded_image_guid = GRUB_EFI_LOADED_IMAGE_GUID; void * grub_efi_locate_protocol (grub_efi_guid_t *protocol, void *registration) @@ -83,6 +86,26 @@ grub_efi_stall (grub_efi_uintn_t microseconds) grub_efi_system_table->boot_services->stall (microseconds); } +grub_efi_loaded_image_t * +grub_efi_get_loaded_image (void) +{ + grub_efi_boot_services_t *b; + void *interface; + grub_efi_status_t status; + + b = grub_efi_system_table->boot_services; + status = b->open_protocol (grub_efi_image_handle, + &grub_efi_loaded_image_guid, + &interface, + grub_efi_image_handle, + 0, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (status != GRUB_EFI_SUCCESS) + return 0; + + return interface; +} + void grub_stop (void) { @@ -108,3 +131,46 @@ grub_get_rtc (void) + time.nanosecond / 1000000) * GRUB_TICKS_PER_SECOND / 1000); } + +/* Search the mods section from the PE32/PE32+ image. This code uses + a PE32 header, but should work with PE32+ as well. */ +grub_addr_t +grub_arch_modules_addr (void) +{ + grub_efi_loaded_image_t *image; + struct grub_pe32_header *header; + struct grub_pe32_coff_header *coff_header; + struct grub_pe32_section_table *sections; + struct grub_pe32_section_table *section; + struct grub_module_info *info; + grub_uint16_t i; + + image = grub_efi_get_loaded_image (); + if (! image) + return 0; + + header = image->image_base; + coff_header = &(header->coff_header); + sections + = (struct grub_pe32_section_table *) ((char *) coff_header + + sizeof (*coff_header) + + coff_header->optional_header_size); + + for (i = 0, section = sections; + i < coff_header->num_sections; + i++, section++) + { + if (grub_strcmp (section->name, "mods") == 0) + break; + } + + if (i == coff_header->num_sections) + return 0; + + info = (struct grub_module_info *) ((char *) image->image_base + + section->virtual_address); + if (info->magic != GRUB_MODULE_MAGIC) + return 0; + + return (grub_addr_t) info; +} diff --git a/kern/i386/efi/init.c b/kern/i386/efi/init.c index 364f78bbd..dab9dddfd 100644 --- a/kern/i386/efi/init.c +++ b/kern/i386/efi/init.c @@ -45,9 +45,3 @@ grub_arch_sync_caches (void *address __attribute__ ((unused)), grub_size_t len __attribute__ ((unused))) { } - -grub_addr_t -grub_arch_modules_addr (void) -{ - return 0; -} diff --git a/util/i386/efi/grub-mkimage.c b/util/i386/efi/grub-mkimage.c index 72abda64e..aae418db2 100644 --- a/util/i386/efi/grub-mkimage.c +++ b/util/i386/efi/grub-mkimage.c @@ -591,14 +591,74 @@ write_data_sections (FILE *out, Elf32_Addr current_address, /* Write modules. */ static Elf32_Addr -make_mods_section (FILE *out, Elf32_Addr current_address, char *mods[]) +make_mods_section (FILE *out, Elf32_Addr current_address, + const char *dir, char *mods[]) { - /* FIXME: not implemented yet. */ - (void) mods; - write_padding (out, GRUB_PE32_SECTION_ALIGNMENT); - current_address += GRUB_PE32_SECTION_ALIGNMENT; + struct grub_util_path_list *path_list; + grub_size_t total_module_size; + struct grub_util_path_list *p; + struct grub_module_info modinfo; + Elf32_Addr addr; - return current_address; + path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods); + + total_module_size = sizeof (struct grub_module_info); + for (p = path_list; p; p = p->next) + { + total_module_size += (grub_util_get_image_size (p->name) + + sizeof (struct grub_module_header)); + } + + grub_util_info ("the total module size is 0x%x", total_module_size); + + modinfo.magic = grub_cpu_to_le32 (GRUB_MODULE_MAGIC); + modinfo.offset = grub_cpu_to_le32 (sizeof (modinfo)); + modinfo.size = grub_cpu_to_le32 (total_module_size); + + if (fwrite (&modinfo, sizeof (modinfo), 1, out) != 1) + grub_util_error ("write failed"); + + for (p = path_list; p; p = p->next) + { + struct grub_module_header header; + size_t mod_size; + char *mod_image; + + grub_util_info ("adding module %s", p->name); + + mod_size = grub_util_get_image_size (p->name); + header.offset = grub_cpu_to_le32 (sizeof (header)); + header.size = grub_cpu_to_le32 (mod_size + sizeof (header)); + + mod_image = grub_util_read_image (p->name); + + if (fwrite (&header, sizeof (header), 1, out) != 1 + || fwrite (mod_image, mod_size, 1, out) != 1) + grub_util_error ("write failed"); + + free (mod_image); + } + + for (p = path_list; p; ) + { + struct grub_util_path_list *q; + + q = p->next; + free (p); + p = q; + } + + current_address += total_module_size; + + addr = align_pe32_section (current_address); + if (addr != current_address) + { + grub_util_info ("padding %d bytes for the PE32 section alignment", + addr - current_address); + write_padding (out, addr - current_address); + } + + return addr; } /* Make a .reloc section. */ @@ -837,7 +897,7 @@ convert_elf (const char *dir, FILE *out, char *mods[]) mods_address = write_data_sections (out, data_address, e, sections, section_entsize, num_sections, strtab); - reloc_address = make_mods_section (out, mods_address, mods); + reloc_address = make_mods_section (out, mods_address, dir, mods); end_address = make_reloc_section (out, reloc_address, e, section_addresses, sections, section_entsize, num_sections, strtab);