X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fpowerpc%2Fkernel%2Fmodule_64.c;h=75c7c4f1928059689353927c2c67d198c62e715f;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=928b8581fcb043142c088052885b3f5b671ec4cf;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 928b8581f..75c7c4f19 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -20,8 +20,12 @@ #include #include #include +#include #include #include +#include + +#include "setup.h" /* FIXME: We don't do .init separately. To do this, we'd need to have a separate r2 value in the init and core section, and stub between @@ -191,11 +195,19 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr, (void *)hdr + sechdrs[sechdrs[i].sh_link].sh_offset); } - if (!me->arch.stubs_section || !me->arch.toc_section) { - printk("%s: doesn't contain .toc or .stubs.\n", me->name); + + if (!me->arch.stubs_section) { + printk("%s: doesn't contain .stubs.\n", me->name); return -ENOEXEC; } + /* If we don't have a .toc, just use .stubs. We need to set r2 + to some reasonable value in case the module calls out to + other functions via a stub, or if a function pointer escapes + the module by some means. */ + if (!me->arch.toc_section) + me->arch.toc_section = me->arch.stubs_section; + /* Override the stubs size */ sechdrs[me->arch.stubs_section].sh_size = get_stubs_size(hdr, sechdrs); return 0; @@ -342,7 +354,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, break; case R_PPC64_TOC16: - /* Subtact TOC pointer */ + /* Subtract TOC pointer */ value -= my_r2(sechdrs, me); if (value + 0x8000 > 0xffff) { printk("%s: bad TOC16 relocation (%lu)\n", @@ -355,7 +367,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, break; case R_PPC64_TOC16_DS: - /* Subtact TOC pointer */ + /* Subtract TOC pointer */ value -= my_r2(sechdrs, me); if ((value & 3) != 0 || value + 0x8000 > 0xffff) { printk("%s: bad TOC16_DS relocation (%lu)\n", @@ -392,6 +404,11 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, | (value & 0x03fffffc); break; + case R_PPC64_REL64: + /* 64 bits relative (used by features fixups) */ + *location = value - (unsigned long)location; + break; + default: printk("%s: Unknown ADD relocation: %lu\n", me->name, @@ -405,38 +422,49 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, LIST_HEAD(module_bug_list); -int module_finalize(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, struct module *me) +static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + const char *name) { char *secstrings; unsigned int i; - me->arch.bug_table = NULL; - me->arch.num_bugs = 0; - - /* Find the __bug_table section, if present */ secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; - for (i = 1; i < hdr->e_shnum; i++) { - if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table")) - continue; - me->arch.bug_table = (void *) sechdrs[i].sh_addr; - me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry); - break; - } + for (i = 1; i < hdr->e_shnum; i++) + if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0) + return &sechdrs[i]; + return NULL; +} - /* - * Strictly speaking this should have a spinlock to protect against - * traversals, but since we only traverse on BUG()s, a spinlock - * could potentially lead to deadlock and thus be counter-productive. - */ - list_add(&me->arch.bug_list, &module_bug_list); +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, struct module *me) +{ + const Elf_Shdr *sect; + int err; + + err = module_bug_finalize(hdr, sechdrs, me); + if (err) + return err; + + /* Apply feature fixups */ + sect = find_section(hdr, sechdrs, "__ftr_fixup"); + if (sect != NULL) + do_feature_fixups(cur_cpu_spec->cpu_features, + (void *)sect->sh_addr, + (void *)sect->sh_addr + sect->sh_size); + + sect = find_section(hdr, sechdrs, "__fw_ftr_fixup"); + if (sect != NULL) + do_feature_fixups(powerpc_firmware_features, + (void *)sect->sh_addr, + (void *)sect->sh_addr + sect->sh_size); return 0; } void module_arch_cleanup(struct module *mod) { - list_del(&mod->arch.bug_list); + module_bug_cleanup(mod); } struct bug_entry *module_find_bug(unsigned long bugaddr)