|
|
1.1 root 1: /******************************************************************************
2: * Copyright (c) 2004, 2008 IBM Corporation
3: * All rights reserved.
4: * This program and the accompanying materials
5: * are made available under the terms of the BSD License
6: * which accompanies this distribution, and is available at
7: * http://www.opensource.org/licenses/bsd-license.php
8: *
9: * Contributors:
10: * IBM Corporation - initial implementation
11: *****************************************************************************/
12:
13: /* this is elf.fs rewritten in C */
14:
15: #include <string.h>
16: #include <cpu.h>
17: #include <libelf.h>
18:
19: struct ehdr {
20: unsigned int ei_ident;
21: unsigned char ei_class;
22: unsigned char ei_data;
23: unsigned char ei_version;
24: unsigned char ei_pad[9];
25: unsigned short e_type;
26: unsigned short e_machine;
27: unsigned int e_version;
28: unsigned int e_entry;
29: unsigned int e_phoff;
30: unsigned int e_shoff;
31: unsigned int e_flags;
32: unsigned short e_ehsize;
33: unsigned short e_phentsize;
34: unsigned short e_phnum;
35: unsigned short e_shentsize;
36: unsigned short e_shnum;
37: unsigned short e_shstrndx;
38: };
39:
40: struct phdr {
41: unsigned int p_type;
42: unsigned int p_offset;
43: unsigned int p_vaddr;
44: unsigned int p_paddr;
45: unsigned int p_filesz;
46: unsigned int p_memsz;
47: unsigned int p_flags;
48: unsigned int p_align;
49: };
50:
51: struct ehdr64 {
52: unsigned int ei_ident;
53: unsigned char ei_class;
54: unsigned char ei_data;
55: unsigned char ei_version;
56: unsigned char ei_pad[9];
57: unsigned short e_type;
58: unsigned short e_machine;
59: unsigned int e_version;
60: unsigned long e_entry;
61: unsigned long e_phoff;
62: unsigned long e_shoff;
63: unsigned int e_flags;
64: unsigned short e_ehsize;
65: unsigned short e_phentsize;
66: unsigned short e_phnum;
67: unsigned short e_shentsize;
68: unsigned short e_shnum;
69: unsigned short e_shstrndx;
70: };
71:
72: struct phdr64 {
73: unsigned int p_type;
74: unsigned int p_flags;
75: unsigned long p_offset;
76: unsigned long p_vaddr;
77: unsigned long p_paddr;
78: unsigned long p_filesz;
79: unsigned long p_memsz;
80: unsigned long p_align;
81: };
82:
83: #define VOID(x) (void *)((unsigned long)x)
84:
85: static void
86: load_segment(unsigned long *file_addr, struct phdr *phdr)
87: {
88: unsigned long src = phdr->p_offset + (unsigned long) file_addr;
89: /* copy into storage */
90: memmove(VOID(phdr->p_vaddr), VOID(src), phdr->p_filesz);
91:
92: /* clear bss */
93: memset(VOID(phdr->p_vaddr + phdr->p_filesz), 0,
94: phdr->p_memsz - phdr->p_filesz);
95:
96: if (phdr->p_memsz) {
97: flush_cache(VOID(phdr->p_vaddr), phdr->p_memsz);
98: }
99: }
100:
101: static unsigned int
102: load_segments(unsigned long *file_addr)
103: {
104: struct ehdr *ehdr = (struct ehdr *) file_addr;
105: /* Calculate program header address */
106: struct phdr *phdr =
107: (struct phdr *) (((unsigned char *) file_addr) + ehdr->e_phoff);
108: int i;
109: /* loop e_phnum times */
110: for (i = 0; i <= ehdr->e_phnum; i++) {
111: /* PT_LOAD ? */
112: if (phdr->p_type == 1) {
113: /* copy segment */
114: load_segment(file_addr, phdr);
115: }
116: /* step to next header */
117: phdr =
118: (struct phdr *) (((unsigned char *) phdr) +
119: ehdr->e_phentsize);
120: }
121: return ehdr->e_entry;
122: }
123:
124: static void
125: load_segment64(unsigned long *file_addr, struct phdr64 *phdr64)
126: {
127: unsigned long src = phdr64->p_offset + (unsigned long) file_addr;
128: /* copy into storage */
129: memmove(VOID(phdr64->p_vaddr), VOID(src), phdr64->p_filesz);
130:
131: /* clear bss */
132: memset(VOID(phdr64->p_vaddr + phdr64->p_filesz), 0,
133: phdr64->p_memsz - phdr64->p_filesz);
134:
135: if (phdr64->p_memsz) {
136: flush_cache(VOID(phdr64->p_vaddr), phdr64->p_memsz);
137: }
138: }
139:
140: static unsigned long
141: load_segments64(unsigned long *file_addr)
142: {
143: struct ehdr64 *ehdr64 = (struct ehdr64 *) file_addr;
144: /* Calculate program header address */
145: struct phdr64 *phdr64 =
146: (struct phdr64 *) (((unsigned char *) file_addr) + ehdr64->e_phoff);
147: int i;
148: /* loop e_phnum times */
149: for (i = 0; i <= ehdr64->e_phnum; i++) {
150: /* PT_LOAD ? */
151: if (phdr64->p_type == 1) {
152: /* copy segment */
153: load_segment64(file_addr, phdr64);
154: }
155: /* step to next header */
156: phdr64 =
157: (struct phdr64 *) (((unsigned char *) phdr64) +
158: ehdr64->e_phentsize);
159: }
160: return ehdr64->e_entry;
161: }
162:
163: #if __BYTE_ORDER == __BIG_ENDIAN
164: #define cpu_to_be32(x) (x)
165: #else
166: #define cpu_to_be32(x) bswap_32(x)
167: #endif
168:
169: /**
170: * elf_check_file tests if the file at file_addr is
171: * a correct endian, ELF PPC executable
172: * @param file_addr pointer to the start of the ELF file
173: * @return the class (1 for 32 bit, 2 for 64 bit)
174: * -1 if it is not an ELF file
175: * -2 if it has the wrong endianess
176: * -3 if it is not an ELF executable
177: * -4 if it is not for PPC
178: */
179: static int
180: elf_check_file(unsigned long *file_addr)
181: {
182: struct ehdr *ehdr = (struct ehdr *) file_addr;
183: /* check if it is an ELF image at all */
184: if (cpu_to_be32(ehdr->ei_ident) != 0x7f454c46)
185: return -1;
186:
187: /* endian check */
188: #if __BYTE_ORDER == __BIG_ENDIAN
189: if (ehdr->ei_data != 2)
190: /* not a big endian image */
191: #else
192: if (ehdr->ei_data == 2)
193: /* not a little endian image */
194: #endif
195: return -2;
196:
197: /* check if it is an ELF executable */
198: if (ehdr->e_type != 2)
199: return -3;
200:
201: /* check if it is a PPC ELF executable */
202: if (ehdr->e_machine != 0x14 && ehdr->e_machine != 0x15)
203: return -4;
204:
205: return ehdr->ei_class;
206: }
207:
208: /**
209: * load_elf_file tries to load the ELF file specified in file_addr
210: *
211: * it first checks if the file is a PPC ELF executable and then loads
212: * the segments depending if it is a 64bit or 32 bit ELF file
213: *
214: * @param file_addr pointer to the start of the elf file
215: * @param entry pointer where the ELF loader will store
216: * the entry point
217: * @return 1 for a 32 bit file
218: * 2 for a 64 bit file
219: * anything else means an error during load
220: */
221: int
222: load_elf_file(unsigned long *file_addr, unsigned long *entry)
223: {
224: int type = elf_check_file(file_addr);
225: switch (type) {
226: case 1:
227: *entry = load_segments(file_addr);
228: break;
229: case 2:
230: *entry = load_segments64(file_addr);
231: break;
232: }
233: return type;
234: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.