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