summaryrefslogtreecommitdiff
path: root/arch/m68k/kernel/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/kernel/module.c')
-rw-r--r--arch/m68k/kernel/module.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/arch/m68k/kernel/module.c b/arch/m68k/kernel/module.c
new file mode 100644
index 000000000..eb46fd603
--- /dev/null
+++ b/arch/m68k/kernel/module.c
@@ -0,0 +1,129 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt...)
+#endif
+
+#ifdef CONFIG_MODULES
+
+int apply_relocate(Elf32_Shdr *sechdrs,
+ const char *strtab,
+ unsigned int symindex,
+ unsigned int relsec,
+ struct module *me)
+{
+ unsigned int i;
+ Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
+ Elf32_Sym *sym;
+ uint32_t *location;
+
+ DEBUGP("Applying relocate section %u to %u\n", relsec,
+ sechdrs[relsec].sh_info);
+ for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+ /* This is where to make the change */
+ location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ + rel[i].r_offset;
+ /* This is the symbol it is referring to. Note that all
+ undefined symbols have been resolved. */
+ sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ + ELF32_R_SYM(rel[i].r_info);
+
+ switch (ELF32_R_TYPE(rel[i].r_info)) {
+ case R_68K_32:
+ /* We add the value into the location given */
+ *location += sym->st_value;
+ break;
+ case R_68K_PC32:
+ /* Add the value, subtract its position */
+ *location += sym->st_value - (uint32_t)location;
+ break;
+ default:
+ printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+ me->name, ELF32_R_TYPE(rel[i].r_info));
+ return -ENOEXEC;
+ }
+ }
+ return 0;
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+ const char *strtab,
+ unsigned int symindex,
+ unsigned int relsec,
+ struct module *me)
+{
+ unsigned int i;
+ Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+ Elf32_Sym *sym;
+ uint32_t *location;
+
+ DEBUGP("Applying relocate_add section %u to %u\n", relsec,
+ sechdrs[relsec].sh_info);
+ for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+ /* This is where to make the change */
+ location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ + rel[i].r_offset;
+ /* This is the symbol it is referring to. Note that all
+ undefined symbols have been resolved. */
+ sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ + ELF32_R_SYM(rel[i].r_info);
+
+ switch (ELF32_R_TYPE(rel[i].r_info)) {
+ case R_68K_32:
+ /* We add the value into the location given */
+ *location = rel[i].r_addend + sym->st_value;
+ break;
+ case R_68K_PC32:
+ /* Add the value, subtract its position */
+ *location = rel[i].r_addend + sym->st_value - (uint32_t)location;
+ break;
+ default:
+ printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+ me->name, ELF32_R_TYPE(rel[i].r_info));
+ return -ENOEXEC;
+ }
+ }
+ return 0;
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ struct module *mod)
+{
+ module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end);
+ return 0;
+}
+
+#endif /* CONFIG_MODULES */
+
+void module_fixup(struct module *mod, struct m68k_fixup_info *start,
+ struct m68k_fixup_info *end)
+{
+#ifdef CONFIG_MMU
+ struct m68k_fixup_info *fixup;
+
+ for (fixup = start; fixup < end; fixup++) {
+ switch (fixup->type) {
+ case m68k_fixup_memoffset:
+ *(u32 *)fixup->addr = m68k_memoffset;
+ break;
+ case m68k_fixup_vnode_shift:
+ *(u16 *)fixup->addr += m68k_virt_to_node_shift;
+ break;
+ }
+ }
+#endif
+}