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));