summaryrefslogtreecommitdiff
path: root/efi/wrapper.c
diff options
context:
space:
mode:
authorchandramouli narayanan <mouli@linux.intel.com>2012-06-25 12:37:31 -0700
committerchandramouli narayanan <mouli@linux.intel.com>2012-06-25 12:37:31 -0700
commitca8533f1ef1d60dffa21449633dec9d26baeb29d (patch)
treee7351ad01dfe86333b6869648218c0506a8d63ff /efi/wrapper.c
parent3f7a44b8c18d9c9916b279872a0ef8701179e2e8 (diff)
downloadsyslinux-ca8533f1ef1d60dffa21449633dec9d26baeb29d.tar.gz
EFI boot loader in efi_boot_linux() now supports booting i386 and x86_64 linux kernels.
Main x86_64 changes are in a) setting up high part of EFI system table and memmap b) loader signature c) setting up jump vector to hand off to kernel. The EFI wrapper (efi/wraper.[ch]) takes an ELF shared libary and wraps it into PE32. While that's fine for EFI32, for EFI64, it needs to support PE32+ format so that a 64bit loadable module or executable can work under a 64bit capable syslinux.efi. The EFI wrapper is enhanced to support both EFI32 and EFI64 by writing out PE32 or PE32+ header fields as appropriate for the build architecture environment. Remanants of the unused old i386-only files, if any, need to be pruned.
Diffstat (limited to 'efi/wrapper.c')
-rw-r--r--efi/wrapper.c145
1 files changed, 103 insertions, 42 deletions
diff --git a/efi/wrapper.c b/efi/wrapper.c
index 203f79e9..4e1c5fc5 100644
--- a/efi/wrapper.c
+++ b/efi/wrapper.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2011 Intel Corporation; author Matt Fleming
*
- * Wrap the ELF shared library in a PE32 suit.
+ * Wrap the ELF shared library in a PE32 (32bit) or PE32+ (64bit) suit.
*
* Syslinux plays some games with the ELF sections that are not easily
* converted to a PE32 executable. For instance, Syslinux requires
@@ -24,14 +24,31 @@
#include "wrapper.h"
+#if __SIZEOF_POINTER__ == 4
+typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Addr Elf_Addr;
+#elif __SIZEOF_POINTER__ == 8
+typedef Elf64_Ehdr Elf_Ehdr;
+typedef Elf64_Addr Elf_Addr;
+#else
+#error "unsupported architecture"
+#endif
+
/*
* 'so_size' is the file size of the ELF shared object.
+ * 'class' dictates how the header is written
+ * For 32bit machines (class == ELFCLASS32), the optional
+ * header includes PE32 header fields
+ * For 64bit machines (class == ELFCLASS64), the optional
+ * header includes PE32+header fields
*/
-static void write_header(FILE *f, __uint32_t entry, __uint32_t so_size)
+static void write_header(FILE *f, __uint32_t entry, __uint32_t so_size, __uint8_t class)
{
struct optional_hdr o_hdr;
+ struct optional_hdr_pe32p o_hdr_pe32p;
struct section t_sec, r_sec;
struct extra_hdr e_hdr;
+ struct extra_hdr_pe32p e_hdr_pe32p;
struct coff_hdr c_hdr;
struct header hdr;
struct coff_reloc c_rel;
@@ -40,11 +57,6 @@ static void write_header(FILE *f, __uint32_t entry, __uint32_t so_size)
__uint32_t hdr_sz;
__uint32_t reloc_start, reloc_end;
- hdr_sz = sizeof(o_hdr) + sizeof(t_sec) + sizeof(e_hdr) +
- sizeof(r_sec) + sizeof(c_hdr) + sizeof(hdr) + sizeof(c_rel)
- + sizeof(dummy);
- total_sz += hdr_sz;
- entry += hdr_sz;
memset(&hdr, 0, sizeof(hdr));
hdr.msdos_signature = MSDOS_SIGNATURE;
@@ -53,31 +65,63 @@ static void write_header(FILE *f, __uint32_t entry, __uint32_t so_size)
fwrite(&hdr, sizeof(hdr), 1, f);
memset(&c_hdr, 0, sizeof(c_hdr));
- c_hdr.arch = IMAGE_FILE_MACHINE_I386;
c_hdr.nr_sections = 2;
c_hdr.nr_syms = 1;
- c_hdr.optional_hdr_sz = sizeof(o_hdr) + sizeof(e_hdr);
- c_hdr.characteristics = IMAGE_FILE_32BIT_MACHINE |
- IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE |
- IMAGE_FILE_LINE_NUMBERS_STRIPPED;
- fwrite(&c_hdr, sizeof(c_hdr), 1, f);
-
- memset(&o_hdr, 0, sizeof(o_hdr));
- o_hdr.format = PE32_FORMAT;
- o_hdr.major_linker_version = 0x02;
- o_hdr.minor_linker_version = 0x14;
- o_hdr.code_sz = total_sz;
- o_hdr.entry_point = entry;
- fwrite(&o_hdr, sizeof(o_hdr), 1, f);
-
- memset(&e_hdr, 0, sizeof(e_hdr));
- e_hdr.section_align = 4096;
- e_hdr.file_align = 512;
- e_hdr.image_sz = total_sz;
- e_hdr.headers_sz = 512;
- e_hdr.subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
- e_hdr.rva_and_sizes_nr = 1;
- fwrite(&e_hdr, sizeof(e_hdr), 1, f);
+ if (class == ELFCLASS32) {
+ hdr_sz = sizeof(o_hdr) + sizeof(t_sec) + sizeof(e_hdr) +
+ sizeof(r_sec) + sizeof(c_hdr) + sizeof(hdr) + sizeof(c_rel)
+ + sizeof(dummy);
+ total_sz += hdr_sz;
+ entry += hdr_sz;
+ c_hdr.arch = IMAGE_FILE_MACHINE_I386;
+ c_hdr.characteristics = IMAGE_FILE_32BIT_MACHINE |
+ IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE |
+ IMAGE_FILE_LINE_NUMBERS_STRIPPED;
+ c_hdr.optional_hdr_sz = sizeof(o_hdr) + sizeof(e_hdr);
+ fwrite(&c_hdr, sizeof(c_hdr), 1, f);
+ memset(&o_hdr, 0, sizeof(o_hdr));
+ o_hdr.format = PE32_FORMAT;
+ o_hdr.major_linker_version = 0x02;
+ o_hdr.minor_linker_version = 0x14;
+ o_hdr.code_sz = total_sz;
+ o_hdr.entry_point = entry;
+ fwrite(&o_hdr, sizeof(o_hdr), 1, f);
+ memset(&e_hdr, 0, sizeof(e_hdr));
+ e_hdr.section_align = 4096;
+ e_hdr.file_align = 512;
+ e_hdr.image_sz = total_sz;
+ e_hdr.headers_sz = 512;
+ e_hdr.subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
+ e_hdr.rva_and_sizes_nr = 1;
+ fwrite(&e_hdr, sizeof(e_hdr), 1, f);
+ }
+ else if (class == ELFCLASS64) {
+ hdr_sz = sizeof(o_hdr_pe32p) + sizeof(t_sec) + sizeof(e_hdr_pe32p) +
+ sizeof(r_sec) + sizeof(c_hdr) + sizeof(hdr) + sizeof(c_rel)
+ + sizeof(dummy);
+ total_sz += hdr_sz;
+ entry += hdr_sz;
+ c_hdr.arch = IMAGE_FILE_MACHINE_X86_64;
+ c_hdr.characteristics = IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE |
+ IMAGE_FILE_LINE_NUMBERS_STRIPPED;
+ c_hdr.optional_hdr_sz = sizeof(o_hdr_pe32p) + sizeof(e_hdr_pe32p);
+ fwrite(&c_hdr, sizeof(c_hdr), 1, f);
+ memset(&o_hdr_pe32p, 0, sizeof(o_hdr_pe32p));
+ o_hdr_pe32p.format = PE32P_FORMAT;
+ o_hdr_pe32p.major_linker_version = 0x02;
+ o_hdr_pe32p.minor_linker_version = 0x14;
+ o_hdr_pe32p.code_sz = total_sz;
+ o_hdr_pe32p.entry_point = entry;
+ fwrite(&o_hdr_pe32p, sizeof(o_hdr_pe32p), 1, f);
+ memset(&e_hdr, 0, sizeof(e_hdr));
+ e_hdr_pe32p.section_align = 4096;
+ e_hdr_pe32p.file_align = 512;
+ e_hdr_pe32p.image_sz = total_sz;
+ e_hdr_pe32p.headers_sz = 512;
+ e_hdr_pe32p.subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
+ e_hdr_pe32p.rva_and_sizes_nr = 1;
+ fwrite(&e_hdr_pe32p, sizeof(e_hdr_pe32p), 1, f);
+ }
memset(&t_sec, 0, sizeof(t_sec));
strcpy((char *)t_sec.name, ".text");
@@ -119,7 +163,11 @@ static void usage(char *progname)
int main(int argc, char **argv)
{
struct stat st;
- Elf32_Ehdr e_hdr;
+ Elf32_Ehdr e32_hdr;
+ Elf64_Ehdr e64_hdr;
+ __uint32_t entry;
+ __uint8_t class;
+ unsigned char *id;
FILE *f_in, *f_out;
void *buf;
size_t rv;
@@ -149,18 +197,31 @@ int main(int argc, char **argv)
/*
* Parse the ELF header and find the entry point.
*/
- fread((void *)&e_hdr, sizeof(e_hdr), 1, f_in);
- if (e_hdr.e_ident[EI_MAG0] != ELFMAG0 ||
- e_hdr.e_ident[EI_MAG1] != ELFMAG1 ||
- e_hdr.e_ident[EI_MAG2] != ELFMAG2 ||
- e_hdr.e_ident[EI_MAG3] != ELFMAG3) {
- fprintf(stderr, "Input file not ELF shared object\n");
+ fread((void *)&e32_hdr, sizeof(e32_hdr), 1, f_in);
+ if (e32_hdr.e_ident[EI_CLASS] == ELFCLASS32) {
+ id = e32_hdr.e_ident;
+ class = ELFCLASS32;
+ entry = e32_hdr.e_entry;
+ }
+ else if (e32_hdr.e_ident[EI_CLASS] == ELFCLASS64) {
+ /* read the header again for x86_64
+ * note that the elf header entry point is 64bit whereas
+ * the entry point in PE/COFF format is 32bit!*/
+ class = ELFCLASS64;
+ rewind(f_in);
+ fread((void *)&e64_hdr, sizeof(e64_hdr), 1, f_in);
+ id = e64_hdr.e_ident;
+ entry = e64_hdr.e_entry;
+ } else {
+ fprintf(stderr, "Unsupported architecture\n");
exit(EXIT_FAILURE);
}
-
- /* We only support 32-bit for now.. */
- if (e_hdr.e_ident[EI_CLASS] != ELFCLASS32) {
- fprintf(stderr, "Input file not 32-bit ELF shared object\n");
+
+ if (id[EI_MAG0] != ELFMAG0 ||
+ id[EI_MAG1] != ELFMAG1 ||
+ id[EI_MAG2] != ELFMAG2 ||
+ id[EI_MAG3] != ELFMAG3) {
+ fprintf(stderr, "Input file not ELF shared object\n");
exit(EXIT_FAILURE);
}
@@ -170,7 +231,7 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
- write_header(f_out, e_hdr.e_entry, st.st_size);
+ write_header(f_out, entry, st.st_size, class);
/* Write out the entire ELF shared object */
rewind(f_in);