4
* Open Hack'Ware BIOS ELF executable file loader
6
* Copyright (c) 2004-2005 Jocelyn Mayer
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
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;
37
typedef struct elf32_hdr_t {
38
unsigned char e_ident[EI_NIDENT];
42
Elf32_Addr e_entry; /* Entry point */
47
Elf32_Half e_phentsize;
49
Elf32_Half e_shentsize;
51
Elf32_Half e_shstrndx;
54
typedef struct elf32_phdr_t {
65
#define EI_MAG0 0 /* e_ident[] indexes */
75
#define ELFMAG0 0x7f /* EI_MAG */
80
#define ELFCLASSNONE 0 /* EI_CLASS */
85
#define ELFDATANONE 0 /* e_ident[EI_DATA] */
89
#define EV_NONE 0 /* e_version, EI_VERSION */
93
/* These constants define the different elf file types */
99
#define ET_LOPROC 0xff00
100
#define ET_HIPROC 0xffff
102
/* These constants define the various ELF target machines */
109
#define EM_486 6 /* Perhaps disused */
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,
143
void *address, *first, *last;
144
uint32_t offset, fsize, msize;
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");
152
DPRINTF("Check ELF file\n");
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);
161
if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
162
ERROR("Not a 32 bits ELF file\n");
165
if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
166
ERROR("Not a big-endian ELF file\n");
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);
175
if (ehdr.e_type != ET_EXEC) {
176
ERROR("Not an executable ELF file\n");
179
if (ehdr.e_machine != EM_PPC) {
180
ERROR("Not a PPC ELF executable\n");
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);
189
offset = ehdr.e_phoff;
190
for (i = 0; i < ehdr.e_phnum; i++) {
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));
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);
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);
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));
213
/* As we won't remap memory, load it at it's virtual address (!) */
214
address = (void *)phdr.p_vaddr;
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);
228
memset(address + fsize, 0, msize - fsize);
230
offset += ehdr.e_phentsize;
232
*dest = (void *)first;
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));