]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[ELF] Add ability to boot ELF images generated by wraplinux and mkelfImage
authorMichael Brown <mcb30@etherboot.org>
Mon, 9 Jun 2008 12:11:46 +0000 (13:11 +0100)
committerMichael Brown <mcb30@etherboot.org>
Mon, 9 Jun 2008 12:50:00 +0000 (13:50 +0100)
Delete ELF as a generic image type.  The method for invoking an
ELF-based image (as well as any tables that must be set up to allow it
to boot) will always depend on the specific architecture.  core/elf.c
now only provides the elf_load() function, to avoid duplicating
functionality between ELF-based image types.

Add arch/i386/image/elfboot.c, to handle the generic case of 32-bit
x86 ELF images.  We don't currently set up any multiboot tables, ELF
notes, etc.  This seems to be sufficient for loading kernels generated
using both wraplinux and coreboot's mkelfImage.

Note that while Etherboot 5.4 allowed ELF images to return, we don't.
There is no callback mechanism for the loaded image to shut down gPXE,
which means that we have to shut down before invoking the image.  This
means that we lose device state, protection against being trampled on,
etc.  It is not safe to continue afterwards.

src/arch/i386/image/elfboot.c [new file with mode: 0644]
src/arch/i386/include/bits/errfile.h
src/config.h
src/core/config.c
src/image/elf.c
src/include/gpxe/features.h

diff --git a/src/arch/i386/image/elfboot.c b/src/arch/i386/image/elfboot.c
new file mode 100644 (file)
index 0000000..52510aa
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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 <errno.h>
+#include <elf.h>
+#include <gpxe/image.h>
+#include <gpxe/elf.h>
+#include <gpxe/features.h>
+#include <gpxe/init.h>
+
+/**
+ * @file
+ *
+ * ELF bootable image
+ *
+ */
+
+FEATURE ( FEATURE_IMAGE, "ELF", DHCP_EB_FEATURE_ELF, 1 );
+
+struct image_type elfboot_image_type __image_type ( PROBE_NORMAL );
+
+/**
+ * Execute ELF image
+ *
+ * @v image            ELF image
+ * @ret rc             Return status code
+ */
+static int elfboot_exec ( struct image *image ) {
+       physaddr_t entry = image->priv.phys;
+
+       /* An ELF image has no callback interface, so we need to shut
+        * down before invoking it.
+        */
+       shutdown();
+
+       /* Jump to OS with flat physical addressing */
+       __asm__ __volatile__ ( PHYS_CODE ( "call *%%edi\n\t" )
+                              : : "D" ( entry )
+                              : "eax", "ebx", "ecx", "edx", "esi", "ebp",
+                                "memory" );
+
+       DBGC ( image, "ELF %p returned\n", image );
+
+       /* It isn't safe to continue after calling shutdown() */
+       while ( 1 ) {}
+
+       return -ECANCELED;  /* -EIMPOSSIBLE, anyone? */
+}
+
+/**
+ * Load ELF image into memory
+ *
+ * @v image            ELF file
+ * @ret rc             Return status code
+ */
+static int elfboot_load ( struct image *image ) {
+       Elf32_Ehdr ehdr;
+       static const uint8_t e_ident[] = {
+               [EI_MAG0]       = ELFMAG0,
+               [EI_MAG1]       = ELFMAG1,
+               [EI_MAG2]       = ELFMAG2,
+               [EI_MAG3]       = ELFMAG3,
+               [EI_CLASS]      = ELFCLASS32,
+               [EI_DATA]       = ELFDATA2LSB,
+               [EI_VERSION]    = EV_CURRENT,
+       };
+       int rc;
+
+       /* Read ELF header */
+       copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
+       if ( memcmp ( ehdr.e_ident, e_ident, sizeof ( e_ident ) ) != 0 ) {
+               DBG ( "Invalid ELF identifier\n" );
+               return -ENOEXEC;
+       }
+
+       /* This is an ELF image, valid or otherwise */
+       if ( ! image->type )
+               image->type = &elfboot_image_type;
+
+       /* Load the image using core ELF support */
+       if ( ( rc = elf_load ( image ) ) != 0 ) {
+               DBGC ( image, "ELF %p could not load: %s\n",
+                      image, strerror ( rc ) );
+               return rc;
+       }
+
+       return 0;
+}
+
+/** ELF image type */
+struct image_type elfboot_image_type __image_type ( PROBE_NORMAL ) = {
+       .name = "ELF",
+       .load = elfboot_load,
+       .exec = elfboot_exec,
+};
index 678be0457ebb961383fe3a25cd237b757c45115c..c5b04a26a7456ca44fb36e35391305018a82540a 100644 (file)
@@ -20,6 +20,7 @@
 #define ERRFILE_multiboot      ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00030000 )
 #define ERRFILE_nbi           ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00040000 )
 #define ERRFILE_pxe_image      ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00050000 )
