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