]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
migrate kernel.img to elf
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 24 Apr 2010 23:54:46 +0000 (01:54 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 24 Apr 2010 23:54:46 +0000 (01:54 +0200)
conf/i386-pc.rmk
conf/i386-qemu.rmk
conf/mips-qemu-mips.rmk
conf/mips-yeeloong.rmk
conf/sparc64-ieee1275.rmk
conf/x86-efi.rmk
include/grub/x86_64/efi/boot.h [new file with mode: 0644]
util/grub-mkrawimage.c

index a5a1b08ea54f62aa8556d62b322f9f5b45c5f0f3..f2490ba979f6e397886cf365e1fb3a728ca857b6 100644 (file)
@@ -5,8 +5,7 @@ GRUB_KERNEL_MACHINE_LINK_ADDR = 0x8200
 COMMON_CFLAGS = -mrtd -mregparm=3
 
 # Images.
-pkglib_IMAGES = boot.img cdboot.img diskboot.img kernel.img lnxboot.img \
-       pxeboot.img
+pkglib_IMAGES = boot.img cdboot.img diskboot.img lnxboot.img pxeboot.img
 
 # For boot.img.
 boot_img_SOURCES = boot/i386/pc/boot.S
@@ -39,6 +38,7 @@ cdboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)0x7C00
 cdboot_img_FORMAT = binary
 
 # For kernel.img.
+pkglib_PROGRAMS = kernel.img
 kernel_img_SOURCES = kern/i386/pc/startup.S \
        kern/i386/misc.S \
        kern/main.c kern/device.c \
@@ -59,7 +59,6 @@ kernel_img_HEADERS += machine/biosdisk.h machine/vga.h machine/vbe.h \
 kernel_img_CFLAGS = $(COMMON_CFLAGS)  $(TARGET_IMG_CFLAGS)
 kernel_img_ASFLAGS = $(COMMON_ASFLAGS)
 kernel_img_LDFLAGS += $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)$(GRUB_KERNEL_MACHINE_LINK_ADDR) $(COMMON_CFLAGS)
-kernel_img_FORMAT = binary
 
 # Utilities.
 bin_UTILITIES = grub-mkimage
index 664bef12a3d8bbf4da0865f2ad96cb5643efc621..9232317911d1db1d5369417104470649af1f5a7f 100644 (file)
@@ -19,7 +19,7 @@ grub_mkimage_SOURCES = util/grub-mkrawimage.c util/misc.c \
 grub_mkimage_CFLAGS = -DGRUB_KERNEL_MACHINE_LINK_ADDR=$(GRUB_KERNEL_MACHINE_LINK_ADDR)
 util/grub-mkrawimage.c_DEPENDENCIES = Makefile
 
-pkglib_IMAGES += kernel.img
+pkglib_PROGRAMS += kernel.img
 kernel_img_SOURCES = kern/i386/qemu/startup.S \
        kern/i386/misc.S \
        kern/i386/coreboot/init.c \
index af5b26bec8a4b828d911f42c56376142fd0db4ae..2f80ab2e306516aeeacef6f016807e371de3cf8f 100644 (file)
@@ -5,7 +5,7 @@ COMMON_CFLAGS += -march=mips3
 COMMON_ASFLAGS += -march=mips3
 include $(srcdir)/conf/mips.mk
 
-pkglib_IMAGES = kernel.img
+pkglib_PROGRAMS = kernel.img
 kernel_img_SOURCES = kern/$(target_cpu)/startup.S \
        kern/main.c kern/device.c kern/$(target_cpu)/init.c \
        kern/$(target_cpu)/$(target_machine)/init.c             \
index 6a96ddfafa1a16e73db01d0b776dcad147621c19..5ce8ede9d73cfb08f5d27d2f4f7b100226718c99 100644 (file)
@@ -8,7 +8,7 @@ kernel_img_HEADERS += pci.h bitmap.h video.h gfxterm.h font.h bitmap_scale.h buf
 
 include $(srcdir)/conf/mips.mk
 
-pkglib_IMAGES = kernel.img
+pkglib_PROGRAMS = kernel.img
 kernel_img_SOURCES = kern/$(target_cpu)/startup.S \
        kern/main.c kern/device.c kern/$(target_cpu)/init.c \
        kern/$(target_cpu)/$(target_machine)/init.c             \
