1/* Kernel module help for sh64. 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 Copyright 2004 SuperH (UK) Ltd 18 Author: Richard Curnow 19 20 Based on the sh version, and on code from the sh64-specific parts of 21 modutils, originally written by Richard Curnow and Ben Gaster. 22 23*/ 24#include <linux/moduleloader.h> 25#include <linux/elf.h> 26#include <linux/vmalloc.h> 27#include <linux/fs.h> 28#include <linux/string.h> 29#include <linux/kernel.h> 30 31#define DEBUGP(fmt...) 32 33void *module_alloc(unsigned long size) 34{ 35 if (size == 0) 36 return NULL; 37 return vmalloc(size); 38} 39 40 41/* Free memory returned from module_alloc */ 42void module_free(struct module *mod, void *module_region) 43{ 44 vfree(module_region); 45} 46 47/* We don't need anything special. */ 48int module_frob_arch_sections(Elf_Ehdr *hdr, 49 Elf_Shdr *sechdrs, 50 char *secstrings, 51 struct module *mod) 52{ 53 return 0; 54} 55 56int apply_relocate_add(Elf32_Shdr *sechdrs, 57 const char *strtab, 58 unsigned int symindex, 59 unsigned int relsec, 60 struct module *me) 61{ 62 unsigned int i; 63 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; 64 Elf32_Sym *sym; 65 Elf32_Addr relocation; 66 uint32_t *location; 67 int align; 68 int is_shmedia; 69 70 DEBUGP("Applying relocate section %u to %u\n", relsec, 71 sechdrs[relsec].sh_info); 72 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 73 /* This is where to make the change */ 74 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 75 + rel[i].r_offset; 76 /* This is the symbol it is referring to. Note that all 77 undefined symbols have been resolved. */ 78 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr 79 + ELF32_R_SYM(rel[i].r_info); 80 relocation = sym->st_value + rel[i].r_addend; 81 align = (int)location & 3; 82 83 /* For text addresses, bit2 of the st_other field indicates 84 * whether the symbol is SHmedia (1) or SHcompact (0). If 85 * SHmedia, the LSB of the symbol needs to be asserted 86 * for the CPU to be in SHmedia mode when it starts executing 87 * the branch target. */ 88 is_shmedia = (sym->st_other & 4) ? 1 : 0; 89 if (is_shmedia) { 90 relocation |= 1; 91 } 92 93 switch (ELF32_R_TYPE(rel[i].r_info)) { 94 case R_SH_DIR32: 95 DEBUGP("R_SH_DIR32 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation); 96 *location += relocation; 97 break; 98 case R_SH_REL32: 99 DEBUGP("R_SH_REL32 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation); 100 relocation -= (Elf32_Addr) location; 101 *location += relocation; 102 break; 103 case R_SH_IMM_LOW16: 104 DEBUGP("R_SH_IMM_LOW16 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation); 105 *location = (*location & ~0x3fffc00) | 106 ((relocation & 0xffff) << 10); 107 break; 108 case R_SH_IMM_MEDLOW16: 109 DEBUGP("R_SH_IMM_MEDLOW16 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation); 110 *location = (*location & ~0x3fffc00) | 111 (((relocation >> 16) & 0xffff) << 10); 112 break; 113 case R_SH_IMM_LOW16_PCREL: 114 DEBUGP("R_SH_IMM_LOW16_PCREL @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation); 115 relocation -= (Elf32_Addr) location; 116 *location = (*location & ~0x3fffc00) | 117 ((relocation & 0xffff) << 10); 118 break; 119 case R_SH_IMM_MEDLOW16_PCREL: 120 DEBUGP("R_SH_IMM_MEDLOW16_PCREL @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation); 121 relocation -= (Elf32_Addr) location; 122 *location = (*location & ~0x3fffc00) | 123 (((relocation >> 16) & 0xffff) << 10); 124 break; 125 default: 126 printk(KERN_ERR "module %s: Unknown relocation: %u\n", 127 me->name, ELF32_R_TYPE(rel[i].r_info)); 128 return -ENOEXEC; 129 } 130 } 131 return 0; 132} 133 134int apply_relocate(Elf32_Shdr *sechdrs, 135 const char *strtab, 136 unsigned int symindex, 137 unsigned int relsec, 138 struct module *me) 139{ 140 printk(KERN_ERR "module %s: REL RELOCATION unsupported\n", 141 me->name); 142 return -ENOEXEC; 143} 144 145int module_finalize(const Elf_Ehdr *hdr, 146 const Elf_Shdr *sechdrs, 147 struct module *me) 148{ 149 return 0; 150} 151 152void module_arch_cleanup(struct module *mod) 153{ 154} 155