elf32_machdep.c revision 288287
1204766Sjkim/*- 2204766Sjkim * Copyright 1996-1998 John D. Polstra. 3204766Sjkim * All rights reserved. 4204766Sjkim * 5204766Sjkim * Redistribution and use in source and binary forms, with or without 6204766Sjkim * modification, are permitted provided that the following conditions 7217365Sjkim * are met: 8306536Sjkim * 1. Redistributions of source code must retain the above copyright 9204766Sjkim * notice, this list of conditions and the following disclaimer. 10204766Sjkim * 2. Redistributions in binary form must reproduce the above copyright 11217365Sjkim * notice, this list of conditions and the following disclaimer in the 12217365Sjkim * documentation and/or other materials provided with the distribution. 13217365Sjkim * 14217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15217365Sjkim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16217365Sjkim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17217365Sjkim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18217365Sjkim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19217365Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20217365Sjkim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21217365Sjkim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22217365Sjkim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23217365Sjkim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24217365Sjkim * 25204766Sjkim * $FreeBSD: stable/10/sys/powerpc/powerpc/elf32_machdep.c 288287 2015-09-27 01:33:43Z kib $ 26217365Sjkim */ 27217365Sjkim 28217365Sjkim#include <sys/param.h> 29204766Sjkim#include <sys/kernel.h> 30217365Sjkim#include <sys/systm.h> 31217365Sjkim 32217365Sjkim#define __ELF_WORD_SIZE 32 33217365Sjkim 34217365Sjkim#include <sys/exec.h> 35217365Sjkim#include <sys/imgact.h> 36217365Sjkim#include <sys/malloc.h> 37217365Sjkim#include <sys/proc.h> 38217365Sjkim#include <sys/namei.h> 39217365Sjkim#include <sys/fcntl.h> 40217365Sjkim#include <sys/sysent.h> 41217365Sjkim#include <sys/imgact_elf.h> 42217365Sjkim#include <sys/syscall.h> 43204766Sjkim#include <sys/signalvar.h> 44204766Sjkim#include <sys/vnode.h> 45249112Sjkim#include <sys/linker.h> 46204766Sjkim 47204773Sjkim#include <vm/vm.h> 48204766Sjkim#include <vm/vm_param.h> 49204773Sjkim 50246849Sjkim#include <machine/cpu.h> 51204766Sjkim#include <machine/elf.h> 52204766Sjkim#include <machine/reg.h> 53204766Sjkim#include <machine/md_var.h> 54204766Sjkim 55204766Sjkim#ifdef __powerpc64__ 56204766Sjkim#include <compat/freebsd32/freebsd32_proto.h> 57204766Sjkim#include <compat/freebsd32/freebsd32_util.h> 58204766Sjkim 59218590Sjkimextern const char *freebsd32_syscallnames[]; 60218590Sjkim#endif 61218590Sjkim 62218590Sjkimstruct sysentvec elf32_freebsd_sysvec = { 63218590Sjkim .sv_size = SYS_MAXSYSCALL, 64204766Sjkim#ifdef __powerpc64__ 65204766Sjkim .sv_table = freebsd32_sysent, 66204766Sjkim#else 67204766Sjkim .sv_table = sysent, 68204766Sjkim#endif 69204766Sjkim .sv_mask = 0, 70204766Sjkim .sv_sigsize = 0, 71204766Sjkim .sv_sigtbl = NULL, 72204766Sjkim .sv_errsize = 0, 73204766Sjkim .sv_errtbl = NULL, 74204766Sjkim .sv_transtrap = NULL, 75204766Sjkim .sv_fixup = __elfN(freebsd_fixup), 76204766Sjkim .sv_sendsig = sendsig, 77204766Sjkim .sv_sigcode = sigcode32, 78204766Sjkim .sv_szsigcode = &szsigcode32, 79204766Sjkim .sv_prepsyscall = NULL, 80204766Sjkim .sv_name = "FreeBSD ELF32", 81204766Sjkim .sv_coredump = __elfN(coredump), 82204766Sjkim .sv_imgact_try = NULL, 83204766Sjkim .sv_minsigstksz = MINSIGSTKSZ, 84204766Sjkim .sv_pagesize = PAGE_SIZE, 85220663Sjkim .sv_minuser = VM_MIN_ADDRESS, 86204766Sjkim .sv_stackprot = VM_PROT_ALL, 87204766Sjkim#ifdef __powerpc64__ 88204766Sjkim .sv_maxuser = VM_MAXUSER_ADDRESS, 89204766Sjkim .sv_usrstack = FREEBSD32_USRSTACK, 90249112Sjkim .sv_psstrings = FREEBSD32_PS_STRINGS, 91249112Sjkim .sv_copyout_strings = freebsd32_copyout_strings, 92249112Sjkim .sv_setregs = ppc32_setregs, 93204766Sjkim .sv_syscallnames = freebsd32_syscallnames, 94204766Sjkim#else 95204766Sjkim .sv_maxuser = VM_MAXUSER_ADDRESS, 96204766Sjkim .sv_usrstack = USRSTACK, 97204766Sjkim .sv_psstrings = PS_STRINGS, 98204766Sjkim .sv_copyout_strings = exec_copyout_strings, 99204766Sjkim .sv_setregs = exec_setregs, 100204766Sjkim .sv_syscallnames = syscallnames, 101204766Sjkim#endif 102204766Sjkim .sv_fixlimit = NULL, 103204766Sjkim .sv_maxssiz = NULL, 104204766Sjkim .sv_flags = SV_ABI_FREEBSD | SV_ILP32 | SV_SHP, 105204766Sjkim .sv_set_syscall_retval = cpu_set_syscall_retval, 106220663Sjkim .sv_fetch_syscall_args = cpu_fetch_syscall_args, 107204766Sjkim .sv_shared_page_base = FREEBSD32_SHAREDPAGE, 108204766Sjkim .sv_shared_page_len = PAGE_SIZE, 109207344Sjkim .sv_schedtail = NULL, 110204766Sjkim}; 111204766SjkimINIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec); 112204766Sjkim 113207344Sjkimstatic Elf32_Brandinfo freebsd_brand_info = { 114204766Sjkim .brand = ELFOSABI_FREEBSD, 115204766Sjkim .machine = EM_PPC, 116204766Sjkim .compat_3_brand = "FreeBSD", 117209746Sjkim .emul_path = NULL, 118204766Sjkim .interp_path = "/libexec/ld-elf.so.1", 119204766Sjkim .sysvec = &elf32_freebsd_sysvec, 120204766Sjkim#ifdef __powerpc64__ 121204766Sjkim .interp_newpath = "/libexec/ld-elf32.so.1", 122204766Sjkim#else 123204766Sjkim .interp_newpath = NULL, 124204766Sjkim#endif 125204766Sjkim .brand_note = &elf32_freebsd_brandnote, 126204766Sjkim .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 127249663Sjkim}; 128249663Sjkim 129204766SjkimSYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST, 130249663Sjkim (sysinit_cfunc_t) elf32_insert_brand_entry, 131249663Sjkim &freebsd_brand_info); 132204766Sjkim 133204766Sjkimstatic Elf32_Brandinfo freebsd_brand_oinfo = { 134249112Sjkim .brand = ELFOSABI_FREEBSD, 135249663Sjkim .machine = EM_PPC, 136204766Sjkim .compat_3_brand = "FreeBSD", 137249112Sjkim .emul_path = NULL, 138204766Sjkim .interp_path = "/usr/libexec/ld-elf.so.1", 139209746Sjkim .sysvec = &elf32_freebsd_sysvec, 140249112Sjkim .interp_newpath = NULL, 141204766Sjkim .brand_note = &elf32_freebsd_brandnote, 142249663Sjkim .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 143204766Sjkim}; 144249663Sjkim 145204766SjkimSYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY, 146204766Sjkim (sysinit_cfunc_t) elf32_insert_brand_entry, 147249663Sjkim &freebsd_brand_oinfo); 148249663Sjkim 149204766Sjkimvoid 150249663Sjkimelf32_dump_thread(struct thread *td __unused, void *dst __unused, 151204766Sjkim size_t *off __unused) 152204766Sjkim{ 153204766Sjkim} 154204766Sjkim 155204766Sjkim#ifndef __powerpc64__ 156204766Sjkim/* Process one elf relocation with addend. */ 157204766Sjkimstatic int 158204766Sjkimelf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, 159204766Sjkim int type, int local, elf_lookup_fn lookup) 160249112Sjkim{ 161204766Sjkim Elf_Addr *where; 162249112Sjkim Elf_Half *hwhere; 163249112Sjkim Elf_Addr addr; 164204766Sjkim Elf_Addr addend; 165206117Sjkim Elf_Word rtype, symidx; 166249112Sjkim const Elf_Rela *rela; 167206117Sjkim int error; 168204766Sjkim 169204766Sjkim switch (type) { 170204766Sjkim case ELF_RELOC_REL: 171204766Sjkim panic("PPC only supports RELA relocations"); 172204766Sjkim break; 173220663Sjkim case ELF_RELOC_RELA: 174220663Sjkim rela = (const Elf_Rela *)data; 175204766Sjkim where = (Elf_Addr *) ((uintptr_t)relocbase + rela->r_offset); 176204766Sjkim hwhere = (Elf_Half *) ((uintptr_t)relocbase + rela->r_offset); 177204766Sjkim addend = rela->r_addend; 178204766Sjkim rtype = ELF_R_TYPE(rela->r_info); 179204766Sjkim symidx = ELF_R_SYM(rela->r_info); 180218590Sjkim break; 181218590Sjkim default: 182218590Sjkim panic("elf_reloc: unknown relocation mode %d\n", type); 183218590Sjkim } 184218590Sjkim 185218590Sjkim switch (rtype) { 186218590Sjkim 187218590Sjkim case R_PPC_NONE: 188218590Sjkim break; 189218590Sjkim 190218590Sjkim case R_PPC_ADDR32: /* word32 S + A */ 191218590Sjkim error = lookup(lf, symidx, 1, &addr); 192218590Sjkim if (error != 0) 193218590Sjkim return -1; 194218590Sjkim addr += addend; 195218590Sjkim *where = addr; 196218590Sjkim break; 197218590Sjkim 198218590Sjkim case R_PPC_ADDR16_LO: /* #lo(S) */ 199218590Sjkim error = lookup(lf, symidx, 1, &addr); 200218590Sjkim if (error != 0) 201218590Sjkim return -1; 202218590Sjkim /* 203218590Sjkim * addend values are sometimes relative to sections 204218590Sjkim * (i.e. .rodata) in rela, where in reality they 205218590Sjkim * are relative to relocbase. Detect this condition. 206218590Sjkim */ 207218590Sjkim if (addr > relocbase && addr <= (relocbase + addend)) 208218590Sjkim addr = relocbase + addend; 209218590Sjkim else 210218590Sjkim addr += addend; 211218590Sjkim *hwhere = addr & 0xffff; 212218590Sjkim break; 213218590Sjkim 214218590Sjkim case R_PPC_ADDR16_HA: /* #ha(S) */ 215218590Sjkim error = lookup(lf, symidx, 1, &addr); 216218590Sjkim if (error != 0) 217218590Sjkim return -1; 218218590Sjkim /* 219218590Sjkim * addend values are sometimes relative to sections 220218590Sjkim * (i.e. .rodata) in rela, where in reality they 221218590Sjkim * are relative to relocbase. Detect this condition. 222218590Sjkim */ 223218590Sjkim if (addr > relocbase && addr <= (relocbase + addend)) 224218590Sjkim addr = relocbase + addend; 225218590Sjkim else 226218590Sjkim addr += addend; 227206117Sjkim *hwhere = ((addr >> 16) + ((addr & 0x8000) ? 1 : 0)) 228206117Sjkim & 0xffff; 229206117Sjkim break; 230206117Sjkim 231206117Sjkim case R_PPC_RELATIVE: /* word32 B + A */ 232206117Sjkim *where = elf_relocaddr(lf, relocbase + addend); 233206117Sjkim break; 234206117Sjkim 235206117Sjkim default: 236206117Sjkim printf("kldload: unexpected relocation type %d\n", 237206117Sjkim (int) rtype); 238218590Sjkim return -1; 239218590Sjkim } 240218590Sjkim return(0); 241206117Sjkim} 242206117Sjkim 243206117Sjkimint 244206117Sjkimelf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, 245206117Sjkim elf_lookup_fn lookup) 246206117Sjkim{ 247206117Sjkim 248206117Sjkim return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup)); 249249112Sjkim} 250249112Sjkim 251249112Sjkimint 252206117Sjkimelf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, 253206117Sjkim int type, elf_lookup_fn lookup) 254281075Sdim{ 255281075Sdim 256281075Sdim return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup)); 257281075Sdim} 258281075Sdim 259281075Sdimint 260281075Sdimelf_cpu_load_file(linker_file_t lf) 261206117Sjkim{ 262306536Sjkim /* Only sync the cache for non-kernel modules */ 263281075Sdim if (lf->id != 1) 264206117Sjkim __syncicache(lf->address, lf->size); 265206117Sjkim return (0); 266206117Sjkim} 267218590Sjkim 268218590Sjkimint 269218590Sjkimelf_cpu_unload_file(linker_file_t lf __unused) 270218590Sjkim{ 271218590Sjkim 272218590Sjkim return (0); 273218590Sjkim} 274206117Sjkim#endif 275206117Sjkim