xref: /openbmc/linux/arch/powerpc/kernel/module_32.c (revision 9a3d6458)
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 */
18ed981856SPaul Mackerras #include <linux/module.h>
19ed981856SPaul Mackerras #include <linux/moduleloader.h>
20ed981856SPaul Mackerras #include <linux/elf.h>
21ed981856SPaul Mackerras #include <linux/vmalloc.h>
22ed981856SPaul Mackerras #include <linux/fs.h>
23ed981856SPaul Mackerras #include <linux/string.h>
24ed981856SPaul Mackerras #include <linux/kernel.h>
25ed981856SPaul Mackerras #include <linux/cache.h>
2673c9ceabSJeremy Fitzhardinge #include <linux/bug.h>
27ed981856SPaul Mackerras 
2821c4ff80SBenjamin Herrenschmidt #include "setup.h"
2921c4ff80SBenjamin Herrenschmidt 
30ed981856SPaul Mackerras #if 0
31ed981856SPaul Mackerras #define DEBUGP printk
32ed981856SPaul Mackerras #else
33ed981856SPaul Mackerras #define DEBUGP(fmt , ...)
34ed981856SPaul Mackerras #endif
35ed981856SPaul Mackerras 
36ed981856SPaul Mackerras LIST_HEAD(module_bug_list);
37ed981856SPaul Mackerras 
38ed981856SPaul Mackerras void *module_alloc(unsigned long size)
39ed981856SPaul Mackerras {
40ed981856SPaul Mackerras 	if (size == 0)
41ed981856SPaul Mackerras 		return NULL;
42ed981856SPaul Mackerras 	return vmalloc(size);
43ed981856SPaul Mackerras }
44ed981856SPaul Mackerras 
45ed981856SPaul Mackerras /* Free memory returned from module_alloc */
46ed981856SPaul Mackerras void module_free(struct module *mod, void *module_region)
47ed981856SPaul Mackerras {
48ed981856SPaul Mackerras 	vfree(module_region);
49ed981856SPaul Mackerras 	/* FIXME: If module_region == mod->init_region, trim exception
50ed981856SPaul Mackerras            table entries. */
51ed981856SPaul Mackerras }
52ed981856SPaul Mackerras 
53ed981856SPaul Mackerras /* Count how many different relocations (different symbol, different
54ed981856SPaul Mackerras    addend) */
55ed981856SPaul Mackerras static unsigned int count_relocs(const Elf32_Rela *rela, unsigned int num)
56ed981856SPaul Mackerras {
57ed981856SPaul Mackerras 	unsigned int i, j, ret = 0;
58ed981856SPaul Mackerras 
59ed981856SPaul Mackerras 	/* Sure, this is order(n^2), but it's usually short, and not
60ed981856SPaul Mackerras            time critical */
61ed981856SPaul Mackerras 	for (i = 0; i < num; i++) {
62ed981856SPaul Mackerras 		for (j = 0; j < i; j++) {
63ed981856SPaul Mackerras 			/* If this addend appeared before, it's
64ed981856SPaul Mackerras                            already been counted */
65ed981856SPaul Mackerras 			if (ELF32_R_SYM(rela[i].r_info)
66ed981856SPaul Mackerras 			    == ELF32_R_SYM(rela[j].r_info)
67ed981856SPaul Mackerras 			    && rela[i].r_addend == rela[j].r_addend)
68ed981856SPaul Mackerras 				break;
69ed981856SPaul Mackerras 		}
70ed981856SPaul Mackerras 		if (j == i) ret++;
71ed981856SPaul Mackerras 	}
72ed981856SPaul Mackerras 	return ret;
73ed981856SPaul Mackerras }
74ed981856SPaul Mackerras 
75ed981856SPaul Mackerras /* Get the potential trampolines size required of the init and
76ed981856SPaul Mackerras    non-init sections */
77ed981856SPaul Mackerras static unsigned long get_plt_size(const Elf32_Ehdr *hdr,
78ed981856SPaul Mackerras 				  const Elf32_Shdr *sechdrs,
79ed981856SPaul Mackerras 				  const char *secstrings,
80ed981856SPaul Mackerras 				  int is_init)
81ed981856SPaul Mackerras {
82ed981856SPaul Mackerras 	unsigned long ret = 0;
83ed981856SPaul Mackerras 	unsigned i;
84ed981856SPaul Mackerras 
85ed981856SPaul Mackerras 	/* Everything marked ALLOC (this includes the exported
86ed981856SPaul Mackerras            symbols) */
87ed981856SPaul Mackerras 	for (i = 1; i < hdr->e_shnum; i++) {
88ed981856SPaul Mackerras 		/* If it's called *.init*, and we're not init, we're
89ed981856SPaul Mackerras                    not interested */
90ed981856SPaul Mackerras 		if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
91ed981856SPaul Mackerras 		    != is_init)
92ed981856SPaul Mackerras 			continue;
93ed981856SPaul Mackerras 
94ed981856SPaul Mackerras 		/* We don't want to look at debug sections. */
95ed981856SPaul Mackerras 		if (strstr(secstrings + sechdrs[i].sh_name, ".debug") != 0)
96ed981856SPaul Mackerras 			continue;
97ed981856SPaul Mackerras 
98ed981856SPaul Mackerras 		if (sechdrs[i].sh_type == SHT_RELA) {
99ed981856SPaul Mackerras 			DEBUGP("Found relocations in section %u\n", i);
100ed981856SPaul Mackerras 			DEBUGP("Ptr: %p.  Number: %u\n",
101ed981856SPaul Mackerras 			       (void *)hdr + sechdrs[i].sh_offset,
102ed981856SPaul Mackerras 			       sechdrs[i].sh_size / sizeof(Elf32_Rela));
103ed981856SPaul Mackerras 			ret += count_relocs((void *)hdr
104ed981856SPaul Mackerras 					     + sechdrs[i].sh_offset,
105ed981856SPaul Mackerras 					     sechdrs[i].sh_size
106ed981856SPaul Mackerras 					     / sizeof(Elf32_Rela))
107ed981856SPaul Mackerras 				* sizeof(struct ppc_plt_entry);
108ed981856SPaul Mackerras 		}
109ed981856SPaul Mackerras 	}
110ed981856SPaul Mackerras 
111ed981856SPaul Mackerras 	return ret;
112ed981856SPaul Mackerras }
113ed981856SPaul Mackerras 
114ed981856SPaul Mackerras int module_frob_arch_sections(Elf32_Ehdr *hdr,
115ed981856SPaul Mackerras 			      Elf32_Shdr *sechdrs,
116ed981856SPaul Mackerras 			      char *secstrings,
117ed981856SPaul Mackerras 			      struct module *me)
118ed981856SPaul Mackerras {
119ed981856SPaul Mackerras 	unsigned int i;
120ed981856SPaul Mackerras 
121ed981856SPaul Mackerras 	/* Find .plt and .init.plt sections */
122ed981856SPaul Mackerras 	for (i = 0; i < hdr->e_shnum; i++) {
123ed981856SPaul Mackerras 		if (strcmp(secstrings + sechdrs[i].sh_name, ".init.plt") == 0)
124ed981856SPaul Mackerras 			me->arch.init_plt_section = i;
125ed981856SPaul Mackerras 		else if (strcmp(secstrings + sechdrs[i].sh_name, ".plt") == 0)
126ed981856SPaul Mackerras 			me->arch.core_plt_section = i;
127ed981856SPaul Mackerras 	}
128ed981856SPaul Mackerras 	if (!me->arch.core_plt_section || !me->arch.init_plt_section) {
129ed981856SPaul Mackerras 		printk("Module doesn't contain .plt or .init.plt sections.\n");
130ed981856SPaul Mackerras 		return -ENOEXEC;
131ed981856SPaul Mackerras 	}
132ed981856SPaul Mackerras 
133ed981856SPaul Mackerras 	/* Override their sizes */
134ed981856SPaul Mackerras 	sechdrs[me->arch.core_plt_section].sh_size
135ed981856SPaul Mackerras 		= get_plt_size(hdr, sechdrs, secstrings, 0);
136ed981856SPaul Mackerras 	sechdrs[me->arch.init_plt_section].sh_size
137ed981856SPaul Mackerras 		= get_plt_size(hdr, sechdrs, secstrings, 1);
138ed981856SPaul Mackerras 	return 0;
139ed981856SPaul Mackerras }
140ed981856SPaul Mackerras 
141ed981856SPaul Mackerras int apply_relocate(Elf32_Shdr *sechdrs,
142ed981856SPaul Mackerras 		   const char *strtab,
143ed981856SPaul Mackerras 		   unsigned int symindex,
144ed981856SPaul Mackerras 		   unsigned int relsec,
145ed981856SPaul Mackerras 		   struct module *module)
146ed981856SPaul Mackerras {
147ed981856SPaul Mackerras 	printk(KERN_ERR "%s: Non-ADD RELOCATION unsupported\n",
148ed981856SPaul Mackerras 	       module->name);
149ed981856SPaul Mackerras 	return -ENOEXEC;
150ed981856SPaul Mackerras }
151ed981856SPaul Mackerras 
152ed981856SPaul Mackerras static inline int entry_matches(struct ppc_plt_entry *entry, Elf32_Addr val)
153ed981856SPaul Mackerras {
154ed981856SPaul Mackerras 	if (entry->jump[0] == 0x3d600000 + ((val + 0x8000) >> 16)
155ed981856SPaul Mackerras 	    && entry->jump[1] == 0x396b0000 + (val & 0xffff))
156ed981856SPaul Mackerras 		return 1;
157ed981856SPaul Mackerras 	return 0;
158ed981856SPaul Mackerras }
159ed981856SPaul Mackerras 
160ed981856SPaul Mackerras /* Set up a trampoline in the PLT to bounce us to the distant function */
161ed981856SPaul Mackerras static uint32_t do_plt_call(void *location,
162ed981856SPaul Mackerras 			    Elf32_Addr val,
163ed981856SPaul Mackerras 			    Elf32_Shdr *sechdrs,
164ed981856SPaul Mackerras 			    struct module *mod)
165ed981856SPaul Mackerras {
166ed981856SPaul Mackerras 	struct ppc_plt_entry *entry;
167ed981856SPaul Mackerras 
168ed981856SPaul Mackerras 	DEBUGP("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location);
169ed981856SPaul Mackerras 	/* Init, or core PLT? */
170ed981856SPaul Mackerras 	if (location >= mod->module_core
171ed981856SPaul Mackerras 	    && location < mod->module_core + mod->core_size)
172ed981856SPaul Mackerras 		entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr;
173ed981856SPaul Mackerras 	else
174ed981856SPaul Mackerras 		entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr;
175ed981856SPaul Mackerras 
176ed981856SPaul Mackerras 	/* Find this entry, or if that fails, the next avail. entry */
177ed981856SPaul Mackerras 	while (entry->jump[0]) {
178ed981856SPaul Mackerras 		if (entry_matches(entry, val)) return (uint32_t)entry;
179ed981856SPaul Mackerras 		entry++;
180ed981856SPaul Mackerras 	}
181ed981856SPaul Mackerras 
182ed981856SPaul Mackerras 	/* Stolen from Paul Mackerras as well... */
183ed981856SPaul Mackerras 	entry->jump[0] = 0x3d600000+((val+0x8000)>>16);	/* lis r11,sym@ha */
184ed981856SPaul Mackerras 	entry->jump[1] = 0x396b0000 + (val&0xffff);	/* addi r11,r11,sym@l*/
185ed981856SPaul Mackerras 	entry->jump[2] = 0x7d6903a6;			/* mtctr r11 */
186ed981856SPaul Mackerras 	entry->jump[3] = 0x4e800420;			/* bctr */
187ed981856SPaul Mackerras 
188ed981856SPaul Mackerras 	DEBUGP("Initialized plt for 0x%x at %p\n", val, entry);
189ed981856SPaul Mackerras 	return (uint32_t)entry;
190ed981856SPaul Mackerras }
191ed981856SPaul Mackerras 
192ed981856SPaul Mackerras int apply_relocate_add(Elf32_Shdr *sechdrs,
193ed981856SPaul Mackerras 		       const char *strtab,
194ed981856SPaul Mackerras 		       unsigned int symindex,
195ed981856SPaul Mackerras 		       unsigned int relsec,
196ed981856SPaul Mackerras 		       struct module *module)
197ed981856SPaul Mackerras {
198ed981856SPaul Mackerras 	unsigned int i;
199ed981856SPaul Mackerras 	Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
200ed981856SPaul Mackerras 	Elf32_Sym *sym;
201ed981856SPaul Mackerras 	uint32_t *location;
202ed981856SPaul Mackerras 	uint32_t value;
203ed981856SPaul Mackerras 
204ed981856SPaul Mackerras 	DEBUGP("Applying ADD relocate section %u to %u\n", relsec,
205ed981856SPaul Mackerras 	       sechdrs[relsec].sh_info);
206ed981856SPaul Mackerras 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
207ed981856SPaul Mackerras 		/* This is where to make the change */
208ed981856SPaul Mackerras 		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
209ed981856SPaul Mackerras 			+ rela[i].r_offset;
210ed981856SPaul Mackerras 		/* This is the symbol it is referring to.  Note that all
211ed981856SPaul Mackerras 		   undefined symbols have been resolved.  */
212ed981856SPaul Mackerras 		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
213ed981856SPaul Mackerras 			+ ELF32_R_SYM(rela[i].r_info);
214ed981856SPaul Mackerras 		/* `Everything is relative'. */
215ed981856SPaul Mackerras 		value = sym->st_value + rela[i].r_addend;
216ed981856SPaul Mackerras 
217ed981856SPaul Mackerras 		switch (ELF32_R_TYPE(rela[i].r_info)) {
218ed981856SPaul Mackerras 		case R_PPC_ADDR32:
219ed981856SPaul Mackerras 			/* Simply set it */
220ed981856SPaul Mackerras 			*(uint32_t *)location = value;
221ed981856SPaul Mackerras 			break;
222ed981856SPaul Mackerras 
223ed981856SPaul Mackerras 		case R_PPC_ADDR16_LO:
224ed981856SPaul Mackerras 			/* Low half of the symbol */
225ed981856SPaul Mackerras 			*(uint16_t *)location = value;
226ed981856SPaul Mackerras 			break;
227ed981856SPaul Mackerras 
2289a3d6458SSimon Vallet 		case R_PPC_ADDR16_HI:
2299a3d6458SSimon Vallet 			/* Higher half of the symbol */
2309a3d6458SSimon Vallet 			*(uint16_t *)location = (value >> 16);
2319a3d6458SSimon Vallet 			break;
2329a3d6458SSimon Vallet 
233ed981856SPaul Mackerras 		case R_PPC_ADDR16_HA:
234ed981856SPaul Mackerras 			/* Sign-adjusted lower 16 bits: PPC ELF ABI says:
235ed981856SPaul Mackerras 			   (((x >> 16) + ((x & 0x8000) ? 1 : 0))) & 0xFFFF.
236ed981856SPaul Mackerras 			   This is the same, only sane.
237ed981856SPaul Mackerras 			 */
238ed981856SPaul Mackerras 			*(uint16_t *)location = (value + 0x8000) >> 16;
239ed981856SPaul Mackerras 			break;
240ed981856SPaul Mackerras 
241ed981856SPaul Mackerras 		case R_PPC_REL24:
242ed981856SPaul Mackerras 			if ((int)(value - (uint32_t)location) < -0x02000000
243ed981856SPaul Mackerras 			    || (int)(value - (uint32_t)location) >= 0x02000000)
244ed981856SPaul Mackerras 				value = do_plt_call(location, value,
245ed981856SPaul Mackerras 						    sechdrs, module);
246ed981856SPaul Mackerras 
247ed981856SPaul Mackerras 			/* Only replace bits 2 through 26 */
248ed981856SPaul Mackerras 			DEBUGP("REL24 value = %08X. location = %08X\n",
249ed981856SPaul Mackerras 			       value, (uint32_t)location);
250ed981856SPaul Mackerras 			DEBUGP("Location before: %08X.\n",
251ed981856SPaul Mackerras 			       *(uint32_t *)location);
252ed981856SPaul Mackerras 			*(uint32_t *)location
253ed981856SPaul Mackerras 				= (*(uint32_t *)location & ~0x03fffffc)
254ed981856SPaul Mackerras 				| ((value - (uint32_t)location)
255ed981856SPaul Mackerras 				   & 0x03fffffc);
256ed981856SPaul Mackerras 			DEBUGP("Location after: %08X.\n",
257ed981856SPaul Mackerras 			       *(uint32_t *)location);
258ed981856SPaul Mackerras 			DEBUGP("ie. jump to %08X+%08X = %08X\n",
259ed981856SPaul Mackerras 			       *(uint32_t *)location & 0x03fffffc,
260ed981856SPaul Mackerras 			       (uint32_t)location,
261ed981856SPaul Mackerras 			       (*(uint32_t *)location & 0x03fffffc)
262ed981856SPaul Mackerras 			       + (uint32_t)location);
263ed981856SPaul Mackerras 			break;
264ed981856SPaul Mackerras 
265ed981856SPaul Mackerras 		case R_PPC_REL32:
266ed981856SPaul Mackerras 			/* 32-bit relative jump. */
267ed981856SPaul Mackerras 			*(uint32_t *)location = value - (uint32_t)location;
268ed981856SPaul Mackerras 			break;
269ed981856SPaul Mackerras 
270ed981856SPaul Mackerras 		default:
271ed981856SPaul Mackerras 			printk("%s: unknown ADD relocation: %u\n",
272ed981856SPaul Mackerras 			       module->name,
273ed981856SPaul Mackerras 			       ELF32_R_TYPE(rela[i].r_info));
274ed981856SPaul Mackerras 			return -ENOEXEC;
275ed981856SPaul Mackerras 		}
276ed981856SPaul Mackerras 	}
277ed981856SPaul Mackerras 	return 0;
278ed981856SPaul Mackerras }
279ed981856SPaul Mackerras 
28021c4ff80SBenjamin Herrenschmidt static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
28121c4ff80SBenjamin Herrenschmidt 				    const Elf_Shdr *sechdrs,
28221c4ff80SBenjamin Herrenschmidt 				    const char *name)
28321c4ff80SBenjamin Herrenschmidt {
28421c4ff80SBenjamin Herrenschmidt 	char *secstrings;
28521c4ff80SBenjamin Herrenschmidt 	unsigned int i;
28621c4ff80SBenjamin Herrenschmidt 
28721c4ff80SBenjamin Herrenschmidt 	secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
28821c4ff80SBenjamin Herrenschmidt 	for (i = 1; i < hdr->e_shnum; i++)
28921c4ff80SBenjamin Herrenschmidt 		if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0)
29021c4ff80SBenjamin Herrenschmidt 			return &sechdrs[i];
29121c4ff80SBenjamin Herrenschmidt 	return NULL;
29221c4ff80SBenjamin Herrenschmidt }
29321c4ff80SBenjamin Herrenschmidt 
294ed981856SPaul Mackerras int module_finalize(const Elf_Ehdr *hdr,
295ed981856SPaul Mackerras 		    const Elf_Shdr *sechdrs,
296ed981856SPaul Mackerras 		    struct module *me)
297ed981856SPaul Mackerras {
29821c4ff80SBenjamin Herrenschmidt 	const Elf_Shdr *sect;
29973c9ceabSJeremy Fitzhardinge 	int err;
300ed981856SPaul Mackerras 
30173c9ceabSJeremy Fitzhardinge 	err = module_bug_finalize(hdr, sechdrs, me);
30273c9ceabSJeremy Fitzhardinge 	if (err)		/* never true, currently */
30373c9ceabSJeremy Fitzhardinge 		return err;
304ed981856SPaul Mackerras 
30521c4ff80SBenjamin Herrenschmidt 	/* Apply feature fixups */
30621c4ff80SBenjamin Herrenschmidt 	sect = find_section(hdr, sechdrs, "__ftr_fixup");
30721c4ff80SBenjamin Herrenschmidt 	if (sect != NULL)
30821c4ff80SBenjamin Herrenschmidt 		do_feature_fixups(cur_cpu_spec->cpu_features,
30921c4ff80SBenjamin Herrenschmidt 				  (void *)sect->sh_addr,
31021c4ff80SBenjamin Herrenschmidt 				  (void *)sect->sh_addr + sect->sh_size);
31121c4ff80SBenjamin Herrenschmidt 
312ed981856SPaul Mackerras 	return 0;
313ed981856SPaul Mackerras }
314ed981856SPaul Mackerras 
315ed981856SPaul Mackerras void module_arch_cleanup(struct module *mod)
316ed981856SPaul Mackerras {
31773c9ceabSJeremy Fitzhardinge 	module_bug_cleanup(mod);
318ed981856SPaul Mackerras }
319ed981856SPaul Mackerras 
320ed981856SPaul Mackerras struct bug_entry *module_find_bug(unsigned long bugaddr)
321ed981856SPaul Mackerras {
322ed981856SPaul Mackerras 	struct mod_arch_specific *mod;
323ed981856SPaul Mackerras 	unsigned int i;
324ed981856SPaul Mackerras 	struct bug_entry *bug;
325ed981856SPaul Mackerras 
326ed981856SPaul Mackerras 	list_for_each_entry(mod, &module_bug_list, bug_list) {
327ed981856SPaul Mackerras 		bug = mod->bug_table;
328ed981856SPaul Mackerras 		for (i = 0; i < mod->num_bugs; ++i, ++bug)
329ed981856SPaul Mackerras 			if (bugaddr == bug->bug_addr)
330ed981856SPaul Mackerras 				return bug;
331ed981856SPaul Mackerras 	}
332ed981856SPaul Mackerras 	return NULL;
333ed981856SPaul Mackerras }
334