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/fs.h> 20 #include <linux/string.h> 21 #include <linux/gfp.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 39 void *module_alloc(unsigned long size) 40 { 41 return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, 42 GFP_KERNEL, PAGE_KERNEL_EXEC, -1, 43 __builtin_return_address(0)); 44 } 45 #else /* CONFIG_MMU */ 46 void *module_alloc(unsigned long size) 47 { 48 return size == 0 ? NULL : vmalloc(size); 49 } 50 #endif /* !CONFIG_MMU */ 51 52 void module_free(struct module *module, void *region) 53 { 54 vfree(region); 55 } 56 57 int module_frob_arch_sections(Elf_Ehdr *hdr, 58 Elf_Shdr *sechdrs, 59 char *secstrings, 60 struct module *mod) 61 { 62 return 0; 63 } 64 65 int 66 apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, 67 unsigned int relindex, struct module *module) 68 { 69 Elf32_Shdr *symsec = sechdrs + symindex; 70 Elf32_Shdr *relsec = sechdrs + relindex; 71 Elf32_Shdr *dstsec = sechdrs + relsec->sh_info; 72 Elf32_Rel *rel = (void *)relsec->sh_addr; 73 unsigned int i; 74 75 for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) { 76 unsigned long loc; 77 Elf32_Sym *sym; 78 s32 offset; 79 #ifdef CONFIG_THUMB2_KERNEL 80 u32 upper, lower, sign, j1, j2; 81 #endif 82 83 offset = ELF32_R_SYM(rel->r_info); 84 if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) { 85 printk(KERN_ERR "%s: bad relocation, section %d reloc %d\n", 86 module->name, relindex, i); 87 return -ENOEXEC; 88 } 89 90 sym = ((Elf32_Sym *)symsec->sh_addr) + offset; 91 92 if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) { 93 printk(KERN_ERR "%s: out of bounds relocation, " 94 "section %d reloc %d offset %d size %d\n", 95 module->name, relindex, i, rel->r_offset, 96 dstsec->sh_size); 97 return -ENOEXEC; 98 } 99 100 loc = dstsec->sh_addr + rel->r_offset; 101 102 switch (ELF32_R_TYPE(rel->r_info)) { 103 case R_ARM_NONE: 104 /* ignore */ 105 break; 106 107 case R_ARM_ABS32: 108 *(u32 *)loc += sym->st_value; 109 break; 110 111 case R_ARM_PC24: 112 case R_ARM_CALL: 113 case R_ARM_JUMP24: 114 offset = (*(u32 *)loc & 0x00ffffff) << 2; 115 if (offset & 0x02000000) 116 offset -= 0x04000000; 117 118 offset += sym->st_value - loc; 119 if (offset & 3 || 120 offset <= (s32)0xfe000000 || 121 offset >= (s32)0x02000000) { 122 printk(KERN_ERR 123 "%s: relocation out of range, section " 124 "%d reloc %d sym '%s'\n", module->name, 125 relindex, i, strtab + sym->st_name); 126 return -ENOEXEC; 127 } 128 129 offset >>= 2; 130 131 *(u32 *)loc &= 0xff000000; 132 *(u32 *)loc |= offset & 0x00ffffff; 133 break; 134 135 case R_ARM_V4BX: 136 /* Preserve Rm and the condition code. Alter 137 * other bits to re-code instruction as 138 * MOV PC,Rm. 139 */ 140 *(u32 *)loc &= 0xf000000f; 141 *(u32 *)loc |= 0x01a0f000; 142 break; 143 144 case R_ARM_PREL31: 145 offset = *(u32 *)loc + sym->st_value - loc; 146 *(u32 *)loc = offset & 0x7fffffff; 147 break; 148 149 case R_ARM_MOVW_ABS_NC: 150 case R_ARM_MOVT_ABS: 151 offset = *(u32 *)loc; 152 offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff); 153 offset = (offset ^ 0x8000) - 0x8000; 154 155 offset += sym->st_value; 156 if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_ABS) 157 offset >>= 16; 158 159 *(u32 *)loc &= 0xfff0f000; 160 *(u32 *)loc |= ((offset & 0xf000) << 4) | 161 (offset & 0x0fff); 162 break; 163 164 #ifdef CONFIG_THUMB2_KERNEL 165 case R_ARM_THM_CALL: 166 case R_ARM_THM_JUMP24: 167 upper = *(u16 *)loc; 168 lower = *(u16 *)(loc + 2); 169 170 /* 171 * 25 bit signed address range (Thumb-2 BL and B.W 172 * instructions): 173 * S:I1:I2:imm10:imm11:0 174 * where: 175 * S = upper[10] = offset[24] 176 * I1 = ~(J1 ^ S) = offset[23] 177 * I2 = ~(J2 ^ S) = offset[22] 178 * imm10 = upper[9:0] = offset[21:12] 179 * imm11 = lower[10:0] = offset[11:1] 180 * J1 = lower[13] 181 * J2 = lower[11] 182 */ 183 sign = (upper >> 10) & 1; 184 j1 = (lower >> 13) & 1; 185 j2 = (lower >> 11) & 1; 186 offset = (sign << 24) | ((~(j1 ^ sign) & 1) << 23) | 187 ((~(j2 ^ sign) & 1) << 22) | 188 ((upper & 0x03ff) << 12) | 189 ((lower & 0x07ff) << 1); 190 if (offset & 0x01000000) 191 offset -= 0x02000000; 192 offset += sym->st_value - loc; 193 194 /* only Thumb addresses allowed (no interworking) */ 195 if (!(offset & 1) || 196 offset <= (s32)0xff000000 || 197 offset >= (s32)0x01000000) { 198 printk(KERN_ERR 199 "%s: relocation out of range, section " 200 "%d reloc %d sym '%s'\n", module->name, 201 relindex, i, strtab + sym->st_name); 202 return -ENOEXEC; 203 } 204 205 sign = (offset >> 24) & 1; 206 j1 = sign ^ (~(offset >> 23) & 1); 207 j2 = sign ^ (~(offset >> 22) & 1); 208 *(u16 *)loc = (u16)((upper & 0xf800) | (sign << 10) | 209 ((offset >> 12) & 0x03ff)); 210 *(u16 *)(loc + 2) = (u16)((lower & 0xd000) | 211 (j1 << 13) | (j2 << 11) | 212 ((offset >> 1) & 0x07ff)); 213 break; 214 215 case R_ARM_THM_MOVW_ABS_NC: 216 case R_ARM_THM_MOVT_ABS: 217 upper = *(u16 *)loc; 218 lower = *(u16 *)(loc + 2); 219 220 /* 221 * MOVT/MOVW instructions encoding in Thumb-2: 222 * 223 * i = upper[10] 224 * imm4 = upper[3:0] 225 * imm3 = lower[14:12] 226 * imm8 = lower[7:0] 227 * 228 * imm16 = imm4:i:imm3:imm8 229 */ 230 offset = ((upper & 0x000f) << 12) | 231 ((upper & 0x0400) << 1) | 232 ((lower & 0x7000) >> 4) | (lower & 0x00ff); 233 offset = (offset ^ 0x8000) - 0x8000; 234 offset += sym->st_value; 235 236 if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS) 237 offset >>= 16; 238 239 *(u16 *)loc = (u16)((upper & 0xfbf0) | 240 ((offset & 0xf000) >> 12) | 241 ((offset & 0x0800) >> 1)); 242 *(u16 *)(loc + 2) = (u16)((lower & 0x8f00) | 243 ((offset & 0x0700) << 4) | 244 (offset & 0x00ff)); 245 break; 246 #endif 247 248 default: 249 printk(KERN_ERR "%s: unknown relocation: %u\n", 250 module->name, ELF32_R_TYPE(rel->r_info)); 251 return -ENOEXEC; 252 } 253 } 254 return 0; 255 } 256 257 int 258 apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, 259 unsigned int symindex, unsigned int relsec, struct module *module) 260 { 261 printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", 262 module->name); 263 return -ENOEXEC; 264 } 265 266 struct mod_unwind_map { 267 const Elf_Shdr *unw_sec; 268 const Elf_Shdr *txt_sec; 269 }; 270 271 int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, 272 struct module *mod) 273 { 274 #ifdef CONFIG_ARM_UNWIND 275 const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 276 const Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum; 277 struct mod_unwind_map maps[ARM_SEC_MAX]; 278 int i; 279 280 memset(maps, 0, sizeof(maps)); 281 282 for (s = sechdrs; s < sechdrs_end; s++) { 283 const char *secname = secstrs + s->sh_name; 284 285 if (!(s->sh_flags & SHF_ALLOC)) 286 continue; 287 288 if (strcmp(".ARM.exidx.init.text", secname) == 0) 289 maps[ARM_SEC_INIT].unw_sec = s; 290 else if (strcmp(".ARM.exidx.devinit.text", secname) == 0) 291 maps[ARM_SEC_DEVINIT].unw_sec = s; 292 else if (strcmp(".ARM.exidx", secname) == 0) 293 maps[ARM_SEC_CORE].unw_sec = s; 294 else if (strcmp(".ARM.exidx.exit.text", secname) == 0) 295 maps[ARM_SEC_EXIT].unw_sec = s; 296 else if (strcmp(".ARM.exidx.devexit.text", secname) == 0) 297 maps[ARM_SEC_DEVEXIT].unw_sec = s; 298 else if (strcmp(".init.text", secname) == 0) 299 maps[ARM_SEC_INIT].txt_sec = s; 300 else if (strcmp(".devinit.text", secname) == 0) 301 maps[ARM_SEC_DEVINIT].txt_sec = s; 302 else if (strcmp(".text", secname) == 0) 303 maps[ARM_SEC_CORE].txt_sec = s; 304 else if (strcmp(".exit.text", secname) == 0) 305 maps[ARM_SEC_EXIT].txt_sec = s; 306 else if (strcmp(".devexit.text", secname) == 0) 307 maps[ARM_SEC_DEVEXIT].txt_sec = s; 308 } 309 310 for (i = 0; i < ARM_SEC_MAX; i++) 311 if (maps[i].unw_sec && maps[i].txt_sec) 312 mod->arch.unwind[i] = 313 unwind_table_add(maps[i].unw_sec->sh_addr, 314 maps[i].unw_sec->sh_size, 315 maps[i].txt_sec->sh_addr, 316 maps[i].txt_sec->sh_size); 317 #endif 318 return 0; 319 } 320 321 void 322 module_arch_cleanup(struct module *mod) 323 { 324 #ifdef CONFIG_ARM_UNWIND 325 int i; 326 327 for (i = 0; i < ARM_SEC_MAX; i++) 328 if (mod->arch.unwind[i]) 329 unwind_table_del(mod->arch.unwind[i]); 330 #endif 331 } 332