diff --git a/include/grub/elf.h b/include/grub/elf.h index e54989cde..b9401f241 100644 --- a/include/grub/elf.h +++ b/include/grub/elf.h @@ -555,6 +555,7 @@ typedef struct #define PT_NUM 8 /* Number of defined types */ #define PT_LOOS 0x60000000 /* Start of OS-specific */ #define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ +#define PT_GNU_STACK 0x6474e551 /* GCC stack segment */ #define PT_LOSUNW 0x6ffffffa #define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ #define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ diff --git a/include/grub/i386/kernel.h b/include/grub/i386/kernel.h index a0d806929..45c7abd72 100644 --- a/include/grub/i386/kernel.h +++ b/include/grub/i386/kernel.h @@ -19,14 +19,4 @@ #ifndef GRUB_KERNEL_CPU_HEADER #define GRUB_KERNEL_CPU_HEADER 1 - -#ifdef GRUB_MACHINE_IEEE1275 -#define GRUB_MOD_ALIGN 0x1000 -#else -#define GRUB_MOD_ALIGN 0x1 -#endif - -/* Non-zero value is only needed for PowerMacs. */ -#define GRUB_MOD_GAP 0x0 - #endif diff --git a/include/grub/offsets.h b/include/grub/offsets.h index 768e4726a..a7f252e85 100644 --- a/include/grub/offsets.h +++ b/include/grub/offsets.h @@ -127,9 +127,25 @@ #define GRUB_KERNEL_I386_IEEE1275_DATA_END 0x42 #define GRUB_KERNEL_I386_IEEE1275_LINK_ADDR 0x10000 +#define GRUB_KERNEL_I386_IEEE1275_MOD_ALIGN 0x1000 +#define GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN 0x1 + +/* Non-zero value is only needed for PowerMacs. */ +#define GRUB_KERNEL_I386_IEEE1275_MOD_GAP 0x0 +#define GRUB_KERNEL_I386_COREBOOT_MOD_GAP 0x0 + +#define GRUB_KERNEL_POWERPC_IEEE1275_MOD_ALIGN 0x1000 + +/* Minimal gap between _end and the start of the modules. It's a hack + for PowerMac to prevent "CLAIM failed" error. The real fix is to + rewrite grub-mkimage to generate valid ELF files. */ +#define GRUB_KERNEL_POWERPC_IEEE1275_MOD_GAP 0x8000 + #ifdef MACHINE #define GRUB_OFFSETS_CONCAT_(a,b,c) a ## b ## c #define GRUB_OFFSETS_CONCAT(a,b,c) GRUB_OFFSETS_CONCAT_(a,b,c) +#define GRUB_KERNEL_MACHINE_MOD_ALIGN GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _MOD_ALIGN) +#define GRUB_KERNEL_MACHINE_MOD_GAP GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _MOD_GAP) #define GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _TOTAL_MODULE_SIZE) #define GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _KERNEL_IMAGE_SIZE) #define GRUB_KERNEL_MACHINE_COMPRESSED_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _COMPRESSED_SIZE) diff --git a/include/grub/powerpc/kernel.h b/include/grub/powerpc/kernel.h index e4ff65174..3fc0b9e23 100644 --- a/include/grub/powerpc/kernel.h +++ b/include/grub/powerpc/kernel.h @@ -19,11 +19,4 @@ #ifndef GRUB_KERNEL_CPU_HEADER #define GRUB_KERNEL_CPU_HEADER 1 -#define GRUB_MOD_ALIGN 0x1000 - -/* Minimal gap between _end and the start of the modules. It's a hack - for PowerMac to prevent "CLAIM failed" error. The real fix is to - rewrite grub-mkimage to generate valid ELF files. */ -#define GRUB_MOD_GAP 0x8000 - #endif diff --git a/kern/i386/coreboot/init.c b/kern/i386/coreboot/init.c index 5f80f28c1..f367269c4 100644 --- a/kern/i386/coreboot/init.c +++ b/kern/i386/coreboot/init.c @@ -144,6 +144,6 @@ grub_arch_modules_addr (void) #ifdef GRUB_MACHINE_QEMU return grub_core_entry_addr + grub_kernel_image_size; #else - return ALIGN_UP((grub_addr_t) _end, GRUB_MOD_ALIGN); + return ALIGN_UP((grub_addr_t) _end, GRUB_KERNEL_MACHINE_MOD_ALIGN); #endif } diff --git a/kern/ieee1275/init.c b/kern/ieee1275/init.c index 75f261a71..db9583d8b 100644 --- a/kern/ieee1275/init.c +++ b/kern/ieee1275/init.c @@ -284,5 +284,5 @@ grub_get_rtc (void) grub_addr_t grub_arch_modules_addr (void) { - return ALIGN_UP((grub_addr_t) _end + GRUB_MOD_GAP, GRUB_MOD_ALIGN); + return ALIGN_UP((grub_addr_t) _end + GRUB_KERNEL_MACHINE_MOD_GAP, GRUB_KERNEL_MACHINE_MOD_ALIGN); } diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c index 25ab5afe4..cc4a225d4 100644 --- a/util/grub-mkimage.c +++ b/util/grub-mkimage.c @@ -72,6 +72,7 @@ struct image_target_desc signed vaddr_offset; unsigned install_dos_part, install_bsd_part; grub_uint64_t link_addr; + unsigned mod_gap, mod_align; }; struct image_target_desc image_targets[] = @@ -92,7 +93,11 @@ struct image_target_desc image_targets[] = .vaddr_offset = 0, .install_dos_part = TARGET_NO_FIELD, .install_bsd_part = TARGET_NO_FIELD, - .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR + .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR, + .elf_target = EM_386, + .link_align = 4, + .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP, + .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN }, { .name = "i386-pc", @@ -150,7 +155,11 @@ struct image_target_desc image_targets[] = .vaddr_offset = 0, .install_dos_part = TARGET_NO_FIELD, .install_bsd_part = TARGET_NO_FIELD, - .link_addr = GRUB_KERNEL_I386_IEEE1275_LINK_ADDR + .link_addr = GRUB_KERNEL_I386_IEEE1275_LINK_ADDR, + .elf_target = EM_386, + .mod_gap = GRUB_KERNEL_I386_IEEE1275_MOD_GAP, + .mod_align = GRUB_KERNEL_I386_IEEE1275_MOD_ALIGN, + .link_align = 4, }, { .name = "i386-qemu", @@ -228,7 +237,11 @@ struct image_target_desc image_targets[] = .vaddr_offset = 0, .install_dos_part = TARGET_NO_FIELD, .install_bsd_part = TARGET_NO_FIELD, - .link_addr = GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR + .link_addr = GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR, + .elf_target = EM_PPC, + .mod_gap = GRUB_KERNEL_POWERPC_IEEE1275_MOD_GAP, + .mod_align = GRUB_KERNEL_POWERPC_IEEE1275_MOD_ALIGN, + .link_align = 4 }, { .name = "sparc64-ieee1275-raw", @@ -463,7 +476,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], grub_size_t bss_size; grub_uint64_t start_address; void *rel_section; - grub_size_t reloc_size; + grub_size_t reloc_size, align; path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods); kernel_path = grub_util_get_path (dir, "kernel.img"); @@ -503,11 +516,11 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], if (image_target->voidp_sizeof == 4) kernel_img = load_image32 (kernel_path, &exec_size, &kernel_size, &bss_size, total_module_size, &start_address, &rel_section, - &reloc_size, image_target); + &reloc_size, &align, image_target); else kernel_img = load_image64 (kernel_path, &exec_size, &kernel_size, &bss_size, total_module_size, &start_address, &rel_section, - &reloc_size, image_target); + &reloc_size, &align, image_target); if (image_target->prefix + strlen (prefix) + 1 > image_target->data_end) grub_util_error (_("prefix is too long")); @@ -961,6 +974,9 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], grub_uint32_t target_addr; int header_size, footer_size = 0; int phnum = 1; + + if (image_target->id != IMAGE_YEELOONG_ELF) + phnum += 2; if (note) { @@ -994,7 +1010,10 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], /* No section headers. */ ehdr->e_shoff = grub_host_to_target32 (0); - ehdr->e_shentsize = grub_host_to_target16 (0); + if (image_target->id == IMAGE_YEELOONG_ELF) + ehdr->e_shentsize = grub_host_to_target16 (0); + else + ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf32_Shdr)); ehdr->e_shnum = grub_host_to_target16 (0); ehdr->e_shstrndx = grub_host_to_target16 (0); @@ -1012,14 +1031,44 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], ehdr->e_entry = grub_host_to_target32 (target_addr); phdr->p_vaddr = grub_host_to_target32 (target_addr); phdr->p_paddr = grub_host_to_target32 (target_addr); - phdr->p_align = grub_host_to_target32 (image_target->link_align); + phdr->p_align = grub_host_to_target32 (align > image_target->link_align ? align : image_target->link_align); if (image_target->id == IMAGE_YEELOONG_ELF) ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER | EF_MIPS_PIC | EF_MIPS_CPIC); else ehdr->e_flags = 0; - phdr->p_filesz = grub_host_to_target32 (core_size); - phdr->p_memsz = grub_host_to_target32 (core_size); + if (image_target->id == IMAGE_YEELOONG_ELF) + { + phdr->p_filesz = grub_host_to_target32 (core_size); + phdr->p_memsz = grub_host_to_target32 (core_size); + } + else + { + grub_uint32_t target_addr_mods; + phdr->p_filesz = grub_host_to_target32 (kernel_size); + phdr->p_memsz = grub_host_to_target32 (kernel_size + bss_size); + + phdr++; + phdr->p_type = grub_host_to_target32 (PT_GNU_STACK); + phdr->p_offset = grub_host_to_target32 (header_size + kernel_size); + phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0; + phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); + phdr->p_align = grub_host_to_target32 (image_target->link_align); + + phdr++; + phdr->p_type = grub_host_to_target32 (PT_LOAD); + phdr->p_offset = grub_host_to_target32 (header_size + kernel_size); + phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); + phdr->p_filesz = phdr->p_memsz + = grub_host_to_target32 (core_size - kernel_size); + + target_addr_mods = ALIGN_UP (target_addr + kernel_size + bss_size + + image_target->mod_gap, + image_target->mod_align); + phdr->p_vaddr = grub_host_to_target32 (target_addr_mods); + phdr->p_paddr = grub_host_to_target32 (target_addr_mods); + phdr->p_align = grub_host_to_target32 (image_target->link_align); + } if (note) { @@ -1040,14 +1089,15 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], note->descriptor.virt_size = grub_host_to_target32 (0xffffffff); note->descriptor.load_base = grub_host_to_target32 (0x00004000); - phdr[1].p_type = grub_host_to_target32 (PT_NOTE); - phdr[1].p_flags = grub_host_to_target32 (PF_R); - phdr[1].p_align = grub_host_to_target32 (image_target->voidp_sizeof); - phdr[1].p_vaddr = 0; - phdr[1].p_paddr = 0; - phdr[1].p_filesz = grub_host_to_target32 (note_size); - phdr[1].p_memsz = 0; - phdr[1].p_offset = grub_host_to_target32 (header_size + program_size); + phdr++; + phdr->p_type = grub_host_to_target32 (PT_NOTE); + phdr->p_flags = grub_host_to_target32 (PF_R); + phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); + phdr->p_vaddr = 0; + phdr->p_paddr = 0; + phdr->p_filesz = grub_host_to_target32 (note_size); + phdr->p_memsz = 0; + phdr->p_offset = grub_host_to_target32 (header_size + program_size); } free (core_img); diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index abfe56d42..e9fdc7428 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -523,6 +523,7 @@ static Elf_Addr * SUFFIX (locate_sections) (Elf_Shdr *sections, Elf_Half section_entsize, Elf_Half num_sections, const char *strtab, grub_size_t *exec_size, grub_size_t *kernel_sz, + grub_size_t *all_align, struct image_target_desc *image_target) { int i; @@ -530,11 +531,21 @@ SUFFIX (locate_sections) (Elf_Shdr *sections, Elf_Half section_entsize, Elf_Addr *section_addresses; Elf_Shdr *s; + *all_align = 1; + section_addresses = xmalloc (sizeof (*section_addresses) * num_sections); memset (section_addresses, 0, sizeof (*section_addresses) * num_sections); current_address = 0; + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC) + && grub_host_to_target32 (s->sh_addralign) > *all_align) + *all_align = grub_host_to_target32 (s->sh_addralign); + + /* .text */ for (i = 0, s = sections; i < num_sections; @@ -546,7 +557,6 @@ SUFFIX (locate_sections) (Elf_Shdr *sections, Elf_Half section_entsize, if (align) current_address = ALIGN_UP (current_address + image_target->vaddr_offset, align) - image_target->vaddr_offset; - grub_util_info ("locating the section %s at 0x%x", name, current_address); section_addresses[i] = current_address; @@ -589,6 +599,7 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size, grub_size_t *kernel_sz, grub_size_t *bss_size, grub_size_t total_module_size, grub_uint64_t *start, void **reloc_section, grub_size_t *reloc_size, + grub_size_t *align, struct image_target_desc *image_target) { char *kernel_img, *out_img; @@ -631,44 +642,47 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size, section_addresses = SUFFIX (locate_sections) (sections, section_entsize, num_sections, strtab, - exec_size, kernel_sz, image_target); + exec_size, kernel_sz, align, + image_target); + + section_vaddresses = xmalloc (sizeof (*section_addresses) * num_sections); + + for (i = 0; i < num_sections; i++) + section_vaddresses[i] = section_addresses[i] + image_target->vaddr_offset; + + if (image_target->id != IMAGE_EFI) + { + Elf_Addr current_address = *kernel_sz; + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) + { + Elf_Word align = grub_host_to_target32 (s->sh_addralign); + const char *name = strtab + grub_host_to_target32 (s->sh_name); + + if (align) + current_address = ALIGN_UP (current_address + + image_target->vaddr_offset, align) + - image_target->vaddr_offset; + + grub_util_info ("locating the section %s at 0x%x", + name, current_address); + section_vaddresses[i] = current_address + + image_target->vaddr_offset; + current_address += grub_host_to_target_addr (s->sh_size); + } + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + image_target->section_align) + - image_target->vaddr_offset; + *bss_size = current_address - *kernel_sz; + } + else + *bss_size = 0; if (image_target->id == IMAGE_EFI) { - section_vaddresses = xmalloc (sizeof (*section_addresses) * num_sections); - - for (i = 0; i < num_sections; i++) - section_vaddresses[i] = section_addresses[i] + image_target->vaddr_offset; - -#if 0 - { - Elf_Addr current_address = *kernel_sz; - - for (i = 0, s = sections; - i < num_sections; - i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) - if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) - { - Elf_Word align = grub_host_to_target32 (s->sh_addralign); - const char *name = strtab + grub_host_to_target32 (s->sh_name); - - if (align) - current_address = ALIGN_UP (current_address + VADDR_OFFSET, align) - - VADDR_OFFSET; - - grub_util_info ("locating the section %s at 0x%x", - name, current_address); - section_vaddresses[i] = current_address + VADDR_OFFSET; - current_address += grub_host_to_target_addr (s->sh_size); - } - current_address = ALIGN_UP (current_address + VADDR_OFFSET, SECTION_ALIGN) - - VADDR_OFFSET; - *bss_size = current_address - *kernel_sz; - } -#else - *bss_size = 0; -#endif - symtab_section = NULL; for (i = 0, s = sections; i < num_sections; @@ -699,7 +713,6 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size, } else { - *bss_size = 0; *reloc_size = 0; *reloc_section = NULL; }