1/* 2 * AVR32-specific kernel module loader 3 * 4 * Copyright (C) 2005-2006 Atmel Corporation 5 * 6 * GOT initialization parts are based on the s390 version 7 * Copyright (C) 2002, 2003 IBM Deutschland Entwicklung GmbH, 8 * IBM Corporation 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 15#include <linux/bug.h> 16#include <linux/elf.h> 17#include <linux/kernel.h> 18#include <linux/module.h> 19#include <linux/moduleloader.h> 20#include <linux/vmalloc.h> 21 22void *module_alloc(unsigned long size) 23{ 24 if (size == 0) 25 return NULL; 26 return vmalloc(size); 27} 28 29void module_free(struct module *mod, void *module_region) 30{ 31 vfree(mod->arch.syminfo); 32 mod->arch.syminfo = NULL; 33 34 vfree(module_region); 35} 36 37static inline int check_rela(Elf32_Rela *rela, struct module *module, 38 char *strings, Elf32_Sym *symbols) 39{ 40 struct mod_arch_syminfo *info; 41 42 info = module->arch.syminfo + ELF32_R_SYM(rela->r_info); 43 switch (ELF32_R_TYPE(rela->r_info)) { 44 case R_AVR32_GOT32: 45 case R_AVR32_GOT16: 46 case R_AVR32_GOT8: 47 case R_AVR32_GOT21S: 48 case R_AVR32_GOT18SW: /* mcall */ 49 case R_AVR32_GOT16S: /* ld.w */ 50 if (rela->r_addend != 0) { 51 printk(KERN_ERR 52 "GOT relocation against %s at offset %u with addend\n", 53 strings + symbols[ELF32_R_SYM(rela->r_info)].st_name, 54 rela->r_offset); 55 return -ENOEXEC; 56 } 57 if (info->got_offset == -1UL) { 58 info->got_offset = module->arch.got_size; 59 module->arch.got_size += sizeof(void *); 60 } 61 pr_debug("GOT[%3lu] %s\n", info->got_offset, 62 strings + symbols[ELF32_R_SYM(rela->r_info)].st_name); 63 break; 64 } 65 66 return 0; 67} 68 69int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, 70 char *secstrings, struct module *module) 71{ 72 Elf32_Shdr *symtab; 73 Elf32_Sym *symbols; 74 Elf32_Rela *rela; 75 char *strings; 76 int nrela, i, j; 77 int ret; 78 79 /* Find the symbol table */ 80 symtab = NULL; 81 for (i = 0; i < hdr->e_shnum; i++) 82 switch (sechdrs[i].sh_type) { 83 case SHT_SYMTAB: 84 symtab = &sechdrs[i]; 85 break; 86 } 87 if (!symtab) { 88 printk(KERN_ERR "module %s: no symbol table\n", module->name); 89 return -ENOEXEC; 90 } 91 92 /* Allocate room for one syminfo structure per symbol. */ 93 module->arch.nsyms = symtab->sh_size / sizeof(Elf_Sym); 94 module->arch.syminfo = vmalloc(module->arch.nsyms 95 * sizeof(struct mod_arch_syminfo)); 96 if (!module->arch.syminfo) 97 return -ENOMEM; 98 99 symbols = (void *)hdr + symtab->sh_offset; 100 strings = (void *)hdr + sechdrs[symtab->sh_link].sh_offset; 101 for (i = 0; i < module->arch.nsyms; i++) { 102 if (symbols[i].st_shndx == SHN_UNDEF && 103 strcmp(strings + symbols[i].st_name, 104 "_GLOBAL_OFFSET_TABLE_") == 0) 105 /* "Define" it as absolute. */ 106 symbols[i].st_shndx = SHN_ABS; 107 module->arch.syminfo[i].got_offset = -1UL; 108 module->arch.syminfo[i].got_initialized = 0; 109 } 110 111 /* Allocate GOT entries for symbols that need it. */ 112 module->arch.got_size = 0; 113 for (i = 0; i < hdr->e_shnum; i++) { 114 if (sechdrs[i].sh_type != SHT_RELA) 115 continue; 116 nrela = sechdrs[i].sh_size / sizeof(Elf32_Rela); 117 rela = (void *)hdr + sechdrs[i].sh_offset; 118 for (j = 0; j < nrela; j++) { 119 ret = check_rela(rela + j, module, 120 strings, symbols); 121 if (ret) 122 goto out_free_syminfo; 123 } 124 } 125 126 /* 127 * Increase core size to make room for GOT and set start 128 * offset for GOT. 129 */ 130 module->core_size = ALIGN(module->core_size, 4); 131 module->arch.got_offset = module->core_size; 132 module->core_size += module->arch.got_size; 133 134 return 0; 135 136out_free_syminfo: 137 vfree(module->arch.syminfo); 138 module->arch.syminfo = NULL; 139 140 return ret; 141} 142 143static inline int reloc_overflow(struct module *module, const char *reloc_name, 144 Elf32_Addr relocation) 145{ 146 printk(KERN_ERR "module %s: Value %lx does not fit relocation %s\n", 147 module->name, (unsigned long)relocation, reloc_name); 148 return -ENOEXEC; 149} 150 151#define get_u16(loc) (*((uint16_t *)loc)) 152#define put_u16(loc, val) (*((uint16_t *)loc) = (val)) 153 154int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, 155 unsigned int symindex, unsigned int relindex, 156 struct module *module) 157{ 158 Elf32_Shdr *symsec = sechdrs + symindex; 159 Elf32_Shdr *relsec = sechdrs + relindex; 160 Elf32_Shdr *dstsec = sechdrs + relsec->sh_info; 161 Elf32_Rela *rel = (void *)relsec->sh_addr; 162 unsigned int i; 163 int ret = 0; 164 165 for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rela); i++, rel++) { 166 struct mod_arch_syminfo *info; 167 Elf32_Sym *sym; 168 Elf32_Addr relocation; 169 uint32_t *location; 170 uint32_t value; 171 172 location = (void *)dstsec->sh_addr + rel->r_offset; 173 sym = (Elf32_Sym *)symsec->sh_addr + ELF32_R_SYM(rel->r_info); 174 relocation = sym->st_value + rel->r_addend; 175 176 info = module->arch.syminfo + ELF32_R_SYM(rel->r_info); 177 178 /* Initialize GOT entry if necessary */ 179 switch (ELF32_R_TYPE(rel->r_info)) { 180 case R_AVR32_GOT32: 181 case R_AVR32_GOT16: 182 case R_AVR32_GOT8: 183 case R_AVR32_GOT21S: 184 case R_AVR32_GOT18SW: 185 case R_AVR32_GOT16S: 186 if (!info->got_initialized) { 187 Elf32_Addr *gotent; 188 189 gotent = (module->module_core 190 + module->arch.got_offset 191 + info->got_offset); 192 *gotent = relocation; 193 info->got_initialized = 1; 194 } 195 196 relocation = info->got_offset; 197 break; 198 } 199 200 switch (ELF32_R_TYPE(rel->r_info)) { 201 case R_AVR32_32: 202 case R_AVR32_32_CPENT: 203 *location = relocation; 204 break; 205 case R_AVR32_22H_PCREL: 206 relocation -= (Elf32_Addr)location; 207 if ((relocation & 0xffe00001) != 0 208 && (relocation & 0xffc00001) != 0xffc00000) 209 return reloc_overflow(module, 210 "R_AVR32_22H_PCREL", 211 relocation); 212 relocation >>= 1; 213 214 value = *location; 215 value = ((value & 0xe1ef0000) 216 | (relocation & 0xffff) 217 | ((relocation & 0x10000) << 4) 218 | ((relocation & 0x1e0000) << 8)); 219 *location = value; 220 break; 221 case R_AVR32_11H_PCREL: 222 relocation -= (Elf32_Addr)location; 223 if ((relocation & 0xfffffc01) != 0 224 && (relocation & 0xfffff801) != 0xfffff800) 225 return reloc_overflow(module, 226 "R_AVR32_11H_PCREL", 227 relocation); 228 value = get_u16(location); 229 value = ((value & 0xf00c) 230 | ((relocation & 0x1fe) << 3) 231 | ((relocation & 0x600) >> 9)); 232 put_u16(location, value); 233 break; 234 case R_AVR32_9H_PCREL: 235 relocation -= (Elf32_Addr)location; 236 if ((relocation & 0xffffff01) != 0 237 && (relocation & 0xfffffe01) != 0xfffffe00) 238 return reloc_overflow(module, 239 "R_AVR32_9H_PCREL", 240 relocation); 241 value = get_u16(location); 242 value = ((value & 0xf00f) 243 | ((relocation & 0x1fe) << 3)); 244 put_u16(location, value); 245 break; 246 case R_AVR32_9UW_PCREL: 247 relocation -= ((Elf32_Addr)location) & 0xfffffffc; 248 if ((relocation & 0xfffffc03) != 0) 249 return reloc_overflow(module, 250 "R_AVR32_9UW_PCREL", 251 relocation); 252 value = get_u16(location); 253 value = ((value & 0xf80f) 254 | ((relocation & 0x1fc) << 2)); 255 put_u16(location, value); 256 break; 257 case R_AVR32_GOTPC: 258 /* 259 * R6 = PC - (PC - GOT) 260 * 261 * At this point, relocation contains the 262 * value of PC. Just subtract the value of 263 * GOT, and we're done. 264 */ 265 pr_debug("GOTPC: PC=0x%x, got_offset=0x%lx, core=0x%p\n", 266 relocation, module->arch.got_offset, 267 module->module_core); 268 relocation -= ((unsigned long)module->module_core 269 + module->arch.got_offset); 270 *location = relocation; 271 break; 272 case R_AVR32_GOT18SW: 273 if ((relocation & 0xfffe0003) != 0 274 && (relocation & 0xfffc0003) != 0xffff0000) 275 return reloc_overflow(module, "R_AVR32_GOT18SW", 276 relocation); 277 relocation >>= 2; 278 /* fall through */ 279 case R_AVR32_GOT16S: 280 if ((relocation & 0xffff8000) != 0 281 && (relocation & 0xffff0000) != 0xffff0000) 282 return reloc_overflow(module, "R_AVR32_GOT16S", 283 relocation); 284 pr_debug("GOT reloc @ 0x%x -> %u\n", 285 rel->r_offset, relocation); 286 value = *location; 287 value = ((value & 0xffff0000) 288 | (relocation & 0xffff)); 289 *location = value; 290 break; 291 292 default: 293 printk(KERN_ERR "module %s: Unknown relocation: %u\n", 294 module->name, ELF32_R_TYPE(rel->r_info)); 295 return -ENOEXEC; 296 } 297 } 298 299 return ret; 300} 301 302int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, 303 unsigned int symindex, unsigned int relindex, 304 struct module *module) 305{ 306 printk(KERN_ERR "module %s: REL relocations are not supported\n", 307 module->name); 308 return -ENOEXEC; 309} 310 311int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, 312 struct module *module) 313{ 314 vfree(module->arch.syminfo); 315 module->arch.syminfo = NULL; 316 317 return 0; 318} 319 320void module_arch_cleanup(struct module *module) 321{ 322} 323