14e6a05feSThiemo Seufer /* 24e6a05feSThiemo Seufer * This program is free software; you can redistribute it and/or modify 34e6a05feSThiemo Seufer * it under the terms of the GNU General Public License as published by 44e6a05feSThiemo Seufer * the Free Software Foundation; either version 2 of the License, or 54e6a05feSThiemo Seufer * (at your option) any later version. 64e6a05feSThiemo Seufer * 74e6a05feSThiemo Seufer * This program is distributed in the hope that it will be useful, 84e6a05feSThiemo Seufer * but WITHOUT ANY WARRANTY; without even the implied warranty of 94e6a05feSThiemo Seufer * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 104e6a05feSThiemo Seufer * GNU General Public License for more details. 114e6a05feSThiemo Seufer * 124e6a05feSThiemo Seufer * You should have received a copy of the GNU General Public License 134e6a05feSThiemo Seufer * along with this program; if not, write to the Free Software 144e6a05feSThiemo Seufer * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 154e6a05feSThiemo Seufer * 164e6a05feSThiemo Seufer * Copyright (C) 2001 Rusty Russell. 174e6a05feSThiemo Seufer * Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org) 184e6a05feSThiemo Seufer * Copyright (C) 2005 Thiemo Seufer 194e6a05feSThiemo Seufer */ 204e6a05feSThiemo Seufer 214e6a05feSThiemo Seufer #undef DEBUG 224e6a05feSThiemo Seufer 234e6a05feSThiemo Seufer #include <linux/moduleloader.h> 244e6a05feSThiemo Seufer #include <linux/elf.h> 2527ac792cSAndrea Righi #include <linux/mm.h> 26761845f0SRalf Baechle #include <linux/numa.h> 274e6a05feSThiemo Seufer #include <linux/vmalloc.h> 284e6a05feSThiemo Seufer #include <linux/slab.h> 294e6a05feSThiemo Seufer #include <linux/fs.h> 304e6a05feSThiemo Seufer #include <linux/string.h> 314e6a05feSThiemo Seufer #include <linux/kernel.h> 321da177e4SLinus Torvalds #include <linux/spinlock.h> 3394bb0c1aSDavid Daney #include <linux/jump_label.h> 3494bb0c1aSDavid Daney 35656be92fSAtsushi Nemoto #include <asm/pgtable.h> /* MODULE_START */ 361da177e4SLinus Torvalds 374e6a05feSThiemo Seufer struct mips_hi16 { 384e6a05feSThiemo Seufer struct mips_hi16 *next; 394e6a05feSThiemo Seufer Elf_Addr *addr; 404e6a05feSThiemo Seufer Elf_Addr value; 414e6a05feSThiemo Seufer }; 424e6a05feSThiemo Seufer 431da177e4SLinus Torvalds static LIST_HEAD(dbe_list); 441da177e4SLinus Torvalds static DEFINE_SPINLOCK(dbe_lock); 451da177e4SLinus Torvalds 4666574cc0SJonas Bonn #ifdef MODULE_START 474e6a05feSThiemo Seufer void *module_alloc(unsigned long size) 484e6a05feSThiemo Seufer { 49d0a21265SDavid Rientjes return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END, 50cb9e3c29SAndrey Ryabinin GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, 51d0a21265SDavid Rientjes __builtin_return_address(0)); 5266574cc0SJonas Bonn } 53656be92fSAtsushi Nemoto #endif 544e6a05feSThiemo Seufer 556ede8123SRalf Baechle int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v) 564e6a05feSThiemo Seufer { 574e6a05feSThiemo Seufer return 0; 584e6a05feSThiemo Seufer } 594e6a05feSThiemo Seufer 604e6a05feSThiemo Seufer static int apply_r_mips_32_rel(struct module *me, u32 *location, Elf_Addr v) 614e6a05feSThiemo Seufer { 624e6a05feSThiemo Seufer *location += v; 634e6a05feSThiemo Seufer 644e6a05feSThiemo Seufer return 0; 654e6a05feSThiemo Seufer } 664e6a05feSThiemo Seufer 674e6a05feSThiemo Seufer static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v) 684e6a05feSThiemo Seufer { 694e6a05feSThiemo Seufer if (v % 4) { 706f9fdeb6SRalf Baechle pr_err("module %s: dangerous R_MIPS_26 REL relocation\n", 716f9fdeb6SRalf Baechle me->name); 724e6a05feSThiemo Seufer return -ENOEXEC; 734e6a05feSThiemo Seufer } 744e6a05feSThiemo Seufer 754e6a05feSThiemo Seufer if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { 764e6a05feSThiemo Seufer printk(KERN_ERR 774e6a05feSThiemo Seufer "module %s: relocation overflow\n", 784e6a05feSThiemo Seufer me->name); 794e6a05feSThiemo Seufer return -ENOEXEC; 804e6a05feSThiemo Seufer } 814e6a05feSThiemo Seufer 824e6a05feSThiemo Seufer *location = (*location & ~0x03ffffff) | 834e6a05feSThiemo Seufer ((*location + (v >> 2)) & 0x03ffffff); 844e6a05feSThiemo Seufer 854e6a05feSThiemo Seufer return 0; 864e6a05feSThiemo Seufer } 874e6a05feSThiemo Seufer 884e6a05feSThiemo Seufer static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v) 894e6a05feSThiemo Seufer { 904e6a05feSThiemo Seufer struct mips_hi16 *n; 914e6a05feSThiemo Seufer 924e6a05feSThiemo Seufer /* 934e6a05feSThiemo Seufer * We cannot relocate this one now because we don't know the value of 944e6a05feSThiemo Seufer * the carry we need to add. Save the information, and let LO16 do the 954e6a05feSThiemo Seufer * actual relocation. 964e6a05feSThiemo Seufer */ 974e6a05feSThiemo Seufer n = kmalloc(sizeof *n, GFP_KERNEL); 984e6a05feSThiemo Seufer if (!n) 994e6a05feSThiemo Seufer return -ENOMEM; 1004e6a05feSThiemo Seufer 1014e6a05feSThiemo Seufer n->addr = (Elf_Addr *)location; 1024e6a05feSThiemo Seufer n->value = v; 103861667dcSRalf Baechle n->next = me->arch.r_mips_hi16_list; 104861667dcSRalf Baechle me->arch.r_mips_hi16_list = n; 1054e6a05feSThiemo Seufer 1064e6a05feSThiemo Seufer return 0; 1074e6a05feSThiemo Seufer } 1084e6a05feSThiemo Seufer 109c54de490SRalf Baechle static void free_relocation_chain(struct mips_hi16 *l) 110c54de490SRalf Baechle { 111c54de490SRalf Baechle struct mips_hi16 *next; 112c54de490SRalf Baechle 113c54de490SRalf Baechle while (l) { 114c54de490SRalf Baechle next = l->next; 115c54de490SRalf Baechle kfree(l); 116c54de490SRalf Baechle l = next; 117c54de490SRalf Baechle } 118c54de490SRalf Baechle } 119c54de490SRalf Baechle 1204e6a05feSThiemo Seufer static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v) 1214e6a05feSThiemo Seufer { 1224e6a05feSThiemo Seufer unsigned long insnlo = *location; 123c54de490SRalf Baechle struct mips_hi16 *l; 1244e6a05feSThiemo Seufer Elf_Addr val, vallo; 1254e6a05feSThiemo Seufer 1264e6a05feSThiemo Seufer /* Sign extend the addend we extract from the lo insn. */ 1274e6a05feSThiemo Seufer vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; 1284e6a05feSThiemo Seufer 129861667dcSRalf Baechle if (me->arch.r_mips_hi16_list != NULL) { 130861667dcSRalf Baechle l = me->arch.r_mips_hi16_list; 1314e6a05feSThiemo Seufer while (l != NULL) { 132c54de490SRalf Baechle struct mips_hi16 *next; 1334e6a05feSThiemo Seufer unsigned long insn; 1344e6a05feSThiemo Seufer 1354e6a05feSThiemo Seufer /* 1364e6a05feSThiemo Seufer * The value for the HI16 had best be the same. 1374e6a05feSThiemo Seufer */ 1384e6a05feSThiemo Seufer if (v != l->value) 1394e6a05feSThiemo Seufer goto out_danger; 1404e6a05feSThiemo Seufer 1414e6a05feSThiemo Seufer /* 1424e6a05feSThiemo Seufer * Do the HI16 relocation. Note that we actually don't 1434e6a05feSThiemo Seufer * need to know anything about the LO16 itself, except 1444e6a05feSThiemo Seufer * where to find the low 16 bits of the addend needed 1454e6a05feSThiemo Seufer * by the LO16. 1464e6a05feSThiemo Seufer */ 1474e6a05feSThiemo Seufer insn = *l->addr; 1484e6a05feSThiemo Seufer val = ((insn & 0xffff) << 16) + vallo; 1494e6a05feSThiemo Seufer val += v; 1504e6a05feSThiemo Seufer 1514e6a05feSThiemo Seufer /* 1524e6a05feSThiemo Seufer * Account for the sign extension that will happen in 1534e6a05feSThiemo Seufer * the low bits. 1544e6a05feSThiemo Seufer */ 1554e6a05feSThiemo Seufer val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff; 1564e6a05feSThiemo Seufer 1574e6a05feSThiemo Seufer insn = (insn & ~0xffff) | val; 1584e6a05feSThiemo Seufer *l->addr = insn; 1594e6a05feSThiemo Seufer 1604e6a05feSThiemo Seufer next = l->next; 1614e6a05feSThiemo Seufer kfree(l); 1624e6a05feSThiemo Seufer l = next; 1634e6a05feSThiemo Seufer } 1644e6a05feSThiemo Seufer 165861667dcSRalf Baechle me->arch.r_mips_hi16_list = NULL; 1664e6a05feSThiemo Seufer } 1674e6a05feSThiemo Seufer 1684e6a05feSThiemo Seufer /* 1694e6a05feSThiemo Seufer * Ok, we're done with the HI16 relocs. Now deal with the LO16. 1704e6a05feSThiemo Seufer */ 1714e6a05feSThiemo Seufer val = v + vallo; 1724e6a05feSThiemo Seufer insnlo = (insnlo & ~0xffff) | (val & 0xffff); 1734e6a05feSThiemo Seufer *location = insnlo; 1744e6a05feSThiemo Seufer 1754e6a05feSThiemo Seufer return 0; 1764e6a05feSThiemo Seufer 1774e6a05feSThiemo Seufer out_danger: 178c54de490SRalf Baechle free_relocation_chain(l); 179c54de490SRalf Baechle me->arch.r_mips_hi16_list = NULL; 180d3cac35cSRalf Baechle 1816f9fdeb6SRalf Baechle pr_err("module %s: dangerous R_MIPS_LO16 REL relocation\n", me->name); 1824e6a05feSThiemo Seufer 1834e6a05feSThiemo Seufer return -ENOEXEC; 1844e6a05feSThiemo Seufer } 1854e6a05feSThiemo Seufer 1864e6a05feSThiemo Seufer static int (*reloc_handlers_rel[]) (struct module *me, u32 *location, 1874e6a05feSThiemo Seufer Elf_Addr v) = { 1884e6a05feSThiemo Seufer [R_MIPS_NONE] = apply_r_mips_none, 1894e6a05feSThiemo Seufer [R_MIPS_32] = apply_r_mips_32_rel, 1904e6a05feSThiemo Seufer [R_MIPS_26] = apply_r_mips_26_rel, 1914e6a05feSThiemo Seufer [R_MIPS_HI16] = apply_r_mips_hi16_rel, 1924e6a05feSThiemo Seufer [R_MIPS_LO16] = apply_r_mips_lo16_rel 1934e6a05feSThiemo Seufer }; 1944e6a05feSThiemo Seufer 1954e6a05feSThiemo Seufer int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, 1964e6a05feSThiemo Seufer unsigned int symindex, unsigned int relsec, 1974e6a05feSThiemo Seufer struct module *me) 1984e6a05feSThiemo Seufer { 1994e6a05feSThiemo Seufer Elf_Mips_Rel *rel = (void *) sechdrs[relsec].sh_addr; 20004211a57SPaul Burton int (*handler)(struct module *me, u32 *location, Elf_Addr v); 2014e6a05feSThiemo Seufer Elf_Sym *sym; 2024e6a05feSThiemo Seufer u32 *location; 20304211a57SPaul Burton unsigned int i, type; 2044e6a05feSThiemo Seufer Elf_Addr v; 2054e6a05feSThiemo Seufer int res; 2064e6a05feSThiemo Seufer 2074e6a05feSThiemo Seufer pr_debug("Applying relocate section %u to %u\n", relsec, 2084e6a05feSThiemo Seufer sechdrs[relsec].sh_info); 2094e6a05feSThiemo Seufer 210861667dcSRalf Baechle me->arch.r_mips_hi16_list = NULL; 2114e6a05feSThiemo Seufer for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 2124e6a05feSThiemo Seufer /* This is where to make the change */ 2134e6a05feSThiemo Seufer location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 2144e6a05feSThiemo Seufer + rel[i].r_offset; 2154e6a05feSThiemo Seufer /* This is the symbol it is referring to */ 2164e6a05feSThiemo Seufer sym = (Elf_Sym *)sechdrs[symindex].sh_addr 2174e6a05feSThiemo Seufer + ELF_MIPS_R_SYM(rel[i]); 2180e66fff8SGabor Juhos if (IS_ERR_VALUE(sym->st_value)) { 219f3bf07b9SAtsushi Nemoto /* Ignore unresolved weak symbol */ 220f3bf07b9SAtsushi Nemoto if (ELF_ST_BIND(sym->st_info) == STB_WEAK) 221f3bf07b9SAtsushi Nemoto continue; 2224e6a05feSThiemo Seufer printk(KERN_WARNING "%s: Unknown symbol %s\n", 2234e6a05feSThiemo Seufer me->name, strtab + sym->st_name); 2244e6a05feSThiemo Seufer return -ENOENT; 2254e6a05feSThiemo Seufer } 2264e6a05feSThiemo Seufer 22704211a57SPaul Burton type = ELF_MIPS_R_TYPE(rel[i]); 2284e6a05feSThiemo Seufer 22904211a57SPaul Burton if (type < ARRAY_SIZE(reloc_handlers_rel)) 23004211a57SPaul Burton handler = reloc_handlers_rel[type]; 23104211a57SPaul Burton else 23204211a57SPaul Burton handler = NULL; 23304211a57SPaul Burton 23404211a57SPaul Burton if (!handler) { 23504211a57SPaul Burton pr_err("%s: Unknown relocation type %u\n", 23604211a57SPaul Burton me->name, type); 23704211a57SPaul Burton return -EINVAL; 23804211a57SPaul Burton } 23904211a57SPaul Burton 24004211a57SPaul Burton v = sym->st_value; 24104211a57SPaul Burton res = handler(me, location, v); 2424e6a05feSThiemo Seufer if (res) 2434e6a05feSThiemo Seufer return res; 2444e6a05feSThiemo Seufer } 2454e6a05feSThiemo Seufer 246c54de490SRalf Baechle /* 247c54de490SRalf Baechle * Normally the hi16 list should be deallocated at this point. A 248c54de490SRalf Baechle * malformed binary however could contain a series of R_MIPS_HI16 249c54de490SRalf Baechle * relocations not followed by a R_MIPS_LO16 relocation. In that 250c54de490SRalf Baechle * case, free up the list and return an error. 251c54de490SRalf Baechle */ 252c54de490SRalf Baechle if (me->arch.r_mips_hi16_list) { 253c54de490SRalf Baechle free_relocation_chain(me->arch.r_mips_hi16_list); 254c54de490SRalf Baechle me->arch.r_mips_hi16_list = NULL; 255c54de490SRalf Baechle 256c54de490SRalf Baechle return -ENOEXEC; 257c54de490SRalf Baechle } 258c54de490SRalf Baechle 2594e6a05feSThiemo Seufer return 0; 2604e6a05feSThiemo Seufer } 2614e6a05feSThiemo Seufer 2621da177e4SLinus Torvalds /* Given an address, look for it in the module exception tables. */ 2631da177e4SLinus Torvalds const struct exception_table_entry *search_module_dbetables(unsigned long addr) 2641da177e4SLinus Torvalds { 2651da177e4SLinus Torvalds unsigned long flags; 2661da177e4SLinus Torvalds const struct exception_table_entry *e = NULL; 2671da177e4SLinus Torvalds struct mod_arch_specific *dbe; 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds spin_lock_irqsave(&dbe_lock, flags); 2701da177e4SLinus Torvalds list_for_each_entry(dbe, &dbe_list, dbe_list) { 2711da177e4SLinus Torvalds e = search_extable(dbe->dbe_start, dbe->dbe_end - 1, addr); 2721da177e4SLinus Torvalds if (e) 2731da177e4SLinus Torvalds break; 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds spin_unlock_irqrestore(&dbe_lock, flags); 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds /* Now, if we found one, we are running inside it now, hence 2781da177e4SLinus Torvalds we cannot unload the module, hence no refcnt needed. */ 2791da177e4SLinus Torvalds return e; 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds 2823a4fa0a2SRobert P. J. Day /* Put in dbe list if necessary. */ 2831da177e4SLinus Torvalds int module_finalize(const Elf_Ehdr *hdr, 2841da177e4SLinus Torvalds const Elf_Shdr *sechdrs, 2851da177e4SLinus Torvalds struct module *me) 2861da177e4SLinus Torvalds { 2871da177e4SLinus Torvalds const Elf_Shdr *s; 2881da177e4SLinus Torvalds char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 2891da177e4SLinus Torvalds 29094bb0c1aSDavid Daney /* Make jump label nops. */ 29194bb0c1aSDavid Daney jump_label_apply_nops(me); 29294bb0c1aSDavid Daney 2931da177e4SLinus Torvalds INIT_LIST_HEAD(&me->arch.dbe_list); 2941da177e4SLinus Torvalds for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { 2951da177e4SLinus Torvalds if (strcmp("__dbe_table", secstrings + s->sh_name) != 0) 2961da177e4SLinus Torvalds continue; 2971da177e4SLinus Torvalds me->arch.dbe_start = (void *)s->sh_addr; 2981da177e4SLinus Torvalds me->arch.dbe_end = (void *)s->sh_addr + s->sh_size; 2991da177e4SLinus Torvalds spin_lock_irq(&dbe_lock); 3001da177e4SLinus Torvalds list_add(&me->arch.dbe_list, &dbe_list); 3011da177e4SLinus Torvalds spin_unlock_irq(&dbe_lock); 3021da177e4SLinus Torvalds } 3031da177e4SLinus Torvalds return 0; 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds void module_arch_cleanup(struct module *mod) 3071da177e4SLinus Torvalds { 3081da177e4SLinus Torvalds spin_lock_irq(&dbe_lock); 3091da177e4SLinus Torvalds list_del(&mod->arch.dbe_list); 3101da177e4SLinus Torvalds spin_unlock_irq(&dbe_lock); 3111da177e4SLinus Torvalds } 312