Merge branch 'old_next' into next
[pandora-kernel.git] / arch / arm / kernel / module.c
index 2cfe816..fee7c36 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <asm/pgtable.h>
 #include <asm/sections.h>
+#include <asm/smp_plat.h>
 #include <asm/unwind.h>
 
 #ifdef CONFIG_XIP_KERNEL
@@ -75,6 +76,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
        for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) {
                unsigned long loc;
                Elf32_Sym *sym;
+               const char *symname;
                s32 offset;
 #ifdef CONFIG_THUMB2_KERNEL
                u32 upper, lower, sign, j1, j2;
@@ -82,18 +84,18 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
 
                offset = ELF32_R_SYM(rel->r_info);
                if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) {
-                       printk(KERN_ERR "%s: bad relocation, section %d reloc %d\n",
+                       pr_err("%s: section %u reloc %u: bad relocation sym offset\n",
                                module->name, relindex, i);
                        return -ENOEXEC;
                }
 
                sym = ((Elf32_Sym *)symsec->sh_addr) + offset;
+               symname = strtab + sym->st_name;
 
                if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) {
-                       printk(KERN_ERR "%s: out of bounds relocation, "
-                               "section %d reloc %d offset %d size %d\n",
-                               module->name, relindex, i, rel->r_offset,
-                               dstsec->sh_size);
+                       pr_err("%s: section %u reloc %u sym '%s': out of bounds relocation, offset %d size %u\n",
+                              module->name, relindex, i, symname,
+                              rel->r_offset, dstsec->sh_size);
                        return -ENOEXEC;
                }
 
@@ -119,10 +121,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
                        if (offset & 3 ||
                            offset <= (s32)0xfe000000 ||
                            offset >= (s32)0x02000000) {
-                               printk(KERN_ERR
-                                      "%s: relocation out of range, section "
-                                      "%d reloc %d sym '%s'\n", module->name,
-                                      relindex, i, strtab + sym->st_name);
+                               pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n",
+                                      module->name, relindex, i, symname,
+                                      ELF32_R_TYPE(rel->r_info), loc,
+                                      sym->st_value);
                                return -ENOEXEC;
                        }
 
@@ -195,10 +197,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
                        if (!(offset & 1) ||
                            offset <= (s32)0xff000000 ||
                            offset >= (s32)0x01000000) {
-                               printk(KERN_ERR
-                                      "%s: relocation out of range, section "
-                                      "%d reloc %d sym '%s'\n", module->name,
-                                      relindex, i, strtab + sym->st_name);
+                               pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n",
+                                      module->name, relindex, i, symname,
+                                      ELF32_R_TYPE(rel->r_info), loc,
+                                      sym->st_value);
                                return -ENOEXEC;
                        }
 
@@ -268,12 +270,29 @@ struct mod_unwind_map {
        const Elf_Shdr *txt_sec;
 };
 
+static const Elf_Shdr *find_mod_section(const Elf32_Ehdr *hdr,
+       const Elf_Shdr *sechdrs, const char *name)
+{
+       const Elf_Shdr *s, *se;
+       const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+       for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++)
+               if (strcmp(name, secstrs + s->sh_name) == 0)
+                       return s;
+
+       return NULL;
+}
+
+extern void fixup_pv_table(const void *, unsigned long);
+extern void fixup_smp(const void *, unsigned long);
+
 int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
                    struct module *mod)
 {
+       const Elf_Shdr *s = NULL;
 #ifdef CONFIG_ARM_UNWIND
        const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
-       const Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
+       const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum;
        struct mod_unwind_map maps[ARM_SEC_MAX];
        int i;
 
@@ -315,6 +334,14 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
                                                 maps[i].txt_sec->sh_addr,
                                                 maps[i].txt_sec->sh_size);
 #endif
+#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
+       s = find_mod_section(hdr, sechdrs, ".pv_table");
+       if (s)
+               fixup_pv_table((void *)s->sh_addr, s->sh_size);
+#endif
+       s = find_mod_section(hdr, sechdrs, ".alt.smp.init");
+       if (s && !is_smp())
+               fixup_smp((void *)s->sh_addr, s->sh_size);
        return 0;
 }