summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2007-01-11 15:44:03 +0100
committerMichael Brown2007-01-11 15:44:03 +0100
commit7ad1c2eaa8d7fb4e41bd56ed4d2e72d82748244b (patch)
tree94f2f8a818b8edb0701d4507d5ea0ca41cb84419
parentAdd image directory back in (diff)
downloadipxe-7ad1c2eaa8d7fb4e41bd56ed4d2e72d82748244b.tar.gz
ipxe-7ad1c2eaa8d7fb4e41bd56ed4d2e72d82748244b.tar.xz
ipxe-7ad1c2eaa8d7fb4e41bd56ed4d2e72d82748244b.zip
Removed the Etherboot-specific ELF-image code and replaced it with a
generic ELF loader, to be used by the multiboot code.
-rw-r--r--src/arch/i386/core/elf.c136
-rw-r--r--src/image/elf.c130
-rw-r--r--src/include/elf.h6
-rw-r--r--src/include/elf_boot.h84
4 files changed, 134 insertions, 222 deletions
diff --git a/src/arch/i386/core/elf.c b/src/arch/i386/core/elf.c
deleted file mode 100644
index fbb4032f..00000000
--- a/src/arch/i386/core/elf.c
+++ /dev/null
@@ -1,136 +0,0 @@
-#include "etherboot.h"
-#include "elf.h"
-#include "memsizes.h"
-
-
-#define NAME "Etherboot"
-
-#if defined(PCBIOS)
-#define FIRMWARE "PCBIOS"
-#endif
-#if defined(LINUXBIOS)
-#define FIRMWARE "LinuxBIOS"
-#endif
-#if !defined(FIRMWARE)
-#error "No BIOS selected"
-#endif
-
-#define SZ(X) ((sizeof(X)+3) & ~3)
-#define CP(D,S) (memcpy(&(D), &(S), sizeof(S)))
-
-struct elf_notes {
- /* The note header */
- struct Elf_Bhdr hdr;
-
- /* First the Fixed sized entries that must be well aligned */
-
- /* Pointer to bootp data */
- Elf_Nhdr nf1;
- char nf1_name[SZ(EB_PARAM_NOTE)];
- uint32_t nf1_bootp_data;
-
- /* Pointer to ELF header */
- Elf_Nhdr nf2;
- char nf2_name[SZ(EB_PARAM_NOTE)];
- uint32_t nf2_header;
-
- /* A copy of the i386 memory map */
- Elf_Nhdr nf3;
- char nf3_name[SZ(EB_PARAM_NOTE)];
- struct meminfo nf3_meminfo;
-
- /* Then the variable sized data string data where alignment does not matter */
-
- /* The bootloader name */
- Elf_Nhdr nv1;
- char nv1_desc[SZ(NAME)];
- /* The bootloader version */
- Elf_Nhdr nv2;
- char nv2_desc[SZ(VERSION)];
- /* The firmware type */
- Elf_Nhdr nv3;
- char nv3_desc[SZ(FIRMWARE)];
- /* Name of the loaded image */
- Elf_Nhdr nv4;
- char nv4_loaded_image[128];
- /* An empty command line */
- Elf_Nhdr nv5;
- char nv5_cmdline[SZ("")];
-};
-
-#define ELF_NOTE_COUNT (3 + 5)
-
-static struct elf_notes notes;
-struct Elf_Bhdr *prepare_boot_params(void *header)
-{
- memset(&notes, 0, sizeof(notes));
- notes.hdr.b_signature = ELF_BHDR_MAGIC;
- notes.hdr.b_size = sizeof(notes);
- notes.hdr.b_checksum = 0;
- notes.hdr.b_records = ELF_NOTE_COUNT;
-
- /* Initialize the fixed length entries. */
- notes.nf1.n_namesz = sizeof(EB_PARAM_NOTE);
- notes.nf1.n_descsz = sizeof(notes.nf1_bootp_data);
- notes.nf1.n_type = EB_BOOTP_DATA;
- CP(notes.nf1_name, EB_PARAM_NOTE);
- notes.nf1_bootp_data = virt_to_phys(&bootp_data);
-
- notes.nf2.n_namesz = sizeof(EB_PARAM_NOTE);
- notes.nf2.n_descsz = sizeof(notes.nf2_header);
- notes.nf2.n_type = EB_HEADER;
- CP(notes.nf2_name, EB_PARAM_NOTE);
- notes.nf2_header = virt_to_phys(header);
-
- notes.nf3.n_namesz = sizeof(EB_PARAM_NOTE);
- notes.nf3.n_descsz = sizeof(notes.nf3_meminfo);
- notes.nf3.n_type = EB_I386_MEMMAP;
- CP(notes.nf3_name, EB_PARAM_NOTE);
- memcpy(&notes.nf3_meminfo, &meminfo, sizeof(meminfo));
-
- /* Initialize the variable length entries */
- notes.nv1.n_namesz = 0;
- notes.nv1.n_descsz = sizeof(NAME);
- notes.nv1.n_type = EBN_BOOTLOADER_NAME;
- CP(notes.nv1_desc, NAME);
-
- notes.nv2.n_namesz = 0;
- notes.nv2.n_descsz = sizeof(VERSION);
- notes.nv2.n_type = EBN_BOOTLOADER_VERSION;
- CP(notes.nv2_desc, VERSION);
-
- notes.nv3.n_namesz = 0;
- notes.nv3.n_descsz = sizeof(FIRMWARE);
- notes.nv3.n_type = EBN_FIRMWARE_TYPE;
- CP(notes.nv3_desc, FIRMWARE);
-
- /* Attempt to pass the name of the loaded image */
- notes.nv4.n_namesz = 0;
- notes.nv4.n_descsz = sizeof(notes.nv4_loaded_image);
- notes.nv4.n_type = EBN_LOADED_IMAGE;
- memcpy(&notes.nv4_loaded_image, KERNEL_BUF, sizeof(notes.nv4_loaded_image));
-
- /* Pass an empty command line for now */
- notes.nv5.n_namesz = 0;
- notes.nv5.n_descsz = sizeof("");
- notes.nv5.n_type = EBN_COMMAND_LINE;
- CP(notes.nv5_cmdline, "");
-
-
- notes.hdr.b_checksum = ipchksum(&notes, sizeof(notes));
- /* Like UDP invert a 0 checksum to show that a checksum is present */
- if (notes.hdr.b_checksum == 0) {
- notes.hdr.b_checksum = 0xffff;
- }
- return &notes.hdr;
-}
-
-int elf_start(unsigned long machine __unused_i386, unsigned long entry, unsigned long params)
-{
-#if defined(CONFIG_X86_64)
- if (machine == EM_X86_64) {
- return xstart_lm(entry, params);
- }
-#endif
- return xstart32(entry, params);
-}
diff --git a/src/image/elf.c b/src/image/elf.c
new file mode 100644
index 00000000..c746caa4
--- /dev/null
+++ b/src/image/elf.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+/**
+ * @file
+ *
+ * ELF image format
+ *
+ */
+
+#include <errno.h>
+#include <elf.h>
+#include <gpxe/uaccess.h>
+#include <gpxe/segment.h>
+
+typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Phdr Elf_Phdr;
+typedef Elf32_Off Elf_Off;
+
+/** An ELF file */
+struct elf {
+ /** ELF file image */
+ userptr_t image;
+ /** Length of ELF file image */
+ size_t len;
+};
+
+/**
+ * Load ELF segment into memory
+ *
+ * @v elf ELF file
+ * @v phdr ELF program header
+ * @ret rc Return status code
+ */
+static int elf_load_segment ( struct elf *elf, Elf_Phdr *phdr ) {
+ physaddr_t dest;
+ userptr_t buffer;
+ int rc;
+
+ /* Do nothing for non-PT_LOAD segments */
+ if ( phdr->p_type != PT_LOAD )
+ return 0;
+
+ /* Check segment lies within image */
+ if ( ( phdr->p_offset + phdr->p_filesz ) > elf->len ) {
+ DBG ( "ELF segment outside ELF file\n" );
+ return -ENOEXEC;
+ }
+
+ /* Find start address: use physical address for preference,
+ * fall back to virtual address if no physical address
+ * supplied.
+ */
+ dest = phdr->p_paddr;
+ if ( ! dest )
+ dest = phdr->p_vaddr;
+ if ( ! dest ) {
+ DBG ( "ELF segment loads to physical address 0\n" );
+ return -ENOEXEC;
+ }
+ buffer = phys_to_user ( dest );
+
+ DBG ( "ELF loading segment [%lx,%lx) to [%lx,%lx,%lx)\n",
+ phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
+ phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ),
+ ( phdr->p_paddr + phdr->p_memsz ) );
+
+ /* Verify and prepare segment */
+ if ( ( rc = prep_segment ( buffer, phdr->p_filesz,
+ phdr->p_memsz ) ) != 0 ) {
+ DBG ( "ELF could not prepare segment: %s\n", strerror ( rc ) );
+ return rc;
+ }
+
+ /* Copy image to segment */
+ copy_user ( buffer, 0, elf->image, phdr->p_offset, phdr->p_filesz );
+
+ return 0;
+}
+
+/**
+ * Load ELF image into memory
+ *
+ * @v elf ELF file
+ * @ret rc Return status code
+ */
+int elf_load ( struct elf *elf ) {
+ Elf_Ehdr ehdr;
+ Elf_Phdr phdr;
+ Elf_Off phoff;
+ unsigned int phnum;
+ int rc;
+
+ /* Read ELF header */
+ copy_from_user ( &ehdr, elf->image, 0, sizeof ( ehdr ) );
+ if ( memcmp ( &ehdr.e_ident[EI_MAG0], ELFMAG, SELFMAG ) != 0 ) {
+ DBG ( "Invalid ELF signature\n" );
+ return -ENOEXEC;
+ }
+
+ /* Read ELF program headers */
+ for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ;
+ phoff += ehdr.e_phentsize, phnum-- ) {
+ if ( phoff > elf->len ) {
+ DBG ( "ELF program header %d outside ELF image\n",
+ phnum );
+ return -ENOEXEC;
+ }
+ copy_from_user ( &phdr, elf->image, phoff, sizeof ( phdr ) );
+ if ( ( rc = elf_load_segment ( elf, &phdr ) ) != 0 )
+ return rc;
+ }
+
+ return 0;
+}
diff --git a/src/include/elf.h b/src/include/elf.h
index 606b4192..a6eb5d9c 100644
--- a/src/include/elf.h
+++ b/src/include/elf.h
@@ -121,6 +121,7 @@
#define ELFMAG3 'F'
#define ELFMAG "\177ELF"
+#define SELFMAG 4
#define EI_CLASS 4 /* File class byte index */
#define ELFCLASSNONE 0 /* Invalid class */
@@ -141,6 +142,9 @@
#define ELF32_PHDR_SIZE (8*4) /* Size of an elf program header */
#ifndef ASSEMBLY
+
+#include <stdint.h>
+
/*
* ELF definitions common to all 32-bit architectures.
*/
@@ -229,6 +233,4 @@ typedef struct {
#endif /* ASSEMBLY */
-#include "elf_boot.h"
-
#endif /* ELF_H */
diff --git a/src/include/elf_boot.h b/src/include/elf_boot.h
deleted file mode 100644
index 878a870a..00000000
--- a/src/include/elf_boot.h
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef ELF_BOOT_H
-#define ELF_BOOT_H
-
-
-/* This defines the structure of a table of parameters useful for ELF
- * bootable images. These parameters are all passed and generated
- * by the bootloader to the booted image. For simplicity and
- * consistency the Elf Note format is reused.
- *
- * All of the information must be Position Independent Data.
- * That is it must be safe to relocate the whole ELF boot parameter
- * block without changing the meaning or correctnes of the data.
- * Additionally it must be safe to permute the order of the ELF notes
- * to any possible permutation without changing the meaning or correctness
- * of the data.
- *
- */
-
-#define ELF_BHDR_MAGIC 0x0E1FB007
-
-#ifndef ASSEMBLY
-#include <stdint.h>
-typedef uint16_t Elf_Half;
-typedef uint32_t Elf_Word;
-
-typedef struct Elf_Bhdr
-{
- Elf_Word b_signature; /* "0x0E1FB007" */
- Elf_Word b_size;
- Elf_Half b_checksum;
- Elf_Half b_records;
-} Elf_Bhdr;
-
-typedef struct Elf_Nhdr
-{
- Elf_Word n_namesz; /* Length of the note's name. */
- Elf_Word n_descsz; /* Length of the note's descriptor. */
- Elf_Word n_type; /* Type of the note. */
-} Elf_Nhdr;
-
-#endif /* ASSEMBLY */
-
-/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */
-#define ELF_NOTE_BOOT "ELFBoot"
-
-#define EIN_PROGRAM_NAME 0x00000001
-/* The program in this ELF file */
-#define EIN_PROGRAM_VERSION 0x00000002
-/* The version of the program in this ELF file */
-#define EIN_PROGRAM_CHECKSUM 0x00000003
-/* ip style checksum of the memory image. */
-
-
-/* Notes that are passed to a loaded image */
-/* For standard notes n_namesz must be zero */
-#define EBN_FIRMWARE_TYPE 0x00000001
-/* ASCIZ name of the platform firmware. */
-#define EBN_BOOTLOADER_NAME 0x00000002
-/* This specifies just the ASCIZ name of the bootloader */
-#define EBN_BOOTLOADER_VERSION 0x00000003
-/* This specifies the version of the bootloader as an ASCIZ string */
-#define EBN_COMMAND_LINE 0x00000004
-/* This specifies a command line that can be set by user interaction,
- * and is provided as a free form ASCIZ string to the loaded image.
- */
-#define EBN_NOP 0x00000005
-/* A note nop note has no meaning, useful for inserting explicit padding */
-#define EBN_LOADED_IMAGE 0x00000006
-/* An ASCIZ string naming the loaded image */
-
-
-/* Etherboot specific notes */
-#define EB_PARAM_NOTE "Etherboot"
-#define EB_IA64_SYSTAB 0x00000001
-#define EB_IA64_MEMMAP 0x00000002
-#define EB_IA64_FPSWA 0x00000003
-#define EB_IA64_CONINFO 0x00000004
-#define EB_BOOTP_DATA 0x00000005
-#define EB_HEADER 0x00000006
-#define EB_IA64_IMAGE_HANDLE 0x00000007
-#define EB_I386_MEMMAP 0x00000008
-
-
-#endif /* ELF_BOOT_H */