Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq
[pandora-kernel.git] / arch / xtensa / kernel / module.c
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
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
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
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 }