xref: /openbmc/linux/arch/powerpc/kernel/module_32.c (revision 4eb4516e)
1ed981856SPaul Mackerras /*  Kernel module help for PPC.
2ed981856SPaul Mackerras     Copyright (C) 2001 Rusty Russell.
3ed981856SPaul Mackerras 
4ed981856SPaul Mackerras     This program is free software; you can redistribute it and/or modify
5ed981856SPaul Mackerras     it under the terms of the GNU General Public License as published by
6ed981856SPaul Mackerras     the Free Software Foundation; either version 2 of the License, or
7ed981856SPaul Mackerras     (at your option) any later version.
8ed981856SPaul Mackerras 
9ed981856SPaul Mackerras     This program is distributed in the hope that it will be useful,
10ed981856SPaul Mackerras     but WITHOUT ANY WARRANTY; without even the implied warranty of
11ed981856SPaul Mackerras     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12ed981856SPaul Mackerras     GNU General Public License for more details.
13ed981856SPaul Mackerras 
14ed981856SPaul Mackerras     You should have received a copy of the GNU General Public License
15ed981856SPaul Mackerras     along with this program; if not, write to the Free Software
16ed981856SPaul Mackerras     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17ed981856SPaul Mackerras */
18c7d1f6afSAnton Blanchard 
19c7d1f6afSAnton Blanchard #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20c7d1f6afSAnton Blanchard 
21ed981856SPaul Mackerras #include <linux/module.h>
22ed981856SPaul Mackerras #include <linux/moduleloader.h>
23ed981856SPaul Mackerras #include <linux/elf.h>
24ed981856SPaul Mackerras #include <linux/vmalloc.h>
25ed981856SPaul Mackerras #include <linux/fs.h>
26ed981856SPaul Mackerras #include <linux/string.h>
27ed981856SPaul Mackerras #include <linux/kernel.h>
287cc45e64SSteven Rostedt #include <linux/ftrace.h>
29ed981856SPaul Mackerras #include <linux/cache.h>
3073c9ceabSJeremy Fitzhardinge #include <linux/bug.h>
31eda09fbdSEmil Medve #include <linux/sort.h>
32b88c4767SRobert Jennings #include <asm/setup.h>
3321c4ff80SBenjamin Herrenschmidt 
34ed981856SPaul Mackerras /* Count how many different relocations (different symbol, different
35ed981856SPaul Mackerras    addend) */
36ed981856SPaul Mackerras static unsigned int count_relocs(const Elf32_Rela *rela, unsigned int num)
37ed981856SPaul Mackerras {
38eda09fbdSEmil Medve 	unsigned int i, r_info, r_addend, _count_relocs;
39ed981856SPaul Mackerras 
40eda09fbdSEmil Medve 	_count_relocs = 0;
41eda09fbdSEmil Medve 	r_info = 0;
42eda09fbdSEmil Medve 	r_addend = 0;
43eda09fbdSEmil Medve 	for (i = 0; i < num; i++)
44eda09fbdSEmil Medve 		/* Only count 24-bit relocs, others don't need stubs */
45eda09fbdSEmil Medve 		if (ELF32_R_TYPE(rela[i].r_info) == R_PPC_REL24 &&
46eda09fbdSEmil Medve 		    (r_info != ELF32_R_SYM(rela[i].r_info) ||
47eda09fbdSEmil Medve 		     r_addend != rela[i].r_addend)) {
48eda09fbdSEmil Medve 			_count_relocs++;
49eda09fbdSEmil Medve 			r_info = ELF32_R_SYM(rela[i].r_info);
50eda09fbdSEmil Medve 			r_addend = rela[i].r_addend;
51ed981856SPaul Mackerras 		}
52eda09fbdSEmil Medve 
537cc45e64SSteven Rostedt #ifdef CONFIG_DYNAMIC_FTRACE
547cc45e64SSteven Rostedt 	_count_relocs++;	/* add one for ftrace_caller */
557cc45e64SSteven Rostedt #endif
56eda09fbdSEmil Medve 	return _count_relocs;
57ed981856SPaul Mackerras }
58eda09fbdSEmil Medve 
59eda09fbdSEmil Medve static int relacmp(const void *_x, const void *_y)
60eda09fbdSEmil Medve {
61eda09fbdSEmil Medve 	const Elf32_Rela *x, *y;
62eda09fbdSEmil Medve 
63eda09fbdSEmil Medve 	y = (Elf32_Rela *)_x;
64eda09fbdSEmil Medve 	x = (Elf32_Rela *)_y;
65eda09fbdSEmil Medve 
66eda09fbdSEmil Medve 	/* Compare the entire r_info (as opposed to ELF32_R_SYM(r_info) only) to
67eda09fbdSEmil Medve 	 * make the comparison cheaper/faster. It won't affect the sorting or
68eda09fbdSEmil Medve 	 * the counting algorithms' performance
69eda09fbdSEmil Medve 	 */
70eda09fbdSEmil Medve 	if (x->r_info < y->r_info)
71eda09fbdSEmil Medve 		return -1;
72eda09fbdSEmil Medve 	else if (x->r_info > y->r_info)
73eda09fbdSEmil Medve 		return 1;
74eda09fbdSEmil Medve 	else if (x->r_addend < y->r_addend)
75eda09fbdSEmil Medve 		return -1;
76eda09fbdSEmil Medve 	else if (x->r_addend > y->r_addend)
77eda09fbdSEmil Medve 		return 1;
78eda09fbdSEmil Medve 	else
79eda09fbdSEmil Medve 		return 0;
80eda09fbdSEmil Medve }
81eda09fbdSEmil Medve 
82eda09fbdSEmil Medve static void relaswap(void *_x, void *_y, int size)
83eda09fbdSEmil Medve {
84eda09fbdSEmil Medve 	uint32_t *x, *y, tmp;
85eda09fbdSEmil Medve 	int i;
86eda09fbdSEmil Medve 
87eda09fbdSEmil Medve 	y = (uint32_t *)_x;
88eda09fbdSEmil Medve 	x = (uint32_t *)_y;
89eda09fbdSEmil Medve 
90eda09fbdSEmil Medve 	for (i = 0; i < sizeof(Elf32_Rela) / sizeof(uint32_t); i++) {
91eda09fbdSEmil Medve 		tmp = x[i];
92eda09fbdSEmil Medve 		x[i] = y[i];
93eda09fbdSEmil Medve 		y[i] = tmp;
94eda09fbdSEmil Medve 	}
95ed981856SPaul Mackerras }
96ed981856SPaul Mackerras 
97ed981856SPaul Mackerras /* Get the potential trampolines size required of the init and
98ed981856SPaul Mackerras    non-init sections */
99ed981856SPaul Mackerras static unsigned long get_plt_size(const Elf32_Ehdr *hdr,
100ed981856SPaul Mackerras 				  const Elf32_Shdr *sechdrs,
101ed981856SPaul Mackerras 				  const char *secstrings,
102ed981856SPaul Mackerras 				  int is_init)
103ed981856SPaul Mackerras {
104ed981856SPaul Mackerras 	unsigned long ret = 0;
105ed981856SPaul Mackerras 	unsigned i;
106ed981856SPaul Mackerras 
107ed981856SPaul Mackerras 	/* Everything marked ALLOC (this includes the exported
108ed981856SPaul Mackerras            symbols) */
109ed981856SPaul Mackerras 	for (i = 1; i < hdr->e_shnum; i++) {
110ed981856SPaul Mackerras 		/* If it's called *.init*, and we're not init, we're
111ed981856SPaul Mackerras                    not interested */
112d8731527SMathieu Malaterre 		if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != NULL)
113ed981856SPaul Mackerras 		    != is_init)
114ed981856SPaul Mackerras 			continue;
115ed981856SPaul Mackerras 
116ed981856SPaul Mackerras 		/* We don't want to look at debug sections. */
117d8731527SMathieu Malaterre 		if (strstr(secstrings + sechdrs[i].sh_name, ".debug"))
118ed981856SPaul Mackerras 			continue;
119ed981856SPaul Mackerras 
120ed981856SPaul Mackerras 		if (sechdrs[i].sh_type == SHT_RELA) {
121c7d1f6afSAnton Blanchard 			pr_debug("Found relocations in section %u\n", i);
122c7d1f6afSAnton Blanchard 			pr_debug("Ptr: %p.  Number: %u\n",
123ed981856SPaul Mackerras 			       (void *)hdr + sechdrs[i].sh_offset,
124ed981856SPaul Mackerras 			       sechdrs[i].sh_size / sizeof(Elf32_Rela));
125eda09fbdSEmil Medve 
126eda09fbdSEmil Medve 			/* Sort the relocation information based on a symbol and
127eda09fbdSEmil Medve 			 * addend key. This is a stable O(n*log n) complexity
128eda09fbdSEmil Medve 			 * alogrithm but it will reduce the complexity of
129eda09fbdSEmil Medve 			 * count_relocs() to linear complexity O(n)
130eda09fbdSEmil Medve 			 */
131eda09fbdSEmil Medve 			sort((void *)hdr + sechdrs[i].sh_offset,
132eda09fbdSEmil Medve 			     sechdrs[i].sh_size / sizeof(Elf32_Rela),
133eda09fbdSEmil Medve 			     sizeof(Elf32_Rela), relacmp, relaswap);
134eda09fbdSEmil Medve 
135ed981856SPaul Mackerras 			ret += count_relocs((void *)hdr
136ed981856SPaul Mackerras 					     + sechdrs[i].sh_offset,
137ed981856SPaul Mackerras 					     sechdrs[i].sh_size
138ed981856SPaul Mackerras 					     / sizeof(Elf32_Rela))
139ed981856SPaul Mackerras 				* sizeof(struct ppc_plt_entry);
140ed981856SPaul Mackerras 		}
141ed981856SPaul Mackerras 	}
142ed981856SPaul Mackerras 
143ed981856SPaul Mackerras 	return ret;
144ed981856SPaul Mackerras }
145ed981856SPaul Mackerras 
146ed981856SPaul Mackerras int module_frob_arch_sections(Elf32_Ehdr *hdr,
147ed981856SPaul Mackerras 			      Elf32_Shdr *sechdrs,
148ed981856SPaul Mackerras 			      char *secstrings,
149ed981856SPaul Mackerras 			      struct module *me)
150ed981856SPaul Mackerras {
151ed981856SPaul Mackerras 	unsigned int i;
152ed981856SPaul Mackerras 
153ed981856SPaul Mackerras 	/* Find .plt and .init.plt sections */
154ed981856SPaul Mackerras 	for (i = 0; i < hdr->e_shnum; i++) {
155ed981856SPaul Mackerras 		if (strcmp(secstrings + sechdrs[i].sh_name, ".init.plt") == 0)
156ed981856SPaul Mackerras 			me->arch.init_plt_section = i;
157ed981856SPaul Mackerras 		else if (strcmp(secstrings + sechdrs[i].sh_name, ".plt") == 0)
158ed981856SPaul Mackerras 			me->arch.core_plt_section = i;
159ed981856SPaul Mackerras 	}
160ed981856SPaul Mackerras 	if (!me->arch.core_plt_section || !me->arch.init_plt_section) {
161c7d1f6afSAnton Blanchard 		pr_err("Module doesn't contain .plt or .init.plt sections.\n");
162ed981856SPaul Mackerras 		return -ENOEXEC;
163ed981856SPaul Mackerras 	}
164ed981856SPaul Mackerras 
165ed981856SPaul Mackerras 	/* Override their sizes */
166ed981856SPaul Mackerras 	sechdrs[me->arch.core_plt_section].sh_size
167ed981856SPaul Mackerras 		= get_plt_size(hdr, sechdrs, secstrings, 0);
168ed981856SPaul Mackerras 	sechdrs[me->arch.init_plt_section].sh_size
169ed981856SPaul Mackerras 		= get_plt_size(hdr, sechdrs, secstrings, 1);
170ed981856SPaul Mackerras 	return 0;
171ed981856SPaul Mackerras }
172ed981856SPaul Mackerras 
173ed981856SPaul Mackerras static inline int entry_matches(struct ppc_plt_entry *entry, Elf32_Addr val)
174ed981856SPaul Mackerras {
1754eb4516eSChristophe Leroy 	if (entry->jump[0] != (PPC_INST_ADDIS | __PPC_RT(R12) | PPC_HA(val)))
176ed981856SPaul Mackerras 		return 0;
1774eb4516eSChristophe Leroy 	if (entry->jump[1] != (PPC_INST_ADDI | __PPC_RT(R12) | __PPC_RA(R12) |
1784eb4516eSChristophe Leroy 			       PPC_LO(val)))
1794eb4516eSChristophe Leroy 		return 0;
1804eb4516eSChristophe Leroy 	return 1;
181ed981856SPaul Mackerras }
182ed981856SPaul Mackerras 
183ed981856SPaul Mackerras /* Set up a trampoline in the PLT to bounce us to the distant function */
184ed981856SPaul Mackerras static uint32_t do_plt_call(void *location,
185ed981856SPaul Mackerras 			    Elf32_Addr val,
186136cd345SMichael Ellerman 			    const Elf32_Shdr *sechdrs,
187ed981856SPaul Mackerras 			    struct module *mod)
188ed981856SPaul Mackerras {
189ed981856SPaul Mackerras 	struct ppc_plt_entry *entry;
190ed981856SPaul Mackerras 
191c7d1f6afSAnton Blanchard 	pr_debug("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location);
192ed981856SPaul Mackerras 	/* Init, or core PLT? */
1937523e4dcSRusty Russell 	if (location >= mod->core_layout.base
1947523e4dcSRusty Russell 	    && location < mod->core_layout.base + mod->core_layout.size)
195ed981856SPaul Mackerras 		entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr;
196ed981856SPaul Mackerras 	else
197ed981856SPaul Mackerras 		entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr;
198ed981856SPaul Mackerras 
199ed981856SPaul Mackerras 	/* Find this entry, or if that fails, the next avail. entry */
200ed981856SPaul Mackerras 	while (entry->jump[0]) {
201ed981856SPaul Mackerras 		if (entry_matches(entry, val)) return (uint32_t)entry;
202ed981856SPaul Mackerras 		entry++;
203ed981856SPaul Mackerras 	}
204ed981856SPaul Mackerras 
2054eb4516eSChristophe Leroy 	/*
2064eb4516eSChristophe Leroy 	 * lis r12, sym@ha
2074eb4516eSChristophe Leroy 	 * addi r12, r12, sym@l
2084eb4516eSChristophe Leroy 	 * mtctr r12
2094eb4516eSChristophe Leroy 	 * bctr
2104eb4516eSChristophe Leroy 	 */
2114eb4516eSChristophe Leroy 	entry->jump[0] = PPC_INST_ADDIS | __PPC_RT(R12) | PPC_HA(val);
2124eb4516eSChristophe Leroy 	entry->jump[1] = PPC_INST_ADDI | __PPC_RT(R12) | __PPC_RA(R12) | PPC_LO(val);
2134eb4516eSChristophe Leroy 	entry->jump[2] = PPC_INST_MTCTR | __PPC_RS(R12);
2144eb4516eSChristophe Leroy 	entry->jump[3] = PPC_INST_BCTR;
215ed981856SPaul Mackerras 
216c7d1f6afSAnton Blanchard 	pr_debug("Initialized plt for 0x%x at %p\n", val, entry);
217ed981856SPaul Mackerras 	return (uint32_t)entry;
218ed981856SPaul Mackerras }
219ed981856SPaul Mackerras 
220ed981856SPaul Mackerras int apply_relocate_add(Elf32_Shdr *sechdrs,
221ed981856SPaul Mackerras 		       const char *strtab,
222ed981856SPaul Mackerras 		       unsigned int symindex,
223ed981856SPaul Mackerras 		       unsigned int relsec,
224ed981856SPaul Mackerras 		       struct module *module)
225ed981856SPaul Mackerras {
226ed981856SPaul Mackerras 	unsigned int i;
227ed981856SPaul Mackerras 	Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
228ed981856SPaul Mackerras 	Elf32_Sym *sym;
229ed981856SPaul Mackerras 	uint32_t *location;
230ed981856SPaul Mackerras 	uint32_t value;
231ed981856SPaul Mackerras 
232c7d1f6afSAnton Blanchard 	pr_debug("Applying ADD relocate section %u to %u\n", relsec,
233ed981856SPaul Mackerras 	       sechdrs[relsec].sh_info);
234ed981856SPaul Mackerras 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
235ed981856SPaul Mackerras 		/* This is where to make the change */
236ed981856SPaul Mackerras 		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
237ed981856SPaul Mackerras 			+ rela[i].r_offset;
238ed981856SPaul Mackerras 		/* This is the symbol it is referring to.  Note that all
239ed981856SPaul Mackerras 		   undefined symbols have been resolved.  */
240ed981856SPaul Mackerras 		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
241ed981856SPaul Mackerras 			+ ELF32_R_SYM(rela[i].r_info);
242ed981856SPaul Mackerras 		/* `Everything is relative'. */
243ed981856SPaul Mackerras 		value = sym->st_value + rela[i].r_addend;
244ed981856SPaul Mackerras 
245ed981856SPaul Mackerras 		switch (ELF32_R_TYPE(rela[i].r_info)) {
246ed981856SPaul Mackerras 		case R_PPC_ADDR32:
247ed981856SPaul Mackerras 			/* Simply set it */
248ed981856SPaul Mackerras 			*(uint32_t *)location = value;
249ed981856SPaul Mackerras 			break;
250ed981856SPaul Mackerras 
251ed981856SPaul Mackerras 		case R_PPC_ADDR16_LO:
252ed981856SPaul Mackerras 			/* Low half of the symbol */
253ed981856SPaul Mackerras 			*(uint16_t *)location = value;
254ed981856SPaul Mackerras 			break;
255ed981856SPaul Mackerras 
2569a3d6458SSimon Vallet 		case R_PPC_ADDR16_HI:
2579a3d6458SSimon Vallet 			/* Higher half of the symbol */
2589a3d6458SSimon Vallet 			*(uint16_t *)location = (value >> 16);
2599a3d6458SSimon Vallet 			break;
2609a3d6458SSimon Vallet 
261ed981856SPaul Mackerras 		case R_PPC_ADDR16_HA:
262ed981856SPaul Mackerras 			/* Sign-adjusted lower 16 bits: PPC ELF ABI says:
263ed981856SPaul Mackerras 			   (((x >> 16) + ((x & 0x8000) ? 1 : 0))) & 0xFFFF.
264ed981856SPaul Mackerras 			   This is the same, only sane.
265ed981856SPaul Mackerras 			 */
266ed981856SPaul Mackerras 			*(uint16_t *)location = (value + 0x8000) >> 16;
267ed981856SPaul Mackerras 			break;
268ed981856SPaul Mackerras 
269ed981856SPaul Mackerras 		case R_PPC_REL24:
270ed981856SPaul Mackerras 			if ((int)(value - (uint32_t)location) < -0x02000000
271ed981856SPaul Mackerras 			    || (int)(value - (uint32_t)location) >= 0x02000000)
272ed981856SPaul Mackerras 				value = do_plt_call(location, value,
273ed981856SPaul Mackerras 						    sechdrs, module);
274ed981856SPaul Mackerras 
275ed981856SPaul Mackerras 			/* Only replace bits 2 through 26 */
276c7d1f6afSAnton Blanchard 			pr_debug("REL24 value = %08X. location = %08X\n",
277ed981856SPaul Mackerras 			       value, (uint32_t)location);
278c7d1f6afSAnton Blanchard 			pr_debug("Location before: %08X.\n",
279ed981856SPaul Mackerras 			       *(uint32_t *)location);
280ed981856SPaul Mackerras 			*(uint32_t *)location
281ed981856SPaul Mackerras 				= (*(uint32_t *)location & ~0x03fffffc)
282ed981856SPaul Mackerras 				| ((value - (uint32_t)location)
283ed981856SPaul Mackerras 				   & 0x03fffffc);
284c7d1f6afSAnton Blanchard 			pr_debug("Location after: %08X.\n",
285ed981856SPaul Mackerras 			       *(uint32_t *)location);
286c7d1f6afSAnton Blanchard 			pr_debug("ie. jump to %08X+%08X = %08X\n",
287ed981856SPaul Mackerras 			       *(uint32_t *)location & 0x03fffffc,
288ed981856SPaul Mackerras 			       (uint32_t)location,
289ed981856SPaul Mackerras 			       (*(uint32_t *)location & 0x03fffffc)
290ed981856SPaul Mackerras 			       + (uint32_t)location);
291ed981856SPaul Mackerras 			break;
292ed981856SPaul Mackerras 
293ed981856SPaul Mackerras 		case R_PPC_REL32:
294ed981856SPaul Mackerras 			/* 32-bit relative jump. */
295ed981856SPaul Mackerras 			*(uint32_t *)location = value - (uint32_t)location;
296ed981856SPaul Mackerras 			break;
297ed981856SPaul Mackerras 
298ed981856SPaul Mackerras 		default:
299c7d1f6afSAnton Blanchard 			pr_err("%s: unknown ADD relocation: %u\n",
300ed981856SPaul Mackerras 			       module->name,
301ed981856SPaul Mackerras 			       ELF32_R_TYPE(rela[i].r_info));
302ed981856SPaul Mackerras 			return -ENOEXEC;
303ed981856SPaul Mackerras 		}
304ed981856SPaul Mackerras 	}
305136cd345SMichael Ellerman 
306ed981856SPaul Mackerras 	return 0;
307ed981856SPaul Mackerras }
308136cd345SMichael Ellerman 
309136cd345SMichael Ellerman #ifdef CONFIG_DYNAMIC_FTRACE
310136cd345SMichael Ellerman int module_finalize_ftrace(struct module *module, const Elf_Shdr *sechdrs)
311136cd345SMichael Ellerman {
312136cd345SMichael Ellerman 	module->arch.tramp = do_plt_call(module->core_layout.base,
313136cd345SMichael Ellerman 					 (unsigned long)ftrace_caller,
314136cd345SMichael Ellerman 					 sechdrs, module);
315136cd345SMichael Ellerman 	if (!module->arch.tramp)
316136cd345SMichael Ellerman 		return -ENOENT;
317136cd345SMichael Ellerman 
318136cd345SMichael Ellerman 	return 0;
319136cd345SMichael Ellerman }
320136cd345SMichael Ellerman #endif
321