Author: mcayland Date: Sat Mar 27 11:57:03 2010 New Revision: 710 URL: http://tracker.coreboot.org/trac/openbios/changeset/710
Log: Create a brand new ELF loader based upon arch/*/elfload.c and libopenbios/elfload.c combined together in libopenbios. This means that each arch no longer needs its own ELF loader implementation.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@siriusit.co.uk
Added: trunk/openbios-devel/include/libopenbios/elf_load.h trunk/openbios-devel/libopenbios/elf_load.c Deleted: trunk/openbios-devel/arch/amd64/elfload.c trunk/openbios-devel/arch/sparc32/elfload.c trunk/openbios-devel/arch/sparc64/elfload.c trunk/openbios-devel/arch/x86/elfload.c trunk/openbios-devel/include/libopenbios/elfload.h trunk/openbios-devel/libopenbios/elfload.c Modified: trunk/openbios-devel/arch/ppc/qemu/main.c trunk/openbios-devel/arch/sparc32/build.xml trunk/openbios-devel/arch/sparc64/boot.c trunk/openbios-devel/arch/sparc64/boot.h trunk/openbios-devel/arch/sparc64/build.xml trunk/openbios-devel/arch/unix/boot.c trunk/openbios-devel/arch/x86/build.xml trunk/openbios-devel/arch/x86/linux_load.c trunk/openbios-devel/arch/x86/segment.c trunk/openbios-devel/include/arch/amd64/io.h trunk/openbios-devel/include/arch/amd64/types.h trunk/openbios-devel/include/arch/sparc32/types.h trunk/openbios-devel/include/arch/sparc64/types.h trunk/openbios-devel/include/arch/x86/io.h trunk/openbios-devel/include/arch/x86/types.h trunk/openbios-devel/libopenbios/build.xml
Modified: trunk/openbios-devel/arch/ppc/qemu/main.c ============================================================================== --- trunk/openbios-devel/arch/ppc/qemu/main.c Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/arch/ppc/qemu/main.c Sat Mar 27 11:57:03 2010 (r710) @@ -16,7 +16,7 @@
#include "config.h" #include "libopenbios/bindings.h" -#include "libopenbios/elfload.h" +#include "libopenbios/elf_load.h" #include "arch/common/nvram.h" #include "packages/nvram.h" #include "libc/diskio.h"
Modified: trunk/openbios-devel/arch/sparc32/build.xml ============================================================================== --- trunk/openbios-devel/arch/sparc32/build.xml Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/arch/sparc32/build.xml Sat Mar 27 11:57:03 2010 (r710) @@ -15,7 +15,6 @@ <object source="udiv.S"/> <object source="linux_load.c"/> <object source="sys_info.c"/> - <object source="elfload.c"/> <object source="aoutload.c"/> <object source="forthload.c"/> <object source="romvec.c"/>
Modified: trunk/openbios-devel/arch/sparc64/boot.c ============================================================================== --- trunk/openbios-devel/arch/sparc64/boot.c Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/arch/sparc64/boot.c Sat Mar 27 11:57:03 2010 (r710) @@ -8,6 +8,7 @@ #include "libc/diskio.h" #include "libc/vsprintf.h" #include "libopenbios/sys_info.h" +#include "libopenbios/elf_load.h" #include "boot.h"
struct sys_info sys_info; @@ -26,7 +27,7 @@ int image_retval = 0;
/* ELF Boot loader */ - elf_load(&sys_info, path, param); + elf_load(&sys_info, path, param, &boot_notes); feval("state-valid @"); valid = POP(); if (valid)
Modified: trunk/openbios-devel/arch/sparc64/boot.h ============================================================================== --- trunk/openbios-devel/arch/sparc64/boot.h Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/arch/sparc64/boot.h Sat Mar 27 11:57:03 2010 (r710) @@ -9,9 +9,6 @@ // forthload.c int forth_load(const char *filename);
-// elfload.c -int elf_load(struct sys_info *info, const char *filename, const char *cmdline); - // aout_load.c int aout_load(struct sys_info *info, const char *filename);
Modified: trunk/openbios-devel/arch/sparc64/build.xml ============================================================================== --- trunk/openbios-devel/arch/sparc64/build.xml Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/arch/sparc64/build.xml Sat Mar 27 11:57:03 2010 (r710) @@ -14,7 +14,6 @@ <object source="switch.S"/> <object source="linux_load.c"/> <object source="sys_info.c"/> - <object source="elfload.c"/> <object source="aoutload.c"/> <object source="forthload.c"/> <object source="fcodeload.c"/>
Modified: trunk/openbios-devel/arch/unix/boot.c ============================================================================== --- trunk/openbios-devel/arch/unix/boot.c Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/arch/unix/boot.c Sat Mar 27 11:57:03 2010 (r710) @@ -4,7 +4,7 @@ #undef BOOTSTRAP #include "config.h" #include "libopenbios/bindings.h" -#include "libopenbios/elfload.h" +#include "libopenbios/elf_load.h" #include "arch/common/nvram.h" #include "libc/diskio.h"
Modified: trunk/openbios-devel/arch/x86/build.xml ============================================================================== --- trunk/openbios-devel/arch/x86/build.xml Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/arch/x86/build.xml Sat Mar 27 11:57:03 2010 (r710) @@ -14,7 +14,6 @@ <object source="linux_load.c"/> <object source="segment.c"/> <object source="sys_info.c"/> - <object source="elfload.c"/> <object source="forthload.c"/> <object source="entry.S"/> <object source="xbox/console.c" condition="XBOX"/>
Modified: trunk/openbios-devel/arch/x86/linux_load.c ============================================================================== --- trunk/openbios-devel/arch/x86/linux_load.c Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/arch/x86/linux_load.c Sat Mar 27 11:57:03 2010 (r710) @@ -460,7 +460,6 @@ uint32_t max; uint32_t start, end, size; uint64_t forced; - extern char _start[], _end[];
fd = open_io(initrd_file); if (!fd) {
Modified: trunk/openbios-devel/arch/x86/segment.c ============================================================================== --- trunk/openbios-devel/arch/x86/segment.c Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/arch/x86/segment.c Sat Mar 27 11:57:03 2010 (r710) @@ -40,7 +40,6 @@ {0xffff, 0, 0, 0x93, 0xcf, 0}, };
-extern char _start[], _end[];
void relocate(struct sys_info *info) {
Modified: trunk/openbios-devel/include/arch/amd64/io.h ============================================================================== --- trunk/openbios-devel/include/arch/amd64/io.h Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/include/arch/amd64/io.h Sat Mar 27 11:57:03 2010 (r710) @@ -1,6 +1,7 @@ #ifndef _ASM_IO_H #define _ASM_IO_H
+extern char _start, _end; extern unsigned long virt_offset;
#define phys_to_virt(phys) ((void *) ((unsigned long) (phys) - virt_offset))
Modified: trunk/openbios-devel/include/arch/amd64/types.h ============================================================================== --- trunk/openbios-devel/include/arch/amd64/types.h Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/include/arch/amd64/types.h Sat Mar 27 11:57:03 2010 (r710) @@ -23,6 +23,8 @@ typedef __int128_t dcell; typedef __uint128_t ducell;
+#define FMT_elf "%#x" + #define bitspercell (sizeof(cell)<<3) #define bitsperdcell (sizeof(dcell)<<3)
Modified: trunk/openbios-devel/include/arch/sparc32/types.h ============================================================================== --- trunk/openbios-devel/include/arch/sparc32/types.h Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/include/arch/sparc32/types.h Sat Mar 27 11:57:03 2010 (r710) @@ -40,6 +40,8 @@ #define FMT_ucellx "%08x" #define FMT_ucellX "%08X"
+#define FMT_elf "%#x" + #define bitspercell (sizeof(cell)<<3) #define bitsperdcell (sizeof(dcell)<<3)
Modified: trunk/openbios-devel/include/arch/sparc64/types.h ============================================================================== --- trunk/openbios-devel/include/arch/sparc64/types.h Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/include/arch/sparc64/types.h Sat Mar 27 11:57:03 2010 (r710) @@ -37,6 +37,10 @@ #define FMT_ucellx "%016llx" #define FMT_ucellX "%016llX"
+#define FMT_sizet "%lx" +#define FMT_elf "%#llx" +#define FMT_aout_ehdr "%x" + #ifdef NEED_FAKE_INT128_T typedef struct { uint64_t hi;
Modified: trunk/openbios-devel/include/arch/x86/io.h ============================================================================== --- trunk/openbios-devel/include/arch/x86/io.h Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/include/arch/x86/io.h Sat Mar 27 11:57:03 2010 (r710) @@ -3,6 +3,7 @@
#include "asm/types.h"
+extern char _start, _end; extern unsigned long virt_offset;
#define phys_to_virt(phys) ((void *) ((unsigned long) (phys) - virt_offset))
Modified: trunk/openbios-devel/include/arch/x86/types.h ============================================================================== --- trunk/openbios-devel/include/arch/x86/types.h Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/include/arch/x86/types.h Sat Mar 27 11:57:03 2010 (r710) @@ -29,6 +29,8 @@ #define FMT_ucellx "%08x" #define FMT_ucellX "%08X"
+#define FMT_elf "%#x" + #define bitspercell (sizeof(cell)<<3) #define bitsperdcell (sizeof(dcell)<<3)
Added: trunk/openbios-devel/include/libopenbios/elf_load.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ trunk/openbios-devel/include/libopenbios/elf_load.h Sat Mar 27 11:57:03 2010 (r710) @@ -0,0 +1,30 @@ +/* + * Creation Date: <2001/05/05 16:44:17 samuel> + * Time-stamp: <2003/10/22 23:18:42 samuel> + * + * <elfload.h> + * + * Elf loader + * + * Copyright (C) 2001, 2003 Samuel Rydh (samuel@ibrium.se) + * + * 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 + * + */ + +#ifndef _H_ELFLOAD +#define _H_ELFLOAD + +#include "arch/common/elf.h" +#include "asm/elf.h" +#include "libopenbios/sys_info.h" + +extern int elf_load(struct sys_info *info, const char *filename, const char *cmdline, void **boot_notes); +extern int is_elf(Elf_ehdr *ehdr); +extern int find_elf(Elf_ehdr *ehdr); + +extern Elf_phdr * elf_readhdrs(int offset, Elf_ehdr *ehdr); + +#endif /* _H_ELFLOAD */
Modified: trunk/openbios-devel/libopenbios/build.xml ============================================================================== --- trunk/openbios-devel/libopenbios/build.xml Fri Mar 26 23:33:50 2010 (r709) +++ trunk/openbios-devel/libopenbios/build.xml Sat Mar 27 11:57:03 2010 (r710) @@ -9,6 +9,10 @@ <object source="elf_info.c" condition="SPARC32"/> <object source="elf_info.c" condition="SPARC64"/> <object source="elf_info.c" condition="PPC"/> + <object source="elf_load.c" condition="X86"/> + <object source="elf_load.c" condition="SPARC32"/> + <object source="elf_load.c" condition="SPARC64"/> + <object source="elf_load.c" condition="AMD64"/> <object source="font_8x8.c" condition="FONT_8X8"/> <object source="font_8x16.c" condition="FONT_8X16"/> <object source="ipchecksum.c"/>
Added: trunk/openbios-devel/libopenbios/elf_load.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ trunk/openbios-devel/libopenbios/elf_load.c Sat Mar 27 11:57:03 2010 (r710) @@ -0,0 +1,462 @@ +/* ELF Boot loader + * As we have seek, this implementation can be straightforward. + * 2003-07 by SONE Takeshi + */ + +#include "config.h" +#include "kernel/kernel.h" +#include "libc/diskio.h" +#include "arch/common/elf_boot.h" +#include "libopenbios/elf_load.h" +#include "libopenbios/sys_info.h" +#include "libopenbios/ipchecksum.h" +#include "libopenbios/bindings.h" +#define printf printk +#define debug printk + +#define DEBUG 0 + +#define MAX_HEADERS 0x20 +#define BS 0x100 /* smallest step used when looking for the ELF header */ + +/* FreeBSD and possibly others mask the high 8 bits */ +#define addr_fixup(addr) ((addr) & 0x00ffffff) + +static char *image_name, *image_version; +static int fd; + +/* Note: avoid name collision with platforms which have their own version of calloc() */ +static void *ob_calloc(size_t nmemb, size_t size) +{ + size_t alloc_size = nmemb * size; + void *mem; + + if (alloc_size < nmemb || alloc_size < size) { + printf("calloc overflow: %u, %u\n", nmemb, size); + return NULL; + } + + mem = malloc(alloc_size); + memset(mem, 0, alloc_size); + + return mem; +} + +static int check_mem_ranges(struct sys_info *info, + Elf_phdr *phdr, int phnum) +{ + int i, j; + unsigned long start, end; + unsigned long prog_start, prog_end; + struct memrange *mem; + + prog_start = virt_to_phys(&_start); + prog_end = virt_to_phys(&_end); + + for (i = 0; i < phnum; i++) { + if (phdr[i].p_type != PT_LOAD) + continue; + start = addr_fixup(phdr[i].p_paddr); + end = start + phdr[i].p_memsz; + if (start < prog_start && end > prog_start) + goto conflict; + if (start < prog_end && end > prog_end) + goto conflict; + mem=info->memrange; + for (j = 0; j < info->n_memranges; j++) { + if (mem[j].base <= start && mem[j].base + mem[j].size >= end) + break; + } + if (j >= info->n_memranges) + goto badseg; + } + return 1; + +conflict: + printf("%s occupies [%#lx-%#lx]\n", program_name, prog_start, prog_end); + +badseg: + printf("Segment %d [%#lx-%#lx] doesn't fit into memory\n", i, start, end-1); + return 0; +} + +static unsigned long process_image_notes(Elf_phdr *phdr, int phnum, + unsigned short *sum_ptr, + unsigned int offset) +{ + int i; + char *buf = NULL; + int retval = 0; + unsigned long addr, end; + Elf_Nhdr *nhdr; + const char *name; + void *desc; + + for (i = 0; i < phnum; i++) { + if (phdr[i].p_type != PT_NOTE) + continue; + buf = malloc(phdr[i].p_filesz); + seek_io(fd, offset + phdr[i].p_offset); + if ((size_t)read_io(fd, buf, phdr[i].p_filesz) != phdr[i].p_filesz) { + printf("Can't read note segment\n"); + goto out; + } + addr = (unsigned long) buf; + end = addr + phdr[i].p_filesz; + while (addr < end) { + nhdr = (Elf_Nhdr *) addr; + addr += sizeof(Elf_Nhdr); + name = (const char *) addr; + addr += (nhdr->n_namesz+3) & ~3; + desc = (void *) addr; + addr += (nhdr->n_descsz+3) & ~3; + + if (nhdr->n_namesz==sizeof(ELF_NOTE_BOOT) + && memcmp(name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT))==0) { + if (nhdr->n_type == EIN_PROGRAM_NAME) { + image_name = ob_calloc(1, nhdr->n_descsz + 1); + memcpy(image_name, desc, nhdr->n_descsz); + } + if (nhdr->n_type == EIN_PROGRAM_VERSION) { + image_version = ob_calloc(1, nhdr->n_descsz + 1); + memcpy(image_version, desc, nhdr->n_descsz); + } + if (nhdr->n_type == EIN_PROGRAM_CHECKSUM) { + *sum_ptr = *(unsigned short *) desc; + debug("Image checksum: %#04x\n", *sum_ptr); + /* Where in the file */ + retval = phdr[i].p_offset + + (unsigned long) desc - (unsigned long) buf; + } + } + } + } +out: + close_io(fd); + if (buf) + free(buf); + return retval; +} + +static int load_segments(Elf_phdr *phdr, int phnum, + unsigned long checksum_offset, + unsigned int offset, unsigned long *bytes) +{ + //unsigned int start_time, time; + int i; + + *bytes = 0; + // start_time = currticks(); + for (i = 0; i < phnum; i++) { + if (phdr[i].p_type != PT_LOAD) + continue; + debug("segment %d addr:" FMT_elf " file:" FMT_elf " mem:" FMT_elf " ", + i, addr_fixup(phdr[i].p_paddr), phdr[i].p_filesz, phdr[i].p_memsz); + seek_io(fd, offset + phdr[i].p_offset); + debug("loading... "); + if ((size_t)read_io(fd, phys_to_virt(addr_fixup(phdr[i].p_paddr)), phdr[i].p_filesz) + != phdr[i].p_filesz) { + printf("Can't read program segment %d\n", i); + return 0; + } + bytes += phdr[i].p_filesz; + debug("clearing... "); + memset(phys_to_virt(addr_fixup(phdr[i].p_paddr) + phdr[i].p_filesz), 0, + phdr[i].p_memsz - phdr[i].p_filesz); + if (phdr[i].p_offset <= checksum_offset + && phdr[i].p_offset + phdr[i].p_filesz >= checksum_offset+2) { + debug("clearing checksum... "); + memset(phys_to_virt(addr_fixup(phdr[i].p_paddr) + checksum_offset + - phdr[i].p_offset), 0, 2); + } + debug("ok\n"); + + } + // time = currticks() - start_time; + //debug("Loaded %lu bytes in %ums (%luKB/s)\n", bytes, time, + // time? bytes/time : 0); + debug("Loaded %lu bytes \n", *bytes); + + return 1; +} + +static int verify_image(Elf_ehdr *ehdr, Elf_phdr *phdr, int phnum, + unsigned short image_sum) +{ + unsigned short sum, part_sum; + unsigned long offset; + int i; + + sum = 0; + offset = 0; + + part_sum = ipchksum(ehdr, sizeof *ehdr); + sum = add_ipchksums(offset, sum, part_sum); + offset += sizeof *ehdr; + + part_sum = ipchksum(phdr, phnum * sizeof(*phdr)); + sum = add_ipchksums(offset, sum, part_sum); + offset += phnum * sizeof(*phdr); + + for (i = 0; i < phnum; i++) { + if (phdr[i].p_type != PT_LOAD) + continue; + part_sum = ipchksum(phys_to_virt(addr_fixup(phdr[i].p_paddr)), phdr[i].p_memsz); + sum = add_ipchksums(offset, sum, part_sum); + offset += phdr[i].p_memsz; + } + + if (sum != image_sum) { + printf("Verify FAILED (image:%#04x vs computed:%#04x)\n", + image_sum, sum); + return 0; + } + return 1; +} + +static inline unsigned padded(unsigned s) +{ + return (s + 3) & ~3; +} + +static Elf_Bhdr *add_boot_note(Elf_Bhdr *bhdr, const char *name, + unsigned type, const char *desc, unsigned descsz) +{ + Elf_Nhdr nhdr; + unsigned ent_size, new_size, pad; + char *addr; + + if (!bhdr) + return NULL; + + nhdr.n_namesz = name? strlen(name)+1 : 0; + nhdr.n_descsz = descsz; + nhdr.n_type = type; + ent_size = sizeof(nhdr) + padded(nhdr.n_namesz) + padded(nhdr.n_descsz); + if (bhdr->b_size + ent_size > 0xffff) { + printf("Boot notes too big\n"); + free(bhdr); + return NULL; + } + if (bhdr->b_size + ent_size > bhdr->b_checksum) { + do { + new_size = bhdr->b_checksum * 2; + } while (new_size < bhdr->b_size + ent_size); + if (new_size > 0xffff) + new_size = 0xffff; + debug("expanding boot note size to %u\n", new_size); +#ifdef HAVE_REALLOC + bhdr = realloc(bhdr, new_size); + bhdr->b_checksum = new_size; +#else + printf("Boot notes too big\n"); + free(bhdr); + return NULL; +#endif + } + + addr = (char *) bhdr; + addr += bhdr->b_size; + memcpy(addr, &nhdr, sizeof(nhdr)); + addr += sizeof(nhdr); + + memcpy(addr, name, nhdr.n_namesz); + addr += nhdr.n_namesz; + pad = padded(nhdr.n_namesz) - nhdr.n_namesz; + memset(addr, 0, pad); + addr += pad; + + memcpy(addr, desc, nhdr.n_descsz); + addr += nhdr.n_descsz; + pad = padded(nhdr.n_descsz) - nhdr.n_descsz; + memset(addr, 0, pad); + addr += pad; + + bhdr->b_size += ent_size; + bhdr->b_records++; + return bhdr; +} + +static inline Elf_Bhdr *add_note_string(Elf_Bhdr *bhdr, const char *name, + unsigned type, const char *desc) +{ + return add_boot_note(bhdr, name, type, desc, strlen(desc) + 1); +} + +static Elf_Bhdr *build_boot_notes(struct sys_info *info, const char *cmdline) +{ + Elf_Bhdr *bhdr; + + bhdr = malloc(256); + bhdr->b_signature = ELF_BHDR_MAGIC; + bhdr->b_size = sizeof *bhdr; + bhdr->b_checksum = 256; /* XXX cache the current buffer size here */ + bhdr->b_records = 0; + + if (info->firmware) + bhdr = add_note_string(bhdr, NULL, EBN_FIRMWARE_TYPE, info->firmware); + bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_NAME, program_name); + bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_VERSION, program_version); + if (cmdline) + bhdr = add_note_string(bhdr, NULL, EBN_COMMAND_LINE, cmdline); + if (!bhdr) + return bhdr; + bhdr->b_checksum = 0; + bhdr->b_checksum = ipchksum(bhdr, bhdr->b_size); + return bhdr; +} + +int +is_elf(Elf_ehdr *ehdr) +{ + return (ehdr->e_ident[EI_MAG0] == ELFMAG0 + && ehdr->e_ident[EI_MAG1] == ELFMAG1 + && ehdr->e_ident[EI_MAG2] == ELFMAG2 + && ehdr->e_ident[EI_MAG3] == ELFMAG3 + && ehdr->e_ident[EI_CLASS] == ARCH_ELF_CLASS + && ehdr->e_ident[EI_DATA] == ARCH_ELF_DATA + && ehdr->e_ident[EI_VERSION] == EV_CURRENT + && ehdr->e_type == ET_EXEC + && ARCH_ELF_MACHINE_OK(ehdr->e_machine) + && ehdr->e_version == EV_CURRENT + && ehdr->e_phentsize == sizeof(Elf_phdr)); +} + +int +find_elf(Elf_ehdr *ehdr) +{ + int offset; + + for (offset = 0; offset < MAX_HEADERS * BS; offset += BS) { + if ((size_t)read_io(fd, ehdr, sizeof ehdr) != sizeof ehdr) { + debug("Can't read ELF header\n"); + return 0; + } + + if (is_elf(ehdr)) { + debug("Found ELF header at offset %d\n", offset); + return offset; + } + + seek_io(fd, offset); + } + + debug("Not a bootable ELF image\n"); + return 0; +} + +Elf_phdr * +elf_readhdrs(int offset, Elf_ehdr *ehdr) +{ + unsigned long phdr_size; + Elf_phdr *phdr; + + phdr_size = ehdr->e_phnum * sizeof(Elf_phdr); + phdr = malloc(phdr_size); + seek_io(fd, offset + ehdr->e_phoff); + if ((size_t)read_io(fd, phdr, phdr_size) != phdr_size) { + printf("Can't read program header\n"); + return NULL; + } + + return phdr; +} + +int elf_load(struct sys_info *info, const char *filename, const char *cmdline, void **boot_notes) +{ + Elf_ehdr ehdr; + Elf_phdr *phdr = NULL; + unsigned long checksum_offset, file_size; + unsigned short checksum = 0; + int retval = -1; + unsigned int offset; + + image_name = image_version = NULL; + + /* Mark the saved-program-state as invalid */ + feval("0 state-valid !"); + + fd = open_io(filename); + if (!fd) + goto out; + + offset = find_elf(&ehdr); + if (!offset) { + retval = LOADER_NOT_SUPPORT; + goto out; + } + +#if DEBUG + printk("ELF header:\n"); + printk(" ehdr.e_type = %d\n", (int)ehdr.e_type); + printk(" ehdr.e_machine = %d\n", (int)ehdr.e_machine); + printk(" ehdr.e_version = %d\n", (int)ehdr.e_version); + printk(" ehdr.e_entry = 0x%08x\n", (int)ehdr.e_entry); + printk(" ehdr.e_phoff = 0x%08x\n", (int)ehdr.e_phoff); + printk(" ehdr.e_shoff = 0x%08x\n", (int)ehdr.e_shoff); + printk(" ehdr.e_flags = %d\n", (int)ehdr.e_flags); + printk(" ehdr.e_ehsize = 0x%08x\n", (int)ehdr.e_ehsize); + printk(" ehdr.e_phentsize = 0x%08x\n", (int)ehdr.e_phentsize); + printk(" ehdr.e_phnum = %d\n", (int)ehdr.e_phnum); +#endif + + if (ehdr.e_phnum > MAX_HEADERS) { + printk ("elfload: too many program headers (MAX_HEADERS)\n"); + retval = 0; + goto out; + } + + phdr = elf_readhdrs(offset, &ehdr); + if (!phdr) + goto out; + + if (!check_mem_ranges(info, phdr, ehdr.e_phnum)) + goto out; + + checksum_offset = process_image_notes(phdr, ehdr.e_phnum, &checksum, offset); + + printf("Loading %s", image_name ? image_name : "image"); + if (image_version) + printf(" version %s", image_version); + printf("...\n"); + + if (!load_segments(phdr, ehdr.e_phnum, checksum_offset, offset, &file_size)) + goto out; + + if (checksum_offset) { + if (!verify_image(&ehdr, phdr, ehdr.e_phnum, checksum)) + goto out; + } + + /* If we are attempting an ELF boot image, we pass a non-NULL pointer + into boot_notes and mark the image as elf-boot rather than standard + ELF */ + if (boot_notes) { + *boot_notes = (void *)virt_to_phys(build_boot_notes(info, cmdline)); + feval("elf-boot saved-program-state >sps.file-type !"); + } else { + feval("elf saved-program-state >sps.file-type !"); + } + + //debug("current time: %lu\n", currticks()); + + debug("entry point is " FMT_elf "\n", addr_fixup(ehdr.e_entry)); + + // Initialise saved-program-state + PUSH(addr_fixup(ehdr.e_entry)); + feval("saved-program-state >sps.entry !"); + PUSH(file_size); + feval("saved-program-state >sps.file-size !"); + + feval("-1 state-valid !"); + +out: + close_io(fd); + if (phdr) + free(phdr); + if (image_name) + free(image_name); + if (image_version) + free(image_version); + return retval; +}