index f0c9b0db79842924d5bc0c05c0e11a86e37a7ffb..8e96599aa5db603aa0b1f8b071824627bdd6ba26 100644 (file)
@@ -5,7 +5,8 @@ COMMON_CFLAGS = -mno-app-regs
 COMMON_LDFLAGS = -melf64_sparc -mno-relax
 
 # Images.
-pkglib_IMAGES = boot.img diskboot.img kernel.img
+pkglib_IMAGES = boot.img diskboot.img
+pkglib_PROGRAMS = kernel.img
 
 # For boot.img.
 boot_img_SOURCES = boot/sparc64/ieee1275/boot.S
index 46957d9332ed092554383fee59fc9ca8c9aef248..bab561cc4075fff85d5fe7245ed2d97692f9cf10 100644 (file)
@@ -4,7 +4,7 @@
 bin_UTILITIES = grub-mkimage
 
 # For grub-mkimage.
-grub_mkimage_SOURCES = gnulib/progname.c util/i386/efi/grub-mkimage.c \
+grub_mkimage_SOURCES = gnulib/progname.c util/grub-mkrawimage.c \
        util/misc.c util/resolve.c
 util/i386/efi/grub-mkimage.c_DEPENDENCIES = Makefile
 
diff --git a/include/grub/x86_64/efi/boot.h b/include/grub/x86_64/efi/boot.h
new file mode 100644 (file)
index 0000000..e69de29
index 20a344d04e63916910fc04ce7df445e4e3898e0e..dace903a9fdadf75ba88ab28c64afab4d54e68c7 100644 (file)
@@ -36,6 +36,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <assert.h>
+#include <grub/efi/pe32.h>
 
 #define _GNU_SOURCE    1
 #include <getopt.h>
@@ -44,6 +45,8 @@
 
 #define ALIGN_ADDR(x) (ALIGN_UP((x), GRUB_TARGET_SIZEOF_VOID_P))
 
+#define SECTION_ALIGN 1
+
 #ifdef ENABLE_LZMA
 #include <grub/lib/LzmaEnc.h>
 
