diff --git a/src/arch/i386/Makefile.efi b/src/arch/i386/Makefile.efi index c75338c9e..8d651b04d 100644 --- a/src/arch/i386/Makefile.efi +++ b/src/arch/i386/Makefile.efi @@ -1,19 +1,10 @@ # -*- makefile -*- : Force emacs to use Makefile mode -# The EFI linker script +# Specify EFI image builder # -LDSCRIPT = arch/x86/scripts/efi.lds +ELF2EFI = $(ELF2EFI32) -# Retain relocation information for elf2efi +# Include generic EFI Makefile # -LDFLAGS += -q -S - -# Media types. -# -NON_AUTO_MEDIA += efi - -# Rule for building EFI files -# -$(BIN)/%.efi : $(BIN)/%.efi.tmp $(ELF2EFI32) - $(QM)$(ECHO) " [FINISH] $@" - $(Q)$(ELF2EFI32) $< $@ +MAKEDEPS += arch/x86/Makefile.efi +include arch/x86/Makefile.efi diff --git a/src/arch/x86/Makefile.efi b/src/arch/x86/Makefile.efi new file mode 100644 index 000000000..92cd02048 --- /dev/null +++ b/src/arch/x86/Makefile.efi @@ -0,0 +1,24 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# The EFI linker script +# +LDSCRIPT = arch/x86/scripts/efi.lds + +# Retain relocation information for elf2efi +# +LDFLAGS += -q -S + +# Media types. +# +NON_AUTO_MEDIA += efi +NON_AUTO_MEDIA += efidrv + +# Rules for building EFI files +# +$(BIN)/%.efi : $(BIN)/%.efi.tmp $(ELF2EFI) + $(QM)$(ECHO) " [FINISH] $@" + $(Q)$(ELF2EFI) --subsystem=10 $< $@ + +$(BIN)/%.efidrv : $(BIN)/%.efidrv.tmp $(ELF2EFI) + $(QM)$(ECHO) " [FINISH] $@" + $(Q)$(ELF2EFI) --subsystem=11 $< $@ diff --git a/src/arch/x86/prefix/efidrvprefix.c b/src/arch/x86/prefix/efidrvprefix.c new file mode 100644 index 000000000..5f631588f --- /dev/null +++ b/src/arch/x86/prefix/efidrvprefix.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +/** + * EFI entry point + * + * @v image_handle Image handle + * @v systab System table + * @ret efirc EFI return status code + */ +EFI_STATUS EFIAPI _start ( EFI_HANDLE image_handle, + EFI_SYSTEM_TABLE *systab ) { + EFI_STATUS efirc; + + /* Initialise EFI environment */ + if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 ) + return efirc; + + /* Initialise gPXE environment */ + initialise(); + startup(); + + /* Install SNP driver and return */ + return RC_TO_EFIRC ( efi_snp_install () ); +} diff --git a/src/arch/x86/scripts/efi.lds b/src/arch/x86/scripts/efi.lds index bfe817398..aac310569 100644 --- a/src/arch/x86/scripts/efi.lds +++ b/src/arch/x86/scripts/efi.lds @@ -5,7 +5,6 @@ * */ -EXTERN ( _start ) ENTRY ( _start ) SECTIONS { diff --git a/src/arch/x86_64/Makefile.efi b/src/arch/x86_64/Makefile.efi index 928f5e92a..26b712780 100644 --- a/src/arch/x86_64/Makefile.efi +++ b/src/arch/x86_64/Makefile.efi @@ -4,20 +4,11 @@ # CFLAGS += -mno-red-zone -# The EFI linker script +# Specify EFI image builder # -LDSCRIPT = arch/x86/scripts/efi.lds +ELF2EFI = $(ELF2EFI64) -# Retain relocation information for elf2efi +# Include generic EFI Makefile # -LDFLAGS += -q -S - -# Media types. -# -NON_AUTO_MEDIA += efi - -# Rule for building EFI files -# -$(BIN)/%.efi : $(BIN)/%.efi.tmp $(ELF2EFI64) - $(QM)$(ECHO) " [FINISH] $@" - $(Q)$(ELF2EFI64) $< $@ +MAKEDEPS += arch/x86/Makefile.efi +include arch/x86/Makefile.efi diff --git a/src/include/gpxe/efi/efi.h b/src/include/gpxe/efi/efi.h index 2f9951419..c7f63b6c7 100644 --- a/src/include/gpxe/efi/efi.h +++ b/src/include/gpxe/efi/efi.h @@ -126,5 +126,6 @@ extern EFI_SYSTEM_TABLE *efi_systab; extern const char * efi_strerror ( EFI_STATUS efirc ); extern EFI_STATUS efi_init ( EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab ); +extern int efi_snp_install ( void ); #endif /* _EFI_H */ diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 0c65a440d..ec75be014 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -25,6 +25,7 @@ #include #include #include +#include #include /* Include the EFI PE image header file */ @@ -69,6 +70,8 @@ typedef uint64_t UINT64; #define BIT31 0x80000000 #include "../include/gpxe/efi/IndustryStandard/PeImage.h" +#define eprintf(...) fprintf ( stderr, __VA_ARGS__ ) + #define EFI_FILE_ALIGN 0x20 struct pe_section { @@ -127,13 +130,17 @@ static struct pe_header efi_pe_header = { .FileAlignment = EFI_FILE_ALIGN, .SizeOfImage = sizeof ( efi_pe_header ), .SizeOfHeaders = sizeof ( efi_pe_header ), - .Subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION, .NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES, }, }, }; +/** Command-line options */ +struct options { + unsigned int subsystem; +}; + /** * Allocate memory * @@ -145,7 +152,7 @@ static void * xmalloc ( size_t len ) { ptr = malloc ( len ); if ( ! ptr ) { - fprintf ( stderr, "Could not allocate %zd bytes\n", len ); + eprintf ( "Could not allocate %zd bytes\n", len ); exit ( 1 ); } @@ -190,7 +197,7 @@ static void generate_pe_reloc ( struct pe_relocs **pe_reltab, reloc |= 0x2000; break; default: - fprintf ( stderr, "Unsupported relocation size %zd\n", size ); + eprintf ( "Unsupported relocation size %zd\n", size ); exit ( 1 ); } @@ -271,7 +278,7 @@ static bfd * open_input_bfd ( const char *filename ) { /* Open the file */ bfd = bfd_openr ( filename, NULL ); if ( ! bfd ) { - fprintf ( stderr, "Cannot open %s: ", filename ); + eprintf ( "Cannot open %s: ", filename ); bfd_perror ( NULL ); exit ( 1 ); } @@ -280,7 +287,7 @@ static bfd * open_input_bfd ( const char *filename ) { * we get a segfault from later BFD calls. */ if ( bfd_check_format ( bfd, bfd_object ) < 0 ) { - fprintf ( stderr, "%s is not an object file\n", filename ); + eprintf ( "%s is not an object file\n", filename ); exit ( 1 ); } @@ -442,8 +449,7 @@ static struct pe_section * process_section ( bfd *bfd, if ( flags & SEC_LOAD ) { if ( ! bfd_get_section_contents ( bfd, section, new->contents, 0, section_memsz ) ) { - fprintf ( stderr, "Cannot read section %s: ", - section->name ); + eprintf ( "Cannot read section %s: ", section->name ); bfd_perror ( NULL ); exit ( 1 ); } @@ -518,8 +524,7 @@ static void process_reloc ( bfd *bfd, asection *section, arelent *rel, * remain unaltered when the object is loaded. */ } else { - fprintf ( stderr, "Unrecognised relocation type %s\n", - howto->name ); + eprintf ( "Unrecognised relocation type %s\n", howto->name ); exit ( 1 ); } } @@ -670,7 +675,7 @@ static void write_pe_file ( struct pe_header *pe_header, for ( section = pe_sections ; section ; section = section->next ) { if ( fseek ( pe, section->hdr.PointerToRawData, SEEK_SET ) != 0 ) { - fprintf ( stderr, "Could not seek to %lx: %s\n", + eprintf ( "Could not seek to %lx: %s\n", section->hdr.PointerToRawData, strerror ( errno ) ); exit ( 1 ); @@ -678,7 +683,7 @@ static void write_pe_file ( struct pe_header *pe_header, if ( section->hdr.SizeOfRawData && ( fwrite ( section->contents, section->hdr.SizeOfRawData, 1, pe ) != 1 ) ) { - fprintf ( stderr, "Could not write section %.8s: %s\n", + eprintf ( "Could not write section %.8s: %s\n", section->hdr.Name, strerror ( errno ) ); exit ( 1 ); } @@ -691,7 +696,8 @@ static void write_pe_file ( struct pe_header *pe_header, * @v elf_name ELF file name * @v pe_name PE file name */ -static void elf2pe ( const char *elf_name, const char *pe_name ) { +static void elf2pe ( const char *elf_name, const char *pe_name, + struct options *opts ) { bfd *bfd; asymbol **symtab; asection *section; @@ -711,6 +717,7 @@ static void elf2pe ( const char *elf_name, const char *pe_name ) { memcpy ( &pe_header, &efi_pe_header, sizeof ( pe_header ) ); pe_header.nt.OptionalHeader.AddressOfEntryPoint = bfd_get_start_address ( bfd ); + pe_header.nt.OptionalHeader.Subsystem = opts->subsystem; /* For each input section, build an output section and create * the appropriate relocation records @@ -742,7 +749,7 @@ static void elf2pe ( const char *elf_name, const char *pe_name ) { /* Write out PE file */ pe = fopen ( pe_name, "w" ); if ( ! pe ) { - fprintf ( stderr, "Could not open %s for writing: %s\n", + eprintf ( "Could not open %s for writing: %s\n", pe_name, strerror ( errno ) ); exit ( 1 ); } @@ -753,12 +760,84 @@ static void elf2pe ( const char *elf_name, const char *pe_name ) { bfd_close ( bfd ); } +/** + * Print help + * + * @v program_name Program name + */ +static void print_help ( const char *program_name ) { + eprintf ( "Syntax: %s [--subsystem=] infile outfile\n", + program_name ); +} + +/** + * Parse command-line options + * + * @v argc Argument count + * @v argv Argument list + * @v opts Options structure to populate + */ +static int parse_options ( const int argc, char **argv, + struct options *opts ) { + char *end; + int c; + + while (1) { + int option_index = 0; + static struct option long_options[] = { + { "subsystem", required_argument, NULL, 's' }, + { "help", 0, NULL, 'h' }, + { 0, 0, 0, 0 } + }; + + if ( ( c = getopt_long ( argc, argv, "s:h", + long_options, + &option_index ) ) == -1 ) { + break; + } + + switch ( c ) { + case 's': + opts->subsystem = strtoul ( optarg, &end, 0 ); + if ( *end ) { + eprintf ( "Invalid subsytem \"%s\"\n", + optarg ); + exit ( 2 ); + } + break; + case 'h': + print_help ( argv[0] ); + exit ( 0 ); + case '?': + default: + exit ( 2 ); + } + } + return optind; +} + int main ( int argc, char **argv ) { + struct options opts = { + .subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION, + }; + unsigned int infile_index; + const char *infile; + const char *outfile; /* Initialise libbfd */ bfd_init(); - elf2pe ( argv[1], argv[2] ); + /* Parse command-line arguments */ + infile_index = parse_options ( argc, argv, &opts ); + if ( argc != ( infile_index + 2 ) ) { + print_help ( argv[0] ); + exit ( 2 ); + } + infile = argv[infile_index]; + outfile = argv[infile_index + 1]; + + /* Convert file */ + elf2pe ( infile, outfile, &opts ); return 0; }