linux/arch/arm/kernel/module.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/kernel/module.c
   3 *
   4 *  Copyright (C) 2002 Russell King.
   5 *  Modified for nommu by Hyok S. Choi
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * Module allocation method suggested by Andi Kleen.
  12 */
  13#include <linux/module.h>
  14#include <linux/moduleloader.h>
  15#include <linux/kernel.h>
  16#include <linux/mm.h>
  17#include <linux/elf.h>
  18#include <linux/vmalloc.h>
  19#include <linux/slab.h>
  20#include <linux/fs.h>
  21#include <linux/string.h>
  22
  23#include <asm/pgtable.h>
  24#include <asm/sections.h>
  25#include <asm/unwind.h>
  26
  27#ifdef CONFIG_XIP_KERNEL
  28/*
  29 * The XIP kernel text is mapped in the module area for modules and
  30 * some other stuff to work without any indirect relocations.
  31 * MODULES_VADDR is redefined here and not in asm/memory.h to avoid
  32 * recompiling the whole kernel when CONFIG_XIP_KERNEL is turned on/off.
  33 */
  34#undef MODULES_VADDR
  35#define MODULES_VADDR   (((unsigned long)_etext + ~PGDIR_MASK) & PGDIR_MASK)
  36#endif
  37
  38#ifdef CONFIG_MMU
  39void *module_alloc(unsigned long size)
  40{
  41        struct vm_struct *area;
  42
  43        size = PAGE_ALIGN(size);
  44        if (!size)
  45                return NULL;
  46
  47        area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
  48        if (!area)
  49                return NULL;
  50
  51        return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC);
  52}
  53#else /* CONFIG_MMU */
  54void *module_alloc(unsigned long size)
  55{
  56        return size == 0 ? NULL : vmalloc(size);
  57}
  58#endif /* !CONFIG_MMU */
  59
  60void module_free(struct module *module, void *region)
  61{
  62        vfree(region);
  63}
  64
  65int module_frob_arch_sections(Elf_Ehdr *hdr,
  66                              Elf_Shdr *sechdrs,
  67                              char *secstrings,
  68                              struct module *mod)
  69{
  70#ifdef CONFIG_ARM_UNWIND
  71        Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
  72
  73        for (s = sechdrs; s < sechdrs_end; s++) {
  74                if (strcmp(".ARM.exidx.init.text", secstrings + s->sh_name) == 0)
  75                        mod->arch.unw_sec_init = s;
  76                else if (strcmp(".ARM.exidx.devinit.text", secstrings + s->sh_name) == 0)
  77                        mod->arch.unw_sec_devinit = s;
  78                else if (strcmp(".ARM.exidx", secstrings + s->sh_name) == 0)
  79                        mod->arch.unw_sec_core = s;
  80                else if (strcmp(".init.text", secstrings + s->sh_name) == 0)
  81                        mod->arch.sec_init_text = s;
  82                else if (strcmp(".devinit.text", secstrings + s->sh_name) == 0)
  83                        mod->arch.sec_devinit_text = s;
  84                else if (strcmp(".text", secstrings + s->sh_name) == 0)
  85                        mod->arch.sec_core_text = s;
  86        }
  87#endif
  88        return 0;
  89}
  90
  91int
  92apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
  93               unsigned int relindex, struct module *module)
  94{
  95        Elf32_Shdr *symsec = sechdrs + symindex;
  96        Elf32_Shdr *relsec = sechdrs + relindex;
  97        Elf32_Shdr *dstsec = sechdrs + relsec->sh_info;
  98        Elf32_Rel *rel = (void *)relsec->sh_addr;
  99        unsigned int i;
 100
 101        for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) {
 102                unsigned long loc;
 103                Elf32_Sym *sym;
 104                s32 offset;
 105                u32 upper, lower, sign, j1, j2;
 106
 107                offset = ELF32_R_SYM(rel->r_info);
 108                if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) {
 109                        printk(KERN_ERR "%s: bad relocation, section %d reloc %d\n",
 110                                module->name, relindex, i);
 111                        return -ENOEXEC;
 112                }
 113
 114                sym = ((Elf32_Sym *)symsec->sh_addr) + offset;
 115
 116                if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) {
 117                        printk(KERN_ERR "%s: out of bounds relocation, "
 118                                "section %d reloc %d offset %d size %d\n",
 119                                module->name, relindex, i, rel->r_offset,
 120                                dstsec->sh_size);
 121                        return -ENOEXEC;
 122                }
 123
 124                loc = dstsec->sh_addr + rel->r_offset;
 125
 126                switch (ELF32_R_TYPE(rel->r_info)) {
 127                case R_ARM_NONE:
 128                        /* ignore */
 129                        break;
 130
 131                case R_ARM_ABS32:
 132                        *(u32 *)loc += sym->st_value;
 133                        break;
 134
 135                case R_ARM_PC24:
 136                case R_ARM_CALL:
 137                case R_ARM_JUMP24:
 138                        offset = (*(u32 *)loc & 0x00ffffff) << 2;
 139                        if (offset & 0x02000000)
 140                                offset -= 0x04000000;
 141
 142                        offset += sym->st_value - loc;
 143                        if (offset & 3 ||
 144                            offset <= (s32)0xfe000000 ||
 145                            offset >= (s32)0x02000000) {
 146                                printk(KERN_ERR
 147                                       "%s: relocation out of range, section "
 148                                       "%d reloc %d sym '%s'\n", module->name,
 149                                       relindex, i, strtab + sym->st_name);
 150                                return -ENOEXEC;
 151                        }
 152
 153                        offset >>= 2;
 154
 155                        *(u32 *)loc &= 0xff000000;
 156                        *(u32 *)loc |= offset & 0x00ffffff;
 157                        break;
 158
 159               case R_ARM_V4BX:
 160                       /* Preserve Rm and the condition code. Alter
 161                        * other bits to re-code instruction as
 162                        * MOV PC,Rm.
 163                        */
 164                       *(u32 *)loc &= 0xf000000f;
 165                       *(u32 *)loc |= 0x01a0f000;
 166                       break;
 167
 168                case R_ARM_PREL31:
 169                        offset = *(u32 *)loc + sym->st_value - loc;
 170                        *(u32 *)loc = offset & 0x7fffffff;
 171                        break;
 172
 173                case R_ARM_MOVW_ABS_NC:
 174                case R_ARM_MOVT_ABS:
 175                        offset = *(u32 *)loc;
 176                        offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff);
 177                        offset = (offset ^ 0x8000) - 0x8000;
 178
 179                        offset += sym->st_value;
 180                        if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_ABS)
 181                                offset >>= 16;
 182
 183                        *(u32 *)loc &= 0xfff0f000;
 184                        *(u32 *)loc |= ((offset & 0xf000) << 4) |
 185                                        (offset & 0x0fff);
 186                        break;
 187
 188                case R_ARM_THM_CALL:
 189                case R_ARM_THM_JUMP24:
 190                        upper = *(u16 *)loc;
 191                        lower = *(u16 *)(loc + 2);
 192
 193                        /*
 194                         * 25 bit signed address range (Thumb-2 BL and B.W
 195                         * instructions):
 196                         *   S:I1:I2:imm10:imm11:0
 197                         * where:
 198                         *   S     = upper[10]   = offset[24]
 199                         *   I1    = ~(J1 ^ S)   = offset[23]
 200                         *   I2    = ~(J2 ^ S)   = offset[22]
 201                         *   imm10 = upper[9:0]  = offset[21:12]
 202                         *   imm11 = lower[10:0] = offset[11:1]
 203                         *   J1    = lower[13]
 204                         *   J2    = lower[11]
 205                         */
 206                        sign = (upper >> 10) & 1;
 207                        j1 = (lower >> 13) & 1;
 208                        j2 = (lower >> 11) & 1;
 209                        offset = (sign << 24) | ((~(j1 ^ sign) & 1) << 23) |
 210                                ((~(j2 ^ sign) & 1) << 22) |
 211                                ((upper & 0x03ff) << 12) |
 212                                ((lower & 0x07ff) << 1);
 213                        if (offset & 0x01000000)
 214                                offset -= 0x02000000;
 215                        offset += sym->st_value - loc;
 216
 217                        /* only Thumb addresses allowed (no interworking) */
 218                        if (!(offset & 1) ||
 219                            offset <= (s32)0xff000000 ||
 220                            offset >= (s32)0x01000000) {
 221                                printk(KERN_ERR
 222                                       "%s: relocation out of range, section "
 223                                       "%d reloc %d sym '%s'\n", module->name,
 224                                       relindex, i, strtab + sym->st_name);
 225                                return -ENOEXEC;
 226                        }
 227
 228                        sign = (offset >> 24) & 1;
 229                        j1 = sign ^ (~(offset >> 23) & 1);
 230                        j2 = sign ^ (~(offset >> 22) & 1);
 231                        *(u16 *)loc = (u16)((upper & 0xf800) | (sign << 10) |
 232                                            ((offset >> 12) & 0x03ff));
 233                        *(u16 *)(loc + 2) = (u16)((lower & 0xd000) |
 234                                                  (j1 << 13) | (j2 << 11) |
 235                                                  ((offset >> 1) & 0x07ff));
 236                        upper = *(u16 *)loc;
 237                        lower = *(u16 *)(loc + 2);
 238                        break;
 239
 240                default:
 241                        printk(KERN_ERR "%s: unknown relocation: %u\n",
 242                               module->name, ELF32_R_TYPE(rel->r_info));
 243                        return -ENOEXEC;
 244                }
 245        }
 246        return 0;
 247}
 248
 249int
 250apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
 251                   unsigned int symindex, unsigned int relsec, struct module *module)
 252{
 253        printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
 254               module->name);
 255        return -ENOEXEC;
 256}
 257
 258#ifdef CONFIG_ARM_UNWIND
 259static void register_unwind_tables(struct module *mod)
 260{
 261        if (mod->arch.unw_sec_init && mod->arch.sec_init_text)
 262                mod->arch.unwind_init =
 263                        unwind_table_add(mod->arch.unw_sec_init->sh_addr,
 264                                         mod->arch.unw_sec_init->sh_size,
 265                                         mod->arch.sec_init_text->sh_addr,
 266                                         mod->arch.sec_init_text->sh_size);
 267        if (mod->arch.unw_sec_devinit && mod->arch.sec_devinit_text)
 268                mod->arch.unwind_devinit =
 269                        unwind_table_add(mod->arch.unw_sec_devinit->sh_addr,
 270                                         mod->arch.unw_sec_devinit->sh_size,
 271                                         mod->arch.sec_devinit_text->sh_addr,
 272                                         mod->arch.sec_devinit_text->sh_size);
 273        if (mod->arch.unw_sec_core && mod->arch.sec_core_text)
 274                mod->arch.unwind_core =
 275                        unwind_table_add(mod->arch.unw_sec_core->sh_addr,
 276                                         mod->arch.unw_sec_core->sh_size,
 277                                         mod->arch.sec_core_text->sh_addr,
 278                                         mod->arch.sec_core_text->sh_size);
 279}
 280
 281static void unregister_unwind_tables(struct module *mod)
 282{
 283        unwind_table_del(mod->arch.unwind_init);
 284        unwind_table_del(mod->arch.unwind_devinit);
 285        unwind_table_del(mod->arch.unwind_core);
 286}
 287#else
 288static inline void register_unwind_tables(struct module *mod) { }
 289static inline void unregister_unwind_tables(struct module *mod) { }
 290#endif
 291
 292int
 293module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
 294                struct module *module)
 295{
 296        register_unwind_tables(module);
 297        return 0;
 298}
 299
 300void
 301module_arch_cleanup(struct module *mod)
 302{
 303        unregister_unwind_tables(mod);
 304}
 305
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.