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 */ 18*c767a54bSJoe Perches 19*c767a54bSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 20*c767a54bSJoe Perches 212d5bf28fSAmerigo Wang #include <linux/moduleloader.h> 222d5bf28fSAmerigo Wang #include <linux/elf.h> 232d5bf28fSAmerigo Wang #include <linux/vmalloc.h> 242d5bf28fSAmerigo Wang #include <linux/fs.h> 252d5bf28fSAmerigo Wang #include <linux/string.h> 262d5bf28fSAmerigo Wang #include <linux/kernel.h> 272d5bf28fSAmerigo Wang #include <linux/bug.h> 282d5bf28fSAmerigo Wang #include <linux/mm.h> 295a0e3ad6STejun Heo #include <linux/gfp.h> 30d430d3d7SJason Baron #include <linux/jump_label.h> 312d5bf28fSAmerigo Wang 322d5bf28fSAmerigo Wang #include <asm/page.h> 332d5bf28fSAmerigo Wang #include <asm/pgtable.h> 342d5bf28fSAmerigo Wang 352d5bf28fSAmerigo Wang #if 0 36*c767a54bSJoe Perches #define DEBUGP(fmt, ...) \ 37*c767a54bSJoe Perches printk(KERN_DEBUG fmt, ##__VA_ARGS__) 382d5bf28fSAmerigo Wang #else 39*c767a54bSJoe Perches #define DEBUGP(fmt, ...) \ 40*c767a54bSJoe Perches do { \ 41*c767a54bSJoe Perches if (0) \ 42*c767a54bSJoe Perches printk(KERN_DEBUG fmt, ##__VA_ARGS__); \ 43*c767a54bSJoe Perches } while (0) 442d5bf28fSAmerigo Wang #endif 452d5bf28fSAmerigo Wang 460fdc83b9SAmerigo Wang void *module_alloc(unsigned long size) 470fdc83b9SAmerigo Wang { 48d0a21265SDavid Rientjes if (PAGE_ALIGN(size) > MODULES_LEN) 490fdc83b9SAmerigo Wang return NULL; 50d0a21265SDavid Rientjes return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, 51d0a21265SDavid Rientjes GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC, 52d0a21265SDavid Rientjes -1, __builtin_return_address(0)); 530fdc83b9SAmerigo Wang } 540fdc83b9SAmerigo Wang 550fdc83b9SAmerigo Wang #ifdef CONFIG_X86_32 560fdc83b9SAmerigo Wang int apply_relocate(Elf32_Shdr *sechdrs, 570fdc83b9SAmerigo Wang const char *strtab, 580fdc83b9SAmerigo Wang unsigned int symindex, 590fdc83b9SAmerigo Wang unsigned int relsec, 600fdc83b9SAmerigo Wang struct module *me) 610fdc83b9SAmerigo Wang { 620fdc83b9SAmerigo Wang unsigned int i; 630fdc83b9SAmerigo Wang Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; 640fdc83b9SAmerigo Wang Elf32_Sym *sym; 650fdc83b9SAmerigo Wang uint32_t *location; 660fdc83b9SAmerigo Wang 67*c767a54bSJoe Perches DEBUGP("Applying relocate section %u to %u\n", 68*c767a54bSJoe Perches relsec, sechdrs[relsec].sh_info); 690fdc83b9SAmerigo Wang for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 700fdc83b9SAmerigo Wang /* This is where to make the change */ 710fdc83b9SAmerigo Wang location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 720fdc83b9SAmerigo Wang + rel[i].r_offset; 730fdc83b9SAmerigo Wang /* This is the symbol it is referring to. Note that all 740fdc83b9SAmerigo Wang undefined symbols have been resolved. */ 750fdc83b9SAmerigo Wang sym = (Elf32_Sym *)sechdrs[symindex].sh_addr 760fdc83b9SAmerigo Wang + ELF32_R_SYM(rel[i].r_info); 770fdc83b9SAmerigo Wang 780fdc83b9SAmerigo Wang switch (ELF32_R_TYPE(rel[i].r_info)) { 790fdc83b9SAmerigo Wang case R_386_32: 800fdc83b9SAmerigo Wang /* We add the value into the location given */ 810fdc83b9SAmerigo Wang *location += sym->st_value; 820fdc83b9SAmerigo Wang break; 830fdc83b9SAmerigo Wang case R_386_PC32: 840fdc83b9SAmerigo Wang /* Add the value, subtract its postition */ 850fdc83b9SAmerigo Wang *location += sym->st_value - (uint32_t)location; 860fdc83b9SAmerigo Wang break; 870fdc83b9SAmerigo Wang default: 88*c767a54bSJoe Perches pr_err("%s: Unknown relocation: %u\n", 890fdc83b9SAmerigo Wang me->name, ELF32_R_TYPE(rel[i].r_info)); 900fdc83b9SAmerigo Wang return -ENOEXEC; 910fdc83b9SAmerigo Wang } 920fdc83b9SAmerigo Wang } 930fdc83b9SAmerigo Wang return 0; 940fdc83b9SAmerigo Wang } 950fdc83b9SAmerigo Wang #else /*X86_64*/ 960fdc83b9SAmerigo Wang int apply_relocate_add(Elf64_Shdr *sechdrs, 970fdc83b9SAmerigo Wang const char *strtab, 980fdc83b9SAmerigo Wang unsigned int symindex, 990fdc83b9SAmerigo Wang unsigned int relsec, 1000fdc83b9SAmerigo Wang struct module *me) 1010fdc83b9SAmerigo Wang { 1020fdc83b9SAmerigo Wang unsigned int i; 1030fdc83b9SAmerigo Wang Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; 1040fdc83b9SAmerigo Wang Elf64_Sym *sym; 1050fdc83b9SAmerigo Wang void *loc; 1060fdc83b9SAmerigo Wang u64 val; 1070fdc83b9SAmerigo Wang 108*c767a54bSJoe Perches DEBUGP("Applying relocate section %u to %u\n", 109*c767a54bSJoe Perches relsec, sechdrs[relsec].sh_info); 1100fdc83b9SAmerigo Wang for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 1110fdc83b9SAmerigo Wang /* This is where to make the change */ 1120fdc83b9SAmerigo Wang loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 1130fdc83b9SAmerigo Wang + rel[i].r_offset; 1140fdc83b9SAmerigo Wang 1150fdc83b9SAmerigo Wang /* This is the symbol it is referring to. Note that all 1160fdc83b9SAmerigo Wang undefined symbols have been resolved. */ 1170fdc83b9SAmerigo Wang sym = (Elf64_Sym *)sechdrs[symindex].sh_addr 1180fdc83b9SAmerigo Wang + ELF64_R_SYM(rel[i].r_info); 1190fdc83b9SAmerigo Wang 1200fdc83b9SAmerigo Wang DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n", 1210fdc83b9SAmerigo Wang (int)ELF64_R_TYPE(rel[i].r_info), 1220fdc83b9SAmerigo Wang sym->st_value, rel[i].r_addend, (u64)loc); 1230fdc83b9SAmerigo Wang 1240fdc83b9SAmerigo Wang val = sym->st_value + rel[i].r_addend; 1250fdc83b9SAmerigo Wang 1260fdc83b9SAmerigo Wang switch (ELF64_R_TYPE(rel[i].r_info)) { 1270fdc83b9SAmerigo Wang case R_X86_64_NONE: 1280fdc83b9SAmerigo Wang break; 1290fdc83b9SAmerigo Wang case R_X86_64_64: 1300fdc83b9SAmerigo Wang *(u64 *)loc = val; 1310fdc83b9SAmerigo Wang break; 1320fdc83b9SAmerigo Wang case R_X86_64_32: 1330fdc83b9SAmerigo Wang *(u32 *)loc = val; 1340fdc83b9SAmerigo Wang if (val != *(u32 *)loc) 1350fdc83b9SAmerigo Wang goto overflow; 1360fdc83b9SAmerigo Wang break; 1370fdc83b9SAmerigo Wang case R_X86_64_32S: 1380fdc83b9SAmerigo Wang *(s32 *)loc = val; 1390fdc83b9SAmerigo Wang if ((s64)val != *(s32 *)loc) 1400fdc83b9SAmerigo Wang goto overflow; 1410fdc83b9SAmerigo Wang break; 1420fdc83b9SAmerigo Wang case R_X86_64_PC32: 1430fdc83b9SAmerigo Wang val -= (u64)loc; 1440fdc83b9SAmerigo Wang *(u32 *)loc = val; 1450fdc83b9SAmerigo Wang #if 0 1460fdc83b9SAmerigo Wang if ((s64)val != *(s32 *)loc) 1470fdc83b9SAmerigo Wang goto overflow; 1480fdc83b9SAmerigo Wang #endif 1490fdc83b9SAmerigo Wang break; 1500fdc83b9SAmerigo Wang default: 151*c767a54bSJoe Perches pr_err("%s: Unknown rela relocation: %llu\n", 1520fdc83b9SAmerigo Wang me->name, ELF64_R_TYPE(rel[i].r_info)); 1530fdc83b9SAmerigo Wang return -ENOEXEC; 1540fdc83b9SAmerigo Wang } 1550fdc83b9SAmerigo Wang } 1560fdc83b9SAmerigo Wang return 0; 1570fdc83b9SAmerigo Wang 1580fdc83b9SAmerigo Wang overflow: 159*c767a54bSJoe Perches pr_err("overflow in relocation type %d val %Lx\n", 1600fdc83b9SAmerigo Wang (int)ELF64_R_TYPE(rel[i].r_info), val); 161*c767a54bSJoe Perches pr_err("`%s' likely not compiled with -mcmodel=kernel\n", 1620fdc83b9SAmerigo Wang me->name); 1630fdc83b9SAmerigo Wang return -ENOEXEC; 1640fdc83b9SAmerigo Wang } 1650fdc83b9SAmerigo Wang #endif 1660fdc83b9SAmerigo Wang 1672d5bf28fSAmerigo Wang int module_finalize(const Elf_Ehdr *hdr, 1682d5bf28fSAmerigo Wang const Elf_Shdr *sechdrs, 1692d5bf28fSAmerigo Wang struct module *me) 1702d5bf28fSAmerigo Wang { 1712d5bf28fSAmerigo Wang const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL, 1722d5bf28fSAmerigo Wang *para = NULL; 1732d5bf28fSAmerigo Wang char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 1742d5bf28fSAmerigo Wang 1752d5bf28fSAmerigo Wang for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { 1762d5bf28fSAmerigo Wang if (!strcmp(".text", secstrings + s->sh_name)) 1772d5bf28fSAmerigo Wang text = s; 1782d5bf28fSAmerigo Wang if (!strcmp(".altinstructions", secstrings + s->sh_name)) 1792d5bf28fSAmerigo Wang alt = s; 1802d5bf28fSAmerigo Wang if (!strcmp(".smp_locks", secstrings + s->sh_name)) 1812d5bf28fSAmerigo Wang locks = s; 1822d5bf28fSAmerigo Wang if (!strcmp(".parainstructions", secstrings + s->sh_name)) 1832d5bf28fSAmerigo Wang para = s; 1842d5bf28fSAmerigo Wang } 1852d5bf28fSAmerigo Wang 1862d5bf28fSAmerigo Wang if (alt) { 1872d5bf28fSAmerigo Wang /* patch .altinstructions */ 1882d5bf28fSAmerigo Wang void *aseg = (void *)alt->sh_addr; 1892d5bf28fSAmerigo Wang apply_alternatives(aseg, aseg + alt->sh_size); 1902d5bf28fSAmerigo Wang } 1912d5bf28fSAmerigo Wang if (locks && text) { 1922d5bf28fSAmerigo Wang void *lseg = (void *)locks->sh_addr; 1932d5bf28fSAmerigo Wang void *tseg = (void *)text->sh_addr; 1942d5bf28fSAmerigo Wang alternatives_smp_module_add(me, me->name, 1952d5bf28fSAmerigo Wang lseg, lseg + locks->sh_size, 1962d5bf28fSAmerigo Wang tseg, tseg + text->sh_size); 1972d5bf28fSAmerigo Wang } 1982d5bf28fSAmerigo Wang 1992d5bf28fSAmerigo Wang if (para) { 2002d5bf28fSAmerigo Wang void *pseg = (void *)para->sh_addr; 2012d5bf28fSAmerigo Wang apply_paravirt(pseg, pseg + para->sh_size); 2022d5bf28fSAmerigo Wang } 2032d5bf28fSAmerigo Wang 204d9f5ab7bSJason Baron /* make jump label nops */ 205d9f5ab7bSJason Baron jump_label_apply_nops(me); 206d9f5ab7bSJason Baron 2075336377dSLinus Torvalds return 0; 2082d5bf28fSAmerigo Wang } 2092d5bf28fSAmerigo Wang 2102d5bf28fSAmerigo Wang void module_arch_cleanup(struct module *mod) 2112d5bf28fSAmerigo Wang { 2122d5bf28fSAmerigo Wang alternatives_smp_module_del(mod); 2132d5bf28fSAmerigo Wang } 214