Merge branches 'acerhdf', 'acpi-pci-bind', 'bjorn-pci-root', 'bugzilla-12904', 'bugzi...
[linux-2.6] / 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 void *module_alloc(unsigned long size)
28 {
29         if (size == 0)
30                 return NULL;
31         return vmalloc_exec(size);
32 }
33
34 void module_free(struct module *mod, void *module_region)
35 {
36         vfree(module_region);
37 }
38
39 int module_frob_arch_sections(Elf32_Ehdr *hdr,
40                               Elf32_Shdr *sechdrs,
41                               char *secstrings,
42                               struct module *mod)
43 {
44         return 0;
45 }
46
47 static int
48 decode_calln_opcode (unsigned char *location)
49 {
50 #ifdef __XTENSA_EB__
51         return (location[0] & 0xf0) == 0x50;
52 #endif
53 #ifdef __XTENSA_EL__
54         return (location[0] & 0xf) == 0x5;
55 #endif
56 }
57
58 static int
59 decode_l32r_opcode (unsigned char *location)
60 {
61 #ifdef __XTENSA_EB__
62         return (location[0] & 0xf0) == 0x10;
63 #endif
64 #ifdef __XTENSA_EL__
65         return (location[0] & 0xf) == 0x1;
66 #endif
67 }
68
69 int apply_relocate(Elf32_Shdr *sechdrs,
70                    const char *strtab,
71                    unsigned int symindex,
72                    unsigned int relsec,
73                    struct module *mod)
74 {
75         printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
76                mod->name);
77         return -ENOEXEC;
78
79 }
80
81 int apply_relocate_add(Elf32_Shdr *sechdrs,
82                        const char *strtab,
83                        unsigned int symindex,
84                        unsigned int relsec,
85                        struct module *mod)
86 {
87         unsigned int i;
88         Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
89         Elf32_Sym *sym;
90         unsigned char *location;
91         uint32_t value;
92
93 #ifdef DEBUG_RELOCATE
94         printk("Applying relocate section %u to %u\n", relsec,
95                sechdrs[relsec].sh_info);
96 #endif
97         for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
98                 location = (char *)sechdrs[sechdrs[relsec].sh_info].sh_addr
99                         + rela[i].r_offset;
100                 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
101                         + ELF32_R_SYM(rela[i].r_info);
102                 value = sym->st_value + rela[i].r_addend;
103
104                 switch (ELF32_R_TYPE(rela[i].r_info)) {
105                 case R_XTENSA_NONE:
106                 case R_XTENSA_DIFF8:
107                 case R_XTENSA_DIFF16:
108                 case R_XTENSA_DIFF32:
109                 case R_XTENSA_ASM_EXPAND:
110                         break;
111
112                 case R_XTENSA_32:
113                 case R_XTENSA_PLT:
114                         *(uint32_t *)location += value;
115                         break;
116
117                 case R_XTENSA_SLOT0_OP:
118                         if (decode_calln_opcode(location)) {
119                                 value -= ((unsigned long)location & -4) + 4;
120                                 if ((value & 3) != 0 ||
121                                     ((value + (1 << 19)) >> 20) != 0) {
122                                         printk("%s: relocation out of range, "
123                                                "section %d reloc %d "
124                                                "sym '%s'\n",
125                                                mod->name, relsec, i,
126                                                strtab + sym->st_name);
127                                         return -ENOEXEC;
128                                 }
129                                 value = (signed int)value >> 2;
130 #ifdef __XTENSA_EB__
131                                 location[0] = ((location[0] & ~0x3) |
132                                             ((value >> 16) & 0x3));
133                                 location[1] = (value >> 8) & 0xff;
134                                 location[2] = value & 0xff;
135 #endif
136 #ifdef __XTENSA_EL__
137                                 location[0] = ((location[0] & ~0xc0) |
138                                             ((value << 6) & 0xc0));
139                                 location[1] = (value >> 2) & 0xff;
140                                 location[2] = (value >> 10) & 0xff;
141 #endif
142                         } else if (decode_l32r_opcode(location)) {
143                                 value -= (((unsigned long)location + 3) & -4);
144                                 if ((value & 3) != 0 ||
145                                     (signed int)value >> 18 != -1) {
146                                         printk("%s: relocation out of range, "
147                                                "section %d reloc %d "
148                                                "sym '%s'\n",
149                                                mod->name, relsec, i,
150                                                strtab + sym->st_name);
151                                         return -ENOEXEC;
152                                 }
153                                 value = (signed int)value >> 2;
154
155 #ifdef __XTENSA_EB__
156                                 location[1] = (value >> 8) & 0xff;
157                                 location[2] = value & 0xff;
158 #endif
159 #ifdef __XTENSA_EL__
160                                 location[1] = value & 0xff;
161                                 location[2] = (value >> 8) & 0xff;
162 #endif
163                         }
164                         /* FIXME: Ignore any other opcodes.  The Xtensa
165                            assembler currently assumes that the linker will
166                            always do relaxation and so all PC-relative
167                            operands need relocations.  (The assembler also
168                            writes out the tentative PC-relative values,
169                            assuming no link-time relaxation, so it is usually
170                            safe to ignore the relocations.)  If the
171                            assembler's "--no-link-relax" flag can be made to
172                            work, and if all kernel modules can be assembled
173                            with that flag, then unexpected relocations could
174                            be detected here.  */
175                         break;
176
177                 case R_XTENSA_SLOT1_OP:
178                 case R_XTENSA_SLOT2_OP:
179                 case R_XTENSA_SLOT3_OP:
180                 case R_XTENSA_SLOT4_OP:
181                 case R_XTENSA_SLOT5_OP:
182                 case R_XTENSA_SLOT6_OP:
183                 case R_XTENSA_SLOT7_OP:
184                 case R_XTENSA_SLOT8_OP:
185                 case R_XTENSA_SLOT9_OP:
186                 case R_XTENSA_SLOT10_OP:
187                 case R_XTENSA_SLOT11_OP:
188                 case R_XTENSA_SLOT12_OP:
189                 case R_XTENSA_SLOT13_OP:
190                 case R_XTENSA_SLOT14_OP:
191                         printk("%s: unexpected FLIX relocation: %u\n",
192                                mod->name,
193                                ELF32_R_TYPE(rela[i].r_info));
194                         return -ENOEXEC;
195
196                 case R_XTENSA_SLOT0_ALT:
197                 case R_XTENSA_SLOT1_ALT:
198                 case R_XTENSA_SLOT2_ALT:
199                 case R_XTENSA_SLOT3_ALT:
200                 case R_XTENSA_SLOT4_ALT:
201                 case R_XTENSA_SLOT5_ALT:
202                 case R_XTENSA_SLOT6_ALT:
203                 case R_XTENSA_SLOT7_ALT:
204                 case R_XTENSA_SLOT8_ALT:
205                 case R_XTENSA_SLOT9_ALT:
206                 case R_XTENSA_SLOT10_ALT:
207                 case R_XTENSA_SLOT11_ALT:
208                 case R_XTENSA_SLOT12_ALT:
209                 case R_XTENSA_SLOT13_ALT:
210                 case R_XTENSA_SLOT14_ALT:
211                         printk("%s: unexpected ALT relocation: %u\n",
212                                mod->name,
213                                ELF32_R_TYPE(rela[i].r_info));
214                         return -ENOEXEC;
215
216                 default:
217                         printk("%s: unexpected relocation: %u\n",
218                                mod->name,
219                                ELF32_R_TYPE(rela[i].r_info));
220                         return -ENOEXEC;
221                 }
222         }
223         return 0;
224 }
225
226 int module_finalize(const Elf_Ehdr *hdr,
227                     const Elf_Shdr *sechdrs,
228                     struct module *mod)
229 {
230         return 0;
231 }
232
233 void module_arch_cleanup(struct module *mod)
234 {
235 }