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> 27d430d3d7SJason Baron #include <linux/jump_label.h> 282d5bf28fSAmerigo Wang 292d5bf28fSAmerigo Wang #include <asm/page.h> 302d5bf28fSAmerigo Wang #include <asm/pgtable.h> 312d5bf28fSAmerigo Wang 322d5bf28fSAmerigo Wang #if 0 332d5bf28fSAmerigo Wang #define DEBUGP printk 342d5bf28fSAmerigo Wang #else 352d5bf28fSAmerigo Wang #define DEBUGP(fmt...) 362d5bf28fSAmerigo Wang #endif 372d5bf28fSAmerigo Wang 380fdc83b9SAmerigo Wang void *module_alloc(unsigned long size) 390fdc83b9SAmerigo Wang { 40d0a21265SDavid Rientjes if (PAGE_ALIGN(size) > MODULES_LEN) 410fdc83b9SAmerigo Wang return NULL; 42d0a21265SDavid Rientjes return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, 43d0a21265SDavid Rientjes GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC, 44d0a21265SDavid Rientjes -1, __builtin_return_address(0)); 450fdc83b9SAmerigo Wang } 460fdc83b9SAmerigo Wang 470fdc83b9SAmerigo Wang #ifdef CONFIG_X86_32 480fdc83b9SAmerigo Wang int apply_relocate(Elf32_Shdr *sechdrs, 490fdc83b9SAmerigo Wang const char *strtab, 500fdc83b9SAmerigo Wang unsigned int symindex, 510fdc83b9SAmerigo Wang unsigned int relsec, 520fdc83b9SAmerigo Wang struct module *me) 530fdc83b9SAmerigo Wang { 540fdc83b9SAmerigo Wang unsigned int i; 550fdc83b9SAmerigo Wang Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; 560fdc83b9SAmerigo Wang Elf32_Sym *sym; 570fdc83b9SAmerigo Wang uint32_t *location; 580fdc83b9SAmerigo Wang 590fdc83b9SAmerigo Wang DEBUGP("Applying relocate section %u to %u\n", relsec, 600fdc83b9SAmerigo Wang sechdrs[relsec].sh_info); 610fdc83b9SAmerigo Wang for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 620fdc83b9SAmerigo Wang /* This is where to make the change */ 630fdc83b9SAmerigo Wang location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 640fdc83b9SAmerigo Wang + rel[i].r_offset; 650fdc83b9SAmerigo Wang /* This is the symbol it is referring to. Note that all 660fdc83b9SAmerigo Wang undefined symbols have been resolved. */ 670fdc83b9SAmerigo Wang sym = (Elf32_Sym *)sechdrs[symindex].sh_addr 680fdc83b9SAmerigo Wang + ELF32_R_SYM(rel[i].r_info); 690fdc83b9SAmerigo Wang 700fdc83b9SAmerigo Wang switch (ELF32_R_TYPE(rel[i].r_info)) { 710fdc83b9SAmerigo Wang case R_386_32: 720fdc83b9SAmerigo Wang /* We add the value into the location given */ 730fdc83b9SAmerigo Wang *location += sym->st_value; 740fdc83b9SAmerigo Wang break; 750fdc83b9SAmerigo Wang case R_386_PC32: 76*2e76c283SGeert Uytterhoeven /* Add the value, subtract its position */ 770fdc83b9SAmerigo Wang *location += sym->st_value - (uint32_t)location; 780fdc83b9SAmerigo Wang break; 790fdc83b9SAmerigo Wang default: 800fdc83b9SAmerigo Wang printk(KERN_ERR "module %s: Unknown relocation: %u\n", 810fdc83b9SAmerigo Wang me->name, ELF32_R_TYPE(rel[i].r_info)); 820fdc83b9SAmerigo Wang return -ENOEXEC; 830fdc83b9SAmerigo Wang } 840fdc83b9SAmerigo Wang } 850fdc83b9SAmerigo Wang return 0; 860fdc83b9SAmerigo Wang } 870fdc83b9SAmerigo Wang #else /*X86_64*/ 880fdc83b9SAmerigo Wang int apply_relocate_add(Elf64_Shdr *sechdrs, 890fdc83b9SAmerigo Wang const char *strtab, 900fdc83b9SAmerigo Wang unsigned int symindex, 910fdc83b9SAmerigo Wang unsigned int relsec, 920fdc83b9SAmerigo Wang struct module *me) 930fdc83b9SAmerigo Wang { 940fdc83b9SAmerigo Wang unsigned int i; 950fdc83b9SAmerigo Wang Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; 960fdc83b9SAmerigo Wang Elf64_Sym *sym; 970fdc83b9SAmerigo Wang void *loc; 980fdc83b9SAmerigo Wang u64 val; 990fdc83b9SAmerigo Wang 1000fdc83b9SAmerigo Wang DEBUGP("Applying relocate section %u to %u\n", relsec, 1010fdc83b9SAmerigo Wang sechdrs[relsec].sh_info); 1020fdc83b9SAmerigo Wang for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 1030fdc83b9SAmerigo Wang /* This is where to make the change */ 1040fdc83b9SAmerigo Wang loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 1050fdc83b9SAmerigo Wang + rel[i].r_offset; 1060fdc83b9SAmerigo Wang 1070fdc83b9SAmerigo Wang /* This is the symbol it is referring to. Note that all 1080fdc83b9SAmerigo Wang undefined symbols have been resolved. */ 1090fdc83b9SAmerigo Wang sym = (Elf64_Sym *)sechdrs[symindex].sh_addr 1100fdc83b9SAmerigo Wang + ELF64_R_SYM(rel[i].r_info); 1110fdc83b9SAmerigo Wang 1120fdc83b9SAmerigo Wang DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n", 1130fdc83b9SAmerigo Wang (int)ELF64_R_TYPE(rel[i].r_info), 1140fdc83b9SAmerigo Wang sym->st_value, rel[i].r_addend, (u64)loc); 1150fdc83b9SAmerigo Wang 1160fdc83b9SAmerigo Wang val = sym->st_value + rel[i].r_addend; 1170fdc83b9SAmerigo Wang 1180fdc83b9SAmerigo Wang switch (ELF64_R_TYPE(rel[i].r_info)) { 1190fdc83b9SAmerigo Wang case R_X86_64_NONE: 1200fdc83b9SAmerigo Wang break; 1210fdc83b9SAmerigo Wang case R_X86_64_64: 1220fdc83b9SAmerigo Wang *(u64 *)loc = val; 1230fdc83b9SAmerigo Wang break; 1240fdc83b9SAmerigo Wang case R_X86_64_32: 1250fdc83b9SAmerigo Wang *(u32 *)loc = val; 1260fdc83b9SAmerigo Wang if (val != *(u32 *)loc) 1270fdc83b9SAmerigo Wang goto overflow; 1280fdc83b9SAmerigo Wang break; 1290fdc83b9SAmerigo Wang case R_X86_64_32S: 1300fdc83b9SAmerigo Wang *(s32 *)loc = val; 1310fdc83b9SAmerigo Wang if ((s64)val != *(s32 *)loc) 1320fdc83b9SAmerigo Wang goto overflow; 1330fdc83b9SAmerigo Wang break; 1340fdc83b9SAmerigo Wang case R_X86_64_PC32: 1350fdc83b9SAmerigo Wang val -= (u64)loc; 1360fdc83b9SAmerigo Wang *(u32 *)loc = val; 1370fdc83b9SAmerigo Wang #if 0 1380fdc83b9SAmerigo Wang if ((s64)val != *(s32 *)loc) 1390fdc83b9SAmerigo Wang goto overflow; 1400fdc83b9SAmerigo Wang #endif 1410fdc83b9SAmerigo Wang break; 1420fdc83b9SAmerigo Wang default: 1430fdc83b9SAmerigo Wang printk(KERN_ERR "module %s: Unknown rela relocation: %llu\n", 1440fdc83b9SAmerigo Wang me->name, ELF64_R_TYPE(rel[i].r_info)); 1450fdc83b9SAmerigo Wang return -ENOEXEC; 1460fdc83b9SAmerigo Wang } 1470fdc83b9SAmerigo Wang } 1480fdc83b9SAmerigo Wang return 0; 1490fdc83b9SAmerigo Wang 1500fdc83b9SAmerigo Wang overflow: 1510fdc83b9SAmerigo Wang printk(KERN_ERR "overflow in relocation type %d val %Lx\n", 1520fdc83b9SAmerigo Wang (int)ELF64_R_TYPE(rel[i].r_info), val); 1530fdc83b9SAmerigo Wang printk(KERN_ERR "`%s' likely not compiled with -mcmodel=kernel\n", 1540fdc83b9SAmerigo Wang me->name); 1550fdc83b9SAmerigo Wang return -ENOEXEC; 1560fdc83b9SAmerigo Wang } 1570fdc83b9SAmerigo Wang #endif 1580fdc83b9SAmerigo Wang 1592d5bf28fSAmerigo Wang int module_finalize(const Elf_Ehdr *hdr, 1602d5bf28fSAmerigo Wang const Elf_Shdr *sechdrs, 1612d5bf28fSAmerigo Wang struct module *me) 1622d5bf28fSAmerigo Wang { 1632d5bf28fSAmerigo Wang const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL, 1642d5bf28fSAmerigo Wang *para = NULL; 1652d5bf28fSAmerigo Wang char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 1662d5bf28fSAmerigo Wang 1672d5bf28fSAmerigo Wang for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { 1682d5bf28fSAmerigo Wang if (!strcmp(".text", secstrings + s->sh_name)) 1692d5bf28fSAmerigo Wang text = s; 1702d5bf28fSAmerigo Wang if (!strcmp(".altinstructions", secstrings + s->sh_name)) 1712d5bf28fSAmerigo Wang alt = s; 1722d5bf28fSAmerigo Wang if (!strcmp(".smp_locks", secstrings + s->sh_name)) 1732d5bf28fSAmerigo Wang locks = s; 1742d5bf28fSAmerigo Wang if (!strcmp(".parainstructions", secstrings + s->sh_name)) 1752d5bf28fSAmerigo Wang para = s; 1762d5bf28fSAmerigo Wang } 1772d5bf28fSAmerigo Wang 1782d5bf28fSAmerigo Wang if (alt) { 1792d5bf28fSAmerigo Wang /* patch .altinstructions */ 1802d5bf28fSAmerigo Wang void *aseg = (void *)alt->sh_addr; 1812d5bf28fSAmerigo Wang apply_alternatives(aseg, aseg + alt->sh_size); 1822d5bf28fSAmerigo Wang } 1832d5bf28fSAmerigo Wang if (locks && text) { 1842d5bf28fSAmerigo Wang void *lseg = (void *)locks->sh_addr; 1852d5bf28fSAmerigo Wang void *tseg = (void *)text->sh_addr; 1862d5bf28fSAmerigo Wang alternatives_smp_module_add(me, me->name, 1872d5bf28fSAmerigo Wang lseg, lseg + locks->sh_size, 1882d5bf28fSAmerigo Wang tseg, tseg + text->sh_size); 1892d5bf28fSAmerigo Wang } 1902d5bf28fSAmerigo Wang 1912d5bf28fSAmerigo Wang if (para) { 1922d5bf28fSAmerigo Wang void *pseg = (void *)para->sh_addr; 1932d5bf28fSAmerigo Wang apply_paravirt(pseg, pseg + para->sh_size); 1942d5bf28fSAmerigo Wang } 1952d5bf28fSAmerigo Wang 196d9f5ab7bSJason Baron /* make jump label nops */ 197d9f5ab7bSJason Baron jump_label_apply_nops(me); 198d9f5ab7bSJason Baron 1995336377dSLinus Torvalds return 0; 2002d5bf28fSAmerigo Wang } 2012d5bf28fSAmerigo Wang 2022d5bf28fSAmerigo Wang void module_arch_cleanup(struct module *mod) 2032d5bf28fSAmerigo Wang { 2042d5bf28fSAmerigo Wang alternatives_smp_module_del(mod); 2052d5bf28fSAmerigo Wang } 206