aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/module_64.c
diff options
context:
space:
mode:
authorSam Ravnborg <sam@ravnborg.org>2008-12-03 06:11:52 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-04 12:17:21 -0500
commita88b5ba8bd8ac18aad65ee6c6a254e2e74876db3 (patch)
treeeb3d0ffaf53c3f7ec6083752c2097cecd1cb892a /arch/sparc/kernel/module_64.c
parentd670bd4f803c8b646acd20f3ba21e65458293faf (diff)
sparc,sparc64: unify kernel/
o Move all files from sparc64/kernel/ to sparc/kernel - rename as appropriate o Update sparc/Makefile to the changes o Update sparc/kernel/Makefile to include the sparc64 files NOTE: This commit changes link order on sparc64! Link order had to change for either of sparc32 and sparc64. And assuming sparc64 see more testing than sparc32 change link order on sparc64 where issues will be caught faster. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel/module_64.c')
-rw-r--r--arch/sparc/kernel/module_64.c213
1 files changed, 213 insertions, 0 deletions
diff --git a/arch/sparc/kernel/module_64.c b/arch/sparc/kernel/module_64.c
new file mode 100644
index 000000000000..158484bf5999
--- /dev/null
+++ b/arch/sparc/kernel/module_64.c
@@ -0,0 +1,213 @@
1/* Kernel module help for sparc64.
2 *
3 * Copyright (C) 2001 Rusty Russell.
4 * Copyright (C) 2002 David S. Miller.
5 */
6
7#include <linux/moduleloader.h>
8#include <linux/kernel.h>
9#include <linux/elf.h>
10#include <linux/vmalloc.h>
11#include <linux/fs.h>
12#include <linux/string.h>
13#include <linux/slab.h>
14#include <linux/mm.h>
15
16#include <asm/processor.h>
17#include <asm/spitfire.h>
18
19static void *module_map(unsigned long size)
20{
21 struct vm_struct *area;
22
23 size = PAGE_ALIGN(size);
24 if (!size || size > MODULES_LEN)
25 return NULL;
26
27 area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
28 if (!area)
29 return NULL;
30
31 return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL);
32}
33
34void *module_alloc(unsigned long size)
35{
36 void *ret;
37
38 /* We handle the zero case fine, unlike vmalloc */
39 if (size == 0)
40 return NULL;
41
42 ret = module_map(size);
43 if (!ret)
44 ret = ERR_PTR(-ENOMEM);
45 else
46 memset(ret, 0, size);
47
48 return ret;
49}
50
51/* Free memory returned from module_core_alloc/module_init_alloc */
52void module_free(struct module *mod, void *module_region)
53{
54 vfree(module_region);
55 /* FIXME: If module_region == mod->init_region, trim exception
56 table entries. */
57}
58
59/* Make generic code ignore STT_REGISTER dummy undefined symbols. */
60int module_frob_arch_sections(Elf_Ehdr *hdr,
61 Elf_Shdr *sechdrs,
62 char *secstrings,
63 struct module *mod)
64{
65 unsigned int symidx;
66 Elf64_Sym *sym;
67 const char *strtab;
68 int i;
69
70 for (symidx = 0; sechdrs[symidx].sh_type != SHT_SYMTAB; symidx++) {
71 if (symidx == hdr->e_shnum-1) {
72 printk("%s: no symtab found.\n", mod->name);
73 return -ENOEXEC;
74 }
75 }
76 sym = (Elf64_Sym *)sechdrs[symidx].sh_addr;
77 strtab = (char *)sechdrs[sechdrs[symidx].sh_link].sh_addr;
78
79 for (i = 1; i < sechdrs[symidx].sh_size / sizeof(Elf_Sym); i++) {
80 if (sym[i].st_shndx == SHN_UNDEF &&
81 ELF64_ST_TYPE(sym[i].st_info) == STT_REGISTER)
82 sym[i].st_shndx = SHN_ABS;
83 }
84 return 0;
85}
86
87int apply_relocate(Elf64_Shdr *sechdrs,
88 const char *strtab,
89 unsigned int symindex,
90 unsigned int relsec,
91 struct module *me)
92{
93 printk(KERN_ERR "module %s: non-ADD RELOCATION unsupported\n",
94 me->name);
95 return -ENOEXEC;
96}
97
98int apply_relocate_add(Elf64_Shdr *sechdrs,
99 const char *strtab,
100 unsigned int symindex,
101 unsigned int relsec,
102 struct module *me)
103{
104 unsigned int i;
105 Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
106 Elf64_Sym *sym;
107 u8 *location;
108 u32 *loc32;
109
110 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
111 Elf64_Addr v;
112
113 /* This is where to make the change */
114 location = (u8 *)sechdrs[sechdrs[relsec].sh_info].sh_addr
115 + rel[i].r_offset;
116 loc32 = (u32 *) location;
117
118 BUG_ON(((u64)location >> (u64)32) != (u64)0);
119
120 /* This is the symbol it is referring to. Note that all
121 undefined symbols have been resolved. */
122 sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
123 + ELF64_R_SYM(rel[i].r_info);
124 v = sym->st_value + rel[i].r_addend;
125
126 switch (ELF64_R_TYPE(rel[i].r_info) & 0xff) {
127 case R_SPARC_64:
128 location[0] = v >> 56;
129 location[1] = v >> 48;
130 location[2] = v >> 40;
131 location[3] = v >> 32;
132 location[4] = v >> 24;
133 location[5] = v >> 16;
134 location[6] = v >> 8;
135 location[7] = v >> 0;
136 break;
137
138 case R_SPARC_32:
139 location[0] = v >> 24;
140 location[1] = v >> 16;
141 location[2] = v >> 8;
142 location[3] = v >> 0;
143 break;
144
145 case R_SPARC_DISP32:
146 v -= (Elf64_Addr) location;
147 *loc32 = v;
148 break;
149
150 case R_SPARC_WDISP30:
151 v -= (Elf64_Addr) location;
152 *loc32 = (*loc32 & ~0x3fffffff) |
153 ((v >> 2) & 0x3fffffff);
154 break;
155
156 case R_SPARC_WDISP22:
157 v -= (Elf64_Addr) location;
158 *loc32 = (*loc32 & ~0x3fffff) |
159 ((v >> 2) & 0x3fffff);
160 break;
161
162 case R_SPARC_WDISP19:
163 v -= (Elf64_Addr) location;
164 *loc32 = (*loc32 & ~0x7ffff) |
165 ((v >> 2) & 0x7ffff);
166 break;
167
168 case R_SPARC_LO10:
169 *loc32 = (*loc32 & ~0x3ff) | (v & 0x3ff);
170 break;
171
172 case R_SPARC_HI22:
173 *loc32 = (*loc32 & ~0x3fffff) |
174 ((v >> 10) & 0x3fffff);
175 break;
176
177 case R_SPARC_OLO10:
178 *loc32 = (*loc32 & ~0x1fff) |
179 (((v & 0x3ff) +
180 (ELF64_R_TYPE(rel[i].r_info) >> 8))
181 & 0x1fff);
182 break;
183
184 default:
185 printk(KERN_ERR "module %s: Unknown relocation: %x\n",
186 me->name,
187 (int) (ELF64_R_TYPE(rel[i].r_info) & 0xff));
188 return -ENOEXEC;
189 };
190 }
191 return 0;
192}
193
194int module_finalize(const Elf_Ehdr *hdr,
195 const Elf_Shdr *sechdrs,
196 struct module *me)
197{
198 /* Cheetah's I-cache is fully coherent. */
199 if (tlb_type == spitfire) {
200 unsigned long va;
201
202 flushw_all();
203 for (va = 0; va < (PAGE_SIZE << 1); va += 32)
204 spitfire_put_icache_tag(va, 0x0);
205 __asm__ __volatile__("flush %g6");
206 }
207
208 return 0;
209}
210
211void module_arch_cleanup(struct module *mod)
212{
213}