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(¬es, 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(¬es.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(¬es.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(¬es, 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 ¬es.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 . + * + * 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 +#include +#include +#include + +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 + /* * 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 -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 */