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