linux/arch/mips/kernel/module.c
<<
>>
Prefs
   1/*
   2 *  This program is free software; you can redistribute it and/or modify
   3 *  it under the terms of the GNU General Public License as published by
   4 *  the Free Software Foundation; either version 2 of the License, or
   5 *  (at your option) any later version.
   6 *
   7 *  This program is distributed in the hope that it will be useful,
   8 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   9 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10 *  GNU General Public License for more details.
  11 *
  12 *  You should have received a copy of the GNU General Public License
  13 *  along with this program; if not, write to the Free Software
  14 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  15 *
  16 *  Copyright (C) 2001 Rusty Russell.
  17 *  Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org)
  18 *  Copyright (C) 2005 Thiemo Seufer
  19 */
  20
  21#undef DEBUG
  22
  23#include <linux/moduleloader.h>
  24#include <linux/elf.h>
  25#include <linux/mm.h>
  26#include <linux/vmalloc.h>
  27#include <linux/slab.h>
  28#include <linux/fs.h>
  29#include <linux/string.h>
  30#include <linux/kernel.h>
  31#include <linux/module.h>
  32#include <linux/spinlock.h>
  33#include <linux/jump_label.h>
  34
  35#include <asm/pgtable.h>        /* MODULE_START */
  36
  37struct mips_hi16 {
  38        struct mips_hi16 *next;
  39        Elf_Addr *addr;
  40        Elf_Addr value;
  41};
  42
  43static struct mips_hi16 *mips_hi16_list;
  44
  45static LIST_HEAD(dbe_list);
  46static DEFINE_SPINLOCK(dbe_lock);
  47
  48#ifdef MODULE_START
  49void *module_alloc(unsigned long size)
  50{
  51        return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END,
  52                                GFP_KERNEL, PAGE_KERNEL, -1,
  53                                __builtin_return_address(0));
  54}
  55#endif
  56
  57static int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v)
  58{
  59        return 0;
  60}
  61
  62static int apply_r_mips_32_rel(struct module *me, u32 *location, Elf_Addr v)
  63{
  64        *location += v;
  65
  66        return 0;
  67}
  68
  69static int apply_r_mips_32_rela(struct module *me, u32 *location, Elf_Addr v)
  70{
  71        *location = v;
  72
  73        return 0;
  74}
  75
  76static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
  77{
  78        if (v % 4) {
  79                pr_err("module %s: dangerous R_MIPS_26 REL relocation\n",
  80                       me->name);
  81                return -ENOEXEC;
  82        }
  83
  84        if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
  85                printk(KERN_ERR
  86                       "module %s: relocation overflow\n",
  87                       me->name);
  88                return -ENOEXEC;
  89        }
  90
  91        *location = (*location & ~0x03ffffff) |
  92                    ((*location + (v >> 2)) & 0x03ffffff);
  93
  94        return 0;
  95}
  96
  97static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v)
  98{
  99        if (v % 4) {
 100                pr_err("module %s: dangerous R_MIPS_26 RELArelocation\n",
 101                       me->name);
 102                return -ENOEXEC;
 103        }
 104
 105        if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
 106                printk(KERN_ERR
 107                       "module %s: relocation overflow\n",
 108                       me->name);
 109                return -ENOEXEC;
 110        }
 111
 112        *location = (*location & ~0x03ffffff) | ((v >> 2) & 0x03ffffff);
 113
 114        return 0;
 115}
 116
 117static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v)
 118{
 119        struct mips_hi16 *n;
 120
 121        /*
 122         * We cannot relocate this one now because we don't know the value of
 123         * the carry we need to add.  Save the information, and let LO16 do the
 124         * actual relocation.
 125         */
 126        n = kmalloc(sizeof *n, GFP_KERNEL);
 127        if (!n)
 128                return -ENOMEM;
 129
 130        n->addr = (Elf_Addr *)location;
 131        n->value = v;
 132        n->next = mips_hi16_list;
 133        mips_hi16_list = n;
 134
 135        return 0;
 136}
 137
 138static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v)
 139{
 140        *location = (*location & 0xffff0000) |
 141                    ((((long long) v + 0x8000LL) >> 16) & 0xffff);
 142
 143        return 0;
 144}
 145
 146static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
 147{
 148        unsigned long insnlo = *location;
 149        Elf_Addr val, vallo;
 150
 151        /* Sign extend the addend we extract from the lo insn.  */
 152        vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
 153
 154        if (mips_hi16_list != NULL) {
 155                struct mips_hi16 *l;
 156
 157                l = mips_hi16_list;
 158                while (l != NULL) {
 159                        struct mips_hi16 *next;
 160                        unsigned long insn;
 161
 162                        /*
 163                         * The value for the HI16 had best be the same.
 164                         */
 165                        if (v != l->value)
 166                                goto out_danger;
 167
 168                        /*
 169                         * Do the HI16 relocation.  Note that we actually don't
 170                         * need to know anything about the LO16 itself, except
 171                         * where to find the low 16 bits of the addend needed
 172                         * by the LO16.
 173                         */
 174                        insn = *l->addr;
 175                        val = ((insn & 0xffff) << 16) + vallo;
 176                        val += v;
 177
 178                        /*
 179                         * Account for the sign extension that will happen in
 180                         * the low bits.
 181                         */
 182                        val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff;
 183
 184                        insn = (insn & ~0xffff) | val;
 185                        *l->addr = insn;
 186
 187                        next = l->next;
 188                        kfree(l);
 189                        l = next;
 190                }
 191
 192                mips_hi16_list = NULL;
 193        }
 194
 195        /*
 196         * Ok, we're done with the HI16 relocs.  Now deal with the LO16.
 197         */
 198        val = v + vallo;
 199        insnlo = (insnlo & ~0xffff) | (val & 0xffff);
 200        *location = insnlo;
 201
 202        return 0;
 203
 204out_danger:
 205        pr_err("module %s: dangerous R_MIPS_LO16 REL relocation\n", me->name);
 206
 207        return -ENOEXEC;
 208}
 209
 210static int apply_r_mips_lo16_rela(struct module *me, u32 *location, Elf_Addr v)
 211{
 212        *location = (*location & 0xffff0000) | (v & 0xffff);
 213
 214        return 0;
 215}
 216
 217static int apply_r_mips_64_rela(struct module *me, u32 *location, Elf_Addr v)
 218{
 219        *(Elf_Addr *)location = v;
 220
 221        return 0;
 222}
 223
 224static int apply_r_mips_higher_rela(struct module *me, u32 *location,
 225                                    Elf_Addr v)
 226{
 227        *location = (*location & 0xffff0000) |
 228                    ((((long long) v + 0x80008000LL) >> 32) & 0xffff);
 229
 230        return 0;
 231}
 232
 233static int apply_r_mips_highest_rela(struct module *me, u32 *location,
 234                                     Elf_Addr v)
 235{
 236        *location = (*location & 0xffff0000) |
 237                    ((((long long) v + 0x800080008000LL) >> 48) & 0xffff);
 238
 239        return 0;
 240}
 241
 242static int (*reloc_handlers_rel[]) (struct module *me, u32 *location,
 243                                Elf_Addr v) = {
 244        [R_MIPS_NONE]           = apply_r_mips_none,
 245        [R_MIPS_32]             = apply_r_mips_32_rel,
 246        [R_MIPS_26]             = apply_r_mips_26_rel,
 247        [R_MIPS_HI16]           = apply_r_mips_hi16_rel,
 248        [R_MIPS_LO16]           = apply_r_mips_lo16_rel
 249};
 250
 251static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
 252                                Elf_Addr v) = {
 253        [R_MIPS_NONE]           = apply_r_mips_none,
 254        [R_MIPS_32]             = apply_r_mips_32_rela,
 255        [R_MIPS_26]             = apply_r_mips_26_rela,
 256        [R_MIPS_HI16]           = apply_r_mips_hi16_rela,
 257        [R_MIPS_LO16]           = apply_r_mips_lo16_rela,
 258        [R_MIPS_64]             = apply_r_mips_64_rela,
 259        [R_MIPS_HIGHER]         = apply_r_mips_higher_rela,
 260        [R_MIPS_HIGHEST]        = apply_r_mips_highest_rela
 261};
 262
 263int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
 264                   unsigned int symindex, unsigned int relsec,
 265                   struct module *me)
 266{
 267        Elf_Mips_Rel *rel = (void *) sechdrs[relsec].sh_addr;
 268        Elf_Sym *sym;
 269        u32 *location;
 270        unsigned int i;
 271        Elf_Addr v;
 272        int res;
 273
 274        pr_debug("Applying relocate section %u to %u\n", relsec,
 275               sechdrs[relsec].sh_info);
 276
 277        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
 278                /* This is where to make the change */
 279                location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
 280                        + rel[i].r_offset;
 281                /* This is the symbol it is referring to */
 282                sym = (Elf_Sym *)sechdrs[symindex].sh_addr
 283                        + ELF_MIPS_R_SYM(rel[i]);
 284                if (IS_ERR_VALUE(sym->st_value)) {
 285                        /* Ignore unresolved weak symbol */
 286                        if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
 287                                continue;
 288                        printk(KERN_WARNING "%s: Unknown symbol %s\n",
 289                               me->name, strtab + sym->st_name);
 290                        return -ENOENT;
 291                }
 292
 293                v = sym->st_value;
 294
 295                res = reloc_handlers_rel[ELF_MIPS_R_TYPE(rel[i])](me, location, v);
 296                if (res)
 297                        return res;
 298        }
 299
 300        return 0;
 301}
 302
 303int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
 304                       unsigned int symindex, unsigned int relsec,
 305                       struct module *me)
 306{
 307        Elf_Mips_Rela *rel = (void *) sechdrs[relsec].sh_addr;
 308        Elf_Sym *sym;
 309        u32 *location;
 310        unsigned int i;
 311        Elf_Addr v;
 312        int res;
 313
 314        pr_debug("Applying relocate section %u to %u\n", relsec,
 315               sechdrs[relsec].sh_info);
 316
 317        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
 318                /* This is where to make the change */
 319                location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
 320                        + rel[i].r_offset;
 321                /* This is the symbol it is referring to */
 322                sym = (Elf_Sym *)sechdrs[symindex].sh_addr
 323                        + ELF_MIPS_R_SYM(rel[i]);
 324                if (IS_ERR_VALUE(sym->st_value)) {
 325                        /* Ignore unresolved weak symbol */
 326                        if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
 327                                continue;
 328                        printk(KERN_WARNING "%s: Unknown symbol %s\n",
 329                               me->name, strtab + sym->st_name);
 330                        return -ENOENT;
 331                }
 332
 333                v = sym->st_value + rel[i].r_addend;
 334
 335                res = reloc_handlers_rela[ELF_MIPS_R_TYPE(rel[i])](me, location, v);
 336                if (res)
 337                        return res;
 338        }
 339
 340        return 0;
 341}
 342
 343/* Given an address, look for it in the module exception tables. */
 344const struct exception_table_entry *search_module_dbetables(unsigned long addr)
 345{
 346        unsigned long flags;
 347        const struct exception_table_entry *e = NULL;
 348        struct mod_arch_specific *dbe;
 349
 350        spin_lock_irqsave(&dbe_lock, flags);
 351        list_for_each_entry(dbe, &dbe_list, dbe_list) {
 352                e = search_extable(dbe->dbe_start, dbe->dbe_end - 1, addr);
 353                if (e)
 354                        break;
 355        }
 356        spin_unlock_irqrestore(&dbe_lock, flags);
 357
 358        /* Now, if we found one, we are running inside it now, hence
 359           we cannot unload the module, hence no refcnt needed. */
 360        return e;
 361}
 362
 363/* Put in dbe list if necessary. */
 364int module_finalize(const Elf_Ehdr *hdr,
 365                    const Elf_Shdr *sechdrs,
 366                    struct module *me)
 367{
 368        const Elf_Shdr *s;
 369        char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
 370
 371        /* Make jump label nops. */
 372        jump_label_apply_nops(me);
 373
 374        INIT_LIST_HEAD(&me->arch.dbe_list);
 375        for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
 376                if (strcmp("__dbe_table", secstrings + s->sh_name) != 0)
 377                        continue;
 378                me->arch.dbe_start = (void *)s->sh_addr;
 379                me->arch.dbe_end = (void *)s->sh_addr + s->sh_size;
 380                spin_lock_irq(&dbe_lock);
 381                list_add(&me->arch.dbe_list, &dbe_list);
 382                spin_unlock_irq(&dbe_lock);
 383        }
 384        return 0;
 385}
 386
 387void module_arch_cleanup(struct module *mod)
 388{
 389        spin_lock_irq(&dbe_lock);
 390        list_del(&mod->arch.dbe_list);
 391        spin_unlock_irq(&dbe_lock);
 392}
 393