linux/arch/blackfin/kernel/module.c
<<
>>
Prefs
   1/*
   2 * Copyright 2004-2009 Analog Devices Inc.
   3 *
   4 * Licensed under the GPL-2 or later
   5 */
   6
   7#define pr_fmt(fmt) "module %s: " fmt
   8
   9#include <linux/moduleloader.h>
  10#include <linux/elf.h>
  11#include <linux/vmalloc.h>
  12#include <linux/fs.h>
  13#include <linux/string.h>
  14#include <linux/kernel.h>
  15#include <asm/dma.h>
  16#include <asm/cacheflush.h>
  17#include <asm/uaccess.h>
  18
  19void *module_alloc(unsigned long size)
  20{
  21        if (size == 0)
  22                return NULL;
  23        return vmalloc(size);
  24}
  25
  26/* Free memory returned from module_alloc */
  27void module_free(struct module *mod, void *module_region)
  28{
  29        vfree(module_region);
  30}
  31
  32/* Transfer the section to the L1 memory */
  33int
  34module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
  35                          char *secstrings, struct module *mod)
  36{
  37        /*
  38         * XXX: sechdrs are vmalloced in kernel/module.c
  39         * and would be vfreed just after module is loaded,
  40         * so we hack to keep the only information we needed
  41         * in mod->arch to correctly free L1 I/D sram later.
  42         * NOTE: this breaks the semantic of mod->arch structure.
  43         */
  44        Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
  45        void *dest;
  46
  47        for (s = sechdrs; s < sechdrs_end; ++s) {
  48                const char *shname = secstrings + s->sh_name;
  49
  50                if (s->sh_size == 0)
  51                        continue;
  52
  53                if (!strcmp(".l1.text", shname) ||
  54                    (!strcmp(".text", shname) &&
  55                     (hdr->e_flags & EF_BFIN_CODE_IN_L1))) {
  56
  57                        dest = l1_inst_sram_alloc(s->sh_size);
  58                        mod->arch.text_l1 = dest;
  59                        if (dest == NULL) {
  60                                pr_err("L1 inst memory allocation failed\n",
  61                                        mod->name);
  62                                return -1;
  63                        }
  64                        dma_memcpy(dest, (void *)s->sh_addr, s->sh_size);
  65
  66                } else if (!strcmp(".l1.data", shname) ||
  67                           (!strcmp(".data", shname) &&
  68                            (hdr->e_flags & EF_BFIN_DATA_IN_L1))) {
  69
  70                        dest = l1_data_sram_alloc(s->sh_size);
  71                        mod->arch.data_a_l1 = dest;
  72                        if (dest == NULL) {
  73                                pr_err("L1 data memory allocation failed\n",
  74                                        mod->name);
  75                                return -1;
  76                        }
  77                        memcpy(dest, (void *)s->sh_addr, s->sh_size);
  78
  79                } else if (!strcmp(".l1.bss", shname) ||
  80                           (!strcmp(".bss", shname) &&
  81                            (hdr->e_flags & EF_BFIN_DATA_IN_L1))) {
  82
  83                        dest = l1_data_sram_zalloc(s->sh_size);
  84                        mod->arch.bss_a_l1 = dest;
  85                        if (dest == NULL) {
  86                                pr_err("L1 data memory allocation failed\n",
  87                                        mod->name);
  88                                return -1;
  89                        }
  90
  91                } else if (!strcmp(".l1.data.B", shname)) {
  92
  93                        dest = l1_data_B_sram_alloc(s->sh_size);
  94                        mod->arch.data_b_l1 = dest;
  95                        if (dest == NULL) {
  96                                pr_err("L1 data memory allocation failed\n",
  97                                        mod->name);
  98                                return -1;
  99                        }
 100                        memcpy(dest, (void *)s->sh_addr, s->sh_size);
 101
 102                } else if (!strcmp(".l1.bss.B", shname)) {
 103
 104                        dest = l1_data_B_sram_alloc(s->sh_size);
 105                        mod->arch.bss_b_l1 = dest;
 106                        if (dest == NULL) {
 107                                pr_err("L1 data memory allocation failed\n",
 108                                        mod->name);
 109                                return -1;
 110                        }
 111                        memset(dest, 0, s->sh_size);
 112
 113                } else if (!strcmp(".l2.text", shname) ||
 114                           (!strcmp(".text", shname) &&
 115                            (hdr->e_flags & EF_BFIN_CODE_IN_L2))) {
 116
 117                        dest = l2_sram_alloc(s->sh_size);
 118                        mod->arch.text_l2 = dest;
 119                        if (dest == NULL) {
 120                                pr_err("L2 SRAM allocation failed\n",
 121                                        mod->name);
 122                                return -1;
 123                        }
 124                        memcpy(dest, (void *)s->sh_addr, s->sh_size);
 125
 126                } else if (!strcmp(".l2.data", shname) ||
 127                           (!strcmp(".data", shname) &&
 128                            (hdr->e_flags & EF_BFIN_DATA_IN_L2))) {
 129
 130                        dest = l2_sram_alloc(s->sh_size);
 131                        mod->arch.data_l2 = dest;
 132                        if (dest == NULL) {
 133                                pr_err("L2 SRAM allocation failed\n",
 134                                        mod->name);
 135                                return -1;
 136                        }
 137                        memcpy(dest, (void *)s->sh_addr, s->sh_size);
 138
 139                } else if (!strcmp(".l2.bss", shname) ||
 140                           (!strcmp(".bss", shname) &&
 141                            (hdr->e_flags & EF_BFIN_DATA_IN_L2))) {
 142
 143                        dest = l2_sram_zalloc(s->sh_size);
 144                        mod->arch.bss_l2 = dest;
 145                        if (dest == NULL) {
 146                                pr_err("L2 SRAM allocation failed\n",
 147                                        mod->name);
 148                                return -1;
 149                        }
 150
 151                } else
 152                        continue;
 153
 154                s->sh_flags &= ~SHF_ALLOC;
 155                s->sh_addr = (unsigned long)dest;
 156        }
 157
 158        return 0;
 159}
 160
 161int
 162apply_relocate(Elf_Shdr * sechdrs, const char *strtab,
 163               unsigned int symindex, unsigned int relsec, struct module *me)
 164{
 165        pr_err(".rel unsupported\n", me->name);
 166        return -ENOEXEC;
 167}
 168
 169/*************************************************************************/
 170/* FUNCTION : apply_relocate_add                                         */
 171/* ABSTRACT : Blackfin specific relocation handling for the loadable     */
 172/*            modules. Modules are expected to be .o files.              */
 173/*            Arithmetic relocations are handled.                        */
 174/*            We do not expect LSETUP to be split and hence is not       */
 175/*            handled.                                                   */
 176/*            R_BFIN_BYTE and R_BFIN_BYTE2 are also not handled as the   */
 177/*            gas does not generate it.                                  */
 178/*************************************************************************/
 179int
 180apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
 181                   unsigned int symindex, unsigned int relsec,
 182                   struct module *mod)
 183{
 184        unsigned int i;
 185        Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
 186        Elf32_Sym *sym;
 187        unsigned long location, value, size;
 188
 189        pr_debug("applying relocate section %u to %u\n", mod->name,
 190                relsec, sechdrs[relsec].sh_info);
 191
 192        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
 193                /* This is where to make the change */
 194                location = sechdrs[sechdrs[relsec].sh_info].sh_addr +
 195                           rel[i].r_offset;
 196
 197                /* This is the symbol it is referring to. Note that all
 198                   undefined symbols have been resolved. */
 199                sym = (Elf32_Sym *) sechdrs[symindex].sh_addr
 200                    + ELF32_R_SYM(rel[i].r_info);
 201                value = sym->st_value;
 202                value += rel[i].r_addend;
 203
 204#ifdef CONFIG_SMP
 205                if (location >= COREB_L1_DATA_A_START) {
 206                        pr_err("cannot relocate in L1: %u (SMP kernel)",
 207                                mod->name, ELF32_R_TYPE(rel[i].r_info));
 208                        return -ENOEXEC;
 209                }
 210#endif
 211
 212                pr_debug("location is %lx, value is %lx type is %d\n",
 213                        mod->name, location, value, ELF32_R_TYPE(rel[i].r_info));
 214
 215                switch (ELF32_R_TYPE(rel[i].r_info)) {
 216
 217                case R_BFIN_HUIMM16:
 218                        value >>= 16;
 219                case R_BFIN_LUIMM16:
 220                case R_BFIN_RIMM16:
 221                        size = 2;
 222                        break;
 223                case R_BFIN_BYTE4_DATA:
 224                        size = 4;
 225                        break;
 226
 227                case R_BFIN_PCREL24:
 228                case R_BFIN_PCREL24_JUMP_L:
 229                case R_BFIN_PCREL12_JUMP:
 230                case R_BFIN_PCREL12_JUMP_S:
 231                case R_BFIN_PCREL10:
 232                        pr_err("unsupported relocation: %u (no -mlong-calls?)\n",
 233                                mod->name, ELF32_R_TYPE(rel[i].r_info));
 234                        return -ENOEXEC;
 235
 236                default:
 237                        pr_err("unknown relocation: %u\n", mod->name,
 238                                ELF32_R_TYPE(rel[i].r_info));
 239                        return -ENOEXEC;
 240                }
 241
 242                switch (bfin_mem_access_type(location, size)) {
 243                case BFIN_MEM_ACCESS_CORE:
 244                case BFIN_MEM_ACCESS_CORE_ONLY:
 245                        memcpy((void *)location, &value, size);
 246                        break;
 247                case BFIN_MEM_ACCESS_DMA:
 248                        dma_memcpy((void *)location, &value, size);
 249                        break;
 250                case BFIN_MEM_ACCESS_ITEST:
 251                        isram_memcpy((void *)location, &value, size);
 252                        break;
 253                default:
 254                        pr_err("invalid relocation for %#lx\n",
 255                                mod->name, location);
 256                        return -ENOEXEC;
 257                }
 258        }
 259
 260        return 0;
 261}
 262
 263int
 264module_finalize(const Elf_Ehdr * hdr,
 265                const Elf_Shdr * sechdrs, struct module *mod)
 266{
 267        unsigned int i, strindex = 0, symindex = 0;
 268        char *secstrings;
 269        long err = 0;
 270
 271        secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
 272
 273        for (i = 1; i < hdr->e_shnum; i++) {
 274                /* Internal symbols and strings. */
 275                if (sechdrs[i].sh_type == SHT_SYMTAB) {
 276                        symindex = i;
 277                        strindex = sechdrs[i].sh_link;
 278                }
 279        }
 280
 281        for (i = 1; i < hdr->e_shnum; i++) {
 282                const char *strtab = (char *)sechdrs[strindex].sh_addr;
 283                unsigned int info = sechdrs[i].sh_info;
 284                const char *shname = secstrings + sechdrs[i].sh_name;
 285
 286                /* Not a valid relocation section? */
 287                if (info >= hdr->e_shnum)
 288                        continue;
 289
 290                /* Only support RELA relocation types */
 291                if (sechdrs[i].sh_type != SHT_RELA)
 292                        continue;
 293
 294                if (!strcmp(".rela.l2.text", shname) ||
 295                    !strcmp(".rela.l1.text", shname) ||
 296                    (!strcmp(".rela.text", shname) &&
 297                         (hdr->e_flags & (EF_BFIN_CODE_IN_L1 | EF_BFIN_CODE_IN_L2)))) {
 298
 299                        err = apply_relocate_add((Elf_Shdr *) sechdrs, strtab,
 300                                           symindex, i, mod);
 301                        if (err < 0)
 302                                return -ENOEXEC;
 303                }
 304        }
 305
 306        return 0;
 307}
 308
 309void module_arch_cleanup(struct module *mod)
 310{
 311        l1_inst_sram_free(mod->arch.text_l1);
 312        l1_data_A_sram_free(mod->arch.data_a_l1);
 313        l1_data_A_sram_free(mod->arch.bss_a_l1);
 314        l1_data_B_sram_free(mod->arch.data_b_l1);
 315        l1_data_B_sram_free(mod->arch.bss_b_l1);
 316        l2_sram_free(mod->arch.text_l2);
 317        l2_sram_free(mod->arch.data_l2);
 318        l2_sram_free(mod->arch.bss_l2);
 319}
 320
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.