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