[OpenBIOS] [commit] r710 - in trunk/openbios-devel: arch/amd64 arch/ppc/qemu arch/sparc32 arch/sparc64 arch/unix arch/x86 include/arch/amd64 include/arch/sparc32 include/arch/sparc64 include/arch/x86 include/...

repository service svn at openbios.org
Sat Mar 27 11:57:04 CET 2010


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 at 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 at 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;
+}



More information about the OpenBIOS mailing list