4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 extern list_t
*debug_info
;
26 static char *ptr_ro
= (char *)KERNEL_PHYS_BASE
;
27 static char *ptr_rw
= (char *)KERNEL_PHYS_BASE
;
39 struct bss_tracker tracker
[MAX_BSS_SECTIONS
];
40 static struct bss_tracker
*bss_tracker
= &tracker
[0];
43 * read_block function copies the range of memory within ELF file to any specified location.
45 static inline void read_block(void *file
, long offset
, void *dest
, long length
)
47 memcpy(dest
, (void *)((unsigned long)file
+ offset
), length
);
51 * Test for correct ELF header here
53 static int check_header(struct elfheader
*eh
)
55 if (eh
->ident
[0] != 0x7f ||
56 eh
->ident
[1] != 'E' || eh
->ident
[2] != 'L' || eh
->ident
[3] != 'F') {
60 if (eh
->type
!= ET_REL
|| eh
->machine
!= EM_PPC
) {
67 * Get the memory for chunk and load it
69 static int load_hunk(void *file
, struct sheader
*sh
)
71 void *ptr
= (void *)0;
73 /* empty chunk? Who cares :) */
77 /* Allocate a chunk with write access - take aligned memory beneath the RO kernel */
78 if (sh
->flags
& SHF_WRITE
) {
79 ptr
= (void *)(((unsigned long)ptr_rw
- (unsigned long)sh
->size
80 - (unsigned long)sh
->addralign
+ 1)
81 & ~((unsigned long)sh
->addralign
- 1));
84 /* Read-Only mode? Get the memory from the kernel space, align it accorting to the demand */
85 ptr_ro
= (char *)(((unsigned long)ptr_ro
86 + (unsigned long)sh
->addralign
- 1)
87 & ~((unsigned long)sh
->addralign
- 1));
89 ptr_ro
= ptr_ro
+ sh
->size
;
94 /* copy block of memory from ELF file if it exists */
95 if (sh
->type
!= SHT_NOBITS
) {
96 read_block(file
, sh
->offset
, (void *)((unsigned long)sh
->addr
),
101 (void *)((unsigned long)ptr
+ KERNEL_VIRT_BASE
-
103 bss_tracker
->length
= sh
->size
;
110 /* Perform relocations of given section */
111 static int relocate(struct elfheader
*eh
, struct sheader
*sh
, long shrel_idx
,
114 struct sheader
*shrel
= &sh
[shrel_idx
];
115 struct sheader
*shsymtab
= &sh
[shrel
->link
];
116 struct sheader
*toreloc
= &sh
[shrel
->info
];
118 struct symbol
*symtab
=
119 (struct symbol
*)((unsigned long)shsymtab
->addr
);
120 struct relo
*rel
= (struct relo
*)((unsigned long)shrel
->addr
);
121 char *section
= (char *)((unsigned long)toreloc
->addr
);
123 unsigned int numrel
= (unsigned long)shrel
->size
124 / (unsigned long)shrel
->entsize
;
129 struct symbol
*SysBase_sym
= (void *)0;
131 for (i
= 0; i
< numrel
; i
++, rel
++) {
132 struct symbol
*sym
= &symtab
[ELF32_R_SYM(rel
->info
)];
133 uint32_t *p
= (uint32_t *) & section
[rel
->offset
];
137 switch (sym
->shindex
) {
140 ("[ELF Loader] Undefined symbol '%s' in section '%s'\n",
141 (char *)((uint32_t) sh
[shsymtab
->link
].addr
) +
143 (char *)((uint32_t) sh
[eh
->shstrndx
].addr
) +
149 ("[ELF Loader] COMMON symbol '%s' in section '%s'\n",
150 (char *)((uint32_t) sh
[shsymtab
->link
].addr
) +
152 (char *)((uint32_t) sh
[eh
->shstrndx
].addr
) +
158 if (SysBase_sym
== (void *)0) {
160 ((char *)((uint32_t) sh
[shsymtab
->link
].
161 addr
) + sym
->name
, "SysBase",
167 } else if (SysBase_sym
== sym
) {
168 SysBase_yes
: s
= (uint32_t) 4UL;
171 SysBase_no
: s
= sym
->value
;
174 s
= (uint32_t) sh
[sym
->shindex
].addr
+ sym
->value
;
177 switch (ELF32_R_TYPE(rel
->info
)) {
179 *p
= s
+ rel
->addend
+ virtoffset
;
182 case R_PPC_ADDR16_LO
:
184 unsigned short *c
= (unsigned short *)p
;
185 *c
= (s
+ rel
->addend
+ virtoffset
) & 0xffff;
189 case R_PPC_ADDR16_HA
:
191 unsigned short *c
= (unsigned short *)p
;
192 uint32_t temp
= s
+ rel
->addend
+ virtoffset
;
194 if ((temp
& 0x8000) != 0)
201 *p
|= (s
+ rel
->addend
- (uint32_t) p
) & 0x3fffffc;
205 *p
= s
+ rel
->addend
- (uint32_t) p
;
212 printf("[BOOT] Unknown relocation %d in ELF file\n",
213 ELF32_R_TYPE(rel
->info
));
220 int load_elf_file(const char *name
, void *file
)
222 struct elfheader
*eh
;
231 /* Check the header of ELF file */
232 if (!check_header(eh
)) {
233 printf("[BOOT] ELF header invalid\n");
237 sh
= (struct sheader
*)((unsigned long)file
+ eh
->shoff
);
239 /* Iterate over the section header in order to prepare memory and eventually load some hunks */
240 for (i
= 0; i
< eh
->shnum
; i
++) {
241 /* Load the symbol and string tables */
242 if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
) {
243 sh
[i
].addr
= (unsigned long)file
+ sh
[i
].offset
;
245 /* Does the section require memoy allcation? */
246 else if (sh
[i
].flags
& SHF_ALLOC
) {
247 /* Yup, it does. Load the hunk */
248 if (!load_hunk(file
, &sh
[i
])) {
251 if (sh
[i
].size
&& !shown
) {
253 ("[BOOT] ELF: section loaded at %p (Virtual addr: %p)\n",
255 sh
[i
].addr
+ KERNEL_VIRT_BASE
-
263 /* For every loaded section perform the relocations */
264 for (i
= 0; i
< eh
->shnum
; i
++) {
265 if (sh
[i
].type
== SHT_RELA
&& sh
[sh
[i
].info
].addr
) {
266 sh
[i
].addr
= (uint32_t) file
+ sh
[i
].offset
;
268 || !relocate(eh
, sh
, i
,
269 KERNEL_VIRT_BASE
- KERNEL_PHYS_BASE
)) {
275 /* Register the module */
276 mod
= malloc(sizeof(module_t
));
277 (printf("[BOOT] module=%p\n", mod
));
283 new_list(&mod
->m_symbols
);
285 mod
->m_name
= malloc(strlen(name
)+1);
286 mod
->m_lowest
= 0xffffffff;
287 mod
->m_highest
= 0x00000000;
292 memcpy(mod
->m_name
, name
, strlen(name
)+1);
294 (printf("[BOOT] name=%s\n", mod
->m_name
));
296 for (i
=0; i
< eh
->shnum
; i
++)
298 /* If we have string table, copy it */
299 if (sh
[i
].type
== SHT_STRTAB
&& i
!= eh
->shstrndx
)
303 mod
->m_str
= malloc(sh
[i
].size
);
304 memcpy(mod
->m_str
, (void *)sh
[i
].addr
, sh
[i
].size
);
306 (printf("[BOOT] symbol table copied from %p to %p\n", sh
[i
].addr
, mod
->m_str
));
310 if ((sh
[i
].flags
& (SHF_ALLOC
| SHF_EXECINSTR
)) == (SHF_ALLOC
| SHF_EXECINSTR
))
314 unsigned long virt
= sh
[i
].addr
+ KERNEL_VIRT_BASE
- KERNEL_PHYS_BASE
;
316 if (virt
< mod
->m_lowest
)
317 mod
->m_lowest
= virt
;
318 if (virt
+ sh
[i
].size
> mod
->m_highest
)
319 mod
->m_highest
= virt
+ sh
[i
].size
;
324 (printf("[BOOT] m_lowest=%p, m_highest=%p\n", mod
->m_lowest
, mod
->m_highest
));
325 for (i
=0; i
< eh
->shnum
; i
++)
327 if (sh
[i
].addr
&& sh
[i
].type
== SHT_SYMTAB
)
329 struct symbol
*st
= (struct symbol
*)sh
[i
].addr
;
331 for (j
=0; j
< (sh
[i
].size
/ sizeof(struct symbol
)); j
++)
333 if (sh
[st
[j
].shindex
].addr
&& (sh
[st
[j
].shindex
].flags
& (SHF_ALLOC
| SHF_EXECINSTR
)) == (SHF_ALLOC
| SHF_EXECINSTR
))
335 symbol_t
*sym
= malloc(sizeof(symbol_t
));
336 sym
->s_name
= &mod
->m_str
[st
[j
].name
];
337 sym
->s_lowest
= sh
[st
[j
].shindex
].addr
+ st
[j
].value
+ KERNEL_VIRT_BASE
- KERNEL_PHYS_BASE
;
338 sym
->s_highest
= sym
->s_lowest
+ st
[j
].size
;
340 add_head(&mod
->m_symbols
, &sym
->s_node
);
348 add_head(debug_info
, &mod
->m_node
);