migrate kernel.img to elf

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-04-25 01:54:46 +02:00
parent 553c01f958
commit d31bc9964c
8 changed files with 172 additions and 13 deletions

View file

@ -5,8 +5,7 @@ GRUB_KERNEL_MACHINE_LINK_ADDR = 0x8200
COMMON_CFLAGS = -mrtd -mregparm=3 COMMON_CFLAGS = -mrtd -mregparm=3
# Images. # Images.
pkglib_IMAGES = boot.img cdboot.img diskboot.img kernel.img lnxboot.img \ pkglib_IMAGES = boot.img cdboot.img diskboot.img lnxboot.img pxeboot.img
pxeboot.img
# For boot.img. # For boot.img.
boot_img_SOURCES = boot/i386/pc/boot.S 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 cdboot_img_FORMAT = binary
# For kernel.img. # For kernel.img.
pkglib_PROGRAMS = kernel.img
kernel_img_SOURCES = kern/i386/pc/startup.S \ kernel_img_SOURCES = kern/i386/pc/startup.S \
kern/i386/misc.S \ kern/i386/misc.S \
kern/main.c kern/device.c \ 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_CFLAGS = $(COMMON_CFLAGS) $(TARGET_IMG_CFLAGS)
kernel_img_ASFLAGS = $(COMMON_ASFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS)
kernel_img_LDFLAGS += $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)$(GRUB_KERNEL_MACHINE_LINK_ADDR) $(COMMON_CFLAGS) kernel_img_LDFLAGS += $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)$(GRUB_KERNEL_MACHINE_LINK_ADDR) $(COMMON_CFLAGS)
kernel_img_FORMAT = binary
# Utilities. # Utilities.
bin_UTILITIES = grub-mkimage bin_UTILITIES = grub-mkimage

View 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) grub_mkimage_CFLAGS = -DGRUB_KERNEL_MACHINE_LINK_ADDR=$(GRUB_KERNEL_MACHINE_LINK_ADDR)
util/grub-mkrawimage.c_DEPENDENCIES = Makefile util/grub-mkrawimage.c_DEPENDENCIES = Makefile
pkglib_IMAGES += kernel.img pkglib_PROGRAMS += kernel.img
kernel_img_SOURCES = kern/i386/qemu/startup.S \ kernel_img_SOURCES = kern/i386/qemu/startup.S \
kern/i386/misc.S \ kern/i386/misc.S \
kern/i386/coreboot/init.c \ kern/i386/coreboot/init.c \

View file

@ -5,7 +5,7 @@ COMMON_CFLAGS += -march=mips3
COMMON_ASFLAGS += -march=mips3 COMMON_ASFLAGS += -march=mips3
include $(srcdir)/conf/mips.mk include $(srcdir)/conf/mips.mk
pkglib_IMAGES = kernel.img pkglib_PROGRAMS = kernel.img
kernel_img_SOURCES = kern/$(target_cpu)/startup.S \ kernel_img_SOURCES = kern/$(target_cpu)/startup.S \
kern/main.c kern/device.c kern/$(target_cpu)/init.c \ kern/main.c kern/device.c kern/$(target_cpu)/init.c \
kern/$(target_cpu)/$(target_machine)/init.c \ kern/$(target_cpu)/$(target_machine)/init.c \

View 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 include $(srcdir)/conf/mips.mk
pkglib_IMAGES = kernel.img pkglib_PROGRAMS = kernel.img
kernel_img_SOURCES = kern/$(target_cpu)/startup.S \ kernel_img_SOURCES = kern/$(target_cpu)/startup.S \
kern/main.c kern/device.c kern/$(target_cpu)/init.c \ kern/main.c kern/device.c kern/$(target_cpu)/init.c \
kern/$(target_cpu)/$(target_machine)/init.c \ kern/$(target_cpu)/$(target_machine)/init.c \

View file

@ -5,7 +5,8 @@ COMMON_CFLAGS = -mno-app-regs
COMMON_LDFLAGS = -melf64_sparc -mno-relax COMMON_LDFLAGS = -melf64_sparc -mno-relax
# Images. # Images.
pkglib_IMAGES = boot.img diskboot.img kernel.img pkglib_IMAGES = boot.img diskboot.img
pkglib_PROGRAMS = kernel.img
# For boot.img. # For boot.img.
boot_img_SOURCES = boot/sparc64/ieee1275/boot.S boot_img_SOURCES = boot/sparc64/ieee1275/boot.S

View file

@ -4,7 +4,7 @@
bin_UTILITIES = grub-mkimage bin_UTILITIES = grub-mkimage
# For 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/misc.c util/resolve.c
util/i386/efi/grub-mkimage.c_DEPENDENCIES = Makefile util/i386/efi/grub-mkimage.c_DEPENDENCIES = Makefile

View file

View file

@ -36,6 +36,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <grub/efi/pe32.h>
#define _GNU_SOURCE 1 #define _GNU_SOURCE 1
#include <getopt.h> #include <getopt.h>
@ -44,6 +45,8 @@
#define ALIGN_ADDR(x) (ALIGN_UP((x), GRUB_TARGET_SIZEOF_VOID_P)) #define ALIGN_ADDR(x) (ALIGN_UP((x), GRUB_TARGET_SIZEOF_VOID_P))
#define SECTION_ALIGN 1
#ifdef ENABLE_LZMA #ifdef ENABLE_LZMA
#include <grub/lib/LzmaEnc.h> #include <grub/lib/LzmaEnc.h>
@ -97,6 +100,162 @@ compress_kernel (char *kernel_img, size_t kernel_size,
#endif /* No lzma compression */ #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 static void
generate_image (const char *dir, char *prefix, FILE *out, char *mods[], generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
char *memdisk_path, char *font_path, char *config_path, 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; 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; size_t memdisk_size = 0, font_size = 0, config_size = 0, config_size_pure = 0;
char *kernel_path; char *kernel_path;
size_t offset; size_t offset;
struct grub_util_path_list *path_list, *p, *next; struct grub_util_path_list *path_list, *p, *next;
struct grub_module_info *modinfo; struct grub_module_info *modinfo;
path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods); path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods);
kernel_path = grub_util_get_path (dir, "kernel.img"); 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); 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); grub_util_info ("the total module size is 0x%x", total_module_size);
kernel_img = xmalloc (kernel_size + total_module_size); kernel_img = load_image (kernel_path, &exec_size, &kernel_size,
grub_util_load_image (kernel_path, kernel_img); total_module_size);
if (GRUB_KERNEL_MACHINE_PREFIX + strlen (prefix) + 1 > GRUB_KERNEL_MACHINE_DATA_END) if (GRUB_KERNEL_MACHINE_PREFIX + strlen (prefix) + 1 > GRUB_KERNEL_MACHINE_DATA_END)
grub_util_error (_("prefix is too long")); 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_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE))
= grub_host_to_target32 (total_module_size); = grub_host_to_target32 (total_module_size);
#endif #endif
#ifdef GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE
*((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE)) *((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE))
= grub_host_to_target32 (kernel_size); = grub_host_to_target32 (kernel_size);
#endif
#ifdef GRUB_KERNEL_MACHINE_COMPRESSED_SIZE #ifdef GRUB_KERNEL_MACHINE_COMPRESSED_SIZE
*((grub_uint32_t *) (core_img + 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); = grub_host_to_target32 (core_size - GRUB_KERNEL_MACHINE_RAW_SIZE);