at v2.6.26-rc3 258 lines 7.3 kB view raw
1/* Kernel module help for M32R. 2 3 This program is free software; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License as published by 5 the Free Software Foundation; either version 2 of the License, or 6 (at your option) any later version. 7 8 This program is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License 14 along with this program; if not, write to the Free Software 15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16*/ 17 18#include <linux/moduleloader.h> 19#include <linux/elf.h> 20#include <linux/vmalloc.h> 21#include <linux/fs.h> 22#include <linux/string.h> 23#include <linux/kernel.h> 24 25#if 0 26#define DEBUGP printk 27#else 28#define DEBUGP(fmt...) 29#endif 30 31void *module_alloc(unsigned long size) 32{ 33 if (size == 0) 34 return NULL; 35#ifdef CONFIG_MMU 36 return vmalloc_exec(size); 37#else 38 return vmalloc(size); 39#endif 40} 41 42 43/* Free memory returned from module_alloc */ 44void module_free(struct module *mod, void *module_region) 45{ 46 vfree(module_region); 47 /* FIXME: If module_region == mod->init_region, trim exception 48 table entries. */ 49} 50 51/* We don't need anything special. */ 52int module_frob_arch_sections(Elf_Ehdr *hdr, 53 Elf_Shdr *sechdrs, 54 char *secstrings, 55 struct module *mod) 56{ 57 return 0; 58} 59 60#define COPY_UNALIGNED_WORD(sw, tw, align) \ 61{ \ 62 void *__s = &(sw), *__t = &(tw); \ 63 unsigned short *__s2 = __s, *__t2 =__t; \ 64 unsigned char *__s1 = __s, *__t1 =__t; \ 65 switch ((align)) \ 66 { \ 67 case 0: \ 68 *(unsigned long *) __t = *(unsigned long *) __s; \ 69 break; \ 70 case 2: \ 71 *__t2++ = *__s2++; \ 72 *__t2 = *__s2; \ 73 break; \ 74 default: \ 75 *__t1++ = *__s1++; \ 76 *__t1++ = *__s1++; \ 77 *__t1++ = *__s1++; \ 78 *__t1 = *__s1; \ 79 break; \ 80 } \ 81} 82 83#define COPY_UNALIGNED_HWORD(sw, tw, align) \ 84 { \ 85 void *__s = &(sw), *__t = &(tw); \ 86 unsigned short *__s2 = __s, *__t2 =__t; \ 87 unsigned char *__s1 = __s, *__t1 =__t; \ 88 switch ((align)) \ 89 { \ 90 case 0: \ 91 *__t2 = *__s2; \ 92 break; \ 93 default: \ 94 *__t1++ = *__s1++; \ 95 *__t1 = *__s1; \ 96 break; \ 97 } \ 98 } 99 100int apply_relocate_add(Elf32_Shdr *sechdrs, 101 const char *strtab, 102 unsigned int symindex, 103 unsigned int relsec, 104 struct module *me) 105{ 106 unsigned int i; 107 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; 108 Elf32_Sym *sym; 109 Elf32_Addr relocation; 110 uint32_t *location; 111 uint32_t value; 112 unsigned short *hlocation; 113 unsigned short hvalue; 114 int svalue; 115 int align; 116 117 DEBUGP("Applying relocate section %u to %u\n", relsec, 118 sechdrs[relsec].sh_info); 119 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 120 /* This is where to make the change */ 121 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 122 + rel[i].r_offset; 123 /* This is the symbol it is referring to. Note that all 124 undefined symbols have been resolved. */ 125 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr 126 + ELF32_R_SYM(rel[i].r_info); 127 relocation = sym->st_value + rel[i].r_addend; 128 align = (int)location & 3; 129 130 switch (ELF32_R_TYPE(rel[i].r_info)) { 131 case R_M32R_32_RELA: 132 COPY_UNALIGNED_WORD (*location, value, align); 133 value += relocation; 134 COPY_UNALIGNED_WORD (value, *location, align); 135 break; 136 case R_M32R_HI16_ULO_RELA: 137 COPY_UNALIGNED_WORD (*location, value, align); 138 relocation = (relocation >>16) & 0xffff; 139 /* RELA must has 0 at relocation field. */ 140 value += relocation; 141 COPY_UNALIGNED_WORD (value, *location, align); 142 break; 143 case R_M32R_HI16_SLO_RELA: 144 COPY_UNALIGNED_WORD (*location, value, align); 145 if (relocation & 0x8000) relocation += 0x10000; 146 relocation = (relocation >>16) & 0xffff; 147 /* RELA must has 0 at relocation field. */ 148 value += relocation; 149 COPY_UNALIGNED_WORD (value, *location, align); 150 break; 151 case R_M32R_16_RELA: 152 hlocation = (unsigned short *)location; 153 relocation = relocation & 0xffff; 154 /* RELA must has 0 at relocation field. */ 155 hvalue = relocation; 156 COPY_UNALIGNED_WORD (hvalue, *hlocation, align); 157 break; 158 case R_M32R_SDA16_RELA: 159 case R_M32R_LO16_RELA: 160 COPY_UNALIGNED_WORD (*location, value, align); 161 relocation = relocation & 0xffff; 162 /* RELA must has 0 at relocation field. */ 163 value += relocation; 164 COPY_UNALIGNED_WORD (value, *location, align); 165 break; 166 case R_M32R_24_RELA: 167 COPY_UNALIGNED_WORD (*location, value, align); 168 relocation = relocation & 0xffffff; 169 /* RELA must has 0 at relocation field. */ 170 value += relocation; 171 COPY_UNALIGNED_WORD (value, *location, align); 172 break; 173 case R_M32R_18_PCREL_RELA: 174 relocation = (relocation - (Elf32_Addr) location); 175 if (relocation < -0x20000 || 0x1fffc < relocation) 176 { 177 printk(KERN_ERR "module %s: relocation overflow: %u\n", 178 me->name, relocation); 179 return -ENOEXEC; 180 } 181 COPY_UNALIGNED_WORD (*location, value, align); 182 if (value & 0xffff) 183 { 184 /* RELA must has 0 at relocation field. */ 185 printk(KERN_ERR "module %s: illegal relocation field: %u\n", 186 me->name, value); 187 return -ENOEXEC; 188 } 189 relocation = (relocation >> 2) & 0xffff; 190 value += relocation; 191 COPY_UNALIGNED_WORD (value, *location, align); 192 break; 193 case R_M32R_10_PCREL_RELA: 194 hlocation = (unsigned short *)location; 195 relocation = (relocation - (Elf32_Addr) location); 196 COPY_UNALIGNED_HWORD (*hlocation, hvalue, align); 197 svalue = (int)hvalue; 198 svalue = (signed char)svalue << 2; 199 relocation += svalue; 200 relocation = (relocation >> 2) & 0xff; 201 hvalue = hvalue & 0xff00; 202 hvalue += relocation; 203 COPY_UNALIGNED_HWORD (hvalue, *hlocation, align); 204 break; 205 case R_M32R_26_PCREL_RELA: 206 relocation = (relocation - (Elf32_Addr) location); 207 if (relocation < -0x2000000 || 0x1fffffc < relocation) 208 { 209 printk(KERN_ERR "module %s: relocation overflow: %u\n", 210 me->name, relocation); 211 return -ENOEXEC; 212 } 213 COPY_UNALIGNED_WORD (*location, value, align); 214 if (value & 0xffffff) 215 { 216 /* RELA must has 0 at relocation field. */ 217 printk(KERN_ERR "module %s: illegal relocation field: %u\n", 218 me->name, value); 219 return -ENOEXEC; 220 } 221 relocation = (relocation >> 2) & 0xffffff; 222 value += relocation; 223 COPY_UNALIGNED_WORD (value, *location, align); 224 break; 225 default: 226 printk(KERN_ERR "module %s: Unknown relocation: %u\n", 227 me->name, ELF32_R_TYPE(rel[i].r_info)); 228 return -ENOEXEC; 229 } 230 } 231 return 0; 232} 233 234int apply_relocate(Elf32_Shdr *sechdrs, 235 const char *strtab, 236 unsigned int symindex, 237 unsigned int relsec, 238 struct module *me) 239{ 240#if 0 241 printk(KERN_ERR "module %s: REL RELOCATION unsupported\n", 242 me->name); 243 return -ENOEXEC; 244#endif 245 return 0; 246 247} 248 249int module_finalize(const Elf_Ehdr *hdr, 250 const Elf_Shdr *sechdrs, 251 struct module *me) 252{ 253 return 0; 254} 255 256void module_arch_cleanup(struct module *mod) 257{ 258}