diff options
author | neel <neel@FreeBSD.org> | 2010-02-18 05:49:52 +0000 |
---|---|---|
committer | neel <neel@FreeBSD.org> | 2010-02-18 05:49:52 +0000 |
commit | aa07cd309152c701760f95950436f1dac1e00016 (patch) | |
tree | 56e117e71722a097ba68b1b876cb693097f96568 /sys/mips/mips/elf_machdep.c | |
parent | ffb08c6fd3e283de1c77c3ac7c8834a367b7f6c7 (diff) | |
download | FreeBSD-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.c | 158 |
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); } |