summaryrefslogtreecommitdiffstats
path: root/qemu/roms/SLOF/lib/libelf
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/SLOF/lib/libelf')
-rw-r--r--qemu/roms/SLOF/lib/libelf/Makefile47
-rw-r--r--qemu/roms/SLOF/lib/libelf/elf.c190
-rw-r--r--qemu/roms/SLOF/lib/libelf/elf32.c193
-rw-r--r--qemu/roms/SLOF/lib/libelf/elf64.c473
-rw-r--r--qemu/roms/SLOF/lib/libelf/elf_claim.c28
-rw-r--r--qemu/roms/SLOF/lib/libelf/libelf.code43
-rw-r--r--qemu/roms/SLOF/lib/libelf/libelf.in18
7 files changed, 992 insertions, 0 deletions
diff --git a/qemu/roms/SLOF/lib/libelf/Makefile b/qemu/roms/SLOF/lib/libelf/Makefile
new file mode 100644
index 000000000..34a8f20b6
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libelf/Makefile
@@ -0,0 +1,47 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2011 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH)
+LDFLAGS= -nostdlib
+
+TARGET = ../libelf.a
+
+all: $(TARGET)
+
+SRCS = elf.c elf32.c elf64.c elf_claim.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+$(TARGET): $(OBJS)
+ $(AR) -rc $@ $(OBJS)
+ $(RANLIB) $@
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+ $(RM) Makefile.dep
+
+# Rules for creating the dependency file:
+depend:
+ $(RM) Makefile.dep
+ $(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+ $(CC) -MM $(CPPFLAGS) $(CFLAGS) $(SRCS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
diff --git a/qemu/roms/SLOF/lib/libelf/elf.c b/qemu/roms/SLOF/lib/libelf/elf.c
new file mode 100644
index 000000000..db2d2abc9
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libelf/elf.c
@@ -0,0 +1,190 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * ELF loader
+ */
+
+#include <string.h>
+#include <cache.h>
+#include <libelf.h>
+#include <byteorder.h>
+
+/**
+ * elf_check_file tests if the file at file_addr is
+ * a correct endian, ELF PPC executable
+ * @param file_addr pointer to the start of the ELF file
+ * @return the class (1 for 32 bit, 2 for 64 bit)
+ * -1 if it is not an ELF file
+ * -2 if it has the wrong endianness
+ * -3 if it is not an ELF executable
+ * -4 if it is not for PPC
+ */
+static int
+elf_check_file(unsigned long *file_addr)
+{
+ struct ehdr *ehdr = (struct ehdr *) file_addr;
+ uint8_t native_endian;
+
+ /* check if it is an ELF image at all */
+ if (cpu_to_be32(ehdr->ei_ident) != 0x7f454c46)
+ return -1;
+
+#ifdef __BIG_ENDIAN__
+ native_endian = ELFDATA2MSB;
+#else
+ native_endian = ELFDATA2LSB;
+#endif
+
+ if (native_endian != ehdr->ei_data) {
+ switch (ehdr->ei_class) {
+ case 1:
+ elf_byteswap_header32(file_addr);
+ break;
+ case 2:
+ elf_byteswap_header64(file_addr);
+ break;
+ }
+ }
+
+ /* check if it is an ELF executable ... and also
+ * allow DYN files, since this is specified by ePAPR */
+ if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
+ return -3;
+
+ /* check if it is a PPC ELF executable */
+ if (ehdr->e_machine != 0x14 && ehdr->e_machine != 0x15)
+ return -4;
+
+ return ehdr->ei_class;
+}
+
+/**
+ * load_elf_file tries to load the ELF file specified in file_addr
+ *
+ * it first checks if the file is a PPC ELF executable and then loads
+ * the segments depending if it is a 64bit or 32 bit ELF file
+ *
+ * @param file_addr pointer to the start of the elf file
+ * @param entry pointer where the ELF loader will store
+ * the entry point
+ * @param pre_load handler that is called before copying a segment
+ * @param post_load handler that is called after copying a segment
+ * @return 1 for a 32 bit file
+ * 2 for a 64 bit BE file
+ * 3 for a 64 bit LE ABIv1 file
+ * 4 for a 64 bit LE ABIv2 file
+ * 5 for a 32 bit LE ABIv1 file
+ * anything else means an error during load
+ */
+int
+elf_load_file(void *file_addr, unsigned long *entry,
+ int (*pre_load)(void*, long),
+ void (*post_load)(void*, long))
+{
+ int type = elf_check_file(file_addr);
+ struct ehdr *ehdr = (struct ehdr *) file_addr;
+
+ switch (type) {
+ case 1:
+ *entry = elf_load_segments32(file_addr, 0, pre_load, post_load);
+ if (ehdr->ei_data != ELFDATA2MSB) {
+ type = 5; /* LE32 ABIv1 */
+ }
+ break;
+ case 2:
+ *entry = elf_load_segments64(file_addr, 0, pre_load, post_load);
+ if (ehdr->ei_data != ELFDATA2MSB) {
+ uint32_t flags = elf_get_eflags_64(file_addr);
+ if ((flags & 0x3) == 2)
+ type = 4; /* LE64 ABIv2 */
+ else
+ type = 3; /* LE64 ABIv1 */
+ }
+ break;
+ }
+ if (*entry == 0)
+ type = 0;
+
+ return type;
+}
+
+
+/**
+ * load_elf_file_to_addr loads an ELF file to given address.
+ * This is useful for 64-bit vmlinux images that use the virtual entry
+ * point address in their headers, and thereby need a special treatment.
+ *
+ * @param file_addr pointer to the start of the elf file
+ * @param entry pointer where the ELF loader will store
+ * the entry point
+ * @param pre_load handler that is called before copying a segment
+ * @param post_load handler that is called after copying a segment
+ * @return 1 for a 32 bit file
+ * 2 for a 64 bit file
+ * anything else means an error during load
+ */
+int
+elf_load_file_to_addr(void *file_addr, void *addr, unsigned long *entry,
+ int (*pre_load)(void*, long),
+ void (*post_load)(void*, long))
+{
+ int type;
+ long offset;
+
+ type = elf_check_file(file_addr);
+
+ switch (type) {
+ case 1:
+ /* Parse 32-bit image */
+ offset = (long)addr - elf_get_base_addr32(file_addr);
+ *entry = elf_load_segments32(file_addr, offset, pre_load,
+ post_load) + offset;
+ // TODO: elf_relocate32(...)
+ break;
+ case 2:
+ /* Parse 64-bit image */
+ offset = (long)addr - elf_get_base_addr64(file_addr);
+ *entry = elf_load_segments64(file_addr, offset, pre_load,
+ post_load) + offset;
+ elf_relocate64(file_addr, offset);
+ break;
+ }
+
+ return type;
+}
+
+
+/**
+ * Get the base load address of the ELF image
+ * @return The base address or -1 for error
+ */
+long
+elf_get_base_addr(void *file_addr)
+{
+ int type;
+
+ type = elf_check_file(file_addr);
+
+ switch (type) {
+ case 1:
+ /* Return 32-bit image base address */
+ return elf_get_base_addr32(file_addr);
+ break;
+ case 2:
+ /* Return 64-bit image base address */
+ return elf_get_base_addr64(file_addr);
+ break;
+ }
+
+ return -1;
+}
diff --git a/qemu/roms/SLOF/lib/libelf/elf32.c b/qemu/roms/SLOF/lib/libelf/elf32.c
new file mode 100644
index 000000000..fea5cf420
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libelf/elf32.c
@@ -0,0 +1,193 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * 32-bit ELF loader
+ */
+#include <stdio.h>
+#include <string.h>
+#include <libelf.h>
+#include <byteorder.h>
+
+struct ehdr32 {
+ uint32_t ei_ident;
+ uint8_t ei_class;
+ uint8_t ei_data;
+ uint8_t ei_version;
+ uint8_t ei_pad[9];
+ uint16_t e_type;
+ uint16_t e_machine;
+ uint32_t e_version;
+ uint32_t e_entry;
+ uint32_t e_phoff;
+ uint32_t e_shoff;
+ uint32_t e_flags;
+ uint16_t e_ehsize;
+ uint16_t e_phentsize;
+ uint16_t e_phnum;
+ uint16_t e_shentsize;
+ uint16_t e_shnum;
+ uint16_t e_shstrndx;
+};
+
+struct phdr32 {
+ uint32_t p_type;
+ uint32_t p_offset;
+ uint32_t p_vaddr;
+ uint32_t p_paddr;
+ uint32_t p_filesz;
+ uint32_t p_memsz;
+ uint32_t p_flags;
+ uint32_t p_align;
+};
+
+
+static struct phdr32*
+get_phdr32(void *file_addr)
+{
+ return (struct phdr32 *) (((unsigned char *)file_addr)
+ + ((struct ehdr32 *)file_addr)->e_phoff);
+}
+
+static void
+load_segment(void *file_addr, struct phdr32 *phdr, signed long offset,
+ int (*pre_load)(void*, long),
+ void (*post_load)(void*, long))
+{
+ unsigned long src = phdr->p_offset + (unsigned long) file_addr;
+ unsigned long destaddr;
+
+ destaddr = (unsigned long)phdr->p_paddr;
+ destaddr = destaddr + offset;
+
+ /* check if we're allowed to copy */
+ if (pre_load != NULL) {
+ if (pre_load((void*)destaddr, phdr->p_memsz) != 0)
+ return;
+ }
+
+ /* copy into storage */
+ memmove((void *)destaddr, (void *)src, phdr->p_filesz);
+
+ /* clear bss */
+ memset((void *)(destaddr + phdr->p_filesz), 0,
+ phdr->p_memsz - phdr->p_filesz);
+
+ if (phdr->p_memsz && post_load) {
+ post_load((void*)destaddr, phdr->p_memsz);
+ }
+}
+
+unsigned int
+elf_load_segments32(void *file_addr, signed long offset,
+ int (*pre_load)(void*, long),
+ void (*post_load)(void*, long))
+{
+ struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
+ /* Calculate program header address */
+ struct phdr32 *phdr = get_phdr32(file_addr);
+ int i;
+
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ /* PT_LOAD ? */
+ if (phdr->p_type == 1) {
+ if (phdr->p_paddr != phdr->p_vaddr) {
+ printf("ELF32: VirtAddr(%lx) != PhysAddr(%lx) not supported, aborting\n",
+ (long)phdr->p_vaddr, (long)phdr->p_paddr);
+ return 0;
+ }
+
+ /* copy segment */
+ load_segment(file_addr, phdr, offset, pre_load,
+ post_load);
+ }
+ /* step to next header */
+ phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
+ }
+
+ /* Entry point is always a virtual address, so translate it
+ * to physical before returning it */
+ return ehdr->e_entry;
+}
+
+/**
+ * Return the base address for loading (i.e. the address of the first PT_LOAD
+ * segment)
+ * @param file_addr pointer to the ELF file in memory
+ * @return the base address
+ */
+long
+elf_get_base_addr32(void *file_addr)
+{
+ struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
+ struct phdr32 *phdr = get_phdr32(file_addr);
+ int i;
+
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ /* PT_LOAD ? */
+ if (phdr->p_type == 1) {
+ return phdr->p_paddr;
+ }
+ /* step to next header */
+ phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
+ }
+
+ return 0;
+}
+
+uint32_t elf_get_eflags_32(void *file_addr)
+{
+ struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
+
+ return ehdr->e_flags;
+}
+
+void
+elf_byteswap_header32(void *file_addr)
+{
+ struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
+ struct phdr32 *phdr;
+ int i;
+
+ bswap_16p(&ehdr->e_type);
+ bswap_16p(&ehdr->e_machine);
+ bswap_32p(&ehdr->e_version);
+ bswap_32p(&ehdr->e_entry);
+ bswap_32p(&ehdr->e_phoff);
+ bswap_32p(&ehdr->e_shoff);
+ bswap_32p(&ehdr->e_flags);
+ bswap_16p(&ehdr->e_ehsize);
+ bswap_16p(&ehdr->e_phentsize);
+ bswap_16p(&ehdr->e_phnum);
+ bswap_16p(&ehdr->e_shentsize);
+ bswap_16p(&ehdr->e_shnum);
+ bswap_16p(&ehdr->e_shstrndx);
+
+ phdr = get_phdr32(file_addr);
+
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ bswap_32p(&phdr->p_type);
+ bswap_32p(&phdr->p_offset);
+ bswap_32p(&phdr->p_vaddr);
+ bswap_32p(&phdr->p_paddr);
+ bswap_32p(&phdr->p_filesz);
+ bswap_32p(&phdr->p_memsz);
+ bswap_32p(&phdr->p_flags);
+ bswap_32p(&phdr->p_align);
+
+ /* step to next header */
+ phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
+ }
+}
diff --git a/qemu/roms/SLOF/lib/libelf/elf64.c b/qemu/roms/SLOF/lib/libelf/elf64.c
new file mode 100644
index 000000000..37e9c10a9
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libelf/elf64.c
@@ -0,0 +1,473 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * 64-bit ELF loader for PowerPC.
+ * See the "64-bit PowerPC ELF Application Binary Interface Supplement" and
+ * the "ELF-64 Object File Format" documentation for details.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <libelf.h>
+#include <byteorder.h>
+
+struct ehdr64
+{
+ uint32_t ei_ident;
+ uint8_t ei_class;
+ uint8_t ei_data;
+ uint8_t ei_version;
+ uint8_t ei_pad[9];
+ uint16_t e_type;
+ uint16_t e_machine;
+ uint32_t e_version;
+ uint64_t e_entry;
+ uint64_t e_phoff;
+ uint64_t e_shoff;
+ uint32_t e_flags;
+ uint16_t e_ehsize;
+ uint16_t e_phentsize;
+ uint16_t e_phnum;
+ uint16_t e_shentsize;
+ uint16_t e_shnum;
+ uint16_t e_shstrndx;
+};
+
+struct phdr64
+{
+ uint32_t p_type;
+ uint32_t p_flags;
+ uint64_t p_offset;
+ uint64_t p_vaddr;
+ uint64_t p_paddr;
+ uint64_t p_filesz;
+ uint64_t p_memsz;
+ uint64_t p_align;
+};
+
+struct shdr64
+{
+ uint32_t sh_name; /* Section name */
+ uint32_t sh_type; /* Section type */
+ uint64_t sh_flags; /* Section attributes */
+ uint64_t sh_addr; /* Virtual address in memory */
+ uint64_t sh_offset; /* Offset in file */
+ uint64_t sh_size; /* Size of section */
+ uint32_t sh_link; /* Link to other section */
+ uint32_t sh_info; /* Miscellaneous information */
+ uint64_t sh_addralign; /* Address alignment boundary */
+ uint64_t sh_entsize; /* Size of entries, if section has table */
+};
+
+struct rela /* RelA relocation table entry */
+{
+ uint64_t r_offset; /* Address of reference */
+ uint64_t r_info; /* Symbol index and type of relocation */
+ int64_t r_addend; /* Constant part of expression */
+};
+
+struct sym64
+{
+ uint32_t st_name; /* Symbol name */
+ uint8_t st_info; /* Type and Binding attributes */
+ uint8_t st_other; /* Reserved */
+ uint16_t st_shndx; /* Section table index */
+ uint64_t st_value; /* Symbol value */
+ uint64_t st_size; /* Size of object (e.g., common) */
+};
+
+
+/* For relocations */
+#define ELF_R_SYM(i) ((i)>>32)
+#define ELF_R_TYPE(i) ((uint32_t)(i) & 0xFFFFFFFF)
+#define ELF_R_INFO(s,t) ((((uint64_t) (s)) << 32) + (t))
+
+/*
+ * Relocation types for PowerPC64.
+ */
+#define R_PPC64_NONE 0
+#define R_PPC64_ADDR32 1
+#define R_PPC64_ADDR24 2
+#define R_PPC64_ADDR16 3
+#define R_PPC64_ADDR16_LO 4
+#define R_PPC64_ADDR16_HI 5
+#define R_PPC64_ADDR16_HA 6
+#define R_PPC64_ADDR14 7
+#define R_PPC64_ADDR14_BRTAKEN 8
+#define R_PPC64_ADDR14_BRNTAKEN 9
+#define R_PPC64_REL24 10
+#define R_PPC64_REL14 11
+#define R_PPC64_REL14_BRTAKEN 12
+#define R_PPC64_REL14_BRNTAKEN 13
+#define R_PPC64_GOT16 14
+#define R_PPC64_GOT16_LO 15
+#define R_PPC64_GOT16_HI 16
+#define R_PPC64_GOT16_HA 17
+#define R_PPC64_COPY 19
+#define R_PPC64_GLOB_DAT 20
+#define R_PPC64_JMP_SLOT 21
+#define R_PPC64_RELATIVE 22
+#define R_PPC64_UADDR32 24
+#define R_PPC64_UADDR16 25
+#define R_PPC64_REL32 26
+#define R_PPC64_PLT32 27
+#define R_PPC64_PLTREL32 28
+#define R_PPC64_PLT16_LO 29
+#define R_PPC64_PLT16_HI 30
+#define R_PPC64_PLT16_HA 31
+#define R_PPC64_SECTOFF 33
+#define R_PPC64_SECTOFF_LO 34
+#define R_PPC64_SECTOFF_HI 35
+#define R_PPC64_SECTOFF_HA 36
+#define R_PPC64_ADDR30 37
+#define R_PPC64_ADDR64 38
+#define R_PPC64_ADDR16_HIGHER 39
+#define R_PPC64_ADDR16_HIGHERA 40
+#define R_PPC64_ADDR16_HIGHEST 41
+#define R_PPC64_ADDR16_HIGHESTA 42
+#define R_PPC64_UADDR64 43
+#define R_PPC64_REL64 44
+#define R_PPC64_PLT64 45
+#define R_PPC64_PLTREL64 46
+#define R_PPC64_TOC16 47
+#define R_PPC64_TOC16_LO 48
+#define R_PPC64_TOC16_HI 49
+#define R_PPC64_TOC16_HA 50
+#define R_PPC64_TOC 51
+#define R_PPC64_PLTGOT16 52
+#define R_PPC64_PLTGOT16_LO 53
+#define R_PPC64_PLTGOT16_HI 54
+#define R_PPC64_PLTGOT16_HA 55
+#define R_PPC64_ADDR16_DS 56
+#define R_PPC64_ADDR16_LO_DS 57
+#define R_PPC64_GOT16_DS 58
+#define R_PPC64_GOT16_LO_DS 59
+#define R_PPC64_PLT16_LO_DS 60
+#define R_PPC64_SECTOFF_DS 61
+#define R_PPC64_SECTOFF_LO_DS 62
+#define R_PPC64_TOC16_DS 63
+#define R_PPC64_TOC16_LO_DS 64
+#define R_PPC64_PLTGOT16_DS 65
+#define R_PPC64_PLTGOT16_LO_DS 66
+#define R_PPC64_TLS 67
+#define R_PPC64_DTPMOD64 68
+#define R_PPC64_TPREL16 69
+#define R_PPC64_TPREL16_LO 60
+#define R_PPC64_TPREL16_HI 71
+#define R_PPC64_TPREL16_HA 72
+#define R_PPC64_TPREL64 73
+#define R_PPC64_DTPREL16 74
+#define R_PPC64_DTPREL16_LO 75
+#define R_PPC64_DTPREL16_HI 76
+#define R_PPC64_DTPREL16_HA 77
+#define R_PPC64_DTPREL64 78
+#define R_PPC64_GOT_TLSGD16 79
+#define R_PPC64_GOT_TLSGD16_LO 80
+#define R_PPC64_GOT_TLSGD16_HI 81
+#define R_PPC64_GOT_TLSGD16_HA 82
+#define R_PPC64_GOT_TLSLD16 83
+#define R_PPC64_GOT_TLSLD16_LO 84
+#define R_PPC64_GOT_TLSLD16_HI 85
+#define R_PPC64_GOT_TLSLD16_HA 86
+#define R_PPC64_GOT_TPREL16_DS 87
+#define R_PPC64_GOT_TPREL16_LO_ DS 88
+#define R_PPC64_GOT_TPREL16_HI 89
+#define R_PPC64_GOT_TPREL16_HA 90
+#define R_PPC64_GOT_DTPREL16_DS 91
+#define R_PPC64_GOT_DTPREL16_LO_DS 92
+#define R_PPC64_GOT_DTPREL16_HI 93
+#define R_PPC64_GOT_DTPREL16_HA 94
+#define R_PPC64_TPREL16_DS 95
+#define R_PPC64_TPREL16_LO_DS 96
+#define R_PPC64_TPREL16_HIGHER 97
+#define R_PPC64_TPREL16_HIGHERA 98
+#define R_PPC64_TPREL16_HIGHEST 99
+#define R_PPC64_TPREL16_HIGHESTA 100
+#define R_PPC64_DTPREL16_DS 101
+#define R_PPC64_DTPREL16_LO_DS 102
+#define R_PPC64_DTPREL16_HIGHER 103
+#define R_PPC64_DTPREL16_HIGHERA 104
+#define R_PPC64_DTPREL16_HIGHEST 105
+#define R_PPC64_DTPREL16_HIGHESTA 106
+
+
+static struct phdr64*
+get_phdr64(unsigned long *file_addr)
+{
+ return (struct phdr64 *) (((unsigned char *) file_addr)
+ + ((struct ehdr64 *)file_addr)->e_phoff);
+}
+
+static void
+load_segment64(unsigned long *file_addr, struct phdr64 *phdr, signed long offset,
+ int (*pre_load)(void*, long),
+ void (*post_load)(void*, long))
+{
+ unsigned long src = phdr->p_offset + (unsigned long) file_addr;
+ unsigned long destaddr;
+
+ destaddr = phdr->p_paddr + offset;
+
+ /* check if we're allowed to copy */
+ if (pre_load != NULL) {
+ if (pre_load((void*)destaddr, phdr->p_memsz) != 0)
+ return;
+ }
+
+ /* copy into storage */
+ memmove((void*)destaddr, (void*)src, phdr->p_filesz);
+
+ /* clear bss */
+ memset((void*)(destaddr + phdr->p_filesz), 0,
+ phdr->p_memsz - phdr->p_filesz);
+
+ if (phdr->p_memsz && post_load != NULL) {
+ post_load((void*)destaddr, phdr->p_memsz);
+ }
+}
+
+unsigned long
+elf_load_segments64(void *file_addr, signed long offset,
+ int (*pre_load)(void*, long),
+ void (*post_load)(void*, long))
+{
+ struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
+ /* Calculate program header address */
+ struct phdr64 *phdr = get_phdr64(file_addr);
+ int i;
+
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ /* PT_LOAD ? */
+ if (phdr->p_type == PT_LOAD) {
+ if (phdr->p_paddr != phdr->p_vaddr) {
+ printf("ELF64: VirtAddr(%lx) != PhysAddr(%lx) not supported, aborting\n",
+ (long)phdr->p_vaddr, (long)phdr->p_paddr);
+ return 0;
+ }
+
+ /* copy segment */
+ load_segment64(file_addr, phdr, offset, pre_load, post_load);
+ }
+ /* step to next header */
+ phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
+ }
+
+ /* Entry point is always a virtual address, so translate it
+ * to physical before returning it */
+ return ehdr->e_entry;
+}
+
+/**
+ * Return the base address for loading (i.e. the address of the first PT_LOAD
+ * segment)
+ * @param file_addr pointer to the ELF file in memory
+ * @return the base address
+ */
+long
+elf_get_base_addr64(void *file_addr)
+{
+ struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
+ /* Calculate program header address */
+ struct phdr64 *phdr = get_phdr64(file_addr);
+ int i;
+
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ /* PT_LOAD ? */
+ if (phdr->p_type == PT_LOAD) {
+ /* Return base address */
+ return phdr->p_paddr;
+ }
+ /* step to next header */
+ phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
+ }
+
+ return 0;
+}
+
+
+/**
+ * Apply one relocation entry.
+ */
+static void
+elf_apply_rela64(void *file_addr, signed long offset, struct rela *relaentry,
+ struct sym64 *symtabentry)
+{
+ void *addr;
+ unsigned long s_a;
+ unsigned long base_addr;
+
+ base_addr = elf_get_base_addr64(file_addr);
+
+ /* Sanity check */
+ if (relaentry->r_offset < base_addr) {
+ printf("\nELF relocation out of bounds!\n");
+ return;
+ }
+
+ base_addr += offset;
+
+ /* Actual address where the relocation will be applied at. */
+ addr = (void*)(relaentry->r_offset + offset);
+
+ /* Symbol value (S) + Addend (A) */
+ s_a = symtabentry->st_value + offset + relaentry->r_addend;
+
+ switch (ELF_R_TYPE(relaentry->r_info)) {
+ case R_PPC64_ADDR32: /* S + A */
+ *(uint32_t *)addr = (uint32_t) s_a;
+ break;
+ case R_PPC64_ADDR64: /* S + A */
+ *(uint64_t *)addr = (uint64_t) s_a;
+ break;
+ case R_PPC64_TOC: /* .TOC */
+ *(uint64_t *)addr += offset;
+ break;
+ case R_PPC64_ADDR16_HIGHEST: /* #highest(S + A) */
+ *(uint16_t *)addr = ((s_a >> 48) & 0xffff);
+ break;
+ case R_PPC64_ADDR16_HIGHER: /* #higher(S + A) */
+ *(uint16_t *)addr = ((s_a >> 32) & 0xffff);
+ break;
+ case R_PPC64_ADDR16_HI: /* #hi(S + A) */
+ *(uint16_t *)addr = ((s_a >> 16) & 0xffff);
+ break;
+ case R_PPC64_ADDR16_LO: /* #lo(S + A) */
+ *(uint16_t *)addr = s_a & 0xffff;
+ break;
+ case R_PPC64_ADDR16_LO_DS:
+ *(uint16_t *)addr = (s_a & 0xfffc);
+ break;
+ case R_PPC64_ADDR16_HA: /* #ha(S + A) */
+ *(uint16_t *)addr = (((s_a >> 16) + ((s_a & 0x8000) ? 1 : 0))
+ & 0xffff);
+ break;
+
+ case R_PPC64_TOC16: /* half16* S + A - .TOC. */
+ case R_PPC64_TOC16_LO_DS:
+ case R_PPC64_TOC16_LO: /* #lo(S + A - .TOC.) */
+ case R_PPC64_TOC16_HI: /* #hi(S + A - .TOC.) */
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_DS: /* (S + A - .TOC) >> 2 */
+ case R_PPC64_REL14:
+ case R_PPC64_REL24: /* (S + A - P) >> 2 */
+ case R_PPC64_REL64: /* S + A - P */
+ case R_PPC64_GOT16_DS:
+ case R_PPC64_GOT16_LO_DS:
+ // printf("\t\tignoring relocation type %i\n",
+ // ELF_R_TYPE(relaentry->r_info));
+ break;
+ default:
+ printf("ERROR: Unhandled relocation (A) type %i\n",
+ ELF_R_TYPE(relaentry->r_info));
+ }
+}
+
+
+/**
+ * Step through all relocation entries and apply them one by one.
+ */
+static void
+elf_apply_all_rela64(void *file_addr, signed long offset, struct shdr64 *shdrs, int idx)
+{
+ struct shdr64 *rela_shdr = &shdrs[idx];
+ struct shdr64 *dst_shdr = &shdrs[rela_shdr->sh_info];
+ struct shdr64 *sym_shdr = &shdrs[rela_shdr->sh_link];
+ struct rela *relaentry;
+ struct sym64 *symtabentry;
+ uint32_t symbolidx;
+ int i;
+
+ /* If the referenced section has not been allocated, then it has
+ * not been loaded and thus does not need to be relocated. */
+ if ((dst_shdr->sh_flags & SHF_ALLOC) != SHF_ALLOC)
+ return;
+
+ for (i = 0; i < rela_shdr->sh_size; i += rela_shdr->sh_entsize) {
+ relaentry = (struct rela *)(file_addr + rela_shdr->sh_offset + i);
+
+ symbolidx = ELF_R_SYM(relaentry->r_info);
+ symtabentry = (struct sym64*)(file_addr + sym_shdr->sh_offset) + symbolidx;
+
+ elf_apply_rela64(file_addr, offset, relaentry, symtabentry);
+ }
+}
+
+
+/**
+ * Apply ELF relocations
+ */
+void
+elf_relocate64(void *file_addr, signed long offset)
+{
+ struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
+ /* Calculate section header address */
+ struct shdr64 *shdrs = (struct shdr64 *)
+ (((unsigned char *) file_addr) + ehdr->e_shoff);
+ int i;
+
+ /* loop over all segments */
+ for (i = 0; i <= ehdr->e_shnum; i++) {
+ /* Skip if it is not a relocation segment */
+ if (shdrs[i].sh_type == SHT_RELA) {
+ elf_apply_all_rela64(file_addr, offset, shdrs, i);
+ }
+ }
+}
+
+void
+elf_byteswap_header64(void *file_addr)
+{
+ struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
+ struct phdr64 *phdr;
+ int i;
+
+ bswap_16p(&ehdr->e_type);
+ bswap_16p(&ehdr->e_machine);
+ bswap_32p(&ehdr->e_version);
+ bswap_64p(&ehdr->e_entry);
+ bswap_64p(&ehdr->e_phoff);
+ bswap_64p(&ehdr->e_shoff);
+ bswap_32p(&ehdr->e_flags);
+ bswap_16p(&ehdr->e_ehsize);
+ bswap_16p(&ehdr->e_phentsize);
+ bswap_16p(&ehdr->e_phnum);
+ bswap_16p(&ehdr->e_shentsize);
+ bswap_16p(&ehdr->e_shnum);
+ bswap_16p(&ehdr->e_shstrndx);
+
+ phdr = get_phdr64(file_addr);
+
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ bswap_32p(&phdr->p_type);
+ bswap_32p(&phdr->p_flags);
+ bswap_64p(&phdr->p_offset);
+ bswap_64p(&phdr->p_vaddr);
+ bswap_64p(&phdr->p_paddr);
+ bswap_64p(&phdr->p_filesz);
+ bswap_64p(&phdr->p_memsz);
+ bswap_64p(&phdr->p_align);
+
+ /* step to next header */
+ phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
+ }
+}
+
+uint32_t elf_get_eflags_64(void *file_addr)
+{
+ struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
+
+ return ehdr->e_flags;
+}
diff --git a/qemu/roms/SLOF/lib/libelf/elf_claim.c b/qemu/roms/SLOF/lib/libelf/elf_claim.c
new file mode 100644
index 000000000..43540f9b6
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libelf/elf_claim.c
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2009, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include <libelf.h>
+#include "../../slof/paflof.h"
+
+
+/**
+ * Call Forth code to try to claim the memory region
+ */
+int
+elf_forth_claim(void *addr, long size)
+{
+ forth_push((long)addr);
+ forth_push(size);
+ forth_eval("elf-claim-segment");
+ return forth_pop();
+}
diff --git a/qemu/roms/SLOF/lib/libelf/libelf.code b/qemu/roms/SLOF/lib/libelf/libelf.code
new file mode 100644
index 000000000..551468bdd
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libelf/libelf.code
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * libelf Forth wrapper
+ */
+
+#include <libelf.h>
+
+// : elf-load-file ( fileaddr -- entry type )
+PRIM(ELF_X2d_LOAD_X2d_FILE)
+{
+ void *file_addr = TOS.a;
+ int type;
+ unsigned long entry;
+ type = elf_load_file(file_addr, &entry, elf_forth_claim, flush_cache);
+ TOS.u = entry;
+ PUSH; TOS.n = type;
+}
+MIRP
+
+// : elf-load-file-to-addr ( fileaddr destaddr -- entry type )
+PRIM(ELF_X2d_LOAD_X2d_FILE_X2d_TO_X2d_ADDR)
+{
+ void *dest_addr = TOS.a; POP;
+ void *file_addr = TOS.a;
+ int type;
+ unsigned long entry;
+ type = elf_load_file_to_addr(file_addr, dest_addr, &entry,
+ elf_forth_claim, flush_cache);
+ TOS.u = entry;
+ PUSH; TOS.n = type;
+}
+MIRP
diff --git a/qemu/roms/SLOF/lib/libelf/libelf.in b/qemu/roms/SLOF/lib/libelf/libelf.in
new file mode 100644
index 000000000..9c5f019ce
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libelf/libelf.in
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * libelf bindings for Forth - definitions
+ */
+
+cod(ELF-LOAD-FILE)
+cod(ELF-LOAD-FILE-TO-ADDR)