12d5bf28fSAmerigo Wang /* Kernel module help for x86. 22d5bf28fSAmerigo Wang Copyright (C) 2001 Rusty Russell. 32d5bf28fSAmerigo Wang 42d5bf28fSAmerigo Wang This program is free software; you can redistribute it and/or modify 52d5bf28fSAmerigo Wang it under the terms of the GNU General Public License as published by 62d5bf28fSAmerigo Wang the Free Software Foundation; either version 2 of the License, or 72d5bf28fSAmerigo Wang (at your option) any later version. 82d5bf28fSAmerigo Wang 92d5bf28fSAmerigo Wang This program is distributed in the hope that it will be useful, 102d5bf28fSAmerigo Wang but WITHOUT ANY WARRANTY; without even the implied warranty of 112d5bf28fSAmerigo Wang MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 122d5bf28fSAmerigo Wang GNU General Public License for more details. 132d5bf28fSAmerigo Wang 142d5bf28fSAmerigo Wang You should have received a copy of the GNU General Public License 152d5bf28fSAmerigo Wang along with this program; if not, write to the Free Software 162d5bf28fSAmerigo Wang Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 172d5bf28fSAmerigo Wang */ 182d5bf28fSAmerigo Wang #include <linux/moduleloader.h> 192d5bf28fSAmerigo Wang #include <linux/elf.h> 202d5bf28fSAmerigo Wang #include <linux/vmalloc.h> 212d5bf28fSAmerigo Wang #include <linux/fs.h> 222d5bf28fSAmerigo Wang #include <linux/string.h> 232d5bf28fSAmerigo Wang #include <linux/kernel.h> 242d5bf28fSAmerigo Wang #include <linux/bug.h> 252d5bf28fSAmerigo Wang #include <linux/mm.h> 265a0e3ad6STejun Heo #include <linux/gfp.h> 27*d430d3d7SJason Baron #include <linux/jump_label.h> 282d5bf28fSAmerigo Wang 292d5bf28fSAmerigo Wang #include <asm/system.h> 302d5bf28fSAmerigo Wang #include <asm/page.h> 312d5bf28fSAmerigo Wang #include <asm/pgtable.h> 322d5bf28fSAmerigo Wang 332d5bf28fSAmerigo Wang #if 0 342d5bf28fSAmerigo Wang #define DEBUGP printk 352d5bf28fSAmerigo Wang #else 362d5bf28fSAmerigo Wang #define DEBUGP(fmt...) 372d5bf28fSAmerigo Wang #endif 382d5bf28fSAmerigo Wang 390fdc83b9SAmerigo Wang void *module_alloc(unsigned long size) 400fdc83b9SAmerigo Wang { 41d0a21265SDavid Rientjes if (PAGE_ALIGN(size) > MODULES_LEN) 420fdc83b9SAmerigo Wang return NULL; 43d0a21265SDavid Rientjes return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, 44d0a21265SDavid Rientjes GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC, 45d0a21265SDavid Rientjes -1, __builtin_return_address(0)); 460fdc83b9SAmerigo Wang } 470fdc83b9SAmerigo Wang 482d5bf28fSAmerigo Wang /* Free memory returned from module_alloc */ 492d5bf28fSAmerigo Wang void module_free(struct module *mod, void *module_region) 502d5bf28fSAmerigo Wang { 512d5bf28fSAmerigo Wang vfree(module_region); 522d5bf28fSAmerigo Wang } 532d5bf28fSAmerigo Wang 542d5bf28fSAmerigo Wang /* We don't need anything special. */ 552d5bf28fSAmerigo Wang int module_frob_arch_sections(Elf_Ehdr *hdr, 562d5bf28fSAmerigo Wang Elf_Shdr *sechdrs, 572d5bf28fSAmerigo Wang char *secstrings, 582d5bf28fSAmerigo Wang struct module *mod) 592d5bf28fSAmerigo Wang { 602d5bf28fSAmerigo Wang return 0; 612d5bf28fSAmerigo Wang } 622d5bf28fSAmerigo Wang 630fdc83b9SAmerigo Wang #ifdef CONFIG_X86_32 640fdc83b9SAmerigo Wang int apply_relocate(Elf32_Shdr *sechdrs, 650fdc83b9SAmerigo Wang const char *strtab, 660fdc83b9SAmerigo Wang unsigned int symindex, 670fdc83b9SAmerigo Wang unsigned int relsec, 680fdc83b9SAmerigo Wang struct module *me) 690fdc83b9SAmerigo Wang { 700fdc83b9SAmerigo Wang unsigned int i; 710fdc83b9SAmerigo Wang Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; 720fdc83b9SAmerigo Wang Elf32_Sym *sym; 730fdc83b9SAmerigo Wang uint32_t *location; 740fdc83b9SAmerigo Wang 750fdc83b9SAmerigo Wang DEBUGP("Applying relocate section %u to %u\n", relsec, 760fdc83b9SAmerigo Wang sechdrs[relsec].sh_info); 770fdc83b9SAmerigo Wang for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 780fdc83b9SAmerigo Wang /* This is where to make the change */ 790fdc83b9SAmerigo Wang location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 800fdc83b9SAmerigo Wang + rel[i].r_offset; 810fdc83b9SAmerigo Wang /* This is the symbol it is referring to. Note that all 820fdc83b9SAmerigo Wang undefined symbols have been resolved. */ 830fdc83b9SAmerigo Wang sym = (Elf32_Sym *)sechdrs[symindex].sh_addr 840fdc83b9SAmerigo Wang + ELF32_R_SYM(rel[i].r_info); 850fdc83b9SAmerigo Wang 860fdc83b9SAmerigo Wang switch (ELF32_R_TYPE(rel[i].r_info)) { 870fdc83b9SAmerigo Wang case R_386_32: 880fdc83b9SAmerigo Wang /* We add the value into the location given */ 890fdc83b9SAmerigo Wang *location += sym->st_value; 900fdc83b9SAmerigo Wang break; 910fdc83b9SAmerigo Wang case R_386_PC32: 920fdc83b9SAmerigo Wang /* Add the value, subtract its postition */ 930fdc83b9SAmerigo Wang *location += sym->st_value - (uint32_t)location; 940fdc83b9SAmerigo Wang break; 950fdc83b9SAmerigo Wang default: 960fdc83b9SAmerigo Wang printk(KERN_ERR "module %s: Unknown relocation: %u\n", 970fdc83b9SAmerigo Wang me->name, ELF32_R_TYPE(rel[i].r_info)); 980fdc83b9SAmerigo Wang return -ENOEXEC; 990fdc83b9SAmerigo Wang } 1000fdc83b9SAmerigo Wang } 1010fdc83b9SAmerigo Wang return 0; 1020fdc83b9SAmerigo Wang } 1030fdc83b9SAmerigo Wang 1040fdc83b9SAmerigo Wang int apply_relocate_add(Elf32_Shdr *sechdrs, 1050fdc83b9SAmerigo Wang const char *strtab, 1060fdc83b9SAmerigo Wang unsigned int symindex, 1070fdc83b9SAmerigo Wang unsigned int relsec, 1080fdc83b9SAmerigo Wang struct module *me) 1090fdc83b9SAmerigo Wang { 1100fdc83b9SAmerigo Wang printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", 1110fdc83b9SAmerigo Wang me->name); 1120fdc83b9SAmerigo Wang return -ENOEXEC; 1130fdc83b9SAmerigo Wang } 1140fdc83b9SAmerigo Wang #else /*X86_64*/ 1150fdc83b9SAmerigo Wang int apply_relocate_add(Elf64_Shdr *sechdrs, 1160fdc83b9SAmerigo Wang const char *strtab, 1170fdc83b9SAmerigo Wang unsigned int symindex, 1180fdc83b9SAmerigo Wang unsigned int relsec, 1190fdc83b9SAmerigo Wang struct module *me) 1200fdc83b9SAmerigo Wang { 1210fdc83b9SAmerigo Wang unsigned int i; 1220fdc83b9SAmerigo Wang Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; 1230fdc83b9SAmerigo Wang Elf64_Sym *sym; 1240fdc83b9SAmerigo Wang void *loc; 1250fdc83b9SAmerigo Wang u64 val; 1260fdc83b9SAmerigo Wang 1270fdc83b9SAmerigo Wang DEBUGP("Applying relocate section %u to %u\n", relsec, 1280fdc83b9SAmerigo Wang sechdrs[relsec].sh_info); 1290fdc83b9SAmerigo Wang for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 1300fdc83b9SAmerigo Wang /* This is where to make the change */ 1310fdc83b9SAmerigo Wang loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 1320fdc83b9SAmerigo Wang + rel[i].r_offset; 1330fdc83b9SAmerigo Wang 1340fdc83b9SAmerigo Wang /* This is the symbol it is referring to. Note that all 1350fdc83b9SAmerigo Wang undefined symbols have been resolved. */ 1360fdc83b9SAmerigo Wang sym = (Elf64_Sym *)sechdrs[symindex].sh_addr 1370fdc83b9SAmerigo Wang + ELF64_R_SYM(rel[i].r_info); 1380fdc83b9SAmerigo Wang 1390fdc83b9SAmerigo Wang DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n", 1400fdc83b9SAmerigo Wang (int)ELF64_R_TYPE(rel[i].r_info), 1410fdc83b9SAmerigo Wang sym->st_value, rel[i].r_addend, (u64)loc); 1420fdc83b9SAmerigo Wang 1430fdc83b9SAmerigo Wang val = sym->st_value + rel[i].r_addend; 1440fdc83b9SAmerigo Wang 1450fdc83b9SAmerigo Wang switch (ELF64_R_TYPE(rel[i].r_info)) { 1460fdc83b9SAmerigo Wang case R_X86_64_NONE: 1470fdc83b9SAmerigo Wang break; 1480fdc83b9SAmerigo Wang case R_X86_64_64: 1490fdc83b9SAmerigo Wang *(u64 *)loc = val; 1500fdc83b9SAmerigo Wang break; 1510fdc83b9SAmerigo Wang case R_X86_64_32: 1520fdc83b9SAmerigo Wang *(u32 *)loc = val; 1530fdc83b9SAmerigo Wang if (val != *(u32 *)loc) 1540fdc83b9SAmerigo Wang goto overflow; 1550fdc83b9SAmerigo Wang break; 1560fdc83b9SAmerigo Wang case R_X86_64_32S: 1570fdc83b9SAmerigo Wang *(s32 *)loc = val; 1580fdc83b9SAmerigo Wang if ((s64)val != *(s32 *)loc) 1590fdc83b9SAmerigo Wang goto overflow; 1600fdc83b9SAmerigo Wang break; 1610fdc83b9SAmerigo Wang case R_X86_64_PC32: 1620fdc83b9SAmerigo Wang val -= (u64)loc; 1630fdc83b9SAmerigo Wang *(u32 *)loc = val; 1640fdc83b9SAmerigo Wang #if 0 1650fdc83b9SAmerigo Wang if ((s64)val != *(s32 *)loc) 1660fdc83b9SAmerigo Wang goto overflow; 1670fdc83b9SAmerigo Wang #endif 1680fdc83b9SAmerigo Wang break; 1690fdc83b9SAmerigo Wang default: 1700fdc83b9SAmerigo Wang printk(KERN_ERR "module %s: Unknown rela relocation: %llu\n", 1710fdc83b9SAmerigo Wang me->name, ELF64_R_TYPE(rel[i].r_info)); 1720fdc83b9SAmerigo Wang return -ENOEXEC; 1730fdc83b9SAmerigo Wang } 1740fdc83b9SAmerigo Wang } 1750fdc83b9SAmerigo Wang return 0; 1760fdc83b9SAmerigo Wang 1770fdc83b9SAmerigo Wang overflow: 1780fdc83b9SAmerigo Wang printk(KERN_ERR "overflow in relocation type %d val %Lx\n", 1790fdc83b9SAmerigo Wang (int)ELF64_R_TYPE(rel[i].r_info), val); 1800fdc83b9SAmerigo Wang printk(KERN_ERR "`%s' likely not compiled with -mcmodel=kernel\n", 1810fdc83b9SAmerigo Wang me->name); 1820fdc83b9SAmerigo Wang return -ENOEXEC; 1830fdc83b9SAmerigo Wang } 1840fdc83b9SAmerigo Wang 1850fdc83b9SAmerigo Wang int apply_relocate(Elf_Shdr *sechdrs, 1860fdc83b9SAmerigo Wang const char *strtab, 1870fdc83b9SAmerigo Wang unsigned int symindex, 1880fdc83b9SAmerigo Wang unsigned int relsec, 1890fdc83b9SAmerigo Wang struct module *me) 1900fdc83b9SAmerigo Wang { 1910fdc83b9SAmerigo Wang printk(KERN_ERR "non add relocation not supported\n"); 1920fdc83b9SAmerigo Wang return -ENOSYS; 1930fdc83b9SAmerigo Wang } 1940fdc83b9SAmerigo Wang 1950fdc83b9SAmerigo Wang #endif 1960fdc83b9SAmerigo Wang 1972d5bf28fSAmerigo Wang int module_finalize(const Elf_Ehdr *hdr, 1982d5bf28fSAmerigo Wang const Elf_Shdr *sechdrs, 1992d5bf28fSAmerigo Wang struct module *me) 2002d5bf28fSAmerigo Wang { 2012d5bf28fSAmerigo Wang const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL, 2022d5bf28fSAmerigo Wang *para = NULL; 2032d5bf28fSAmerigo Wang char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 2042d5bf28fSAmerigo Wang 2052d5bf28fSAmerigo Wang for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { 2062d5bf28fSAmerigo Wang if (!strcmp(".text", secstrings + s->sh_name)) 2072d5bf28fSAmerigo Wang text = s; 2082d5bf28fSAmerigo Wang if (!strcmp(".altinstructions", secstrings + s->sh_name)) 2092d5bf28fSAmerigo Wang alt = s; 2102d5bf28fSAmerigo Wang if (!strcmp(".smp_locks", secstrings + s->sh_name)) 2112d5bf28fSAmerigo Wang locks = s; 2122d5bf28fSAmerigo Wang if (!strcmp(".parainstructions", secstrings + s->sh_name)) 2132d5bf28fSAmerigo Wang para = s; 2142d5bf28fSAmerigo Wang } 2152d5bf28fSAmerigo Wang 2162d5bf28fSAmerigo Wang if (alt) { 2172d5bf28fSAmerigo Wang /* patch .altinstructions */ 2182d5bf28fSAmerigo Wang void *aseg = (void *)alt->sh_addr; 2192d5bf28fSAmerigo Wang apply_alternatives(aseg, aseg + alt->sh_size); 2202d5bf28fSAmerigo Wang } 2212d5bf28fSAmerigo Wang if (locks && text) { 2222d5bf28fSAmerigo Wang void *lseg = (void *)locks->sh_addr; 2232d5bf28fSAmerigo Wang void *tseg = (void *)text->sh_addr; 2242d5bf28fSAmerigo Wang alternatives_smp_module_add(me, me->name, 2252d5bf28fSAmerigo Wang lseg, lseg + locks->sh_size, 2262d5bf28fSAmerigo Wang tseg, tseg + text->sh_size); 2272d5bf28fSAmerigo Wang } 2282d5bf28fSAmerigo Wang 2292d5bf28fSAmerigo Wang if (para) { 2302d5bf28fSAmerigo Wang void *pseg = (void *)para->sh_addr; 2312d5bf28fSAmerigo Wang apply_paravirt(pseg, pseg + para->sh_size); 2322d5bf28fSAmerigo Wang } 2332d5bf28fSAmerigo Wang 234d9f5ab7bSJason Baron /* make jump label nops */ 235d9f5ab7bSJason Baron jump_label_apply_nops(me); 236d9f5ab7bSJason Baron 2375336377dSLinus Torvalds return 0; 2382d5bf28fSAmerigo Wang } 2392d5bf28fSAmerigo Wang 2402d5bf28fSAmerigo Wang void module_arch_cleanup(struct module *mod) 2412d5bf28fSAmerigo Wang { 2422d5bf28fSAmerigo Wang alternatives_smp_module_del(mod); 2432d5bf28fSAmerigo Wang } 244