Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / libexec / elf.c
1 /*
2  * <elf.c>
3  *
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
11  *
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.
16  *
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
20  */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include "bios.h"
25 #include "exec.h"
26
27 uint32_t fs_inode_get_size (inode_t *inode);
28
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;
34
35 #define EI_NIDENT       16
36
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;
53
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;
64
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
74
75 #define ELFMAG0         0x7f            /* EI_MAG */
76 #define ELFMAG1         'E'
77 #define ELFMAG2         'L'
78 #define ELFMAG3         'F'
79
80 #define ELFCLASSNONE    0               /* EI_CLASS */
81 #define ELFCLASS32      1
82 #define ELFCLASS64      2
83 #define ELFCLASSNUM     3
84
85 #define ELFDATANONE     0               /* e_ident[EI_DATA] */
86 #define ELFDATA2LSB     1
87 #define ELFDATA2MSB     2
88
89 #define EV_NONE         0               /* e_version, EI_VERSION */
90 #define EV_CURRENT      1
91 #define EV_NUM          2
92
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
101
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     */
126 /*
127  * This is an interim value that we will use until the committee comes
128  * up with a final number.
129  */
130 #define EM_ALPHA        0x9026
131 /* Bogus old v850 magic number, used by old tools.  */
132 #define EM_CYGNUS_V850  0x9080
133 /*
134  * This is the old interim value for S/390 architecture
135  */
136 #define EM_S390_OLD     0xA390
137
138 int exec_load_elf (inode_t *file, void **dest, void **entry, void **end,
139                    uint32_t loffset)
140 {
141     Elf32_Ehdr_t ehdr;
142     Elf32_Phdr_t phdr;
143     void *address, *first, *last;
144     uint32_t offset, fsize, msize;
145     int i;
146
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;
151     }
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;
160     }
161     if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
162         ERROR("Not a 32 bits ELF file\n");
163         return -2;
164     }
165     if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
166         ERROR("Not a big-endian ELF file\n");
167         return -2;
168     }
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;
174     }
175     if (ehdr.e_type != ET_EXEC) {
176         ERROR("Not an executable ELF file\n");
177         return -2;
178     }
179     if (ehdr.e_machine != EM_PPC) {
180         ERROR("Not a PPC ELF executable\n");
181         return -2;
182     }
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;
196         }
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;
203         }
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;
211         }
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;
226         }
227         if (msize > fsize) {
228             memset(address + fsize, 0, msize - fsize);
229         }
230         offset += ehdr.e_phentsize;
231     }
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));
237
238     return 0;
239 }