1 // SPDX-License-Identifier: GPL-2.0-only !! 1 /* Kernel module help for PPC. 2 /* !! 2 Copyright (C) 2001 Rusty Russell. 3 * Copyright (C) 2007-2009 Michal Simek <monst << 4 * Copyright (C) 2007-2009 PetaLogix << 5 */ << 6 3 7 #include <linux/export.h> !! 4 This program is free software; you can redistribute it and/or modify >> 5 it under the terms of the GNU General Public License as published by >> 6 the Free Software Foundation; either version 2 of the License, or >> 7 (at your option) any later version. >> 8 >> 9 This program is distributed in the hope that it will be useful, >> 10 but WITHOUT ANY WARRANTY; without even the implied warranty of >> 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> 12 GNU General Public License for more details. >> 13 >> 14 You should have received a copy of the GNU General Public License >> 15 along with this program; if not, write to the Free Software >> 16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA >> 17 */ >> 18 #include <linux/module.h> 8 #include <linux/moduleloader.h> 19 #include <linux/moduleloader.h> 9 #include <linux/kernel.h> << 10 #include <linux/elf.h> 20 #include <linux/elf.h> 11 #include <linux/vmalloc.h> 21 #include <linux/vmalloc.h> 12 #include <linux/fs.h> 22 #include <linux/fs.h> 13 #include <linux/string.h> 23 #include <linux/string.h> 14 #include <linux/pgtable.h> !! 24 #include <linux/kernel.h> >> 25 #include <linux/cache.h> >> 26 >> 27 #if 0 >> 28 #define DEBUGP printk >> 29 #else >> 30 #define DEBUGP(fmt , ...) >> 31 #endif 15 32 16 #include <asm/cacheflush.h> !! 33 LIST_HEAD(module_bug_list); >> 34 >> 35 void *module_alloc(unsigned long size) >> 36 { >> 37 if (size == 0) >> 38 return NULL; >> 39 return vmalloc(size); >> 40 } >> 41 >> 42 /* Free memory returned from module_alloc */ >> 43 void module_free(struct module *mod, void *module_region) >> 44 { >> 45 vfree(module_region); >> 46 /* FIXME: If module_region == mod->init_region, trim exception >> 47 table entries. */ >> 48 } 17 49 18 int apply_relocate_add(Elf32_Shdr *sechdrs, co !! 50 /* Count how many different relocations (different symbol, different 19 unsigned int symindex, unsigned int re !! 51 addend) */ >> 52 static unsigned int count_relocs(const Elf32_Rela *rela, unsigned int num) 20 { 53 { >> 54 unsigned int i, j, ret = 0; 21 55 >> 56 /* Sure, this is order(n^2), but it's usually short, and not >> 57 time critical */ >> 58 for (i = 0; i < num; i++) { >> 59 for (j = 0; j < i; j++) { >> 60 /* If this addend appeared before, it's >> 61 already been counted */ >> 62 if (ELF32_R_SYM(rela[i].r_info) >> 63 == ELF32_R_SYM(rela[j].r_info) >> 64 && rela[i].r_addend == rela[j].r_addend) >> 65 break; >> 66 } >> 67 if (j == i) ret++; >> 68 } >> 69 return ret; >> 70 } >> 71 >> 72 /* Get the potential trampolines size required of the init and >> 73 non-init sections */ >> 74 static unsigned long get_plt_size(const Elf32_Ehdr *hdr, >> 75 const Elf32_Shdr *sechdrs, >> 76 const char *secstrings, >> 77 int is_init) >> 78 { >> 79 unsigned long ret = 0; >> 80 unsigned i; >> 81 >> 82 /* Everything marked ALLOC (this includes the exported >> 83 symbols) */ >> 84 for (i = 1; i < hdr->e_shnum; i++) { >> 85 /* If it's called *.init*, and we're not init, we're >> 86 not interested */ >> 87 if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0) >> 88 != is_init) >> 89 continue; >> 90 >> 91 if (sechdrs[i].sh_type == SHT_RELA) { >> 92 DEBUGP("Found relocations in section %u\n", i); >> 93 DEBUGP("Ptr: %p. Number: %u\n", >> 94 (void *)hdr + sechdrs[i].sh_offset, >> 95 sechdrs[i].sh_size / sizeof(Elf32_Rela)); >> 96 ret += count_relocs((void *)hdr >> 97 + sechdrs[i].sh_offset, >> 98 sechdrs[i].sh_size >> 99 / sizeof(Elf32_Rela)) >> 100 * sizeof(struct ppc_plt_entry); >> 101 } >> 102 } >> 103 >> 104 return ret; >> 105 } >> 106 >> 107 int module_frob_arch_sections(Elf32_Ehdr *hdr, >> 108 Elf32_Shdr *sechdrs, >> 109 char *secstrings, >> 110 struct module *me) >> 111 { 22 unsigned int i; 112 unsigned int i; 23 Elf32_Rela *rela = (void *)sechdrs[rel << 24 Elf32_Sym *sym; << 25 unsigned long int *location; << 26 unsigned long int value; << 27 113 28 pr_debug("Applying add relocation sect !! 114 /* Find .plt and .init.plt sections */ 29 relsec, sechdrs[relsec].sh_inf !! 115 for (i = 0; i < hdr->e_shnum; i++) { >> 116 if (strcmp(secstrings + sechdrs[i].sh_name, ".init.plt") == 0) >> 117 me->arch.init_plt_section = i; >> 118 else if (strcmp(secstrings + sechdrs[i].sh_name, ".plt") == 0) >> 119 me->arch.core_plt_section = i; >> 120 } >> 121 if (!me->arch.core_plt_section || !me->arch.init_plt_section) { >> 122 printk("Module doesn't contain .plt or .init.plt sections.\n"); >> 123 return -ENOEXEC; >> 124 } 30 125 31 for (i = 0; i < sechdrs[relsec].sh_siz !! 126 /* Override their sizes */ >> 127 sechdrs[me->arch.core_plt_section].sh_size >> 128 = get_plt_size(hdr, sechdrs, secstrings, 0); >> 129 sechdrs[me->arch.init_plt_section].sh_size >> 130 = get_plt_size(hdr, sechdrs, secstrings, 1); >> 131 return 0; >> 132 } 32 133 33 location = (void *)sechdrs[sec !! 134 int apply_relocate(Elf32_Shdr *sechdrs, 34 rela[i].r_offs !! 135 const char *strtab, 35 sym = (Elf32_Sym *)sechdrs[sym !! 136 unsigned int symindex, 36 ELF32_R_SYM(rela[i].r_ !! 137 unsigned int relsec, 37 value = sym->st_value + rela[i !! 138 struct module *module) >> 139 { >> 140 printk(KERN_ERR "%s: Non-ADD RELOCATION unsupported\n", >> 141 module->name); >> 142 return -ENOEXEC; >> 143 } 38 144 39 switch (ELF32_R_TYPE(rela[i].r !! 145 static inline int entry_matches(struct ppc_plt_entry *entry, Elf32_Addr val) >> 146 { >> 147 if (entry->jump[0] == 0x3d600000 + ((val + 0x8000) >> 16) >> 148 && entry->jump[1] == 0x396b0000 + (val & 0xffff)) >> 149 return 1; >> 150 return 0; >> 151 } 40 152 41 /* !! 153 /* Set up a trampoline in the PLT to bounce us to the distant function */ 42 * Be careful! mb-gcc / mb-ld !! 154 static uint32_t do_plt_call(void *location, 43 * text and the reloc table. I !! 155 Elf32_Addr val, 44 * read the current contents o !! 156 Elf32_Shdr *sechdrs, 45 * then store the result back !! 157 struct module *mod) 46 */ !! 158 { >> 159 struct ppc_plt_entry *entry; 47 160 48 case R_MICROBLAZE_32: !! 161 DEBUGP("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location); 49 *location = value; !! 162 /* Init, or core PLT? */ 50 break; !! 163 if (location >= mod->module_core >> 164 && location < mod->module_core + mod->core_size) >> 165 entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr; >> 166 else >> 167 entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr; >> 168 >> 169 /* Find this entry, or if that fails, the next avail. entry */ >> 170 while (entry->jump[0]) { >> 171 if (entry_matches(entry, val)) return (uint32_t)entry; >> 172 entry++; >> 173 } 51 174 52 case R_MICROBLAZE_64: !! 175 /* Stolen from Paul Mackerras as well... */ 53 location[0] = (locatio !! 176 entry->jump[0] = 0x3d600000+((val+0x8000)>>16); /* lis r11,sym@ha */ 54 (value !! 177 entry->jump[1] = 0x396b0000 + (val&0xffff); /* addi r11,r11,sym@l*/ 55 location[1] = (locatio !! 178 entry->jump[2] = 0x7d6903a6; /* mtctr r11 */ 56 (value !! 179 entry->jump[3] = 0x4e800420; /* bctr */ 57 break; !! 180 >> 181 DEBUGP("Initialized plt for 0x%x at %p\n", val, entry); >> 182 return (uint32_t)entry; >> 183 } 58 184 59 case R_MICROBLAZE_64_PCREL: !! 185 int apply_relocate_add(Elf32_Shdr *sechdrs, 60 value -= (unsigned lon !! 186 const char *strtab, 61 location[0] = (locatio !! 187 unsigned int symindex, 62 (value !! 188 unsigned int relsec, 63 location[1] = (locatio !! 189 struct module *module) 64 (value !! 190 { 65 pr_debug("R_MICROBLAZE !! 191 unsigned int i; 66 value); !! 192 Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; >> 193 Elf32_Sym *sym; >> 194 uint32_t *location; >> 195 uint32_t value; >> 196 >> 197 DEBUGP("Applying ADD relocate section %u to %u\n", relsec, >> 198 sechdrs[relsec].sh_info); >> 199 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { >> 200 /* This is where to make the change */ >> 201 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr >> 202 + rela[i].r_offset; >> 203 /* This is the symbol it is referring to. Note that all >> 204 undefined symbols have been resolved. */ >> 205 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr >> 206 + ELF32_R_SYM(rela[i].r_info); >> 207 /* `Everything is relative'. */ >> 208 value = sym->st_value + rela[i].r_addend; >> 209 >> 210 switch (ELF32_R_TYPE(rela[i].r_info)) { >> 211 case R_PPC_ADDR32: >> 212 /* Simply set it */ >> 213 *(uint32_t *)location = value; 67 break; 214 break; 68 215 69 case R_MICROBLAZE_32_PCREL_LO: !! 216 case R_PPC_ADDR16_LO: 70 pr_debug("R_MICROBLAZE !! 217 /* Low half of the symbol */ >> 218 *(uint16_t *)location = value; >> 219 break; >> 220 >> 221 case R_PPC_ADDR16_HA: >> 222 /* Sign-adjusted lower 16 bits: PPC ELF ABI says: >> 223 (((x >> 16) + ((x & 0x8000) ? 1 : 0))) & 0xFFFF. >> 224 This is the same, only sane. >> 225 */ >> 226 *(uint16_t *)location = (value + 0x8000) >> 16; 71 break; 227 break; 72 228 73 case R_MICROBLAZE_64_NONE: !! 229 case R_PPC_REL24: 74 pr_debug("R_MICROBLAZE !! 230 if ((int)(value - (uint32_t)location) < -0x02000000 >> 231 || (int)(value - (uint32_t)location) >= 0x02000000) >> 232 value = do_plt_call(location, value, >> 233 sechdrs, module); >> 234 >> 235 /* Only replace bits 2 through 26 */ >> 236 DEBUGP("REL24 value = %08X. location = %08X\n", >> 237 value, (uint32_t)location); >> 238 DEBUGP("Location before: %08X.\n", >> 239 *(uint32_t *)location); >> 240 *(uint32_t *)location >> 241 = (*(uint32_t *)location & ~0x03fffffc) >> 242 | ((value - (uint32_t)location) >> 243 & 0x03fffffc); >> 244 DEBUGP("Location after: %08X.\n", >> 245 *(uint32_t *)location); >> 246 DEBUGP("ie. jump to %08X+%08X = %08X\n", >> 247 *(uint32_t *)location & 0x03fffffc, >> 248 (uint32_t)location, >> 249 (*(uint32_t *)location & 0x03fffffc) >> 250 + (uint32_t)location); 75 break; 251 break; 76 252 77 case R_MICROBLAZE_NONE: !! 253 case R_PPC_REL32: 78 pr_debug("R_MICROBLAZE !! 254 /* 32-bit relative jump. */ >> 255 *(uint32_t *)location = value - (uint32_t)location; 79 break; 256 break; 80 257 81 default: 258 default: 82 pr_err("module %s: Unk !! 259 printk("%s: unknown ADD relocation: %u\n", 83 module->name, !! 260 module->name, 84 ELF32_R_TYPE(r !! 261 ELF32_R_TYPE(rela[i].r_info)); 85 return -ENOEXEC; 262 return -ENOEXEC; 86 } 263 } 87 } 264 } 88 return 0; 265 return 0; 89 } 266 } 90 267 91 int module_finalize(const Elf32_Ehdr *hdr, con !! 268 /* FIXME: Sort exception table --RR */ 92 struct module *module) !! 269 int module_finalize(const Elf_Ehdr *hdr, >> 270 const Elf_Shdr *sechdrs, >> 271 struct module *me) 93 { 272 { 94 flush_dcache(); !! 273 char *secstrings; >> 274 unsigned int i; >> 275 >> 276 me->arch.bug_table = NULL; >> 277 me->arch.num_bugs = 0; >> 278 >> 279 /* Find the __bug_table section, if present */ >> 280 secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; >> 281 for (i = 1; i < hdr->e_shnum; i++) { >> 282 if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table")) >> 283 continue; >> 284 me->arch.bug_table = (void *) sechdrs[i].sh_addr; >> 285 me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry); >> 286 break; >> 287 } >> 288 >> 289 /* >> 290 * Strictly speaking this should have a spinlock to protect against >> 291 * traversals, but since we only traverse on BUG()s, a spinlock >> 292 * could potentially lead to deadlock and thus be counter-productive. >> 293 */ >> 294 list_add(&me->arch.bug_list, &module_bug_list); >> 295 95 return 0; 296 return 0; >> 297 } >> 298 >> 299 void module_arch_cleanup(struct module *mod) >> 300 { >> 301 list_del(&mod->arch.bug_list); >> 302 } >> 303 >> 304 struct bug_entry *module_find_bug(unsigned long bugaddr) >> 305 { >> 306 struct mod_arch_specific *mod; >> 307 unsigned int i; >> 308 struct bug_entry *bug; >> 309 >> 310 list_for_each_entry(mod, &module_bug_list, bug_list) { >> 311 bug = mod->bug_table; >> 312 for (i = 0; i < mod->num_bugs; ++i, ++bug) >> 313 if (bugaddr == bug->bug_addr) >> 314 return bug; >> 315 } >> 316 return NULL; 96 } 317 } 97 318
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.