xref: /openbmc/linux/arch/x86/kernel/module.c (revision 0fdc83b950df9e2eb45db6fca9c3d92c66fd5028)
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>
262d5bf28fSAmerigo Wang 
272d5bf28fSAmerigo Wang #include <asm/system.h>
282d5bf28fSAmerigo Wang #include <asm/page.h>
292d5bf28fSAmerigo Wang #include <asm/pgtable.h>
302d5bf28fSAmerigo Wang 
312d5bf28fSAmerigo Wang #if 0
322d5bf28fSAmerigo Wang #define DEBUGP printk
332d5bf28fSAmerigo Wang #else
342d5bf28fSAmerigo Wang #define DEBUGP(fmt...)
352d5bf28fSAmerigo Wang #endif
362d5bf28fSAmerigo Wang 
37*0fdc83b9SAmerigo Wang #if defined(CONFIG_UML) || defined(CONFIG_X86_32)
38*0fdc83b9SAmerigo Wang void *module_alloc(unsigned long size)
39*0fdc83b9SAmerigo Wang {
40*0fdc83b9SAmerigo Wang 	if (size == 0)
41*0fdc83b9SAmerigo Wang 		return NULL;
42*0fdc83b9SAmerigo Wang 	return vmalloc_exec(size);
43*0fdc83b9SAmerigo Wang }
44*0fdc83b9SAmerigo Wang #else /*X86_64*/
45*0fdc83b9SAmerigo Wang void *module_alloc(unsigned long size)
46*0fdc83b9SAmerigo Wang {
47*0fdc83b9SAmerigo Wang 	struct vm_struct *area;
48*0fdc83b9SAmerigo Wang 
49*0fdc83b9SAmerigo Wang 	if (!size)
50*0fdc83b9SAmerigo Wang 		return NULL;
51*0fdc83b9SAmerigo Wang 	size = PAGE_ALIGN(size);
52*0fdc83b9SAmerigo Wang 	if (size > MODULES_LEN)
53*0fdc83b9SAmerigo Wang 		return NULL;
54*0fdc83b9SAmerigo Wang 
55*0fdc83b9SAmerigo Wang 	area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
56*0fdc83b9SAmerigo Wang 	if (!area)
57*0fdc83b9SAmerigo Wang 		return NULL;
58*0fdc83b9SAmerigo Wang 
59*0fdc83b9SAmerigo Wang 	return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC);
60*0fdc83b9SAmerigo Wang }
61*0fdc83b9SAmerigo Wang #endif
62*0fdc83b9SAmerigo Wang 
632d5bf28fSAmerigo Wang /* Free memory returned from module_alloc */
642d5bf28fSAmerigo Wang void module_free(struct module *mod, void *module_region)
652d5bf28fSAmerigo Wang {
662d5bf28fSAmerigo Wang 	vfree(module_region);
672d5bf28fSAmerigo Wang 	/* FIXME: If module_region == mod->init_region, trim exception
682d5bf28fSAmerigo Wang 	   table entries. */
692d5bf28fSAmerigo Wang }
702d5bf28fSAmerigo Wang 
712d5bf28fSAmerigo Wang /* We don't need anything special. */
722d5bf28fSAmerigo Wang int module_frob_arch_sections(Elf_Ehdr *hdr,
732d5bf28fSAmerigo Wang 			      Elf_Shdr *sechdrs,
742d5bf28fSAmerigo Wang 			      char *secstrings,
752d5bf28fSAmerigo Wang 			      struct module *mod)
762d5bf28fSAmerigo Wang {
772d5bf28fSAmerigo Wang 	return 0;
782d5bf28fSAmerigo Wang }
792d5bf28fSAmerigo Wang 
80*0fdc83b9SAmerigo Wang #ifdef CONFIG_X86_32
81*0fdc83b9SAmerigo Wang int apply_relocate(Elf32_Shdr *sechdrs,
82*0fdc83b9SAmerigo Wang 		   const char *strtab,
83*0fdc83b9SAmerigo Wang 		   unsigned int symindex,
84*0fdc83b9SAmerigo Wang 		   unsigned int relsec,
85*0fdc83b9SAmerigo Wang 		   struct module *me)
86*0fdc83b9SAmerigo Wang {
87*0fdc83b9SAmerigo Wang 	unsigned int i;
88*0fdc83b9SAmerigo Wang 	Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
89*0fdc83b9SAmerigo Wang 	Elf32_Sym *sym;
90*0fdc83b9SAmerigo Wang 	uint32_t *location;
91*0fdc83b9SAmerigo Wang 
92*0fdc83b9SAmerigo Wang 	DEBUGP("Applying relocate section %u to %u\n", relsec,
93*0fdc83b9SAmerigo Wang 	       sechdrs[relsec].sh_info);
94*0fdc83b9SAmerigo Wang 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
95*0fdc83b9SAmerigo Wang 		/* This is where to make the change */
96*0fdc83b9SAmerigo Wang 		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
97*0fdc83b9SAmerigo Wang 			+ rel[i].r_offset;
98*0fdc83b9SAmerigo Wang 		/* This is the symbol it is referring to.  Note that all
99*0fdc83b9SAmerigo Wang 		   undefined symbols have been resolved.  */
100*0fdc83b9SAmerigo Wang 		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
101*0fdc83b9SAmerigo Wang 			+ ELF32_R_SYM(rel[i].r_info);
102*0fdc83b9SAmerigo Wang 
103*0fdc83b9SAmerigo Wang 		switch (ELF32_R_TYPE(rel[i].r_info)) {
104*0fdc83b9SAmerigo Wang 		case R_386_32:
105*0fdc83b9SAmerigo Wang 			/* We add the value into the location given */
106*0fdc83b9SAmerigo Wang 			*location += sym->st_value;
107*0fdc83b9SAmerigo Wang 			break;
108*0fdc83b9SAmerigo Wang 		case R_386_PC32:
109*0fdc83b9SAmerigo Wang 			/* Add the value, subtract its postition */
110*0fdc83b9SAmerigo Wang 			*location += sym->st_value - (uint32_t)location;
111*0fdc83b9SAmerigo Wang 			break;
112*0fdc83b9SAmerigo Wang 		default:
113*0fdc83b9SAmerigo Wang 			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
114*0fdc83b9SAmerigo Wang 			       me->name, ELF32_R_TYPE(rel[i].r_info));
115*0fdc83b9SAmerigo Wang 			return -ENOEXEC;
116*0fdc83b9SAmerigo Wang 		}
117*0fdc83b9SAmerigo Wang 	}
118*0fdc83b9SAmerigo Wang 	return 0;
119*0fdc83b9SAmerigo Wang }
120*0fdc83b9SAmerigo Wang 
121*0fdc83b9SAmerigo Wang int apply_relocate_add(Elf32_Shdr *sechdrs,
122*0fdc83b9SAmerigo Wang 		       const char *strtab,
123*0fdc83b9SAmerigo Wang 		       unsigned int symindex,
124*0fdc83b9SAmerigo Wang 		       unsigned int relsec,
125*0fdc83b9SAmerigo Wang 		       struct module *me)
126*0fdc83b9SAmerigo Wang {
127*0fdc83b9SAmerigo Wang 	printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
128*0fdc83b9SAmerigo Wang 	       me->name);
129*0fdc83b9SAmerigo Wang 	return -ENOEXEC;
130*0fdc83b9SAmerigo Wang }
131*0fdc83b9SAmerigo Wang #else /*X86_64*/
132*0fdc83b9SAmerigo Wang int apply_relocate_add(Elf64_Shdr *sechdrs,
133*0fdc83b9SAmerigo Wang 		   const char *strtab,
134*0fdc83b9SAmerigo Wang 		   unsigned int symindex,
135*0fdc83b9SAmerigo Wang 		   unsigned int relsec,
136*0fdc83b9SAmerigo Wang 		   struct module *me)
137*0fdc83b9SAmerigo Wang {
138*0fdc83b9SAmerigo Wang 	unsigned int i;
139*0fdc83b9SAmerigo Wang 	Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
140*0fdc83b9SAmerigo Wang 	Elf64_Sym *sym;
141*0fdc83b9SAmerigo Wang 	void *loc;
142*0fdc83b9SAmerigo Wang 	u64 val;
143*0fdc83b9SAmerigo Wang 
144*0fdc83b9SAmerigo Wang 	DEBUGP("Applying relocate section %u to %u\n", relsec,
145*0fdc83b9SAmerigo Wang 	       sechdrs[relsec].sh_info);
146*0fdc83b9SAmerigo Wang 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
147*0fdc83b9SAmerigo Wang 		/* This is where to make the change */
148*0fdc83b9SAmerigo Wang 		loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
149*0fdc83b9SAmerigo Wang 			+ rel[i].r_offset;
150*0fdc83b9SAmerigo Wang 
151*0fdc83b9SAmerigo Wang 		/* This is the symbol it is referring to.  Note that all
152*0fdc83b9SAmerigo Wang 		   undefined symbols have been resolved.  */
153*0fdc83b9SAmerigo Wang 		sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
154*0fdc83b9SAmerigo Wang 			+ ELF64_R_SYM(rel[i].r_info);
155*0fdc83b9SAmerigo Wang 
156*0fdc83b9SAmerigo Wang 		DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
157*0fdc83b9SAmerigo Wang 			(int)ELF64_R_TYPE(rel[i].r_info),
158*0fdc83b9SAmerigo Wang 			sym->st_value, rel[i].r_addend, (u64)loc);
159*0fdc83b9SAmerigo Wang 
160*0fdc83b9SAmerigo Wang 		val = sym->st_value + rel[i].r_addend;
161*0fdc83b9SAmerigo Wang 
162*0fdc83b9SAmerigo Wang 		switch (ELF64_R_TYPE(rel[i].r_info)) {
163*0fdc83b9SAmerigo Wang 		case R_X86_64_NONE:
164*0fdc83b9SAmerigo Wang 			break;
165*0fdc83b9SAmerigo Wang 		case R_X86_64_64:
166*0fdc83b9SAmerigo Wang 			*(u64 *)loc = val;
167*0fdc83b9SAmerigo Wang 			break;
168*0fdc83b9SAmerigo Wang 		case R_X86_64_32:
169*0fdc83b9SAmerigo Wang 			*(u32 *)loc = val;
170*0fdc83b9SAmerigo Wang 			if (val != *(u32 *)loc)
171*0fdc83b9SAmerigo Wang 				goto overflow;
172*0fdc83b9SAmerigo Wang 			break;
173*0fdc83b9SAmerigo Wang 		case R_X86_64_32S:
174*0fdc83b9SAmerigo Wang 			*(s32 *)loc = val;
175*0fdc83b9SAmerigo Wang 			if ((s64)val != *(s32 *)loc)
176*0fdc83b9SAmerigo Wang 				goto overflow;
177*0fdc83b9SAmerigo Wang 			break;
178*0fdc83b9SAmerigo Wang 		case R_X86_64_PC32:
179*0fdc83b9SAmerigo Wang 			val -= (u64)loc;
180*0fdc83b9SAmerigo Wang 			*(u32 *)loc = val;
181*0fdc83b9SAmerigo Wang #if 0
182*0fdc83b9SAmerigo Wang 			if ((s64)val != *(s32 *)loc)
183*0fdc83b9SAmerigo Wang 				goto overflow;
184*0fdc83b9SAmerigo Wang #endif
185*0fdc83b9SAmerigo Wang 			break;
186*0fdc83b9SAmerigo Wang 		default:
187*0fdc83b9SAmerigo Wang 			printk(KERN_ERR "module %s: Unknown rela relocation: %llu\n",
188*0fdc83b9SAmerigo Wang 			       me->name, ELF64_R_TYPE(rel[i].r_info));
189*0fdc83b9SAmerigo Wang 			return -ENOEXEC;
190*0fdc83b9SAmerigo Wang 		}
191*0fdc83b9SAmerigo Wang 	}
192*0fdc83b9SAmerigo Wang 	return 0;
193*0fdc83b9SAmerigo Wang 
194*0fdc83b9SAmerigo Wang overflow:
195*0fdc83b9SAmerigo Wang 	printk(KERN_ERR "overflow in relocation type %d val %Lx\n",
196*0fdc83b9SAmerigo Wang 	       (int)ELF64_R_TYPE(rel[i].r_info), val);
197*0fdc83b9SAmerigo Wang 	printk(KERN_ERR "`%s' likely not compiled with -mcmodel=kernel\n",
198*0fdc83b9SAmerigo Wang 	       me->name);
199*0fdc83b9SAmerigo Wang 	return -ENOEXEC;
200*0fdc83b9SAmerigo Wang }
201*0fdc83b9SAmerigo Wang 
202*0fdc83b9SAmerigo Wang int apply_relocate(Elf_Shdr *sechdrs,
203*0fdc83b9SAmerigo Wang 		   const char *strtab,
204*0fdc83b9SAmerigo Wang 		   unsigned int symindex,
205*0fdc83b9SAmerigo Wang 		   unsigned int relsec,
206*0fdc83b9SAmerigo Wang 		   struct module *me)
207*0fdc83b9SAmerigo Wang {
208*0fdc83b9SAmerigo Wang 	printk(KERN_ERR "non add relocation not supported\n");
209*0fdc83b9SAmerigo Wang 	return -ENOSYS;
210*0fdc83b9SAmerigo Wang }
211*0fdc83b9SAmerigo Wang 
212*0fdc83b9SAmerigo Wang #endif
213*0fdc83b9SAmerigo Wang 
2142d5bf28fSAmerigo Wang int module_finalize(const Elf_Ehdr *hdr,
2152d5bf28fSAmerigo Wang 		    const Elf_Shdr *sechdrs,
2162d5bf28fSAmerigo Wang 		    struct module *me)
2172d5bf28fSAmerigo Wang {
2182d5bf28fSAmerigo Wang 	const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
2192d5bf28fSAmerigo Wang 		*para = NULL;
2202d5bf28fSAmerigo Wang 	char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
2212d5bf28fSAmerigo Wang 
2222d5bf28fSAmerigo Wang 	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
2232d5bf28fSAmerigo Wang 		if (!strcmp(".text", secstrings + s->sh_name))
2242d5bf28fSAmerigo Wang 			text = s;
2252d5bf28fSAmerigo Wang 		if (!strcmp(".altinstructions", secstrings + s->sh_name))
2262d5bf28fSAmerigo Wang 			alt = s;
2272d5bf28fSAmerigo Wang 		if (!strcmp(".smp_locks", secstrings + s->sh_name))
2282d5bf28fSAmerigo Wang 			locks = s;
2292d5bf28fSAmerigo Wang 		if (!strcmp(".parainstructions", secstrings + s->sh_name))
2302d5bf28fSAmerigo Wang 			para = s;
2312d5bf28fSAmerigo Wang 	}
2322d5bf28fSAmerigo Wang 
2332d5bf28fSAmerigo Wang 	if (alt) {
2342d5bf28fSAmerigo Wang 		/* patch .altinstructions */
2352d5bf28fSAmerigo Wang 		void *aseg = (void *)alt->sh_addr;
2362d5bf28fSAmerigo Wang 		apply_alternatives(aseg, aseg + alt->sh_size);
2372d5bf28fSAmerigo Wang 	}
2382d5bf28fSAmerigo Wang 	if (locks && text) {
2392d5bf28fSAmerigo Wang 		void *lseg = (void *)locks->sh_addr;
2402d5bf28fSAmerigo Wang 		void *tseg = (void *)text->sh_addr;
2412d5bf28fSAmerigo Wang 		alternatives_smp_module_add(me, me->name,
2422d5bf28fSAmerigo Wang 					    lseg, lseg + locks->sh_size,
2432d5bf28fSAmerigo Wang 					    tseg, tseg + text->sh_size);
2442d5bf28fSAmerigo Wang 	}
2452d5bf28fSAmerigo Wang 
2462d5bf28fSAmerigo Wang 	if (para) {
2472d5bf28fSAmerigo Wang 		void *pseg = (void *)para->sh_addr;
2482d5bf28fSAmerigo Wang 		apply_paravirt(pseg, pseg + para->sh_size);
2492d5bf28fSAmerigo Wang 	}
2502d5bf28fSAmerigo Wang 
2512d5bf28fSAmerigo Wang 	return module_bug_finalize(hdr, sechdrs, me);
2522d5bf28fSAmerigo Wang }
2532d5bf28fSAmerigo Wang 
2542d5bf28fSAmerigo Wang void module_arch_cleanup(struct module *mod)
2552d5bf28fSAmerigo Wang {
2562d5bf28fSAmerigo Wang 	alternatives_smp_module_del(mod);
2572d5bf28fSAmerigo Wang 	module_bug_cleanup(mod);
2582d5bf28fSAmerigo Wang }
259