diff options
Diffstat (limited to 'arch/xtensa')
-rw-r--r-- | arch/xtensa/kernel/module.c | 195 |
1 files changed, 177 insertions, 18 deletions
diff --git a/arch/xtensa/kernel/module.c b/arch/xtensa/kernel/module.c index 2ea1755a0858..ddf14dcf2ad9 100644 --- a/arch/xtensa/kernel/module.c +++ b/arch/xtensa/kernel/module.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * License. See the file "COPYING" in the main directory of this archive | 7 | * License. See the file "COPYING" in the main directory of this archive |
8 | * for more details. | 8 | * for more details. |
9 | * | 9 | * |
10 | * Copyright (C) 2001 - 2005 Tensilica Inc. | 10 | * Copyright (C) 2001 - 2006 Tensilica Inc. |
11 | * | 11 | * |
12 | * Chris Zankel <chris@zankel.net> | 12 | * Chris Zankel <chris@zankel.net> |
13 | * | 13 | * |
@@ -22,57 +22,216 @@ | |||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/cache.h> | 23 | #include <linux/cache.h> |
24 | 24 | ||
25 | LIST_HEAD(module_buf_list); | 25 | #undef DEBUG_RELOCATE |
26 | 26 | ||
27 | void *module_alloc(unsigned long size) | 27 | void *module_alloc(unsigned long size) |
28 | { | 28 | { |
29 | panic("module_alloc not implemented"); | 29 | if (size == 0) |
30 | return NULL; | ||
31 | return vmalloc(size); | ||
30 | } | 32 | } |
31 | 33 | ||
32 | void module_free(struct module *mod, void *module_region) | 34 | void module_free(struct module *mod, void *module_region) |
33 | { | 35 | { |
34 | panic("module_free not implemented"); | 36 | vfree(module_region); |
37 | /* FIXME: If module_region == mod->init_region, trim exception | ||
38 | table entries. */ | ||
35 | } | 39 | } |
36 | 40 | ||
37 | int module_frob_arch_sections(Elf32_Ehdr *hdr, | 41 | int module_frob_arch_sections(Elf32_Ehdr *hdr, |
38 | Elf32_Shdr *sechdrs, | 42 | Elf32_Shdr *sechdrs, |
39 | char *secstrings, | 43 | char *secstrings, |
40 | struct module *me) | 44 | struct module *mod) |
41 | { | 45 | { |
42 | panic("module_frob_arch_sections not implemented"); | 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 | ||
43 | } | 69 | } |
44 | 70 | ||
45 | int apply_relocate(Elf32_Shdr *sechdrs, | 71 | int apply_relocate(Elf32_Shdr *sechdrs, |
46 | const char *strtab, | 72 | const char *strtab, |
47 | unsigned int symindex, | 73 | unsigned int symindex, |
48 | unsigned int relsec, | 74 | unsigned int relsec, |
49 | struct module *module) | 75 | struct module *mod) |
50 | { | 76 | { |
51 | panic ("apply_relocate not implemented"); | 77 | printk(KERN_ERR "module %s: REL RELOCATION unsupported\n", |
78 | mod->name); | ||
79 | return -ENOEXEC; | ||
80 | |||
52 | } | 81 | } |
53 | 82 | ||
54 | int apply_relocate_add(Elf32_Shdr *sechdrs, | 83 | int apply_relocate_add(Elf32_Shdr *sechdrs, |
55 | const char *strtab, | 84 | const char *strtab, |
56 | unsigned int symindex, | 85 | unsigned int symindex, |
57 | unsigned int relsec, | 86 | unsigned int relsec, |
58 | struct module *module) | 87 | struct module *mod) |
59 | { | 88 | { |
60 | panic("apply_relocate_add not implemented"); | 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; | ||
61 | } | 226 | } |
62 | 227 | ||
63 | int module_finalize(const Elf_Ehdr *hdr, | 228 | int module_finalize(const Elf_Ehdr *hdr, |
64 | const Elf_Shdr *sechdrs, | 229 | const Elf_Shdr *sechdrs, |
65 | struct module *me) | 230 | struct module *mod) |
66 | { | 231 | { |
67 | panic ("module_finalize not implemented"); | 232 | return 0; |
68 | } | 233 | } |
69 | 234 | ||
70 | void module_arch_cleanup(struct module *mod) | 235 | void module_arch_cleanup(struct module *mod) |
71 | { | 236 | { |
72 | panic("module_arch_cleanup not implemented"); | ||
73 | } | ||
74 | |||
75 | struct bug_entry *module_find_bug(unsigned long bugaddr) | ||
76 | { | ||
77 | panic("module_find_bug not implemented"); | ||
78 | } | 237 | } |