xref: /openbmc/linux/arch/x86/kernel/module.c (revision d9f5ab7b1c0a520867af389bab5d5fcdbd0e407e)
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>
272d5bf28fSAmerigo Wang 
282d5bf28fSAmerigo Wang #include <asm/system.h>
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 {
400fdc83b9SAmerigo Wang 	struct vm_struct *area;
410fdc83b9SAmerigo Wang 
420fdc83b9SAmerigo Wang 	if (!size)
430fdc83b9SAmerigo Wang 		return NULL;
440fdc83b9SAmerigo Wang 	size = PAGE_ALIGN(size);
450fdc83b9SAmerigo Wang 	if (size > MODULES_LEN)
460fdc83b9SAmerigo Wang 		return NULL;
470fdc83b9SAmerigo Wang 
480fdc83b9SAmerigo Wang 	area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
490fdc83b9SAmerigo Wang 	if (!area)
500fdc83b9SAmerigo Wang 		return NULL;
510fdc83b9SAmerigo Wang 
52c398df30SAmerigo Wang 	return __vmalloc_area(area, GFP_KERNEL | __GFP_HIGHMEM,
53c398df30SAmerigo Wang 					PAGE_KERNEL_EXEC);
540fdc83b9SAmerigo Wang }
550fdc83b9SAmerigo Wang 
562d5bf28fSAmerigo Wang /* Free memory returned from module_alloc */
572d5bf28fSAmerigo Wang void module_free(struct module *mod, void *module_region)
582d5bf28fSAmerigo Wang {
592d5bf28fSAmerigo Wang 	vfree(module_region);
602d5bf28fSAmerigo Wang }
612d5bf28fSAmerigo Wang 
622d5bf28fSAmerigo Wang /* We don't need anything special. */
632d5bf28fSAmerigo Wang int module_frob_arch_sections(Elf_Ehdr *hdr,
642d5bf28fSAmerigo Wang 			      Elf_Shdr *sechdrs,
652d5bf28fSAmerigo Wang 			      char *secstrings,
662d5bf28fSAmerigo Wang 			      struct module *mod)
672d5bf28fSAmerigo Wang {
682d5bf28fSAmerigo Wang 	return 0;
692d5bf28fSAmerigo Wang }
702d5bf28fSAmerigo Wang 
710fdc83b9SAmerigo Wang #ifdef CONFIG_X86_32
720fdc83b9SAmerigo Wang int apply_relocate(Elf32_Shdr *sechdrs,
730fdc83b9SAmerigo Wang 		   const char *strtab,
740fdc83b9SAmerigo Wang 		   unsigned int symindex,
750fdc83b9SAmerigo Wang 		   unsigned int relsec,
760fdc83b9SAmerigo Wang 		   struct module *me)
770fdc83b9SAmerigo Wang {
780fdc83b9SAmerigo Wang 	unsigned int i;
790fdc83b9SAmerigo Wang 	Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
800fdc83b9SAmerigo Wang 	Elf32_Sym *sym;
810fdc83b9SAmerigo Wang 	uint32_t *location;
820fdc83b9SAmerigo Wang 
830fdc83b9SAmerigo Wang 	DEBUGP("Applying relocate section %u to %u\n", relsec,
840fdc83b9SAmerigo Wang 	       sechdrs[relsec].sh_info);
850fdc83b9SAmerigo Wang 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
860fdc83b9SAmerigo Wang 		/* This is where to make the change */
870fdc83b9SAmerigo Wang 		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
880fdc83b9SAmerigo Wang 			+ rel[i].r_offset;
890fdc83b9SAmerigo Wang 		/* This is the symbol it is referring to.  Note that all
900fdc83b9SAmerigo Wang 		   undefined symbols have been resolved.  */
910fdc83b9SAmerigo Wang 		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
920fdc83b9SAmerigo Wang 			+ ELF32_R_SYM(rel[i].r_info);
930fdc83b9SAmerigo Wang 
940fdc83b9SAmerigo Wang 		switch (ELF32_R_TYPE(rel[i].r_info)) {
950fdc83b9SAmerigo Wang 		case R_386_32:
960fdc83b9SAmerigo Wang 			/* We add the value into the location given */
970fdc83b9SAmerigo Wang 			*location += sym->st_value;
980fdc83b9SAmerigo Wang 			break;
990fdc83b9SAmerigo Wang 		case R_386_PC32:
1000fdc83b9SAmerigo Wang 			/* Add the value, subtract its postition */
1010fdc83b9SAmerigo Wang 			*location += sym->st_value - (uint32_t)location;
1020fdc83b9SAmerigo Wang 			break;
1030fdc83b9SAmerigo Wang 		default:
1040fdc83b9SAmerigo Wang 			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
1050fdc83b9SAmerigo Wang 			       me->name, ELF32_R_TYPE(rel[i].r_info));
1060fdc83b9SAmerigo Wang 			return -ENOEXEC;
1070fdc83b9SAmerigo Wang 		}
1080fdc83b9SAmerigo Wang 	}
1090fdc83b9SAmerigo Wang 	return 0;
1100fdc83b9SAmerigo Wang }
1110fdc83b9SAmerigo Wang 
1120fdc83b9SAmerigo Wang int apply_relocate_add(Elf32_Shdr *sechdrs,
1130fdc83b9SAmerigo Wang 		       const char *strtab,
1140fdc83b9SAmerigo Wang 		       unsigned int symindex,
1150fdc83b9SAmerigo Wang 		       unsigned int relsec,
1160fdc83b9SAmerigo Wang 		       struct module *me)
1170fdc83b9SAmerigo Wang {
1180fdc83b9SAmerigo Wang 	printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
1190fdc83b9SAmerigo Wang 	       me->name);
1200fdc83b9SAmerigo Wang 	return -ENOEXEC;
1210fdc83b9SAmerigo Wang }
1220fdc83b9SAmerigo Wang #else /*X86_64*/
1230fdc83b9SAmerigo Wang int apply_relocate_add(Elf64_Shdr *sechdrs,
1240fdc83b9SAmerigo Wang 		   const char *strtab,
1250fdc83b9SAmerigo Wang 		   unsigned int symindex,
1260fdc83b9SAmerigo Wang 		   unsigned int relsec,
1270fdc83b9SAmerigo Wang 		   struct module *me)
1280fdc83b9SAmerigo Wang {
1290fdc83b9SAmerigo Wang 	unsigned int i;
1300fdc83b9SAmerigo Wang 	Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
1310fdc83b9SAmerigo Wang 	Elf64_Sym *sym;
1320fdc83b9SAmerigo Wang 	void *loc;
1330fdc83b9SAmerigo Wang 	u64 val;
1340fdc83b9SAmerigo Wang 
1350fdc83b9SAmerigo Wang 	DEBUGP("Applying relocate section %u to %u\n", relsec,
1360fdc83b9SAmerigo Wang 	       sechdrs[relsec].sh_info);
1370fdc83b9SAmerigo Wang 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
1380fdc83b9SAmerigo Wang 		/* This is where to make the change */
1390fdc83b9SAmerigo Wang 		loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
1400fdc83b9SAmerigo Wang 			+ rel[i].r_offset;
1410fdc83b9SAmerigo Wang 
1420fdc83b9SAmerigo Wang 		/* This is the symbol it is referring to.  Note that all
1430fdc83b9SAmerigo Wang 		   undefined symbols have been resolved.  */
1440fdc83b9SAmerigo Wang 		sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
1450fdc83b9SAmerigo Wang 			+ ELF64_R_SYM(rel[i].r_info);
1460fdc83b9SAmerigo Wang 
1470fdc83b9SAmerigo Wang 		DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
1480fdc83b9SAmerigo Wang 			(int)ELF64_R_TYPE(rel[i].r_info),
1490fdc83b9SAmerigo Wang 			sym->st_value, rel[i].r_addend, (u64)loc);
1500fdc83b9SAmerigo Wang 
1510fdc83b9SAmerigo Wang 		val = sym->st_value + rel[i].r_addend;
1520fdc83b9SAmerigo Wang 
1530fdc83b9SAmerigo Wang 		switch (ELF64_R_TYPE(rel[i].r_info)) {
1540fdc83b9SAmerigo Wang 		case R_X86_64_NONE:
1550fdc83b9SAmerigo Wang 			break;
1560fdc83b9SAmerigo Wang 		case R_X86_64_64:
1570fdc83b9SAmerigo Wang 			*(u64 *)loc = val;
1580fdc83b9SAmerigo Wang 			break;
1590fdc83b9SAmerigo Wang 		case R_X86_64_32:
1600fdc83b9SAmerigo Wang 			*(u32 *)loc = val;
1610fdc83b9SAmerigo Wang 			if (val != *(u32 *)loc)
1620fdc83b9SAmerigo Wang 				goto overflow;
1630fdc83b9SAmerigo Wang 			break;
1640fdc83b9SAmerigo Wang 		case R_X86_64_32S:
1650fdc83b9SAmerigo Wang 			*(s32 *)loc = val;
1660fdc83b9SAmerigo Wang 			if ((s64)val != *(s32 *)loc)
1670fdc83b9SAmerigo Wang 				goto overflow;
1680fdc83b9SAmerigo Wang 			break;
1690fdc83b9SAmerigo Wang 		case R_X86_64_PC32:
1700fdc83b9SAmerigo Wang 			val -= (u64)loc;
1710fdc83b9SAmerigo Wang 			*(u32 *)loc = val;
1720fdc83b9SAmerigo Wang #if 0
1730fdc83b9SAmerigo Wang 			if ((s64)val != *(s32 *)loc)
1740fdc83b9SAmerigo Wang 				goto overflow;
1750fdc83b9SAmerigo Wang #endif
1760fdc83b9SAmerigo Wang 			break;
1770fdc83b9SAmerigo Wang 		default:
1780fdc83b9SAmerigo Wang 			printk(KERN_ERR "module %s: Unknown rela relocation: %llu\n",
1790fdc83b9SAmerigo Wang 			       me->name, ELF64_R_TYPE(rel[i].r_info));
1800fdc83b9SAmerigo Wang 			return -ENOEXEC;
1810fdc83b9SAmerigo Wang 		}
1820fdc83b9SAmerigo Wang 	}
1830fdc83b9SAmerigo Wang 	return 0;
1840fdc83b9SAmerigo Wang 
1850fdc83b9SAmerigo Wang overflow:
1860fdc83b9SAmerigo Wang 	printk(KERN_ERR "overflow in relocation type %d val %Lx\n",
1870fdc83b9SAmerigo Wang 	       (int)ELF64_R_TYPE(rel[i].r_info), val);
1880fdc83b9SAmerigo Wang 	printk(KERN_ERR "`%s' likely not compiled with -mcmodel=kernel\n",
1890fdc83b9SAmerigo Wang 	       me->name);
1900fdc83b9SAmerigo Wang 	return -ENOEXEC;
1910fdc83b9SAmerigo Wang }
1920fdc83b9SAmerigo Wang 
1930fdc83b9SAmerigo Wang int apply_relocate(Elf_Shdr *sechdrs,
1940fdc83b9SAmerigo Wang 		   const char *strtab,
1950fdc83b9SAmerigo Wang 		   unsigned int symindex,
1960fdc83b9SAmerigo Wang 		   unsigned int relsec,
1970fdc83b9SAmerigo Wang 		   struct module *me)
1980fdc83b9SAmerigo Wang {
1990fdc83b9SAmerigo Wang 	printk(KERN_ERR "non add relocation not supported\n");
2000fdc83b9SAmerigo Wang 	return -ENOSYS;
2010fdc83b9SAmerigo Wang }
2020fdc83b9SAmerigo Wang 
2030fdc83b9SAmerigo Wang #endif
2040fdc83b9SAmerigo Wang 
2052d5bf28fSAmerigo Wang int module_finalize(const Elf_Ehdr *hdr,
2062d5bf28fSAmerigo Wang 		    const Elf_Shdr *sechdrs,
2072d5bf28fSAmerigo Wang 		    struct module *me)
2082d5bf28fSAmerigo Wang {
2092d5bf28fSAmerigo Wang 	const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
2102d5bf28fSAmerigo Wang 		*para = NULL;
2112d5bf28fSAmerigo Wang 	char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
2122d5bf28fSAmerigo Wang 
2132d5bf28fSAmerigo Wang 	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
2142d5bf28fSAmerigo Wang 		if (!strcmp(".text", secstrings + s->sh_name))
2152d5bf28fSAmerigo Wang 			text = s;
2162d5bf28fSAmerigo Wang 		if (!strcmp(".altinstructions", secstrings + s->sh_name))
2172d5bf28fSAmerigo Wang 			alt = s;
2182d5bf28fSAmerigo Wang 		if (!strcmp(".smp_locks", secstrings + s->sh_name))
2192d5bf28fSAmerigo Wang 			locks = s;
2202d5bf28fSAmerigo Wang 		if (!strcmp(".parainstructions", secstrings + s->sh_name))
2212d5bf28fSAmerigo Wang 			para = s;
2222d5bf28fSAmerigo Wang 	}
2232d5bf28fSAmerigo Wang 
2242d5bf28fSAmerigo Wang 	if (alt) {
2252d5bf28fSAmerigo Wang 		/* patch .altinstructions */
2262d5bf28fSAmerigo Wang 		void *aseg = (void *)alt->sh_addr;
2272d5bf28fSAmerigo Wang 		apply_alternatives(aseg, aseg + alt->sh_size);
2282d5bf28fSAmerigo Wang 	}
2292d5bf28fSAmerigo Wang 	if (locks && text) {
2302d5bf28fSAmerigo Wang 		void *lseg = (void *)locks->sh_addr;
2312d5bf28fSAmerigo Wang 		void *tseg = (void *)text->sh_addr;
2322d5bf28fSAmerigo Wang 		alternatives_smp_module_add(me, me->name,
2332d5bf28fSAmerigo Wang 					    lseg, lseg + locks->sh_size,
2342d5bf28fSAmerigo Wang 					    tseg, tseg + text->sh_size);
2352d5bf28fSAmerigo Wang 	}
2362d5bf28fSAmerigo Wang 
2372d5bf28fSAmerigo Wang 	if (para) {
2382d5bf28fSAmerigo Wang 		void *pseg = (void *)para->sh_addr;
2392d5bf28fSAmerigo Wang 		apply_paravirt(pseg, pseg + para->sh_size);
2402d5bf28fSAmerigo Wang 	}
2412d5bf28fSAmerigo Wang 
242*d9f5ab7bSJason Baron 	/* make jump label nops */
243*d9f5ab7bSJason Baron 	jump_label_apply_nops(me);
244*d9f5ab7bSJason Baron 
2452d5bf28fSAmerigo Wang 	return module_bug_finalize(hdr, sechdrs, me);
2462d5bf28fSAmerigo Wang }
2472d5bf28fSAmerigo Wang 
2482d5bf28fSAmerigo Wang void module_arch_cleanup(struct module *mod)
2492d5bf28fSAmerigo Wang {
2502d5bf28fSAmerigo Wang 	alternatives_smp_module_del(mod);
2512d5bf28fSAmerigo Wang 	module_bug_cleanup(mod);
2522d5bf28fSAmerigo Wang }
253