linux/arch/xtensa/kernel/module.c
<<
>>
Prefs
   1/*
   2 * arch/xtensa/kernel/module.c
   3 *
   4 * Module support.
   5 *
   6 * This file is subject to the terms and conditions of the GNU General Public
   7 * License.  See the file "COPYING" in the main directory of this archive
   8 * for more details.
   9 *
  10 * Copyright (C) 2001 - 2006 Tensilica Inc.
  11 *
  12 * Chris Zankel <chris@zankel.net>
  13 *
  14 */
  15
  16#include <linux/module.h>
  17#include <linux/moduleloader.h>
  18#include <linux/elf.h>
  19#include <linux/vmalloc.h>
  20#include <linux/fs.h>
  21#include <linux/string.h>
  22#include <linux/kernel.h>
  23#include <linux/cache.h>
  24
  25static int
  26decode_calln_opcode (unsigned char *location)
  27{
  28#ifdef __XTENSA_EB__
  29        return (location[0] & 0xf0) == 0x50;
  30#endif
  31#ifdef __XTENSA_EL__
  32        return (location[0] & 0xf) == 0x5;
  33#endif
  34}
  35
  36static int
  37decode_l32r_opcode (unsigned char *location)
  38{
  39#ifdef __XTENSA_EB__
  40        return (location[0] & 0xf0) == 0x10;
  41#endif
  42#ifdef __XTENSA_EL__
  43        return (location[0] & 0xf) == 0x1;
  44#endif
  45}
  46
  47int apply_relocate_add(Elf32_Shdr *sechdrs,
  48                       const char *strtab,
  49                       unsigned int symindex,
  50                       unsigned int relsec,
  51                       struct module *mod)
  52{
  53        unsigned int i;
  54        Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
  55        Elf32_Sym *sym;
  56        unsigned char *location;
  57        uint32_t value;
  58
  59        pr_debug("Applying relocate section %u to %u\n", relsec,
  60                 sechdrs[relsec].sh_info);
  61
  62        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
  63                location = (char *)sechdrs[sechdrs[relsec].sh_info].sh_addr
  64                        + rela[i].r_offset;
  65                sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
  66                        + ELF32_R_SYM(rela[i].r_info);
  67                value = sym->st_value + rela[i].r_addend;
  68
  69                switch (ELF32_R_TYPE(rela[i].r_info)) {
  70                case R_XTENSA_NONE:
  71                case R_XTENSA_DIFF8:
  72                case R_XTENSA_DIFF16:
  73                case R_XTENSA_DIFF32:
  74                case R_XTENSA_ASM_EXPAND:
  75                        break;
  76
  77                case R_XTENSA_32:
  78                case R_XTENSA_PLT:
  79                        *(uint32_t *)location += value;
  80                        break;
  81
  82                case R_XTENSA_SLOT0_OP:
  83                        if (decode_calln_opcode(location)) {
  84                                value -= ((unsigned long)location & -4) + 4;
  85                                if ((value & 3) != 0 ||
  86                                    ((value + (1 << 19)) >> 20) != 0) {
  87                                        pr_err("%s: relocation out of range, "
  88                                               "section %d reloc %d "
  89                                               "sym '%s'\n",
  90                                               mod->name, relsec, i,
  91                                               strtab + sym->st_name);
  92                                        return -ENOEXEC;
  93                                }
  94                                value = (signed int)value >> 2;
  95#ifdef __XTENSA_EB__
  96                                location[0] = ((location[0] & ~0x3) |
  97                                            ((value >> 16) & 0x3));
  98                                location[1] = (value >> 8) & 0xff;
  99                                location[2] = value & 0xff;
 100#endif
 101#ifdef __XTENSA_EL__
 102                                location[0] = ((location[0] & ~0xc0) |
 103                                            ((value << 6) & 0xc0));
 104                                location[1] = (value >> 2) & 0xff;
 105                                location[2] = (value >> 10) & 0xff;
 106#endif
 107                        } else if (decode_l32r_opcode(location)) {
 108                                value -= (((unsigned long)location + 3) & -4);
 109                                if ((value & 3) != 0 ||
 110                                    (signed int)value >> 18 != -1) {
 111                                        pr_err("%s: relocation out of range, "
 112                                               "section %d reloc %d "
 113                                               "sym '%s'\n",
 114                                               mod->name, relsec, i,
 115                                               strtab + sym->st_name);
 116                                        return -ENOEXEC;
 117                                }
 118                                value = (signed int)value >> 2;
 119
 120#ifdef __XTENSA_EB__
 121                                location[1] = (value >> 8) & 0xff;
 122                                location[2] = value & 0xff;
 123#endif
 124#ifdef __XTENSA_EL__
 125                                location[1] = value & 0xff;
 126                                location[2] = (value >> 8) & 0xff;
 127#endif
 128                        }
 129                        /* FIXME: Ignore any other opcodes.  The Xtensa
 130                           assembler currently assumes that the linker will
 131                           always do relaxation and so all PC-relative
 132                           operands need relocations.  (The assembler also
 133                           writes out the tentative PC-relative values,
 134                           assuming no link-time relaxation, so it is usually
 135                           safe to ignore the relocations.)  If the
 136                           assembler's "--no-link-relax" flag can be made to
 137                           work, and if all kernel modules can be assembled
 138                           with that flag, then unexpected relocations could
 139                           be detected here.  */
 140                        break;
 141
 142                case R_XTENSA_SLOT1_OP:
 143                case R_XTENSA_SLOT2_OP:
 144                case R_XTENSA_SLOT3_OP:
 145                case R_XTENSA_SLOT4_OP:
 146                case R_XTENSA_SLOT5_OP:
 147                case R_XTENSA_SLOT6_OP:
 148                case R_XTENSA_SLOT7_OP:
 149                case R_XTENSA_SLOT8_OP:
 150                case R_XTENSA_SLOT9_OP:
 151                case R_XTENSA_SLOT10_OP:
 152                case R_XTENSA_SLOT11_OP:
 153                case R_XTENSA_SLOT12_OP:
 154                case R_XTENSA_SLOT13_OP:
 155                case R_XTENSA_SLOT14_OP:
 156                        pr_err("%s: unexpected FLIX relocation: %u\n",
 157                               mod->name,
 158                               ELF32_R_TYPE(rela[i].r_info));
 159                        return -ENOEXEC;
 160
 161                case R_XTENSA_SLOT0_ALT:
 162                case R_XTENSA_SLOT1_ALT:
 163                case R_XTENSA_SLOT2_ALT:
 164                case R_XTENSA_SLOT3_ALT:
 165                case R_XTENSA_SLOT4_ALT:
 166                case R_XTENSA_SLOT5_ALT:
 167                case R_XTENSA_SLOT6_ALT:
 168                case R_XTENSA_SLOT7_ALT:
 169                case R_XTENSA_SLOT8_ALT:
 170                case R_XTENSA_SLOT9_ALT:
 171                case R_XTENSA_SLOT10_ALT:
 172                case R_XTENSA_SLOT11_ALT:
 173                case R_XTENSA_SLOT12_ALT:
 174                case R_XTENSA_SLOT13_ALT:
 175                case R_XTENSA_SLOT14_ALT:
 176                        pr_err("%s: unexpected ALT relocation: %u\n",
 177                               mod->name,
 178                               ELF32_R_TYPE(rela[i].r_info));
 179                        return -ENOEXEC;
 180
 181                default:
 182                        pr_err("%s: unexpected relocation: %u\n",
 183                               mod->name,
 184                               ELF32_R_TYPE(rela[i].r_info));
 185                        return -ENOEXEC;
 186                }
 187        }
 188        return 0;
 189}
 190