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,
25 static char *ptr_ro
= (char *)KERNEL_PHYS_BASE
;
26 static char *ptr_rw
= (char *)KERNEL_PHYS_BASE
;
33 void ptr_ro_add(int amount
)
43 struct bss_tracker tracker
[MAX_BSS_SECTIONS
];
44 static struct bss_tracker
*bss_tracker
= &tracker
[0];
46 extern list_t
*debug_info
;
49 * read_block function copies the range of memory within ELF file to any specified location.
51 static inline void read_block(void *file
, long offset
, void *dest
, long length
)
53 memcpy(dest
, (void *)((unsigned long)file
+ offset
), length
);
57 * Test for correct ELF header here
59 static int check_header(struct elfheader
*eh
)
63 eh
->ident
[0] != 0x7f ||
64 eh
->ident
[1] != 'E' ||
65 eh
->ident
[2] != 'L' ||
72 if (eh
->type
!= ET_REL
|| eh
->machine
!= EM_PPC
)
80 * Get the memory for chunk and load it
82 static int load_hunk(void *file
, struct sheader
*sh
, unsigned long virt
)
86 /* empty chunk? Who cares :) */
90 /* Allocate a chunk with write access - take aligned memory beneath the RO kernel */
91 if (sh
->flags
& SHF_WRITE
)
93 ptr
= (void*)(((unsigned long)ptr_rw
- (unsigned long)sh
->size
- (unsigned long)sh
->addralign
+ 1) & ~((unsigned long)sh
->addralign
-1));
98 /* Read-Only mode? Get the memory from the kernel space, align it accorting to the demand */
99 ptr_ro
= (char *)(((unsigned long)ptr_ro
+ (unsigned long)sh
->addralign
- 1) & ~((unsigned long)sh
->addralign
-1));
101 ptr_ro
= ptr_ro
+ sh
->size
;
104 sh
->addr
= (long)ptr
;
106 /* copy block of memory from ELF file if it exists */
107 if (sh
->type
!= SHT_NOBITS
)
109 read_block(file
, sh
->offset
, (void *)((unsigned long)sh
->addr
), sh
->size
);
113 bzero(ptr
, sh
->size
);
114 bss_tracker
->addr
= (void*)((unsigned long)ptr
+ virt
- KERNEL_PHYS_BASE
);
115 bss_tracker
->length
= sh
->size
;
117 bss_tracker
->addr
= NULL
;
118 bss_tracker
->length
= 0;
124 /* Perform relocations of given section */
125 static int relocate(struct elfheader
*eh
, struct sheader
*sh
, long shrel_idx
, uint32_t virt
)
127 struct sheader
*shrel
= &sh
[shrel_idx
];
128 struct sheader
*shsymtab
= &sh
[shrel
->link
];
129 struct sheader
*toreloc
= &sh
[shrel
->info
];
131 struct symbol
*symtab
= (struct symbol
*)((unsigned long)shsymtab
->addr
);
132 struct relo
*rel
= (struct relo
*)((unsigned long)shrel
->addr
);
133 char *section
= (char *)((unsigned long)toreloc
->addr
);
135 unsigned int numrel
= (unsigned long)shrel
->size
/ (unsigned long)shrel
->entsize
;
140 struct symbol
*SysBase_sym
= (void*)0;
142 for (i
=0; i
<numrel
; i
++, rel
++)
144 struct symbol
*sym
= &symtab
[ELF32_R_SYM(rel
->info
)];
145 uint32_t *p
= (uint32_t *)§ion
[rel
->offset
];
149 switch (sym
->shindex
)
152 bug("[ELF Loader] Undefined symbol '%s' in section '%s'\r\n",
153 (char *)((uint32_t)sh
[shsymtab
->link
].addr
) + sym
->name
,
154 (char *)((uint32_t)sh
[eh
->shstrndx
].addr
) + toreloc
->name
);
158 bug("[ELF Loader] COMMON symbol '%s' in section '%s'\r\n",
159 (char *)((uint32_t)sh
[shsymtab
->link
].addr
) + sym
->name
,
160 (char *)((uint32_t)sh
[eh
->shstrndx
].addr
) + toreloc
->name
);
165 if (SysBase_sym
== (void*)0)
167 if (strncmp((char *)((uint32_t)sh
[shsymtab
->link
].addr
) + sym
->name
, "SysBase", 8) == 0)
176 if (SysBase_sym
== sym
)
178 SysBase_yes
: s
= (uint32_t)4UL;
182 SysBase_no
: s
= sym
->value
;
185 s
= (uint32_t)sh
[sym
->shindex
].addr
+ sym
->value
;
188 switch (ELF32_R_TYPE(rel
->info
))
191 *p
= s
+ rel
->addend
+ virtoffset
;
194 case R_PPC_ADDR16_LO
:
196 unsigned short *c
= (unsigned short *) p
;
197 *c
= (s
+ rel
->addend
+ virtoffset
) & 0xffff;
201 case R_PPC_ADDR16_HA
:
203 unsigned short *c
= (unsigned short *) p
;
204 uint32_t temp
= s
+ rel
->addend
+ virtoffset
;
206 if ((temp
& 0x8000) != 0)
213 *p
|= (s
+ rel
->addend
- (uint32_t) p
) & 0x3fffffc;
217 *p
= s
+ rel
->addend
- (uint32_t) p
;
224 bug("[BOOT] Unknown relocation %d in ELF file\r\n", ELF32_R_TYPE(rel
->info
));
231 int load_elf_file(const char *name
, void *file
, unsigned long virt
)
233 struct elfheader
*eh
;
241 /* Check the header of ELF file */
242 if (!check_header(eh
))
244 D(bug("[BOOT] ELF header invalid\r\n"));
248 sh
= (struct sheader
*)((unsigned long)file
+ eh
->shoff
);
250 /* Iterate over the section header in order to prepare memory and eventually load some hunks */
251 for (i
=0; i
< eh
->shnum
; i
++)
253 /* Load the symbol and string tables */
254 if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
)
256 sh
[i
].addr
= (unsigned long)file
+ sh
[i
].offset
;
258 /* Does the section require memoy allcation? */
259 else if (sh
[i
].flags
& SHF_ALLOC
)
261 /* Yup, it does. Load the hunk */
262 if (!load_hunk(file
, &sh
[i
], virt
))
268 if (sh
[i
].size
&& !shown
)
270 D(bug("[BOOT] ELF: section loaded at %p (Virtual addr: %p)\r\n", sh
[i
].addr
, sh
[i
].addr
+
271 virt
- KERNEL_PHYS_BASE
));
273 bug("@ %p", sh
[i
].addr
+ virt
- KERNEL_PHYS_BASE
);
281 /* For every loaded section perform the relocations */
282 for (i
=0; i
< eh
->shnum
; i
++)
284 if (sh
[i
].type
== SHT_RELA
&& sh
[sh
[i
].info
].addr
)
286 sh
[i
].addr
= (uint32_t)file
+ sh
[i
].offset
;
287 if (!sh
[i
].addr
|| !relocate(eh
, sh
, i
, virt
- KERNEL_PHYS_BASE
))
295 /* Register the module */
297 mod
= __claim(sizeof(module_t
));
299 D(bug("[BOOT] module=%p\n", mod
));
305 new_list(&mod
->m_symbols
);
307 mod
->m_name
= __claim(strlen(name
)+1);
308 mod
->m_lowest
= 0xffffffff;
309 mod
->m_highest
= 0x00000000;
314 memcpy(mod
->m_name
, name
, strlen(name
)+1);
316 D(bug("[BOOT] name=%s\n", mod
->m_name
));
318 for (i
=0; i
< eh
->shnum
; i
++)
320 /* If we have string table, copy it */
321 if (sh
[i
].type
== SHT_STRTAB
&& i
!= eh
->shstrndx
)
325 mod
->m_str
= __claim(sh
[i
].size
);
326 memcpy(mod
->m_str
, (void *)sh
[i
].addr
, sh
[i
].size
);
328 D(bug("[BOOT] symbol table copied from %p to %p\n", sh
[i
].addr
, mod
->m_str
));
332 if ((sh
[i
].flags
& (SHF_ALLOC
| SHF_EXECINSTR
)) == (SHF_ALLOC
| SHF_EXECINSTR
))
336 intptr_t addr
= sh
[i
].addr
+ virt
- KERNEL_PHYS_BASE
;
338 if (addr
< mod
->m_lowest
)
339 mod
->m_lowest
= addr
;
340 if (addr
+ sh
[i
].size
> mod
->m_highest
)
341 mod
->m_highest
= addr
+ sh
[i
].size
;
346 D(bug("[BOOT] m_lowest=%p, m_highest=%p\n", mod
->m_lowest
, mod
->m_highest
));
348 for (i
=0; i
< eh
->shnum
; i
++)
350 if (sh
[i
].addr
&& sh
[i
].type
== SHT_SYMTAB
)
352 struct symbol
*st
= (struct symbol
*)sh
[i
].addr
;
354 for (j
=0; j
< (sh
[i
].size
/ sizeof(struct symbol
)); j
++)
356 if (sh
[st
[j
].shindex
].addr
&& (sh
[st
[j
].shindex
].flags
& (SHF_ALLOC
| SHF_EXECINSTR
)) == (SHF_ALLOC
| SHF_EXECINSTR
))
358 symbol_t
*sym
= __claim(sizeof(symbol_t
));
359 sym
->s_name
= &mod
->m_str
[st
[j
].name
];
360 sym
->s_lowest
= sh
[st
[j
].shindex
].addr
+ st
[j
].value
+ virt
- KERNEL_PHYS_BASE
;
361 sym
->s_highest
= sym
->s_lowest
+ st
[j
].size
;
363 add_head(&mod
->m_symbols
, (node_t
*)sym
);
371 add_head(debug_info
, (node_t
*)mod
);