vserver 2.0 rc7
[linux-2.6.git] / arch / m32r / kernel / module.c
1 /*  Kernel module help for M32R.
2
3     This program is free software; you can redistribute it and/or modify
4     it under the terms of the GNU General Public License as published by
5     the Free Software Foundation; either version 2 of the License, or
6     (at your option) any later version.
7
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12
13     You should have received a copy of the GNU General Public License
14     along with this program; if not, write to the Free Software
15     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 */
17
18 #include <linux/config.h>
19 #include <linux/moduleloader.h>
20 #include <linux/elf.h>
21 #include <linux/vmalloc.h>
22 #include <linux/fs.h>
23 #include <linux/string.h>
24 #include <linux/kernel.h>
25
26 #if 0
27 #define DEBUGP printk
28 #else
29 #define DEBUGP(fmt...)
30 #endif
31
32 void *module_alloc(unsigned long size)
33 {
34         if (size == 0)
35                 return NULL;
36 #ifdef CONFIG_MMU
37         return vmalloc_exec(size);
38 #else
39         return vmalloc(size);
40 #endif
41 }
42
43
44 /* Free memory returned from module_alloc */
45 void module_free(struct module *mod, void *module_region)
46 {
47         vfree(module_region);
48         /* FIXME: If module_region == mod->init_region, trim exception
49            table entries. */
50 }
51
52 /* We don't need anything special. */
53 int module_frob_arch_sections(Elf_Ehdr *hdr,
54                               Elf_Shdr *sechdrs,
55                               char *secstrings,
56                               struct module *mod)
57 {
58         return 0;
59 }
60
61 #define COPY_UNALIGNED_WORD(sw, tw, align) \
62 { \
63         void *__s = &(sw), *__t = &(tw); \
64         unsigned short *__s2 = __s, *__t2 =__t; \
65         unsigned char *__s1 = __s, *__t1 =__t; \
66         switch ((align)) \
67         { \
68         case 0: \
69                 *(unsigned long *) __t = *(unsigned long *) __s; \
70                 break; \
71         case 2: \
72                 *__t2++ = *__s2++; \
73                 *__t2 = *__s2; \
74                 break; \
75         default: \
76                 *__t1++ = *__s1++; \
77                 *__t1++ = *__s1++; \
78                 *__t1++ = *__s1++; \
79                 *__t1 = *__s1; \
80                 break; \
81         } \
82 }
83
84 #define COPY_UNALIGNED_HWORD(sw, tw, align) \
85   { \
86     void *__s = &(sw), *__t = &(tw); \
87     unsigned short *__s2 = __s, *__t2 =__t; \
88     unsigned char *__s1 = __s, *__t1 =__t; \
89     switch ((align)) \
90     { \
91     case 0: \
92       *__t2 = *__s2; \
93       break; \
94     default: \
95       *__t1++ = *__s1++; \
96       *__t1 = *__s1; \
97       break; \
98     } \
99   }
100
101 int apply_relocate_add(Elf32_Shdr *sechdrs,
102                    const char *strtab,
103                    unsigned int symindex,
104                    unsigned int relsec,
105                    struct module *me)
106 {
107         unsigned int i;
108         Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
109         Elf32_Sym *sym;
110         Elf32_Addr relocation;
111         uint32_t *location;
112         uint32_t value;
113         unsigned short *hlocation;
114         unsigned short hvalue;
115         int svalue;
116         int align;
117
118         DEBUGP("Applying relocate section %u to %u\n", relsec,
119                sechdrs[relsec].sh_info);
120         for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
121                 /* This is where to make the change */
122                 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
123                         + rel[i].r_offset;
124                 /* This is the symbol it is referring to.  Note that all
125                    undefined symbols have been resolved.  */
126                 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
127                         + ELF32_R_SYM(rel[i].r_info);
128                 relocation = sym->st_value + rel[i].r_addend;
129                 align = (int)location & 3;
130
131                 switch (ELF32_R_TYPE(rel[i].r_info)) {
132                 case R_M32R_32_RELA:
133                         COPY_UNALIGNED_WORD (*location, value, align);
134                         value += relocation;
135                         COPY_UNALIGNED_WORD (value, *location, align);
136                         break;
137                 case R_M32R_HI16_ULO_RELA:
138                         COPY_UNALIGNED_WORD (*location, value, align);
139                         relocation = (relocation >>16) & 0xffff;
140                         /* RELA must has 0 at relocation field. */
141                         value += relocation;
142                         COPY_UNALIGNED_WORD (value, *location, align);
143                         break;
144                 case R_M32R_HI16_SLO_RELA:
145                         COPY_UNALIGNED_WORD (*location, value, align);
146                         if (relocation & 0x8000) relocation += 0x10000;
147                         relocation = (relocation >>16) & 0xffff;
148                         /* RELA must has 0 at relocation field. */
149                         value += relocation;
150                         COPY_UNALIGNED_WORD (value, *location, align);
151                         break;
152                 case R_M32R_16_RELA:
153                         hlocation = (unsigned short *)location;
154                         relocation = relocation & 0xffff;
155                         /* RELA must has 0 at relocation field. */
156                         hvalue = relocation;
157                         COPY_UNALIGNED_WORD (hvalue, *hlocation, align);
158                         break;
159                 case R_M32R_SDA16_RELA:
160                 case R_M32R_LO16_RELA:
161                         COPY_UNALIGNED_WORD (*location, value, align);
162                         relocation = relocation & 0xffff;
163                         /* RELA must has 0 at relocation field. */
164                         value += relocation;
165                         COPY_UNALIGNED_WORD (value, *location, align);
166                         break;
167                 case R_M32R_24_RELA:
168                         COPY_UNALIGNED_WORD (*location, value, align);
169                         relocation = relocation & 0xffffff;
170                         /* RELA must has 0 at relocation field. */
171                         value += relocation;
172                         COPY_UNALIGNED_WORD (value, *location, align);
173                         break;
174                 case R_M32R_18_PCREL_RELA:
175                         relocation = (relocation - (Elf32_Addr) location);
176                         if (relocation < -0x20000 || 0x1fffc < relocation)
177                                 {
178                                         printk(KERN_ERR "module %s: relocation overflow: %u\n",
179                                         me->name, relocation);
180                                         return -ENOEXEC;
181                                 }
182                         COPY_UNALIGNED_WORD (*location, value, align);
183                         if (value & 0xffff)
184                                 {
185                                         /* RELA must has 0 at relocation field. */
186                                         printk(KERN_ERR "module %s: illegal relocation field: %u\n",
187                                         me->name, value);
188                                         return -ENOEXEC;
189                                 }
190                         relocation = (relocation >> 2) & 0xffff;
191                         value += relocation;
192                         COPY_UNALIGNED_WORD (value, *location, align);
193                         break;
194                 case R_M32R_10_PCREL_RELA:
195                         hlocation = (unsigned short *)location;
196                         relocation = (relocation - (Elf32_Addr) location);
197                         COPY_UNALIGNED_HWORD (*hlocation, hvalue, align);
198                         svalue = (int)hvalue;
199                         svalue = (signed char)svalue << 2;
200                         relocation += svalue;
201                         relocation = (relocation >> 2) & 0xff;
202                         hvalue = hvalue & 0xff00;
203                         hvalue += relocation;
204                         COPY_UNALIGNED_HWORD (hvalue, *hlocation, align);
205                         break;
206                 case R_M32R_26_PCREL_RELA:
207                         relocation = (relocation - (Elf32_Addr) location);
208                         if (relocation < -0x2000000 || 0x1fffffc < relocation)
209                                 {
210                                         printk(KERN_ERR "module %s: relocation overflow: %u\n",
211                                         me->name, relocation);
212                                         return -ENOEXEC;
213                                 }
214                         COPY_UNALIGNED_WORD (*location, value, align);
215                         if (value & 0xffffff)
216                                 {
217                                         /* RELA must has 0 at relocation field. */
218                                         printk(KERN_ERR "module %s: illegal relocation field: %u\n",
219                                         me->name, value);
220                                         return -ENOEXEC;
221                                 }
222                         relocation = (relocation >> 2) & 0xffffff;
223                         value += relocation;
224                         COPY_UNALIGNED_WORD (value, *location, align);
225                         break;
226                 default:
227                         printk(KERN_ERR "module %s: Unknown relocation: %u\n",
228                                me->name, ELF32_R_TYPE(rel[i].r_info));
229                         return -ENOEXEC;
230                 }
231         }
232         return 0;
233 }
234
235 int apply_relocate(Elf32_Shdr *sechdrs,
236                        const char *strtab,
237                        unsigned int symindex,
238                        unsigned int relsec,
239                        struct module *me)
240 {
241 #if 0
242         printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
243                me->name);
244         return -ENOEXEC;
245 #endif
246         return 0;
247
248 }
249
250 int module_finalize(const Elf_Ehdr *hdr,
251                     const Elf_Shdr *sechdrs,
252                     struct module *me)
253 {
254         return 0;
255 }
256
257 void module_arch_cleanup(struct module *mod)
258 {
259 }