1 /* Kernel module help for x86. 2 Copyright (C) 2001 Rusty Russell. 3 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/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 #include <linux/bug.h> 25 #include <linux/mm.h> 26 #include <linux/gfp.h> 27 #include <linux/jump_label.h> 28 29 #include <asm/system.h> 30 #include <asm/page.h> 31 #include <asm/pgtable.h> 32 33 #if 0 34 #define DEBUGP printk 35 #else 36 #define DEBUGP(fmt...) 37 #endif 38 39 void *module_alloc(unsigned long size) 40 { 41 if (PAGE_ALIGN(size) > MODULES_LEN) 42 return NULL; 43 return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, 44 GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC, 45 -1, __builtin_return_address(0)); 46 } 47 48 #ifdef CONFIG_X86_32 49 int apply_relocate(Elf32_Shdr *sechdrs, 50 const char *strtab, 51 unsigned int symindex, 52 unsigned int relsec, 53 struct module *me) 54 { 55 unsigned int i; 56 Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; 57 Elf32_Sym *sym; 58 uint32_t *location; 59 60 DEBUGP("Applying relocate section %u to %u\n", relsec, 61 sechdrs[relsec].sh_info); 62 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 63 /* This is where to make the change */ 64 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 65 + rel[i].r_offset; 66 /* This is the symbol it is referring to. Note that all 67 undefined symbols have been resolved. */ 68 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr 69 + ELF32_R_SYM(rel[i].r_info); 70 71 switch (ELF32_R_TYPE(rel[i].r_info)) { 72 case R_386_32: 73 /* We add the value into the location given */ 74 *location += sym->st_value; 75 break; 76 case R_386_PC32: 77 /* Add the value, subtract its postition */ 78 *location += sym->st_value - (uint32_t)location; 79 break; 80 default: 81 printk(KERN_ERR "module %s: Unknown relocation: %u\n", 82 me->name, ELF32_R_TYPE(rel[i].r_info)); 83 return -ENOEXEC; 84 } 85 } 86 return 0; 87 } 88 #else /*X86_64*/ 89 int apply_relocate_add(Elf64_Shdr *sechdrs, 90 const char *strtab, 91 unsigned int symindex, 92 unsigned int relsec, 93 struct module *me) 94 { 95 unsigned int i; 96 Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; 97 Elf64_Sym *sym; 98 void *loc; 99 u64 val; 100 101 DEBUGP("Applying relocate section %u to %u\n", relsec, 102 sechdrs[relsec].sh_info); 103 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 104 /* This is where to make the change */ 105 loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 106 + rel[i].r_offset; 107 108 /* This is the symbol it is referring to. Note that all 109 undefined symbols have been resolved. */ 110 sym = (Elf64_Sym *)sechdrs[symindex].sh_addr 111 + ELF64_R_SYM(rel[i].r_info); 112 113 DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n", 114 (int)ELF64_R_TYPE(rel[i].r_info), 115 sym->st_value, rel[i].r_addend, (u64)loc); 116 117 val = sym->st_value + rel[i].r_addend; 118 119 switch (ELF64_R_TYPE(rel[i].r_info)) { 120 case R_X86_64_NONE: 121 break; 122 case R_X86_64_64: 123 *(u64 *)loc = val; 124 break; 125 case R_X86_64_32: 126 *(u32 *)loc = val; 127 if (val != *(u32 *)loc) 128 goto overflow; 129 break; 130 case R_X86_64_32S: 131 *(s32 *)loc = val; 132 if ((s64)val != *(s32 *)loc) 133 goto overflow; 134 break; 135 case R_X86_64_PC32: 136 val -= (u64)loc; 137 *(u32 *)loc = val; 138 #if 0 139 if ((s64)val != *(s32 *)loc) 140 goto overflow; 141 #endif 142 break; 143 default: 144 printk(KERN_ERR "module %s: Unknown rela relocation: %llu\n", 145 me->name, ELF64_R_TYPE(rel[i].r_info)); 146 return -ENOEXEC; 147 } 148 } 149 return 0; 150 151 overflow: 152 printk(KERN_ERR "overflow in relocation type %d val %Lx\n", 153 (int)ELF64_R_TYPE(rel[i].r_info), val); 154 printk(KERN_ERR "`%s' likely not compiled with -mcmodel=kernel\n", 155 me->name); 156 return -ENOEXEC; 157 } 158 #endif 159 160 int module_finalize(const Elf_Ehdr *hdr, 161 const Elf_Shdr *sechdrs, 162 struct module *me) 163 { 164 const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL, 165 *para = NULL; 166 char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 167 168 for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { 169 if (!strcmp(".text", secstrings + s->sh_name)) 170 text = s; 171 if (!strcmp(".altinstructions", secstrings + s->sh_name)) 172 alt = s; 173 if (!strcmp(".smp_locks", secstrings + s->sh_name)) 174 locks = s; 175 if (!strcmp(".parainstructions", secstrings + s->sh_name)) 176 para = s; 177 } 178 179 if (alt) { 180 /* patch .altinstructions */ 181 void *aseg = (void *)alt->sh_addr; 182 apply_alternatives(aseg, aseg + alt->sh_size); 183 } 184 if (locks && text) { 185 void *lseg = (void *)locks->sh_addr; 186 void *tseg = (void *)text->sh_addr; 187 alternatives_smp_module_add(me, me->name, 188 lseg, lseg + locks->sh_size, 189 tseg, tseg + text->sh_size); 190 } 191 192 if (para) { 193 void *pseg = (void *)para->sh_addr; 194 apply_paravirt(pseg, pseg + para->sh_size); 195 } 196 197 /* make jump label nops */ 198 jump_label_apply_nops(me); 199 200 return 0; 201 } 202 203 void module_arch_cleanup(struct module *mod) 204 { 205 alternatives_smp_module_del(mod); 206 } 207