+#define ERRFILE_elfboot               ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00060000 )
 
 #define ERRFILE_undi            ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 )
 #define ERRFILE_undiload        ( ERRFILE_ARCH | ERRFILE_NET | 0x00010000 )
index 2d0980b0b3d42ade2941b2b58943c9760eadff36..e695b015a2bcdef4ea555be004bbefab28990670 100644 (file)
  *
  */
 #undef IMAGE_NBI               /* NBI image support */
-#undef IMAGE_ELF64             /* ELF64 image support */
-#undef IMAGE_ELF               /* ELF image support */
+#define        IMAGE_ELF               /* ELF image support */
 #undef IMAGE_FREEBSD           /* FreeBSD kernel image support */
 #define        IMAGE_MULTIBOOT         /* MultiBoot image support */
 #undef IMAGE_AOUT              /* a.out image support */
index 01f709c6256393de97a567bec7440361a1eb964b..018f084a852bde982332bb0e528b89d8e82a0da6 100644 (file)
@@ -131,11 +131,8 @@ REQUIRE_OBJECT ( nmb );
 #ifdef IMAGE_NBI
 REQUIRE_OBJECT ( nbi );
 #endif
-#ifdef IMAGE_ELF64
-REQUIRE_OBJECT ( elf64 );
-#endif
 #ifdef IMAGE_ELF
-REQUIRE_OBJECT ( elf );
+REQUIRE_OBJECT ( elfboot );
 #endif
 #ifdef IMAGE_FREEBSD
 REQUIRE_OBJECT ( freebsd );
index 75c976eaf101d8a0b60f76e94ed3062fd4666b51..b932ff5866a990149c3e64ed7c6b8525fe6b6750 100644 (file)
@@ -21,6 +21,9 @@
  *
  * ELF image format
  *
+ * A "pure" ELF image is not a bootable image.  There are various
+ * bootable formats based upon ELF (e.g. Multiboot), which share
+ * common ELF-related functionality.
  */
 
 #include <errno.h>
 #include <gpxe/image.h>
 #include <gpxe/elf.h>
 
-struct image_type elf_image_type __image_type ( PROBE_NORMAL );
-
 typedef Elf32_Ehdr     Elf_Ehdr;
 typedef Elf32_Phdr     Elf_Phdr;
 typedef Elf32_Off      Elf_Off;
 
-/**
- * Execute ELF image
- *
- * @v image            ELF file
- * @ret rc             Return status code
- */
-static int elf_exec ( struct image *image __unused ) {
-       return -ENOTSUP;
-}
-
 /**
  * Load ELF segment into memory
  *
@@ -112,6 +103,9 @@ int elf_load ( struct image *image ) {
        unsigned int phnum;
        int rc;
 
+       /* Image type must already have been set by caller */
+       assert ( image->type != NULL );
+
        /* Read ELF header */
        copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
        if ( memcmp ( &ehdr.e_ident[EI_MAG0], ELFMAG, SELFMAG ) != 0 ) {
@@ -119,10 +113,6 @@ int elf_load ( struct image *image ) {
                return -ENOEXEC;
        }
 
-       /* This is an ELF image, valid or otherwise */
-       if ( ! image->type )
-               image->type = &elf_image_type;
-
        /* Read ELF program headers */
        for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ;
              phoff += ehdr.e_phentsize, phnum-- ) {
@@ -141,10 +131,3 @@ int elf_load ( struct image *image ) {
 
        return 0;
 }
-
-/** ELF image type */
-struct image_type elf_image_type __image_type ( PROBE_NORMAL ) = {
-       .name = "ELF",
-       .load = elf_load,
-       .exec = elf_exec,
-};
index a520131f10bf66427372c7bb7c4ab15db8bc7b3a..54498b5fadb7bbf3ade60065575aa8c54e083c64 100644 (file)
@@ -43,6 +43,7 @@
 #define DHCP_EB_FEATURE_MULTIBOOT      0x19 /**< Multiboot format */
 #define DHCP_EB_FEATURE_NBI            0x20 /**< NBI format */
 #define DHCP_EB_FEATURE_PXE            0x21 /**< PXE format */
+#define DHCP_EB_FEATURE_ELF            0x22 /**< ELF format */
 
 /** @} */