summaryrefslogtreecommitdiffstats
path: root/sys/mips/mips/elf_machdep.c
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2010-02-18 05:49:52 +0000
committerneel <neel@FreeBSD.org>2010-02-18 05:49:52 +0000
commitaa07cd309152c701760f95950436f1dac1e00016 (patch)
tree56e117e71722a097ba68b1b876cb693097f96568 /sys/mips/mips/elf_machdep.c
parentffb08c6fd3e283de1c77c3ac7c8834a367b7f6c7 (diff)
downloadFreeBSD-src-aa07cd309152c701760f95950436f1dac1e00016.zip
FreeBSD-src-aa07cd309152c701760f95950436f1dac1e00016.tar.gz
Kernel module support for mips.
Reviewed by: gonzo Tested by: Alexandr Rybalko (ray@dlink.ua)
Diffstat (limited to 'sys/mips/mips/elf_machdep.c')
-rw-r--r--sys/mips/mips/elf_machdep.c158
1 files changed, 62 insertions, 96 deletions
diff --git a/sys/mips/mips/elf_machdep.c b/sys/mips/mips/elf_machdep.c
index 54c31e5..90e3dac 100644
--- a/sys/mips/mips/elf_machdep.c
+++ b/sys/mips/mips/elf_machdep.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <machine/elf.h>
#include <machine/md_var.h>
+#include <machine/cache.h>
#ifdef __mips_n64
struct sysentvec elf64_freebsd_sysvec = {
@@ -163,7 +164,12 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
Elf_Addr addend = (Elf_Addr)0;
Elf_Word rtype = (Elf_Word)0, symidx;
const Elf_Rel *rel;
- const Elf_Rela *rela;
+
+ /*
+ * Stash R_MIPS_HI16 info so we can use it when processing R_MIPS_LO16
+ */
+ static Elf_Addr ahl;
+ static Elf_Addr *where_hi16;
switch (type) {
case ELF_RELOC_REL:
@@ -173,108 +179,63 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
rtype = ELF_R_TYPE(rel->r_info);
symidx = ELF_R_SYM(rel->r_info);
break;
- case ELF_RELOC_RELA:
- rela = (const Elf_Rela *)data;
- where = (Elf_Addr *) (relocbase + rela->r_offset);
- addend = rela->r_addend;
- rtype = ELF_R_TYPE(rela->r_info);
- symidx = ELF_R_SYM(rela->r_info);
- break;
default:
panic("unknown reloc type %d\n", type);
}
- if (local) {
-#if 0 /* TBD */
- if (rtype == R_386_RELATIVE) { /* A + B */
- addr = elf_relocaddr(lf, relocbase + addend);
- if (*where != addr)
- *where = addr;
- }
- return (0);
-#endif
- }
-
switch (rtype) {
+ case R_MIPS_NONE: /* none */
+ break;
- case R_MIPS_NONE: /* none */
- break;
-
- case R_MIPS_16: /* S + sign-extend(A) */
- /*
- * There shouldn't be R_MIPS_16 relocs in kernel objects.
- */
- printf("kldload: unexpected R_MIPS_16 relocation\n");
- return -1;
- break;
-
- case R_MIPS_32: /* S + A - P */
- addr = lookup(lf, symidx, 1);
- if (addr == 0)
- return -1;
- addr += addend;
- if (*where != addr)
- *where = addr;
- break;
-
- case R_MIPS_REL32: /* A - EA + S */
- /*
- * There shouldn't be R_MIPS_REL32 relocs in kernel objects?
- */
- printf("kldload: unexpected R_MIPS_REL32 relocation\n");
- return -1;
- break;
-
- case R_MIPS_26: /* ((A << 2) | (P & 0xf0000000) + S) >> 2 */
- break;
-
- case R_MIPS_HI16:
- /* extern/local: ((AHL + S) - ((short)(AHL + S)) >> 16 */
- /* _gp_disp: ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16 */
- break;
-
- case R_MIPS_LO16:
- /* extern/local: AHL + S */
- /* _gp_disp: AHL + GP - P + 4 */
- break;
-
- case R_MIPS_GPREL16:
- /* extern/local: ((AHL + S) - ((short)(AHL + S)) >> 16 */
- /* _gp_disp: ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16 */
- break;
-
- case R_MIPS_LITERAL: /* sign-extend(A) + L */
- break;
-
- case R_MIPS_GOT16: /* external: G */
- /* local: tbd */
- break;
-
- case R_MIPS_PC16: /* sign-extend(A) + S - P */
- break;
-
- case R_MIPS_CALL16: /* G */
- break;
-
- case R_MIPS_GPREL32: /* A + S + GP0 - GP */
- break;
-
- case R_MIPS_GOTHI16: /* (G - (short)G) >> 16 + A */
- break;
-
- case R_MIPS_GOTLO16: /* G & 0xffff */
- break;
-
- case R_MIPS_CALLHI16: /* (G - (short)G) >> 16 + A */
- break;
-
- case R_MIPS_CALLLO16: /* G & 0xffff */
- break;
-
- default:
- printf("kldload: unexpected relocation type %d\n",
- rtype);
+ case R_MIPS_32: /* S + A */
+ addr = lookup(lf, symidx, 1);
+ if (addr == 0)
return (-1);
+ addr += addend;
+ if (*where != addr)
+ *where = addr;
+ break;
+
+ case R_MIPS_26: /* ((A << 2) | (P & 0xf0000000) + S) >> 2 */
+ addr = lookup(lf, symidx, 1);
+ if (addr == 0)
+ return (-1);
+
+ addend &= 0x03ffffff;
+ addend <<= 2;
+
+ addr += ((Elf_Addr)where & 0xf0000000) | addend;
+ addr >>= 2;
+
+ *where &= ~0x03ffffff;
+ *where |= addr & 0x03ffffff;
+ break;
+
+ case R_MIPS_HI16: /* ((AHL + S) - ((short)(AHL + S)) >> 16 */
+ ahl = addend << 16;
+ where_hi16 = where;
+ break;
+
+ case R_MIPS_LO16: /* AHL + S */
+ ahl += (int16_t)addend;
+ addr = lookup(lf, symidx, 1);
+ if (addr == 0)
+ return (-1);
+
+ addend &= 0xffff0000;
+ addend |= (uint16_t)(ahl + addr);
+ *where = addend;
+
+ addend = *where_hi16;
+ addend &= 0xffff0000;
+ addend |= ((ahl + addr) - (int16_t)(ahl + addr)) >> 16;
+ *where_hi16 = addend;
+ break;
+
+ default:
+ printf("kldload: unexpected relocation type %d\n",
+ rtype);
+ return (-1);
}
return(0);
}
@@ -299,6 +260,11 @@ int
elf_cpu_load_file(linker_file_t lf __unused)
{
+ /*
+ * Sync the I and D caches to make sure our relocations are visible.
+ */
+ mips_icache_sync_all();
+
return (0);
}
OpenPOWER on IntegriCloud