Merge branches 'release', 'bugzilla-8570', 'bugzilla-9966', 'bugzilla-9998', 'bugzill...
[linux-2.6] / arch / m68k / kernel / module.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file COPYING in the main directory of this archive
4  * for more details.
5  */
6
7 #include <linux/moduleloader.h>
8 #include <linux/elf.h>
9 #include <linux/vmalloc.h>
10 #include <linux/fs.h>
11 #include <linux/string.h>
12 #include <linux/kernel.h>
13
14 #if 0
15 #define DEBUGP printk
16 #else
17 #define DEBUGP(fmt...)
18 #endif
19
20 #ifdef CONFIG_MODULES
21
22 void *module_alloc(unsigned long size)
23 {
24         if (size == 0)
25                 return NULL;
26         return vmalloc(size);
27 }
28
29
30 /* Free memory returned from module_alloc */
31 void module_free(struct module *mod, void *module_region)
32 {
33         vfree(module_region);
34         /* FIXME: If module_region == mod->init_region, trim exception
35            table entries. */
36 }
37
38 /* We don't need anything special. */
39 int module_frob_arch_sections(Elf_Ehdr *hdr,
40                               Elf_Shdr *sechdrs,
41                               char *secstrings,
42                               struct module *mod)
43 {
44         return 0;
45 }
46
47 int apply_relocate(Elf32_Shdr *sechdrs,
48                    const char *strtab,
49                    unsigned int symindex,
50                    unsigned int relsec,
51                    struct module *me)
52 {
53         unsigned int i;
54         Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
55         Elf32_Sym *sym;
56         uint32_t *location;
57
58         DEBUGP("Applying relocate section %u to %u\n", relsec,
59                sechdrs[relsec].sh_info);
60         for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
61                 /* This is where to make the change */
62                 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
63                         + rel[i].r_offset;
64                 /* This is the symbol it is referring to.  Note that all
65                    undefined symbols have been resolved.  */
66                 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
67                         + ELF32_R_SYM(rel[i].r_info);
68
69                 switch (ELF32_R_TYPE(rel[i].r_info)) {
70                 case R_68K_32:
71                         /* We add the value into the location given */
72                         *location += sym->st_value;
73                         break;
74                 case R_68K_PC32:
75                         /* Add the value, subtract its postition */
76                         *location += sym->st_value - (uint32_t)location;
77                         break;
78                 default:
79                         printk(KERN_ERR "module %s: Unknown relocation: %u\n",
80                                me->name, ELF32_R_TYPE(rel[i].r_info));
81                         return -ENOEXEC;
82                 }
83         }
84         return 0;
85 }
86
87 int apply_relocate_add(Elf32_Shdr *sechdrs,
88                        const char *strtab,
89                        unsigned int symindex,
90                        unsigned int relsec,
91                        struct module *me)
92 {
93         unsigned int i;
94         Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
95         Elf32_Sym *sym;
96         uint32_t *location;
97
98         DEBUGP("Applying relocate_add section %u to %u\n", relsec,
99                sechdrs[relsec].sh_info);
100         for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
101                 /* This is where to make the change */
102                 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
103                         + rel[i].r_offset;
104                 /* This is the symbol it is referring to.  Note that all
105                    undefined symbols have been resolved.  */
106                 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
107                         + ELF32_R_SYM(rel[i].r_info);
108
109                 switch (ELF32_R_TYPE(rel[i].r_info)) {
110                 case R_68K_32:
111                         /* We add the value into the location given */
112                         *location = rel[i].r_addend + sym->st_value;
113                         break;
114                 case R_68K_PC32:
115                         /* Add the value, subtract its postition */
116                         *location = rel[i].r_addend + sym->st_value - (uint32_t)location;
117                         break;
118                 default:
119                         printk(KERN_ERR "module %s: Unknown relocation: %u\n",
120                                me->name, ELF32_R_TYPE(rel[i].r_info));
121                         return -ENOEXEC;
122                 }
123         }
124         return 0;
125 }
126
127 int module_finalize(const Elf_Ehdr *hdr,
128                     const Elf_Shdr *sechdrs,
129                     struct module *mod)
130 {
131         module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end);
132
133         return 0;
134 }
135
136 void module_arch_cleanup(struct module *mod)
137 {
138 }
139
140 #endif /* CONFIG_MODULES */
141
142 void module_fixup(struct module *mod, struct m68k_fixup_info *start,
143                   struct m68k_fixup_info *end)
144 {
145         struct m68k_fixup_info *fixup;
146
147         for (fixup = start; fixup < end; fixup++) {
148                 switch (fixup->type) {
149                 case m68k_fixup_memoffset:
150                         *(u32 *)fixup->addr = m68k_memoffset;
151                         break;
152                 case m68k_fixup_vnode_shift:
153                         *(u16 *)fixup->addr += m68k_virt_to_node_shift;
154                         break;
155                 }
156         }
157 }