aboutsummaryrefslogtreecommitdiffstats
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
parent3f7a44b8c18d9c9916b279872a0ef8701179e2e8 (diff)
downloadsyslinux-ca8533f1ef1d60dffa21449633dec9d26baeb29d.tar.gz
syslinux-ca8533f1ef1d60dffa21449633dec9d26baeb29d.tar.xz
syslinux-ca8533f1ef1d60dffa21449633dec9d26baeb29d.zip
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.
-rw-r--r--efi/main.c55
-rw-r--r--efi/wrapper.c145
-rw-r--r--efi/wrapper.h52
3 files changed, 209 insertions, 43 deletions
diff --git a/efi/main.c b/efi/main.c
index ca098917..07177e0e 100644
--- a/efi/main.c
+++ b/efi/main.c
@@ -308,7 +308,13 @@ struct boot_params {
struct e820_entry e820_map[E820MAX];
} __packed;
+#if __SIZEOF_POINTER__ == 4
#define EFI_LOAD_SIG "EL32"
+#elif __SIZEOF_POINTER__ == 8
+#define EFI_LOAD_SIG "EL64"
+#else
+#error "unsupported architecture"
+#endif
struct dt_desc {
uint16_t limit;
@@ -463,21 +469,34 @@ int efi_boot_linux(void *kernel_buf, size_t kernel_size,
memset(si, 0, sizeof(*si));
setup_screen(si);
+#if __SIZEOF_POINTER__ == 4
gdt.base = (uint16_t *)malloc(gdt.limit);
+#elif __SIZEOF_POINTER__ == 8
+ gdt.base = (uint64_t *)malloc(gdt.limit);
+#else
+#error "unsupported architecture"
+#endif
memset(gdt.base, 0x0, gdt.limit);
first = -1ULL;
find_addr(&first, NULL, 0x1000, -1ULL, kernel_size,
hdr->kernel_alignment);
- if (first != -1ULL)
+ if (first != -1ULL) {
status = allocate_addr(&first, kernel_size);
+ }
if (first == -1ULL || status != EFI_SUCCESS) {
printf("Failed to allocate memory for kernel\n");
goto bail;
}
+#if __SIZEOF_POINTER__ == 4
hdr->code32_start = (uint32_t)first;
+#elif __SIZEOF_POINTER__ == 8
+ hdr->code32_start = (uint32_t)(uint64_t)first;
+#else
+#error "unsupported architecture"
+#endif
/* Skip the setup headers and copy the code */
kernel_buf += (hdr->setup_sects + 1) * 512;
@@ -539,12 +558,25 @@ int efi_boot_linux(void *kernel_buf, size_t kernel_size,
if (!map)
goto free_irf;
+#if __SIZEOF_POINTER__ == 4
bp->efi.memmap = map;
bp->efi.memmap_size = nr_entries * desc_sz;
bp->efi.systab = ST;
bp->efi.desc_size = desc_sz;
bp->efi.desc_version = desc_ver;
+#elif __SIZEOF_POINTER__ == 8
+ bp->efi.memmap = (uint32_t)(unsigned long)map;
+ bp->efi.memmap_hi = ((unsigned long)map) >> 32;
+ bp->efi.memmap_size = nr_entries * desc_sz;
+
+ bp->efi.systab = (uint32_t)(unsigned long)ST;
+ bp->efi.systab_hi = ((unsigned long)ST) >> 32;
+ bp->efi.desc_size = desc_sz;
+ bp->efi.desc_version = desc_ver;
+#else
+#error "unsupported architecture"
+#endif
/*
* Even though 'memmap' contains the memory map we provided
@@ -638,11 +670,32 @@ int efi_boot_linux(void *kernel_buf, size_t kernel_size,
asm volatile ("lidt %0" :: "m" (idt));
asm volatile ("lgdt %0" :: "m" (gdt));
+#if __SIZEOF_POINTER__ == 4
asm volatile ("cli \n"
"movl %0, %%esi \n"
"movl %1, %%ecx \n"
"jmp *%%ecx \n"
:: "m" (bp), "m" (hdr->code32_start));
+#elif __SIZEOF_POINTER__ == 8
+ {
+ struct {
+ uint32_t kernel_entry;
+ uint16_t kernel_cs;
+ } kernel_vector;
+ void *kstart;
+
+ kernel_vector.kernel_entry = hdr->code32_start;
+ kernel_vector.kernel_cs = 0x10;
+ kstart = (VOID *)&kernel_vector;
+ asm volatile ("cli \n"
+ "mov %0, %%rsi \n"
+ "mov %1, %%rcx \n"
+ "ljmp *(%%rcx) \n"
+ :: "m" (bp), "m" (kstart));
+ }
+#else
+#error "unsupported architecture"
+#endif
/* NOTREACHED */
free_map:
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);
diff --git a/efi/wrapper.h b/efi/wrapper.h
index c5f64a3c..492c262b 100644
--- a/efi/wrapper.h
+++ b/efi/wrapper.h
@@ -4,8 +4,10 @@
#define MSDOS_SIGNATURE 0x5a4d
#define PE_SIGNATURE 0x4550
#define PE32_FORMAT 0x10b
+#define PE32P_FORMAT 0x20b /* PE32+ */
#define IMAGE_FILE_MACHINE_I386 0x14c
+#define IMAGE_FILE_MACHINE_X86_64 0x8664
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
#define IMAGE_FILE_LINE_NUMBERS_STRIPPED 0x0004
#define IMAGE_FILE_32BIT_MACHINE 0x0100
@@ -32,6 +34,9 @@ struct header {
__uint16_t _pad2;
} __packed;
+/* FIXME: when setting up coff_hdr, set up optional_hdr_sz
+ * based on PE32 or PE32+ format
+ */
/*
* COFF header
*/
@@ -57,6 +62,19 @@ struct optional_hdr {
__uint32_t data;
} __packed;
+/* For PE32+, the optional_header does NOT have
+ * data after base_code
+ */
+struct optional_hdr_pe32p {
+ __uint16_t format;
+ __uint8_t major_linker_version;
+ __uint8_t minor_linker_version;
+ __uint32_t code_sz;
+ __uint32_t initialized_data_sz;
+ __uint32_t uninitialized_data_sz;
+ __uint32_t entry_point;
+ __uint32_t base_code;
+} __packed;
/*
* Extra header fields
*/
@@ -90,6 +108,40 @@ struct extra_hdr {
__uint64_t base_relocation_table;
} __packed;
+/* Extra header for PE32+ format
+ * FIXME: There are additional fields in Microsoft PE COFF v8
+ */
+
+struct extra_hdr_pe32p {
+ __uint64_t image_base;
+ __uint32_t section_align;
+ __uint32_t file_align;
+ __uint16_t major_os_version;
+ __uint16_t minor_os_version;
+ __uint16_t major_image_version;
+ __uint16_t minor_image_version;
+ __uint16_t major_subsystem_version;
+ __uint16_t minor_subsystem_version;
+ __uint32_t win32_version;
+ __uint32_t image_sz;
+ __uint32_t headers_sz;
+ __uint32_t checksum;
+ __uint16_t subsystem;
+ __uint16_t dll_characteristics;
+ __uint64_t stack_reserve_sz;
+ __uint64_t stack_commit_sz;
+ __uint64_t heap_reserve_sz;
+ __uint64_t heap_commit_sz;
+ __uint32_t loader_flags;
+ __uint32_t rva_and_sizes_nr;
+ __uint64_t export_table;
+ __uint64_t import_table;
+ __uint64_t resource_table;
+ __uint64_t exception_table;
+ __uint64_t certification_table;
+ __uint64_t base_relocation_table;
+} __packed;
+
struct section {
__uint8_t name[8];
__uint32_t virtual_sz;