RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / cfe / cfe / main / cfe_ldr_elf.c
bloba353852355a5a7a70c7c284839a88a53045ea4d8
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * ELF Program Loader File: cfe_ldr_elf.c
5 *
6 * This program parses ELF executables and loads them into memory.
7 *
8 * Author: Mitch Lichtenberg (mpl@broadcom.com)
9 *
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 ********************************************************************* */
46 #ifdef CFG_LDR_ELF
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"
54 #include "cfe_iocb.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"
60 #include "cfe_mem.h"
62 #include "cfe.h"
63 #include "cfe_loader.h"
64 #include "cfe_fileops.h"
65 #include "elf.h"
67 #include "cfe_boot.h"
69 /* *********************************************************************
70 * Externs
71 ********************************************************************* */
73 static int cfe_elfload(cfe_loadargs_t *la);
75 const cfe_loader_t elfloader = {
76 "elf",
77 cfe_elfload,
78 0};
80 /* *********************************************************************
81 * readprogsegment(fsctx,ref,addr,size)
83 * Read a program segment, generally corresponding to one
84 * section of the file.
86 * Input parameters:
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
92 * Return value:
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)
99 int res;
101 #ifdef __long64
102 if (flags & LOADFLG_NOISY) xprintf("0x%016llx/%d ",addr,size);
103 #else
104 if (flags & LOADFLG_NOISY) xprintf("0x%x/%d ",addr,size);
105 #endif
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;
116 return size;
120 /* *********************************************************************
121 * readclearbss(addr,size)
123 * Process a BSS section, zeroing memory corresponding to
124 * the BSS.
126 * Input parameters:
127 * addr - address to zero
128 * size - length of area to zero
130 * Return value:
131 * number of zeroed bytes or <0 if error occured
132 ********************************************************************* */
134 static int readclearbss(void *addr,int size,int flags)
137 #ifdef __long64
138 if (flags & LOADFLG_NOISY) xprintf("0x%016llx/%d ",addr,size);
139 #else
140 if (flags & LOADFLG_NOISY) xprintf("0x%x/%d ",addr,size);
141 #endif
143 if (!cfe_arena_loadcheck((uintptr_t) addr,size)) {
144 return CFE_ERR_BADADDR;
147 if (size > 0) memset(addr,0,size);
148 return size;
152 /* *********************************************************************
153 * elfgetshdr(ops,ref,ep)
155 * Get a section header from the ELF file
157 * Input parameters:
158 * ops - file I/O dispatch
159 * ref - reference data for open file
160 * ep - extended header info
162 * Return value:
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)
168 Elf32_Shdr *shtab;
169 unsigned size = ep->e_shnum * sizeof(Elf32_Shdr);
171 shtab = (Elf32_Shdr *) KMALLOC(size,0);
172 if (!shtab) {
173 return NULL;
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) {
178 KFREE(shtab);
179 return NULL;
182 return (shtab);
185 /* *********************************************************************
186 * elfload_internal(ops,ref,entrypt,flags)
188 * Read an ELF file (main routine)
190 * Input parameters:
191 * ops - file I/O dispatch
192 * ref - open file handle
193 * entrypt - filled in with entry vector
194 * flags - generic boot flags
196 * Return value:
197 * 0 if ok
198 * else error code
199 ********************************************************************* */
201 static int elfload_internal(fileio_ctx_t *fsctx,void *ref,
202 unsigned long *entrypt,int flags)
204 Elf32_Ehdr *ep;
205 Elf32_Phdr *phtab = 0;
206 Elf32_Shdr *shtab = 0;
207 unsigned int nbytes;
208 int i;
209 int res;
210 Elf32_Ehdr ehdr;
212 ep = &ehdr;
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;
227 #ifdef __MIPSEB
228 if (ep->e_ident[EI_DATA] != ELFDATA2MSB) return CFE_ERR_WRONGENDIAN; /* big endian */
229 #endif
230 #ifdef __MIPSEL
231 if (ep->e_ident[EI_DATA] != ELFDATA2LSB) return CFE_ERR_WRONGENDIAN; /* little endian */
232 #endif
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);
246 if (!phtab) {
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) {
252 KFREE(phtab);
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
262 * segments.
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. */
275 while (1) {
276 Elf32_Off lowest_offset = ~0;
277 Elf32_Phdr *ph = 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)) {
282 ph = &phtab[i];
283 lowest_offset = ph->p_offset;
285 if (!ph) {
286 break; /* none found, finished */
289 /* load the segment */
290 if (ph->p_filesz) {
291 if (fs_seek(fsctx,ref,ph->p_offset,FILE_SEEK_BEGINNING) != ph->p_offset) {
292 if (shtab) KFREE(shtab);
293 KFREE(phtab);
294 return CFE_ERR_BADELFFMT;
296 res = readprogsegment(fsctx,ref,
297 (void *)(intptr_t)(signed)ph->p_vaddr,
298 ph->p_filesz,flags);
299 if (res != ph->p_filesz) {
300 if (shtab) KFREE(shtab);
301 KFREE(phtab);
302 return res;
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);
309 if (res < 0) {
310 if (shtab) KFREE(shtab);
311 KFREE(phtab);
312 return res;
316 ph->p_type = PT_NULL; /* remove from consideration */
319 KFREE(phtab);
321 *entrypt = (intptr_t)(signed)ep->e_entry; /* return entry point */
322 return 0;
327 /* *********************************************************************
328 * cfe_elfload(ops,file,flags)
330 * Read an ELF file (main entry point)
332 * Input parameters:
333 * ops - fileio dispatch
334 * file - name of file to read
335 * ept - where to put entry point
336 * flags - load flags
338 * Return value:
339 * 0 if ok, else error code
340 ********************************************************************* */
342 static int cfe_elfload(cfe_loadargs_t *la)
344 fileio_ctx_t *fsctx;
345 void *ref;
346 int res;
349 * Look up the file system type and get a context
353 res = fs_init(la->la_filesys,&fsctx,la->la_device);
354 if (res != 0) {
355 return res;
359 * Turn on compression if we're doing that.
362 if (la->la_flags & LOADFLG_COMPRESSED) {
363 res = fs_hook(fsctx,"z");
364 if (res != 0) {
365 return res;
370 * Open the remote file
373 res = fs_open(fsctx,&ref,la->la_filename,FILE_MODE_READ);
374 if (res != 0) {
375 fs_uninit(fsctx);
376 return CFE_ERR_FILENOTFOUND;
380 * Load the image.
383 la->la_entrypt = 0;
384 res = elfload_internal(fsctx,ref,(unsigned long *)&(la->la_entrypt),la->la_flags);
387 * All done, release resources
390 fs_close(fsctx,ref);
391 fs_uninit(fsctx);
393 return res;
396 #endif /* CFG_LDR_ELF */