@@ -97,6 +100,162 @@ compress_kernel (char *kernel_img, size_t kernel_size,
 
 #endif /* No lzma compression */
 
+/* Determine if this section is a text section. Return false if this
+   section is not allocated.  */
+static int
+is_text_section (Elf_Shdr *s)
+{
+  if (grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
+    return 0;
+  return ((grub_target_to_host32 (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
+         == (SHF_EXECINSTR | SHF_ALLOC));
+}
+
+/* Determine if this section is a data section. This assumes that
+   BSS is also a data section, since the converter initializes BSS
+   when producing PE32 to avoid a bug in EFI implementations.  */
+static int
+is_data_section (Elf_Shdr *s)
+{
+  if (grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
+    return 0;
+  return ((grub_target_to_host32 (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC))
+         == SHF_ALLOC);
+}
+
+/* Locate section addresses by merging code sections and data sections
+   into .text and .data, respectively. Return the array of section
+   addresses.  */
+static Elf_Addr *
+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)
+{
+  int i;
+  Elf_Addr current_address;
+  Elf_Addr *section_addresses;
+  Elf_Shdr *s;
+
+  section_addresses = xmalloc (sizeof (*section_addresses) * num_sections);
+  memset (section_addresses, 0, sizeof (*section_addresses) * num_sections);
+
+  current_address = 0;
+
+  /* .text */
+  for (i = 0, s = sections;
+       i < num_sections;
+       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+    if (is_text_section (s))
+      {
+       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, align);
+
+       grub_util_info ("locating the section %s at 0x%x",
+                       name, current_address);
+       section_addresses[i] = current_address;
+       current_address += grub_host_to_target32 (s->sh_size);
+      }
+
+  current_address = ALIGN_UP (current_address, SECTION_ALIGN);
+  *exec_size = current_address;
+
+  /* .data */
+  for (i = 0, s = sections;
+       i < num_sections;
+       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+    if (is_data_section (s))
+      {
+       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, align);
+
+       grub_util_info ("locating the section %s at 0x%x",
+                       name, current_address);
+       section_addresses[i] = current_address;
+       current_address += grub_host_to_target32 (s->sh_size);
+      }
+
+  current_address = ALIGN_UP (current_address, SECTION_ALIGN);
+  *kernel_sz = current_address;
+  return section_addresses;
+}
+
+/* Return if the ELF header is valid.  */
+static int
+check_elf_header (Elf_Ehdr *e, size_t size)
+{
+  if (size < sizeof (*e)
+      || e->e_ident[EI_MAG0] != ELFMAG0
+      || e->e_ident[EI_MAG1] != ELFMAG1
+      || e->e_ident[EI_MAG2] != ELFMAG2
+      || e->e_ident[EI_MAG3] != ELFMAG3
+      || e->e_ident[EI_VERSION] != EV_CURRENT
+      || e->e_version != grub_host_to_target32 (EV_CURRENT))
+    return 0;
+
+  return 1;
+}
+
+static char *
+load_image (const char *kernel_path, grub_size_t *exec_size, 
+           grub_size_t *kernel_sz, grub_size_t total_module_size)
+{
+  char *kernel_img, *out_img;
+  const char *strtab;
+  Elf_Ehdr *e;
+  Elf_Shdr *sections;
+  Elf_Addr *section_addresses;
+  int i;
+  Elf_Shdr *s;
+  Elf_Half num_sections;
+  Elf_Off section_offset;
+  Elf_Half section_entsize;
+  grub_size_t kernel_size;
+
+  kernel_size = grub_util_get_image_size (kernel_path);
+  kernel_img = xmalloc (kernel_size);
+  grub_util_load_image (kernel_path, kernel_img);
+
+  e = (Elf_Ehdr *) kernel_img;
+  if (! check_elf_header (e, kernel_size))
+    grub_util_error ("invalid ELF header");
+
+  section_offset = grub_target_to_host32 (e->e_shoff);
+  section_entsize = grub_target_to_host16 (e->e_shentsize);
+  num_sections = grub_target_to_host16 (e->e_shnum);
+
+  if (kernel_size < section_offset + section_entsize * num_sections)
+    grub_util_error ("invalid ELF format");
+
+  sections = (Elf_Shdr *) (kernel_img + section_offset);
+
+  /* Relocate sections then symbols in the virtual address space.  */
+  s = (Elf_Shdr *) ((char *) sections
+                     + grub_host_to_target16 (e->e_shstrndx) * section_entsize);
+  strtab = (char *) e + grub_host_to_target32 (s->sh_offset);
+
+  section_addresses = locate_sections (sections, section_entsize,
+                                      num_sections, strtab,
+                                      exec_size, kernel_sz);
+  out_img = xmalloc (*kernel_sz + total_module_size);
+
+  for (i = 0, s = sections;
+       i < num_sections;
+       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+    if (is_data_section (s) || is_text_section (s))
+      memcpy (out_img + section_addresses[i],
+             kernel_img + grub_host_to_target32 (s->sh_offset),
+             grub_host_to_target32 (s->sh_size));
+  free (kernel_img);
+
+  return out_img;
+}
+
 static void
 generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
                char *memdisk_path, char *font_path, char *config_path,
@@ -109,17 +268,15 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
 )
 {
   char *kernel_img, *core_img;
-  size_t kernel_size, total_module_size, core_size;
+  size_t kernel_size, total_module_size, core_size, exec_size;
   size_t memdisk_size = 0, font_size = 0, config_size = 0, config_size_pure = 0;
   char *kernel_path;
   size_t offset;
   struct grub_util_path_list *path_list, *p, *next;
   struct grub_module_info *modinfo;
-
   path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods);
 
   kernel_path = grub_util_get_path (dir, "kernel.img");
-  kernel_size = grub_util_get_image_size (kernel_path);
 
   total_module_size = sizeof (struct grub_module_info);
 
@@ -150,8 +307,8 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
 
   grub_util_info ("the total module size is 0x%x", total_module_size);
 
-  kernel_img = xmalloc (kernel_size + total_module_size);
-  grub_util_load_image (kernel_path, kernel_img);
+  kernel_img = load_image (kernel_path, &exec_size, &kernel_size,
+                          total_module_size);
 
   if (GRUB_KERNEL_MACHINE_PREFIX + strlen (prefix) + 1 > GRUB_KERNEL_MACHINE_DATA_END)
     grub_util_error (_("prefix is too long"));
@@ -237,8 +394,10 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
   *((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE))
     = grub_host_to_target32 (total_module_size);
 #endif
+#ifdef GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE
   *((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE))
     = grub_host_to_target32 (kernel_size);
+#endif
 #ifdef GRUB_KERNEL_MACHINE_COMPRESSED_SIZE
   *((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE))
     = grub_host_to_target32 (core_size - GRUB_KERNEL_MACHINE_RAW_SIZE);