1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * ELF Program Loader File: cfe_ldr_elf.c
6 * This program parses ELF executables and loads them into memory.
8 * Author: Mitch Lichtenberg (mpl@broadcom.com)
10 *********************************************************************
12 * Copyright 2000,2001,2002,2003
13 * Broadcom Corporation. All rights reserved.
15 * This software is furnished under license and may be used and
16 * copied only in accordance with the following terms and
17 * conditions. Subject to these conditions, you may download,
18 * copy, install, use, modify and distribute modified or unmodified
19 * copies of this software in source and/or binary form. No title
20 * or ownership is transferred hereby.
22 * 1) Any source code used, modified or distributed must reproduce
23 * and retain this copyright notice and list of conditions
24 * as they appear in the source file.
26 * 2) No right is granted to use any trade name, trademark, or
27 * logo of Broadcom Corporation. The "Broadcom Corporation"
28 * name may not be used to endorse or promote products derived
29 * from this software without the prior written permission of
30 * Broadcom Corporation.
32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
44 * THE POSSIBILITY OF SUCH DAMAGE.
45 ********************************************************************* */
48 #include "lib_types.h"
49 #include "lib_string.h"
50 #include "lib_queue.h"
51 #include "lib_malloc.h"
52 #include "lib_printf.h"
55 #include "cfe_device.h"
56 #include "cfe_console.h"
57 #include "cfe_error.h"
58 #include "cfe_devfuncs.h"
59 #include "cfe_timer.h"
63 #include "cfe_loader.h"
64 #include "cfe_fileops.h"
69 /* *********************************************************************
71 ********************************************************************* */
73 static int cfe_elfload(cfe_loadargs_t
*la
);
75 const cfe_loader_t elfloader
= {
80 /* *********************************************************************
81 * readprogsegment(fsctx,ref,addr,size)
83 * Read a program segment, generally corresponding to one
84 * section of the file.
87 * fsctx - file I/O dispatch
88 * ref - reference data for open file handle
89 * addr - target virtual address
90 * size - size of region to read
93 * Number of bytes copied or <0 if error occured
94 ********************************************************************* */
96 static int readprogsegment(fileio_ctx_t
*fsctx
,void *ref
,
97 void *addr
,int size
,int flags
)
102 if (flags
& LOADFLG_NOISY
) xprintf("0x%016llx/%d ",addr
,size
);
104 if (flags
& LOADFLG_NOISY
) xprintf("0x%x/%d ",addr
,size
);
107 if (!cfe_arena_loadcheck((uintptr_t) addr
,size
)) {
108 return CFE_ERR_BADADDR
;
111 res
= fs_read(fsctx
,ref
,addr
,size
);
113 if (res
< 0) return CFE_ERR_IOERR
;
114 if (res
!= size
) return CFE_ERR_BADELFFMT
;
120 /* *********************************************************************
121 * readclearbss(addr,size)
123 * Process a BSS section, zeroing memory corresponding to
127 * addr - address to zero
128 * size - length of area to zero
131 * number of zeroed bytes or <0 if error occured
132 ********************************************************************* */
134 static int readclearbss(void *addr
,int size
,int flags
)
138 if (flags
& LOADFLG_NOISY
) xprintf("0x%016llx/%d ",addr
,size
);
140 if (flags
& LOADFLG_NOISY
) xprintf("0x%x/%d ",addr
,size
);
143 if (!cfe_arena_loadcheck((uintptr_t) addr
,size
)) {
144 return CFE_ERR_BADADDR
;
147 if (size
> 0) memset(addr
,0,size
);
152 /* *********************************************************************
153 * elfgetshdr(ops,ref,ep)
155 * Get a section header from the ELF file
158 * ops - file I/O dispatch
159 * ref - reference data for open file
160 * ep - extended header info
163 * copy of section header (malloc'd) or NULL if no memory
164 ********************************************************************* */
166 static Elf32_Shdr
*elfgetshdr(fileio_ctx_t
*fsctx
,void *ref
,Elf32_Ehdr
*ep
)
169 unsigned size
= ep
->e_shnum
* sizeof(Elf32_Shdr
);
171 shtab
= (Elf32_Shdr
*) KMALLOC(size
,0);
176 if (fs_seek(fsctx
,ref
,ep
->e_shoff
,FILE_SEEK_BEGINNING
) != ep
->e_shoff
||
177 fs_read(fsctx
,ref
,(uint8_t *)shtab
,size
) != size
) {
185 /* *********************************************************************
186 * elfload_internal(ops,ref,entrypt,flags)
188 * Read an ELF file (main routine)
191 * ops - file I/O dispatch
192 * ref - open file handle
193 * entrypt - filled in with entry vector
194 * flags - generic boot flags
199 ********************************************************************* */
201 static int elfload_internal(fileio_ctx_t
*fsctx
,void *ref
,
202 unsigned long *entrypt
,int flags
)
205 Elf32_Phdr
*phtab
= 0;
206 Elf32_Shdr
*shtab
= 0;
213 if (fs_read(fsctx
,ref
,(uint8_t *) ep
,sizeof(*ep
)) != sizeof(*ep
)) {
214 return CFE_ERR_IOERR
;
217 /* check header validity */
218 if (ep
->e_ident
[EI_MAG0
] != ELFMAG0
||
219 ep
->e_ident
[EI_MAG1
] != ELFMAG1
||
220 ep
->e_ident
[EI_MAG2
] != ELFMAG2
||
221 ep
->e_ident
[EI_MAG3
] != ELFMAG3
) {
222 return CFE_ERR_NOTELF
;
225 if (ep
->e_ident
[EI_CLASS
] != ELFCLASS32
) return CFE_ERR_NOT32BIT
;
228 if (ep
->e_ident
[EI_DATA
] != ELFDATA2MSB
) return CFE_ERR_WRONGENDIAN
; /* big endian */
231 if (ep
->e_ident
[EI_DATA
] != ELFDATA2LSB
) return CFE_ERR_WRONGENDIAN
; /* little endian */
234 if (ep
->e_ident
[EI_VERSION
] != EV_CURRENT
) return CFE_ERR_BADELFVERS
;
235 if (ep
->e_machine
!= EM_MIPS
) return CFE_ERR_NOTMIPS
;
237 /* Is there a program header? */
238 if (ep
->e_phoff
== 0 || ep
->e_phnum
== 0 ||
239 ep
->e_phentsize
!= sizeof(Elf32_Phdr
)) {
240 return CFE_ERR_BADELFFMT
;
243 /* Load program header */
244 nbytes
= ep
->e_phnum
* sizeof(Elf32_Phdr
);
245 phtab
= (Elf32_Phdr
*) KMALLOC(nbytes
,0);
247 return CFE_ERR_NOMEM
;
250 if (fs_seek(fsctx
,ref
,ep
->e_phoff
,FILE_SEEK_BEGINNING
) != ep
->e_phoff
||
251 fs_read(fsctx
,ref
,(uint8_t *)phtab
,nbytes
) != nbytes
) {
253 return CFE_ERR_IOERR
;
257 * From now on we've got no guarantee about the file order,
258 * even where the section header is. Hopefully most linkers
259 * will put the section header after the program header, when
260 * they know that the executable is not demand paged. We assume
261 * that the symbol and string tables always follow the program
265 /* read section table (if before first program segment) */
266 if (ep
->e_shoff
< phtab
[0].p_offset
) {
267 shtab
= elfgetshdr(fsctx
,ref
,ep
);
270 /* load program segments */
271 /* We cope with a badly sorted program header, as produced by
272 * older versions of the GNU linker, by loading the segments
273 * in file offset order, not in program header order. */
276 Elf32_Off lowest_offset
= ~0;
279 /* find nearest loadable segment */
280 for (i
= 0; i
< ep
->e_phnum
; i
++)
281 if ((phtab
[i
].p_type
== PT_LOAD
) && (phtab
[i
].p_offset
< lowest_offset
)) {
283 lowest_offset
= ph
->p_offset
;
286 break; /* none found, finished */
289 /* load the segment */
291 if (fs_seek(fsctx
,ref
,ph
->p_offset
,FILE_SEEK_BEGINNING
) != ph
->p_offset
) {
292 if (shtab
) KFREE(shtab
);
294 return CFE_ERR_BADELFFMT
;
296 res
= readprogsegment(fsctx
,ref
,
297 (void *)(intptr_t)(signed)ph
->p_vaddr
,
299 if (res
!= ph
->p_filesz
) {
300 if (shtab
) KFREE(shtab
);
306 if (ph
->p_filesz
< ph
->p_memsz
) {
307 res
= readclearbss((void *)(intptr_t)(signed)ph
->p_vaddr
+ ph
->p_filesz
,
308 ph
->p_memsz
- ph
->p_filesz
,flags
);
310 if (shtab
) KFREE(shtab
);
316 ph
->p_type
= PT_NULL
; /* remove from consideration */
321 *entrypt
= (intptr_t)(signed)ep
->e_entry
; /* return entry point */
327 /* *********************************************************************
328 * cfe_elfload(ops,file,flags)
330 * Read an ELF file (main entry point)
333 * ops - fileio dispatch
334 * file - name of file to read
335 * ept - where to put entry point
339 * 0 if ok, else error code
340 ********************************************************************* */
342 static int cfe_elfload(cfe_loadargs_t
*la
)
349 * Look up the file system type and get a context
353 res
= fs_init(la
->la_filesys
,&fsctx
,la
->la_device
);
359 * Turn on compression if we're doing that.
362 if (la
->la_flags
& LOADFLG_COMPRESSED
) {
363 res
= fs_hook(fsctx
,"z");
370 * Open the remote file
373 res
= fs_open(fsctx
,&ref
,la
->la_filename
,FILE_MODE_READ
);
376 return CFE_ERR_FILENOTFOUND
;
384 res
= elfload_internal(fsctx
,ref
,(unsigned long *)&(la
->la_entrypt
),la
->la_flags
);
387 * All done, release resources
396 #endif /* CFG_LDR_ELF */