1178172Simp/*- 2178172Simp * Copyright 1996-1998 John D. Polstra. 3178172Simp * All rights reserved. 4178172Simp * 5178172Simp * Redistribution and use in source and binary forms, with or without 6178172Simp * modification, are permitted provided that the following conditions 7178172Simp * are met: 8178172Simp * 1. Redistributions of source code must retain the above copyright 9178172Simp * notice, this list of conditions and the following disclaimer. 10178172Simp * 2. Redistributions in binary form must reproduce the above copyright 11178172Simp * notice, this list of conditions and the following disclaimer in the 12178172Simp * documentation and/or other materials provided with the distribution. 13178172Simp * 14178172Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15178172Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16178172Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17178172Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18178172Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19178172Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20178172Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21178172Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22178172Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23178172Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24178172Simp * 25178172Simp * from: src/sys/i386/i386/elf_machdep.c,v 1.20 2004/08/11 02:35:05 marcel 26178172Simp */ 27178172Simp 28178172Simp#include <sys/cdefs.h> 29178172Simp__FBSDID("$FreeBSD$"); 30178172Simp 31178172Simp#include <sys/param.h> 32178172Simp#include <sys/kernel.h> 33178172Simp#include <sys/systm.h> 34178172Simp#include <sys/exec.h> 35178172Simp#include <sys/imgact.h> 36178172Simp#include <sys/linker.h> 37178172Simp#include <sys/sysent.h> 38178172Simp#include <sys/imgact_elf.h> 39208453Skib#include <sys/proc.h> 40178172Simp#include <sys/syscall.h> 41178172Simp#include <sys/signalvar.h> 42178172Simp#include <sys/vnode.h> 43178172Simp 44178172Simp#include <vm/vm.h> 45178172Simp#include <vm/pmap.h> 46178172Simp#include <vm/vm_param.h> 47178172Simp 48178172Simp#include <machine/elf.h> 49178172Simp#include <machine/md_var.h> 50204031Sneel#include <machine/cache.h> 51178172Simp 52202046Simp#ifdef __mips_n64 53202046Simpstruct sysentvec elf64_freebsd_sysvec = { 54202046Simp .sv_size = SYS_MAXSYSCALL, 55202046Simp .sv_table = sysent, 56202046Simp .sv_mask = 0, 57202046Simp .sv_sigsize = 0, 58202046Simp .sv_sigtbl = NULL, 59202046Simp .sv_errsize = 0, 60202046Simp .sv_errtbl = NULL, 61202046Simp .sv_transtrap = NULL, 62202046Simp .sv_fixup = __elfN(freebsd_fixup), 63202046Simp .sv_sendsig = sendsig, 64202046Simp .sv_sigcode = sigcode, 65202046Simp .sv_szsigcode = &szsigcode, 66202046Simp .sv_prepsyscall = NULL, 67202046Simp .sv_name = "FreeBSD ELF64", 68202046Simp .sv_coredump = __elfN(coredump), 69202046Simp .sv_imgact_try = NULL, 70202046Simp .sv_minsigstksz = MINSIGSTKSZ, 71202046Simp .sv_pagesize = PAGE_SIZE, 72202046Simp .sv_minuser = VM_MIN_ADDRESS, 73202046Simp .sv_maxuser = VM_MAXUSER_ADDRESS, 74202046Simp .sv_usrstack = USRSTACK, 75202046Simp .sv_psstrings = PS_STRINGS, 76202046Simp .sv_stackprot = VM_PROT_ALL, 77202046Simp .sv_copyout_strings = exec_copyout_strings, 78202046Simp .sv_setregs = exec_setregs, 79202046Simp .sv_fixlimit = NULL, 80202046Simp .sv_maxssiz = NULL, 81208453Skib .sv_flags = SV_ABI_FREEBSD | SV_LP64, 82208453Skib .sv_set_syscall_retval = cpu_set_syscall_retval, 83229374Skib .sv_fetch_syscall_args = cpu_fetch_syscall_args, 84208453Skib .sv_syscallnames = syscallnames, 85219405Sdchagin .sv_schedtail = NULL, 86202046Simp}; 87202046Simp 88202046Simpstatic Elf64_Brandinfo freebsd_brand_info = { 89202046Simp .brand = ELFOSABI_FREEBSD, 90202046Simp .machine = EM_MIPS, 91202046Simp .compat_3_brand = "FreeBSD", 92202046Simp .emul_path = NULL, 93202046Simp .interp_path = "/libexec/ld-elf.so.1", 94202046Simp .sysvec = &elf64_freebsd_sysvec, 95202046Simp .interp_newpath = NULL, 96202046Simp .flags = 0 97202046Simp}; 98202046Simp 99202046SimpSYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_ANY, 100202046Simp (sysinit_cfunc_t) elf64_insert_brand_entry, 101202046Simp &freebsd_brand_info); 102202046Simp 103202046Simpvoid 104202046Simpelf64_dump_thread(struct thread *td __unused, void *dst __unused, 105202046Simp size_t *off __unused) 106202046Simp{ 107202046Simp} 108202046Simp#else 109178172Simpstruct sysentvec elf32_freebsd_sysvec = { 110183322Skib .sv_size = SYS_MAXSYSCALL, 111183322Skib .sv_table = sysent, 112183322Skib .sv_mask = 0, 113183322Skib .sv_sigsize = 0, 114183322Skib .sv_sigtbl = NULL, 115183322Skib .sv_errsize = 0, 116183322Skib .sv_errtbl = NULL, 117183322Skib .sv_transtrap = NULL, 118183322Skib .sv_fixup = __elfN(freebsd_fixup), 119183322Skib .sv_sendsig = sendsig, 120183322Skib .sv_sigcode = sigcode, 121183322Skib .sv_szsigcode = &szsigcode, 122183322Skib .sv_prepsyscall = NULL, 123183322Skib .sv_name = "FreeBSD ELF32", 124183322Skib .sv_coredump = __elfN(coredump), 125183322Skib .sv_imgact_try = NULL, 126183322Skib .sv_minsigstksz = MINSIGSTKSZ, 127183322Skib .sv_pagesize = PAGE_SIZE, 128183322Skib .sv_minuser = VM_MIN_ADDRESS, 129183322Skib .sv_maxuser = VM_MAXUSER_ADDRESS, 130183322Skib .sv_usrstack = USRSTACK, 131183322Skib .sv_psstrings = PS_STRINGS, 132183322Skib .sv_stackprot = VM_PROT_ALL, 133183322Skib .sv_copyout_strings = exec_copyout_strings, 134183322Skib .sv_setregs = exec_setregs, 135183322Skib .sv_fixlimit = NULL, 136185169Skib .sv_maxssiz = NULL, 137208453Skib .sv_flags = SV_ABI_FREEBSD | SV_ILP32, 138208453Skib .sv_set_syscall_retval = cpu_set_syscall_retval, 139229374Skib .sv_fetch_syscall_args = cpu_fetch_syscall_args, 140208453Skib .sv_syscallnames = syscallnames, 141219405Sdchagin .sv_schedtail = NULL, 142178172Simp}; 143178172Simp 144178172Simpstatic Elf32_Brandinfo freebsd_brand_info = { 145183322Skib .brand = ELFOSABI_FREEBSD, 146183322Skib .machine = EM_MIPS, 147183322Skib .compat_3_brand = "FreeBSD", 148183322Skib .emul_path = NULL, 149183322Skib .interp_path = "/libexec/ld-elf.so.1", 150183322Skib .sysvec = &elf32_freebsd_sysvec, 151183322Skib .interp_newpath = NULL, 152202046Simp .flags = 0 153183322Skib}; 154178172Simp 155197729SbzSYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST, 156183322Skib (sysinit_cfunc_t) elf32_insert_brand_entry, 157183322Skib &freebsd_brand_info); 158178172Simp 159178172Simpvoid 160178172Simpelf32_dump_thread(struct thread *td __unused, void *dst __unused, 161178172Simp size_t *off __unused) 162178172Simp{ 163178172Simp} 164202046Simp#endif 165178172Simp 166178172Simp/* Process one elf relocation with addend. */ 167178172Simpstatic int 168178172Simpelf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, 169178172Simp int type, int local, elf_lookup_fn lookup) 170178172Simp{ 171208022Simp Elf_Addr *where = (Elf_Addr *)NULL; 172178172Simp Elf_Addr addr; 173178172Simp Elf_Addr addend = (Elf_Addr)0; 174178172Simp Elf_Word rtype = (Elf_Word)0, symidx; 175178172Simp const Elf_Rel *rel; 176178172Simp 177204031Sneel /* 178204031Sneel * Stash R_MIPS_HI16 info so we can use it when processing R_MIPS_LO16 179204031Sneel */ 180204031Sneel static Elf_Addr ahl; 181204031Sneel static Elf_Addr *where_hi16; 182204031Sneel 183178172Simp switch (type) { 184178172Simp case ELF_RELOC_REL: 185178172Simp rel = (const Elf_Rel *)data; 186178172Simp where = (Elf_Addr *) (relocbase + rel->r_offset); 187178172Simp addend = *where; 188178172Simp rtype = ELF_R_TYPE(rel->r_info); 189178172Simp symidx = ELF_R_SYM(rel->r_info); 190178172Simp break; 191178172Simp default: 192178172Simp panic("unknown reloc type %d\n", type); 193178172Simp } 194178172Simp 195178172Simp switch (rtype) { 196204031Sneel case R_MIPS_NONE: /* none */ 197204031Sneel break; 198178172Simp 199204031Sneel case R_MIPS_32: /* S + A */ 200204031Sneel addr = lookup(lf, symidx, 1); 201204031Sneel if (addr == 0) 202204031Sneel return (-1); 203204031Sneel addr += addend; 204204031Sneel if (*where != addr) 205204031Sneel *where = addr; 206204031Sneel break; 207178172Simp 208204031Sneel case R_MIPS_26: /* ((A << 2) | (P & 0xf0000000) + S) >> 2 */ 209204031Sneel addr = lookup(lf, symidx, 1); 210204031Sneel if (addr == 0) 211204031Sneel return (-1); 212178172Simp 213204031Sneel addend &= 0x03ffffff; 214204031Sneel addend <<= 2; 215178172Simp 216204031Sneel addr += ((Elf_Addr)where & 0xf0000000) | addend; 217204031Sneel addr >>= 2; 218178172Simp 219204031Sneel *where &= ~0x03ffffff; 220204031Sneel *where |= addr & 0x03ffffff; 221204031Sneel break; 222178172Simp 223204031Sneel case R_MIPS_HI16: /* ((AHL + S) - ((short)(AHL + S)) >> 16 */ 224204031Sneel ahl = addend << 16; 225204031Sneel where_hi16 = where; 226204031Sneel break; 227178172Simp 228204031Sneel case R_MIPS_LO16: /* AHL + S */ 229204031Sneel ahl += (int16_t)addend; 230204031Sneel addr = lookup(lf, symidx, 1); 231204031Sneel if (addr == 0) 232204031Sneel return (-1); 233178172Simp 234204031Sneel addend &= 0xffff0000; 235204031Sneel addend |= (uint16_t)(ahl + addr); 236204031Sneel *where = addend; 237178172Simp 238204031Sneel addend = *where_hi16; 239204031Sneel addend &= 0xffff0000; 240204031Sneel addend |= ((ahl + addr) - (int16_t)(ahl + addr)) >> 16; 241204031Sneel *where_hi16 = addend; 242204031Sneel break; 243178172Simp 244204031Sneel default: 245204031Sneel printf("kldload: unexpected relocation type %d\n", 246204031Sneel rtype); 247204031Sneel return (-1); 248178172Simp } 249178172Simp return(0); 250178172Simp} 251178172Simp 252178172Simpint 253178172Simpelf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, 254178172Simp elf_lookup_fn lookup) 255178172Simp{ 256178172Simp 257178172Simp return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup)); 258178172Simp} 259178172Simp 260178172Simpint 261178172Simpelf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, 262178172Simp int type, elf_lookup_fn lookup) 263178172Simp{ 264178172Simp 265178172Simp return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup)); 266178172Simp} 267178172Simp 268178172Simpint 269178172Simpelf_cpu_load_file(linker_file_t lf __unused) 270178172Simp{ 271178172Simp 272204031Sneel /* 273204031Sneel * Sync the I and D caches to make sure our relocations are visible. 274204031Sneel */ 275204031Sneel mips_icache_sync_all(); 276204031Sneel 277178172Simp return (0); 278178172Simp} 279178172Simp 280178172Simpint 281178172Simpelf_cpu_unload_file(linker_file_t lf __unused) 282178172Simp{ 283178172Simp 284178172Simp return (0); 285178172Simp} 286