xref: /openbmc/linux/arch/x86/kernel/module.c (revision 2e76c2838a2c1c6c5c220410bcd3c0d6d82e4e31)
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