xref: /openbmc/linux/arch/xtensa/kernel/module.c (revision c130d3be)
15a0015d6SChris Zankel /*
2f30c2269SUwe Zeisberger  * arch/xtensa/kernel/module.c
35a0015d6SChris Zankel  *
45a0015d6SChris Zankel  * Module support.
55a0015d6SChris Zankel  *
65a0015d6SChris Zankel  * This file is subject to the terms and conditions of the GNU General Public
75a0015d6SChris Zankel  * License.  See the file "COPYING" in the main directory of this archive
85a0015d6SChris Zankel  * for more details.
95a0015d6SChris Zankel  *
10ff6fd469SChris Zankel  * Copyright (C) 2001 - 2006 Tensilica Inc.
115a0015d6SChris Zankel  *
125a0015d6SChris Zankel  * Chris Zankel <chris@zankel.net>
135a0015d6SChris Zankel  *
145a0015d6SChris Zankel  */
155a0015d6SChris Zankel 
165a0015d6SChris Zankel #include <linux/module.h>
175a0015d6SChris Zankel #include <linux/moduleloader.h>
185a0015d6SChris Zankel #include <linux/elf.h>
195a0015d6SChris Zankel #include <linux/vmalloc.h>
205a0015d6SChris Zankel #include <linux/fs.h>
215a0015d6SChris Zankel #include <linux/string.h>
225a0015d6SChris Zankel #include <linux/kernel.h>
235a0015d6SChris Zankel #include <linux/cache.h>
245a0015d6SChris Zankel 
25ff6fd469SChris Zankel static int
decode_calln_opcode(unsigned char * location)26ff6fd469SChris Zankel decode_calln_opcode (unsigned char *location)
27ff6fd469SChris Zankel {
28ff6fd469SChris Zankel #ifdef __XTENSA_EB__
29ff6fd469SChris Zankel 	return (location[0] & 0xf0) == 0x50;
30ff6fd469SChris Zankel #endif
31ff6fd469SChris Zankel #ifdef __XTENSA_EL__
32ff6fd469SChris Zankel 	return (location[0] & 0xf) == 0x5;
33ff6fd469SChris Zankel #endif
34ff6fd469SChris Zankel }
35ff6fd469SChris Zankel 
36ff6fd469SChris Zankel static int
decode_l32r_opcode(unsigned char * location)37ff6fd469SChris Zankel decode_l32r_opcode (unsigned char *location)
38ff6fd469SChris Zankel {
39ff6fd469SChris Zankel #ifdef __XTENSA_EB__
40ff6fd469SChris Zankel 	return (location[0] & 0xf0) == 0x10;
41ff6fd469SChris Zankel #endif
42ff6fd469SChris Zankel #ifdef __XTENSA_EL__
43ff6fd469SChris Zankel 	return (location[0] & 0xf) == 0x1;
44ff6fd469SChris Zankel #endif
455a0015d6SChris Zankel }
465a0015d6SChris Zankel 
apply_relocate_add(Elf32_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * mod)475a0015d6SChris Zankel int apply_relocate_add(Elf32_Shdr *sechdrs,
485a0015d6SChris Zankel 		       const char *strtab,
495a0015d6SChris Zankel 		       unsigned int symindex,
505a0015d6SChris Zankel 		       unsigned int relsec,
51ff6fd469SChris Zankel 		       struct module *mod)
525a0015d6SChris Zankel {
53ff6fd469SChris Zankel 	unsigned int i;
54ff6fd469SChris Zankel 	Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
55ff6fd469SChris Zankel 	Elf32_Sym *sym;
56ff6fd469SChris Zankel 	unsigned char *location;
57ff6fd469SChris Zankel 	uint32_t value;
58ff6fd469SChris Zankel 
59c130d3beSMax Filippov 	pr_debug("Applying relocate section %u to %u\n", relsec,
60ff6fd469SChris Zankel 		 sechdrs[relsec].sh_info);
61c130d3beSMax Filippov 
62ff6fd469SChris Zankel 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
63ff6fd469SChris Zankel 		location = (char *)sechdrs[sechdrs[relsec].sh_info].sh_addr
64ff6fd469SChris Zankel 			+ rela[i].r_offset;
65ff6fd469SChris Zankel 		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
66ff6fd469SChris Zankel 			+ ELF32_R_SYM(rela[i].r_info);
67ff6fd469SChris Zankel 		value = sym->st_value + rela[i].r_addend;
68ff6fd469SChris Zankel 
69ff6fd469SChris Zankel 		switch (ELF32_R_TYPE(rela[i].r_info)) {
70ff6fd469SChris Zankel 		case R_XTENSA_NONE:
71ff6fd469SChris Zankel 		case R_XTENSA_DIFF8:
72ff6fd469SChris Zankel 		case R_XTENSA_DIFF16:
73ff6fd469SChris Zankel 		case R_XTENSA_DIFF32:
74ff6fd469SChris Zankel 		case R_XTENSA_ASM_EXPAND:
75ff6fd469SChris Zankel 			break;
76ff6fd469SChris Zankel 
77ff6fd469SChris Zankel 		case R_XTENSA_32:
78ff6fd469SChris Zankel 		case R_XTENSA_PLT:
79ff6fd469SChris Zankel 			*(uint32_t *)location += value;
80ff6fd469SChris Zankel 			break;
81ff6fd469SChris Zankel 
82ff6fd469SChris Zankel 		case R_XTENSA_SLOT0_OP:
83ff6fd469SChris Zankel 			if (decode_calln_opcode(location)) {
84ff6fd469SChris Zankel 				value -= ((unsigned long)location & -4) + 4;
85ff6fd469SChris Zankel 				if ((value & 3) != 0 ||
86ff6fd469SChris Zankel 				    ((value + (1 << 19)) >> 20) != 0) {
87c130d3beSMax Filippov 					pr_err("%s: relocation out of range, "
88ff6fd469SChris Zankel 					       "section %d reloc %d "
89ff6fd469SChris Zankel 					       "sym '%s'\n",
90ff6fd469SChris Zankel 					       mod->name, relsec, i,
91ff6fd469SChris Zankel 					       strtab + sym->st_name);
92ff6fd469SChris Zankel 					return -ENOEXEC;
93ff6fd469SChris Zankel 				}
94ff6fd469SChris Zankel 				value = (signed int)value >> 2;
95ff6fd469SChris Zankel #ifdef __XTENSA_EB__
96ff6fd469SChris Zankel 				location[0] = ((location[0] & ~0x3) |
97ff6fd469SChris Zankel 					    ((value >> 16) & 0x3));
98ff6fd469SChris Zankel 				location[1] = (value >> 8) & 0xff;
99ff6fd469SChris Zankel 				location[2] = value & 0xff;
100ff6fd469SChris Zankel #endif
101ff6fd469SChris Zankel #ifdef __XTENSA_EL__
102ff6fd469SChris Zankel 				location[0] = ((location[0] & ~0xc0) |
103ff6fd469SChris Zankel 					    ((value << 6) & 0xc0));
104ff6fd469SChris Zankel 				location[1] = (value >> 2) & 0xff;
105ff6fd469SChris Zankel 				location[2] = (value >> 10) & 0xff;
106ff6fd469SChris Zankel #endif
107ff6fd469SChris Zankel 			} else if (decode_l32r_opcode(location)) {
108ff6fd469SChris Zankel 				value -= (((unsigned long)location + 3) & -4);
109ff6fd469SChris Zankel 				if ((value & 3) != 0 ||
110ff6fd469SChris Zankel 				    (signed int)value >> 18 != -1) {
111c130d3beSMax Filippov 					pr_err("%s: relocation out of range, "
112ff6fd469SChris Zankel 					       "section %d reloc %d "
113ff6fd469SChris Zankel 					       "sym '%s'\n",
114ff6fd469SChris Zankel 					       mod->name, relsec, i,
115ff6fd469SChris Zankel 					       strtab + sym->st_name);
116ff6fd469SChris Zankel 					return -ENOEXEC;
117ff6fd469SChris Zankel 				}
118ff6fd469SChris Zankel 				value = (signed int)value >> 2;
119ff6fd469SChris Zankel 
120ff6fd469SChris Zankel #ifdef __XTENSA_EB__
121ff6fd469SChris Zankel 				location[1] = (value >> 8) & 0xff;
122ff6fd469SChris Zankel 				location[2] = value & 0xff;
123ff6fd469SChris Zankel #endif
124ff6fd469SChris Zankel #ifdef __XTENSA_EL__
125ff6fd469SChris Zankel 				location[1] = value & 0xff;
126ff6fd469SChris Zankel 				location[2] = (value >> 8) & 0xff;
127ff6fd469SChris Zankel #endif
128ff6fd469SChris Zankel 			}
129ff6fd469SChris Zankel 			/* FIXME: Ignore any other opcodes.  The Xtensa
130ff6fd469SChris Zankel 			   assembler currently assumes that the linker will
131ff6fd469SChris Zankel 			   always do relaxation and so all PC-relative
132ff6fd469SChris Zankel 			   operands need relocations.  (The assembler also
133ff6fd469SChris Zankel 			   writes out the tentative PC-relative values,
134ff6fd469SChris Zankel 			   assuming no link-time relaxation, so it is usually
135ff6fd469SChris Zankel 			   safe to ignore the relocations.)  If the
136ff6fd469SChris Zankel 			   assembler's "--no-link-relax" flag can be made to
137ff6fd469SChris Zankel 			   work, and if all kernel modules can be assembled
138ff6fd469SChris Zankel 			   with that flag, then unexpected relocations could
139ff6fd469SChris Zankel 			   be detected here.  */
140ff6fd469SChris Zankel 			break;
141ff6fd469SChris Zankel 
142ff6fd469SChris Zankel 		case R_XTENSA_SLOT1_OP:
143ff6fd469SChris Zankel 		case R_XTENSA_SLOT2_OP:
144ff6fd469SChris Zankel 		case R_XTENSA_SLOT3_OP:
145ff6fd469SChris Zankel 		case R_XTENSA_SLOT4_OP:
146ff6fd469SChris Zankel 		case R_XTENSA_SLOT5_OP:
147ff6fd469SChris Zankel 		case R_XTENSA_SLOT6_OP:
148ff6fd469SChris Zankel 		case R_XTENSA_SLOT7_OP:
149ff6fd469SChris Zankel 		case R_XTENSA_SLOT8_OP:
150ff6fd469SChris Zankel 		case R_XTENSA_SLOT9_OP:
151ff6fd469SChris Zankel 		case R_XTENSA_SLOT10_OP:
152ff6fd469SChris Zankel 		case R_XTENSA_SLOT11_OP:
153ff6fd469SChris Zankel 		case R_XTENSA_SLOT12_OP:
154ff6fd469SChris Zankel 		case R_XTENSA_SLOT13_OP:
155ff6fd469SChris Zankel 		case R_XTENSA_SLOT14_OP:
156c130d3beSMax Filippov 			pr_err("%s: unexpected FLIX relocation: %u\n",
157ff6fd469SChris Zankel 			       mod->name,
158ff6fd469SChris Zankel 			       ELF32_R_TYPE(rela[i].r_info));
159ff6fd469SChris Zankel 			return -ENOEXEC;
160ff6fd469SChris Zankel 
161ff6fd469SChris Zankel 		case R_XTENSA_SLOT0_ALT:
162ff6fd469SChris Zankel 		case R_XTENSA_SLOT1_ALT:
163ff6fd469SChris Zankel 		case R_XTENSA_SLOT2_ALT:
164ff6fd469SChris Zankel 		case R_XTENSA_SLOT3_ALT:
165ff6fd469SChris Zankel 		case R_XTENSA_SLOT4_ALT:
166ff6fd469SChris Zankel 		case R_XTENSA_SLOT5_ALT:
167ff6fd469SChris Zankel 		case R_XTENSA_SLOT6_ALT:
168ff6fd469SChris Zankel 		case R_XTENSA_SLOT7_ALT:
169ff6fd469SChris Zankel 		case R_XTENSA_SLOT8_ALT:
170ff6fd469SChris Zankel 		case R_XTENSA_SLOT9_ALT:
171ff6fd469SChris Zankel 		case R_XTENSA_SLOT10_ALT:
172ff6fd469SChris Zankel 		case R_XTENSA_SLOT11_ALT:
173ff6fd469SChris Zankel 		case R_XTENSA_SLOT12_ALT:
174ff6fd469SChris Zankel 		case R_XTENSA_SLOT13_ALT:
175ff6fd469SChris Zankel 		case R_XTENSA_SLOT14_ALT:
176c130d3beSMax Filippov 			pr_err("%s: unexpected ALT relocation: %u\n",
177ff6fd469SChris Zankel 			       mod->name,
178ff6fd469SChris Zankel 			       ELF32_R_TYPE(rela[i].r_info));
179ff6fd469SChris Zankel 			return -ENOEXEC;
180ff6fd469SChris Zankel 
181ff6fd469SChris Zankel 		default:
182c130d3beSMax Filippov 			pr_err("%s: unexpected relocation: %u\n",
183ff6fd469SChris Zankel 			       mod->name,
184ff6fd469SChris Zankel 			       ELF32_R_TYPE(rela[i].r_info));
185ff6fd469SChris Zankel 			return -ENOEXEC;
186ff6fd469SChris Zankel 		}
187ff6fd469SChris Zankel 	}
188ff6fd469SChris Zankel 	return 0;
1895a0015d6SChris Zankel }
190