diff options
| author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-09-14 20:07:33 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-09-14 20:07:33 -0400 |
| commit | 2605a103cadb29053d6bc7e81c7de802ec75ce6c (patch) | |
| tree | e2a83845f59217d66252c7a9265ff99a3b69f525 /arch/xtensa/kernel/module.c | |
| parent | 53a3f3087be361dacfc02e7a85b6d6142a41ce8a (diff) | |
| parent | ebb2a97b2e7422176d52f4f33e3ee400653875b4 (diff) | |
Merge git://git.linux-xtensa.org/kernel/xtensa-feed
* git://git.linux-xtensa.org/kernel/xtensa-feed:
[patch 1/2] Xtensa: enable arbitary tty speed setting ioctls
[patch 2/2] xtensa console.c: remove duplicate #include
[XTENSA] Add support for cache-aliasing
[XTENSA] Add kernel module support
[XTENSA] Add support for executable/non-executable feature in the mmu
[XTENSA] Use the generic version of get_order
[XTENSA] Initialize semaphore_wake_lock
[XTENSA] Add typecast macro for constants
[XTENSA] Fix timer instabilities.
[XTENSA] Fix fadvise64_64
[XTENSA] Remove extraneous include statement
[XTENSA] Move string-io functions to io.c from pci.c
[XTENSA] Move pre-initialized structures to init_task.c
[XTENSA] Add freestanding option to CFLAGS
[XTENSA] Add getpgrp system-call to unistd.h
[XTENSA] add missing system calls
[XTENSA] fix wrong usage of __init and __initdata in traps.c
Diffstat (limited to 'arch/xtensa/kernel/module.c')
| -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 | } |
