david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

Removed the Etherboot-specific ELF-image code and replaced it with a

generic ELF loader, to be used by the multiboot code.
This commit is contained in:
Michael Brown 2007-01-11 14:44:03 +00:00
parent 10980c12ee
commit 7ad1c2eaa8
4 changed files with 134 additions and 222 deletions

View File

@ -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);
}

130
src/image/elf.c Normal file
View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */