Import of openhackware-0.4.1
[openhackware.git] / src / libexec / elf.c
blobae9f8e00e4e33bc51c4b3fc92d09d59005f5d136
1 /*
2 * <elf.c>
4 * Open Hack'Ware BIOS ELF executable file loader
5 *
6 * Copyright (c) 2004-2005 Jocelyn Mayer
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License V2
10 * as published by the Free Software Foundation
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include "bios.h"
25 #include "exec.h"
27 uint32_t fs_inode_get_size (inode_t *inode);
29 /* ELF executable loader */
30 typedef uint16_t Elf32_Half;
31 typedef uint32_t Elf32_Word;
32 typedef uint32_t Elf32_Off;
33 typedef uint32_t Elf32_Addr;
35 #define EI_NIDENT 16
37 typedef struct elf32_hdr_t {
38 unsigned char e_ident[EI_NIDENT];
39 Elf32_Half e_type;
40 Elf32_Half e_machine;
41 Elf32_Word e_version;
42 Elf32_Addr e_entry; /* Entry point */
43 Elf32_Off e_phoff;
44 Elf32_Off e_shoff;
45 Elf32_Word e_flags;
46 Elf32_Half e_ehsize;
47 Elf32_Half e_phentsize;
48 Elf32_Half e_phnum;
49 Elf32_Half e_shentsize;
50 Elf32_Half e_shnum;
51 Elf32_Half e_shstrndx;
52 } Elf32_Ehdr_t;
54 typedef struct elf32_phdr_t {
55 Elf32_Word p_type;
56 Elf32_Off p_offset;
57 Elf32_Addr p_vaddr;
58 Elf32_Addr p_paddr;
59 Elf32_Word p_filesz;
60 Elf32_Word p_memsz;
61 Elf32_Word p_flags;
62 Elf32_Word p_align;
63 } Elf32_Phdr_t;
65 #define EI_MAG0 0 /* e_ident[] indexes */
66 #define EI_MAG1 1
67 #define EI_MAG2 2
68 #define EI_MAG3 3
69 #define EI_CLASS 4
70 #define EI_DATA 5
71 #define EI_VERSION 6
72 #define EI_OSABI 7
73 #define EI_PAD 8
75 #define ELFMAG0 0x7f /* EI_MAG */
76 #define ELFMAG1 'E'
77 #define ELFMAG2 'L'
78 #define ELFMAG3 'F'
80 #define ELFCLASSNONE 0 /* EI_CLASS */
81 #define ELFCLASS32 1
82 #define ELFCLASS64 2
83 #define ELFCLASSNUM 3
85 #define ELFDATANONE 0 /* e_ident[EI_DATA] */
86 #define ELFDATA2LSB 1
87 #define ELFDATA2MSB 2
89 #define EV_NONE 0 /* e_version, EI_VERSION */
90 #define EV_CURRENT 1
91 #define EV_NUM 2
93 /* These constants define the different elf file types */
94 #define ET_NONE 0
95 #define ET_REL 1
96 #define ET_EXEC 2
97 #define ET_DYN 3
98 #define ET_CORE 4
99 #define ET_LOPROC 0xff00
100 #define ET_HIPROC 0xffff
102 /* These constants define the various ELF target machines */
103 #define EM_NONE 0
104 #define EM_M32 1
105 #define EM_SPARC 2
106 #define EM_386 3
107 #define EM_68K 4
108 #define EM_88K 5
109 #define EM_486 6 /* Perhaps disused */
110 #define EM_860 7
111 #define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */
112 #define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
113 #define EM_PARISC 15 /* HPPA */
114 #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
115 #define EM_PPC 20 /* PowerPC */
116 #define EM_PPC64 21 /* PowerPC64 */
117 #define EM_SH 42 /* SuperH */
118 #define EM_SPARCV9 43 /* SPARC v9 64-bit */
119 #define EM_IA_64 50 /* HP/Intel IA-64 */
120 #define EM_X86_64 62 /* AMD x86-64 */
121 #define EM_S390 22 /* IBM S/390 */
122 #define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */
123 #define EM_V850 87 /* NEC v850 */
124 #define EM_H8_300H 47 /* Hitachi H8/300H */
125 #define EM_H8S 48 /* Hitachi H8S */
127 * This is an interim value that we will use until the committee comes
128 * up with a final number.
130 #define EM_ALPHA 0x9026
131 /* Bogus old v850 magic number, used by old tools. */
132 #define EM_CYGNUS_V850 0x9080
134 * This is the old interim value for S/390 architecture
136 #define EM_S390_OLD 0xA390
138 int exec_load_elf (inode_t *file, void **dest, void **entry, void **end,
139 uint32_t loffset)
141 Elf32_Ehdr_t ehdr;
142 Elf32_Phdr_t phdr;
143 void *address, *first, *last;
144 uint32_t offset, fsize, msize;
145 int i;
147 file_seek(file, loffset);
148 if (fs_read(file, &ehdr, sizeof(Elf32_Ehdr_t)) < 0) {
149 ERROR("Cannot load first bloc of file...\n");
150 return -1;
152 DPRINTF("Check ELF file\n");
153 /* Check ident */
154 if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
155 ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
156 ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
157 ehdr.e_ident[EI_MAG3] != ELFMAG3) {
158 DPRINTF("Not an ELF file %0x\n", *(uint32_t *)ehdr.e_ident);
159 return -2;
161 if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
162 ERROR("Not a 32 bits ELF file\n");
163 return -2;
165 if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
166 ERROR("Not a big-endian ELF file\n");
167 return -2;
169 if (ehdr.e_ident[EI_VERSION] != EV_CURRENT /*||
170 ehdr->e_version != EV_CURRENT*/) {
171 ERROR("Invalid ELF executable version %d %08x\n",
172 ehdr.e_ident[EI_VERSION], ehdr.e_version);
173 return -2;
175 if (ehdr.e_type != ET_EXEC) {
176 ERROR("Not an executable ELF file\n");
177 return -2;
179 if (ehdr.e_machine != EM_PPC) {
180 ERROR("Not a PPC ELF executable\n");
181 return -2;
183 /* All right, seems to be a regular ELF program for PPC */
184 *entry = (void *)ehdr.e_entry;
185 DPRINTF("ELF file found entry = %p\n", *entry);
186 last = NULL;
187 first = last - 4;
188 fsize = msize = 0;
189 offset = ehdr.e_phoff;
190 for (i = 0; i < ehdr.e_phnum; i++) {
191 #if 0
192 if (offset > fs_inode_get_size(file)) {
193 ERROR("ELF program header %d offset > file size %d %d\n", i,
194 offset, fs_inode_get_size(file));
195 return -1;
197 #endif
198 DPRINTF("Load program header %d from %08x\n", i, offset);
199 file_seek(file, offset + loffset);
200 if (fs_read(file, &phdr, sizeof(Elf32_Phdr_t)) < 0) {
201 ERROR("Cannot load ELF program header %d...\n", i);
202 return -1;
204 DPRINTF("Load program header %d %08x %08x %08x %08x\n", i,
205 phdr.p_offset, phdr.p_vaddr, phdr.p_filesz, phdr.p_memsz);
206 #if 0
207 if (phdr.p_offset > fs_inode_get_size(file)) {
208 ERROR("ELF program %d offset > file size %d %d\n",
209 i, phdr.p_offset, fs_inode_get_size(file));
210 return -1;
212 #endif
213 /* As we won't remap memory, load it at it's virtual address (!) */
214 address = (void *)phdr.p_vaddr;
215 if (address < first)
216 first = address;
217 fsize = phdr.p_filesz;
218 msize = phdr.p_memsz;
219 if (address + msize > last)
220 last = address + msize;
221 file_seek(file, phdr.p_offset + loffset);
222 set_loadinfo((void *)first, last - first);
223 if (fs_read(file, address, fsize) < 0) {
224 ERROR("Cannot load ELF program %d...\n", i);
225 return -1;
227 if (msize > fsize) {
228 memset(address + fsize, 0, msize - fsize);
230 offset += ehdr.e_phentsize;
232 *dest = (void *)first;
233 *end = (void *)last;
234 DPRINTF("ELF file loaded at %p => %p fsize %08x msize %08x "
235 "(%08x %08x)\n", *dest, *entry, fsize, msize,
236 *(uint32_t *)entry, *((uint32_t *)entry + 1));
238 return 0;