1 /* Kernel module help for parisc.
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.
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.
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
17 (c) 2003 Randolph Chung <tausq@debian.org>
19 The best reference for this stuff is probably the Processor-
20 Specific ELF Supplement for PA-RISC:
21 http://ftp.parisc-linux.org/docs/elf-pa-hp.pdf
23 #include <linux/moduleloader.h>
24 #include <linux/elf.h>
25 #include <linux/vmalloc.h>
27 #include <linux/string.h>
28 #include <linux/kernel.h>
33 #define DEBUGP(fmt...)
48 Elf32_Word insns[2]; /* each stub entry has two insns */
62 Elf64_Word insns[4]; /* each stub entry has four insns */
66 /* Field selection types defined by hppa */
67 #define rnd(x) (((x)+0x1000)&~0x1fff)
68 /* fsel: full 32 bits */
69 #define fsel(v,a) ((v)+(a))
70 /* lsel: select left 21 bits */
71 #define lsel(v,a) (((v)+(a))>>11)
72 /* rsel: select right 11 bits */
73 #define rsel(v,a) (((v)+(a))&0x7ff)
74 /* lrsel with rounding of addend to nearest 8k */
75 #define lrsel(v,a) (((v)+rnd(a))>>11)
76 /* rrsel with rounding of addend to nearest 8k */
77 #define rrsel(v,a) ((((v)+rnd(a))&0x7ff)+((a)-rnd(a)))
79 #define mask(x,sz) ((x) & ~((1<<(sz))-1))
82 /* The reassemble_* functions prepare an immediate value for
83 insertion into an opcode. pa-risc uses all sorts of weird bitfields
84 in the instruction to hold the value. */
85 static inline int reassemble_14(int as14)
87 return (((as14 & 0x1fff) << 1) |
88 ((as14 & 0x2000) >> 13));
91 static inline int reassemble_17(int as17)
93 return (((as17 & 0x10000) >> 16) |
94 ((as17 & 0x0f800) << 5) |
95 ((as17 & 0x00400) >> 8) |
96 ((as17 & 0x003ff) << 3));
99 static inline int reassemble_21(int as21)
101 return (((as21 & 0x100000) >> 20) |
102 ((as21 & 0x0ffe00) >> 8) |
103 ((as21 & 0x000180) << 7) |
104 ((as21 & 0x00007c) << 14) |
105 ((as21 & 0x000003) << 12));
108 static inline int reassemble_22(int as22)
110 return (((as22 & 0x200000) >> 21) |
111 ((as22 & 0x1f0000) << 5) |
112 ((as22 & 0x00f800) << 5) |
113 ((as22 & 0x000400) >> 8) |
114 ((as22 & 0x0003ff) << 3));
117 void *module_alloc(unsigned long size)
121 return vmalloc(size);
125 static inline unsigned long count_gots(const Elf_Rela *rela, unsigned long n)
130 static inline unsigned long count_fdescs(const Elf_Rela *rela, unsigned long n)
135 static inline unsigned long count_stubs(const Elf_Rela *rela, unsigned long n)
137 unsigned long cnt = 0;
139 for (; n > 0; n--, rela++)
141 switch (ELF32_R_TYPE(rela->r_info)) {
142 case R_PARISC_PCREL17F:
143 case R_PARISC_PCREL22F:
151 static inline unsigned long count_gots(const Elf_Rela *rela, unsigned long n)
153 unsigned long cnt = 0;
155 for (; n > 0; n--, rela++)
157 switch (ELF64_R_TYPE(rela->r_info)) {
158 case R_PARISC_LTOFF21L:
159 case R_PARISC_LTOFF14R:
160 case R_PARISC_PCREL22F:
168 static inline unsigned long count_fdescs(const Elf_Rela *rela, unsigned long n)
170 unsigned long cnt = 3; /* 3 for finalize */
172 for (; n > 0; n--, rela++)
174 switch (ELF64_R_TYPE(rela->r_info)) {
175 case R_PARISC_FPTR64:
183 static inline unsigned long count_stubs(const Elf_Rela *rela, unsigned long n)
185 unsigned long cnt = 0;
187 for (; n > 0; n--, rela++)
189 switch (ELF64_R_TYPE(rela->r_info)) {
190 case R_PARISC_PCREL22F:
200 /* Free memory returned from module_alloc */
201 void module_free(struct module *mod, void *module_region)
203 vfree(module_region);
204 /* FIXME: If module_region == mod->init_region, trim exception
209 int module_frob_arch_sections(CONST Elf_Ehdr *hdr,
210 CONST Elf_Shdr *sechdrs,
211 CONST char *secstrings,
214 unsigned long gots = 0, fdescs = 0, stubs = 0;
217 for (i = 1; i < hdr->e_shnum; i++) {
218 const Elf_Rela *rels = (void *)hdr + sechdrs[i].sh_offset;
219 unsigned long nrels = sechdrs[i].sh_size / sizeof(*rels);
221 if (sechdrs[i].sh_type != SHT_RELA)
224 /* some of these are not relevant for 32-bit/64-bit
225 * we leave them here to make the code common. the
226 * compiler will do its thing and optimize out the
227 * stuff we don't need
229 gots += count_gots(rels, nrels);
230 fdescs += count_fdescs(rels, nrels);
231 stubs += count_stubs(rels, nrels);
234 /* align things a bit */
235 me->core_size = ALIGN(me->core_size, 16);
236 me->arch.got_offset = me->core_size;
237 me->core_size += gots * sizeof(struct got_entry);
239 me->core_size = ALIGN(me->core_size, 16);
240 me->arch.fdesc_offset = me->core_size;
241 me->core_size += stubs * sizeof(struct fdesc_entry);
243 me->core_size = ALIGN(me->core_size, 16);
244 me->arch.stub_offset = me->core_size;
245 me->core_size += stubs * sizeof(struct stub_entry);
250 static Elf_Addr get_got(struct module *me, unsigned long value, long addend)
253 struct got_entry *got;
259 got = me->module_core + me->arch.got_offset;
260 for (i = 0; got[i].addr; i++)
261 if (got[i].addr == value)
262 return i * sizeof(struct got_entry);
265 return i * sizeof(struct got_entry);
268 static Elf_Addr get_fdesc(struct module *me, unsigned long value)
270 struct fdesc_entry *fdesc = me->module_core + me->arch.fdesc_offset;
273 printk(KERN_ERR "%s: zero OPD requested!\n", me->name);
277 /* Look for existing fdesc entry. */
278 while (fdesc->addr) {
279 if (fdesc->addr == value)
280 return (Elf_Addr)fdesc;
286 fdesc->gp = (Elf_Addr)me->module_core + me->arch.got_offset;
287 return (Elf_Addr)fdesc;
290 static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
294 struct stub_entry *stub;
296 i = me->arch.stub_count++;
297 stub = me->module_core + me->arch.stub_offset +
298 i * sizeof(struct stub_entry);
301 /* for 32-bit the stub looks like this:
303 * be,n R'XXX(%sr4,%r1)
305 stub->insns[0] = 0x20200000; /* ldil L'XXX,%r1 */
306 stub->insns[1] = 0xe0202002; /* be,n R'XXX(%sr4,%r1) */
308 stub->insns[0] |= reassemble_21(lrsel(value, addend));
309 stub->insns[1] |= reassemble_17(rrsel(value, addend) / 4);
311 /* for 64-bit we have two kinds of stubs:
312 * for normal function calls:
326 stub->insns[0] = 0x537b0000; /* ldd 0(%dp),%dp */
327 stub->insns[1] = 0x53610020; /* ldd 10(%dp),%r1 */
328 stub->insns[2] = 0xe820d000; /* bve (%r1) */
329 stub->insns[3] = 0x537b0030; /* ldd 18(%dp),%dp */
331 stub->insns[0] |= reassemble_21(get_got(me, value, addend));
335 stub->insns[0] = 0x20200000; /* ldil 0,%r1 */
336 stub->insns[1] = 0x34210000; /* ldo 0(%r1), %r1 */
337 stub->insns[2] = 0x50210020; /* ldd 10(%r1),%r1 */
338 stub->insns[3] = 0xe820d002; /* bve,n (%r1) */
340 stub->insns[0] |= reassemble_21(lrsel(value, addend));
341 stub->insns[1] |= reassemble_14(rrsel(value, addend));
345 return (Elf_Addr)stub;
348 int apply_relocate(Elf_Shdr *sechdrs,
350 unsigned int symindex,
354 /* parisc should not need this ... */
355 printk(KERN_ERR "module %s: RELOCATION unsupported\n",
361 int apply_relocate_add(Elf_Shdr *sechdrs,
363 unsigned int symindex,
368 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
374 register unsigned long dp asm ("r27");
376 DEBUGP("Applying relocate section %u to %u\n", relsec,
377 sechdrs[relsec].sh_info);
378 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
379 /* This is where to make the change */
380 loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
382 /* This is the symbol it is referring to */
383 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
384 + ELF32_R_SYM(rel[i].r_info);
385 if (!sym->st_value) {
386 printk(KERN_WARNING "%s: Unknown symbol %s\n",
387 me->name, strtab + sym->st_name);
390 dot = (sechdrs[relsec].sh_addr + rel->r_offset) & ~0x03;
393 addend = rel[i].r_addend;
396 #define r(t) ELF32_R_TYPE(rel[i].r_info)==t ? #t :
397 DEBUGP("Symbol %s loc 0x%x val 0x%x addend 0x%x: %s\n",
398 strtab + sym->st_name,
399 (uint32_t)loc, val, addend,
413 switch (ELF32_R_TYPE(rel[i].r_info)) {
414 case R_PARISC_PLABEL32:
415 /* 32-bit function address */
416 /* no function descriptors... */
417 *loc = fsel(val, addend);
420 /* direct 32-bit ref */
421 *loc = fsel(val, addend);
423 case R_PARISC_DIR21L:
424 /* left 21 bits of effective address */
425 *loc = mask(*loc, 21) | reassemble_21(lrsel(val, addend));
427 case R_PARISC_DIR14R:
428 /* right 14 bits of effective address */
429 *loc = mask(*loc, 14) | reassemble_14(rrsel(val, addend));
431 case R_PARISC_SEGREL32:
432 /* 32-bit segment relative address */
433 val -= (uint32_t)me->module_core;
434 *loc = fsel(val, addend);
436 case R_PARISC_DPREL21L:
437 /* left 21 bit of relative address */
439 *loc = mask(*loc, 21) | reassemble_21(lrsel(val, addend) - dp);
441 case R_PARISC_DPREL14R:
442 /* right 14 bit of relative address */
444 *loc = mask(*loc, 14) | reassemble_14(rrsel(val, addend) - dp);
446 case R_PARISC_PCREL17F:
447 /* 17-bit PC relative address */
448 val = get_stub(me, val, addend, 0) - dot - 8;
449 *loc = (*loc&0x1f1ffd) | reassemble_17(val);
451 case R_PARISC_PCREL22F:
452 /* 22-bit PC relative address; only defined for pa20 */
453 val = get_stub(me, val, addend, 0) - dot - 8;
454 *loc = (*loc&0x3ff1ffd) | reassemble_22(val);
458 printk(KERN_ERR "module %s: Unknown relocation: %u\n",
459 me->name, ELF32_R_TYPE(rel[i].r_info));
468 int apply_relocate_add(Elf_Shdr *sechdrs,
470 unsigned int symindex,
475 Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
482 DEBUGP("Applying relocate section %u to %u\n", relsec,
483 sechdrs[relsec].sh_info);
484 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
485 /* This is where to make the change */
486 loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
488 /* This is the symbol it is referring to */
489 sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
490 + ELF64_R_SYM(rel[i].r_info);
491 if (!sym->st_value) {
492 printk(KERN_WARNING "%s: Unknown symbol %s\n",
493 me->name, strtab + sym->st_name);
496 dot = (sechdrs[relsec].sh_addr + rel->r_offset) & ~0x03;
499 addend = rel[i].r_addend;
502 #define r(t) ELF64_R_TYPE(rel[i].r_info)==t ? #t :
503 DEBUGP("Symbol %s loc %p val 0x%Lx addend 0x%Lx: %s\n",
504 strtab + sym->st_name,
516 switch (ELF64_R_TYPE(rel[i].r_info)) {
517 case R_PARISC_LTOFF21L:
518 /* LT-relative; left 21 bits */
519 *loc = mask(*loc, 21) | reassemble_21(get_got(me, val, addend));
521 case R_PARISC_LTOFF14R:
522 /* L(ltoff(val+addend)) */
523 /* LT-relative; right 14 bits */
524 *loc = mask(*loc, 14) | reassemble_14(get_got(me, val, addend));
526 case R_PARISC_PCREL22F:
527 /* PC-relative; 22 bits */
528 if (strncmp(strtab + sym->st_name, "$$", 2) == 0)
529 val = get_stub(me, val, addend, 1) - dot - 8;
531 val = get_stub(me, val, addend, 0) - dot - 8;
532 *loc = (*loc&0x3ff1ffd) | reassemble_22(val);
535 /* 64-bit effective address */
536 *loc = fsel(val, addend);
538 case R_PARISC_SEGREL32:
539 /* 32-bit segment relative address */
540 val -= (uint64_t)me->module_core;
541 *loc = fsel(val, addend);
543 case R_PARISC_FPTR64:
544 /* 64-bit function address */
545 *loc = get_fdesc(me, val+addend);
549 printk(KERN_ERR "module %s: Unknown relocation: %Lu\n",
550 me->name, ELF64_R_TYPE(rel[i].r_info));
558 int module_finalize(const Elf_Ehdr *hdr,
559 const Elf_Shdr *sechdrs,
563 me->init = (void *)get_fdesc(me, (Elf_Addr)me->init);
564 #ifdef CONFIG_MODULE_UNLOAD
566 me->exit = (void *)get_fdesc(me, (Elf_Addr)me->exit);