139072Sdfr/*- 239072Sdfr * Copyright 1996-1998 John D. Polstra. 339072Sdfr * All rights reserved. 439072Sdfr * 539072Sdfr * Redistribution and use in source and binary forms, with or without 639072Sdfr * modification, are permitted provided that the following conditions 739072Sdfr * are met: 839072Sdfr * 1. Redistributions of source code must retain the above copyright 939072Sdfr * notice, this list of conditions and the following disclaimer. 1039072Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1139072Sdfr * notice, this list of conditions and the following disclaimer in the 1239072Sdfr * documentation and/or other materials provided with the distribution. 1339072Sdfr * 1439072Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1539072Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1639072Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1739072Sdfr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1839072Sdfr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1939072Sdfr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2039072Sdfr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2139072Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2239072Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2339072Sdfr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2439072Sdfr * 2550477Speter * $FreeBSD$ 2639072Sdfr */ 2739072Sdfr 2839072Sdfr#include <sys/param.h> 2939072Sdfr#include <sys/kernel.h> 3039072Sdfr#include <sys/systm.h> 31209975Snwhitehorn 32209975Snwhitehorn#define __ELF_WORD_SIZE 32 33209975Snwhitehorn 34102808Sjake#include <sys/exec.h> 35102808Sjake#include <sys/imgact.h> 3639072Sdfr#include <sys/malloc.h> 3739072Sdfr#include <sys/proc.h> 3839072Sdfr#include <sys/namei.h> 3939072Sdfr#include <sys/fcntl.h> 40100384Speter#include <sys/sysent.h> 41100384Speter#include <sys/imgact_elf.h> 42100384Speter#include <sys/syscall.h> 43100384Speter#include <sys/signalvar.h> 4439072Sdfr#include <sys/vnode.h> 4539072Sdfr#include <sys/linker.h> 46102808Sjake 47102808Sjake#include <vm/vm.h> 48102808Sjake#include <vm/vm_param.h> 49102808Sjake 50132282Sgrehan#include <machine/cpu.h> 5139072Sdfr#include <machine/elf.h> 52209975Snwhitehorn#include <machine/reg.h> 53100384Speter#include <machine/md_var.h> 5439072Sdfr 55209975Snwhitehorn#ifdef __powerpc64__ 56209975Snwhitehorn#include <compat/freebsd32/freebsd32_proto.h> 57209975Snwhitehorn#include <compat/freebsd32/freebsd32_util.h> 58209975Snwhitehorn 59209975Snwhitehornextern const char *freebsd32_syscallnames[]; 60209975Snwhitehorn#endif 61209975Snwhitehorn 62100384Speterstruct sysentvec elf32_freebsd_sysvec = { 63183322Skib .sv_size = SYS_MAXSYSCALL, 64209975Snwhitehorn#ifdef __powerpc64__ 65209975Snwhitehorn .sv_table = freebsd32_sysent, 66209975Snwhitehorn#else 67183322Skib .sv_table = sysent, 68209975Snwhitehorn#endif 69183322Skib .sv_mask = 0, 70183322Skib .sv_sigsize = 0, 71183322Skib .sv_sigtbl = NULL, 72183322Skib .sv_errsize = 0, 73183322Skib .sv_errtbl = NULL, 74183322Skib .sv_transtrap = NULL, 75183322Skib .sv_fixup = __elfN(freebsd_fixup), 76183322Skib .sv_sendsig = sendsig, 77209975Snwhitehorn .sv_sigcode = sigcode32, 78209975Snwhitehorn .sv_szsigcode = &szsigcode32, 79183322Skib .sv_prepsyscall = NULL, 80183322Skib .sv_name = "FreeBSD ELF32", 81183322Skib .sv_coredump = __elfN(coredump), 82183322Skib .sv_imgact_try = NULL, 83183322Skib .sv_minsigstksz = MINSIGSTKSZ, 84183322Skib .sv_pagesize = PAGE_SIZE, 85183322Skib .sv_minuser = VM_MIN_ADDRESS, 86209975Snwhitehorn .sv_stackprot = VM_PROT_ALL, 87209975Snwhitehorn#ifdef __powerpc64__ 88183322Skib .sv_maxuser = VM_MAXUSER_ADDRESS, 89209975Snwhitehorn .sv_usrstack = FREEBSD32_USRSTACK, 90209975Snwhitehorn .sv_psstrings = FREEBSD32_PS_STRINGS, 91209975Snwhitehorn .sv_copyout_strings = freebsd32_copyout_strings, 92209975Snwhitehorn .sv_setregs = ppc32_setregs, 93209975Snwhitehorn .sv_syscallnames = freebsd32_syscallnames, 94209975Snwhitehorn#else 95209975Snwhitehorn .sv_maxuser = VM_MAXUSER_ADDRESS, 96183322Skib .sv_usrstack = USRSTACK, 97183322Skib .sv_psstrings = PS_STRINGS, 98183322Skib .sv_copyout_strings = exec_copyout_strings, 99183322Skib .sv_setregs = exec_setregs, 100209975Snwhitehorn .sv_syscallnames = syscallnames, 101209975Snwhitehorn#endif 102183322Skib .sv_fixlimit = NULL, 103185169Skib .sv_maxssiz = NULL, 104217400Skib .sv_flags = SV_ABI_FREEBSD | SV_ILP32 | SV_SHP, 105208453Skib .sv_set_syscall_retval = cpu_set_syscall_retval, 106208453Skib .sv_fetch_syscall_args = cpu_fetch_syscall_args, 107217400Skib .sv_shared_page_base = FREEBSD32_SHAREDPAGE, 108217400Skib .sv_shared_page_len = PAGE_SIZE, 109219405Sdchagin .sv_schedtail = NULL, 110293490Sdchagin .sv_thread_detach = NULL, 111294136Sdchagin .sv_trap = NULL, 112100384Speter}; 113217400SkibINIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec); 114100384Speter 115100384Speterstatic Elf32_Brandinfo freebsd_brand_info = { 116183322Skib .brand = ELFOSABI_FREEBSD, 117183322Skib .machine = EM_PPC, 118183322Skib .compat_3_brand = "FreeBSD", 119183322Skib .emul_path = NULL, 120183322Skib .interp_path = "/libexec/ld-elf.so.1", 121183322Skib .sysvec = &elf32_freebsd_sysvec, 122209975Snwhitehorn#ifdef __powerpc64__ 123209975Snwhitehorn .interp_newpath = "/libexec/ld-elf32.so.1", 124209975Snwhitehorn#else 125183322Skib .interp_newpath = NULL, 126209975Snwhitehorn#endif 127189771Sdchagin .brand_note = &elf32_freebsd_brandnote, 128190708Sdchagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 129183322Skib}; 130100384Speter 131197729SbzSYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST, 132183322Skib (sysinit_cfunc_t) elf32_insert_brand_entry, 133183322Skib &freebsd_brand_info); 134100384Speter 135123742Speterstatic Elf32_Brandinfo freebsd_brand_oinfo = { 136183322Skib .brand = ELFOSABI_FREEBSD, 137183322Skib .machine = EM_PPC, 138183322Skib .compat_3_brand = "FreeBSD", 139183322Skib .emul_path = NULL, 140183322Skib .interp_path = "/usr/libexec/ld-elf.so.1", 141183322Skib .sysvec = &elf32_freebsd_sysvec, 142183322Skib .interp_newpath = NULL, 143189771Sdchagin .brand_note = &elf32_freebsd_brandnote, 144190708Sdchagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 145183322Skib}; 146123742Speter 147123742SpeterSYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY, 148123742Speter (sysinit_cfunc_t) elf32_insert_brand_entry, 149123742Speter &freebsd_brand_oinfo); 150123742Speter 151133464Smarcelvoid 152133464Smarcelelf32_dump_thread(struct thread *td __unused, void *dst __unused, 153133464Smarcel size_t *off __unused) 154133464Smarcel{ 155133464Smarcel} 156133464Smarcel 157209975Snwhitehorn#ifndef __powerpc64__ 15839072Sdfr/* Process one elf relocation with addend. */ 159109605Sjakestatic int 160129282Speterelf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, 161129282Speter int type, int local, elf_lookup_fn lookup) 16239072Sdfr{ 16340435Speter Elf_Addr *where; 164132282Sgrehan Elf_Half *hwhere; 16545958Sdt Elf_Addr addr; 16640435Speter Elf_Addr addend; 16795410Smarcel Elf_Word rtype, symidx; 16840435Speter const Elf_Rela *rela; 169288287Skib int error; 17039072Sdfr 17140435Speter switch (type) { 17240435Speter case ELF_RELOC_REL: 173132282Sgrehan panic("PPC only supports RELA relocations"); 17440435Speter break; 17540435Speter case ELF_RELOC_RELA: 17645958Sdt rela = (const Elf_Rela *)data; 177209975Snwhitehorn where = (Elf_Addr *) ((uintptr_t)relocbase + rela->r_offset); 178209975Snwhitehorn hwhere = (Elf_Half *) ((uintptr_t)relocbase + rela->r_offset); 17940435Speter addend = rela->r_addend; 18040435Speter rtype = ELF_R_TYPE(rela->r_info); 18195410Smarcel symidx = ELF_R_SYM(rela->r_info); 18240435Speter break; 18340435Speter default: 18440435Speter panic("elf_reloc: unknown relocation mode %d\n", type); 18540435Speter } 18639072Sdfr 18740435Speter switch (rtype) { 18839072Sdfr 189288289Skib case R_PPC_NONE: 190288289Skib break; 19148840Sdfr 192132282Sgrehan case R_PPC_ADDR32: /* word32 S + A */ 193288287Skib error = lookup(lf, symidx, 1, &addr); 194288287Skib if (error != 0) 195288287Skib return -1; 196132282Sgrehan addr += addend; 197132282Sgrehan *where = addr; 198288289Skib break; 19939072Sdfr 200288289Skib case R_PPC_ADDR16_LO: /* #lo(S) */ 201288287Skib error = lookup(lf, symidx, 1, &addr); 202288287Skib if (error != 0) 203132562Sgrehan return -1; 204132562Sgrehan /* 205132562Sgrehan * addend values are sometimes relative to sections 206132562Sgrehan * (i.e. .rodata) in rela, where in reality they 207132562Sgrehan * are relative to relocbase. Detect this condition. 208132562Sgrehan */ 209132562Sgrehan if (addr > relocbase && addr <= (relocbase + addend)) 210132562Sgrehan addr = relocbase + addend; 211132562Sgrehan else 212132562Sgrehan addr += addend; 213132282Sgrehan *hwhere = addr & 0xffff; 214132282Sgrehan break; 21539072Sdfr 216132282Sgrehan case R_PPC_ADDR16_HA: /* #ha(S) */ 217288287Skib error = lookup(lf, symidx, 1, &addr); 218288287Skib if (error != 0) 219132562Sgrehan return -1; 220132562Sgrehan /* 221132562Sgrehan * addend values are sometimes relative to sections 222132562Sgrehan * (i.e. .rodata) in rela, where in reality they 223132562Sgrehan * are relative to relocbase. Detect this condition. 224132562Sgrehan */ 225132562Sgrehan if (addr > relocbase && addr <= (relocbase + addend)) 226132562Sgrehan addr = relocbase + addend; 227132562Sgrehan else 228132562Sgrehan addr += addend; 229288289Skib *hwhere = ((addr >> 16) + ((addr & 0x8000) ? 1 : 0)) 230132282Sgrehan & 0xffff; 231132282Sgrehan break; 23239072Sdfr 233132282Sgrehan case R_PPC_RELATIVE: /* word32 B + A */ 234288289Skib *where = elf_relocaddr(lf, relocbase + addend); 235288289Skib break; 23639072Sdfr 237132282Sgrehan default: 238288289Skib printf("kldload: unexpected relocation type %d\n", 239288289Skib (int) rtype); 240132282Sgrehan return -1; 24139072Sdfr } 24239072Sdfr return(0); 24339072Sdfr} 244105469Smarcel 245105469Smarcelint 246129282Speterelf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, 247129282Speter elf_lookup_fn lookup) 248109605Sjake{ 249109605Sjake 250129282Speter return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup)); 251109605Sjake} 252109605Sjake 253109605Sjakeint 254129282Speterelf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, 255129282Speter int type, elf_lookup_fn lookup) 256109605Sjake{ 257109605Sjake 258129282Speter return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup)); 259109605Sjake} 260109605Sjake 261109605Sjakeint 262132428Sgrehanelf_cpu_load_file(linker_file_t lf) 263105469Smarcel{ 264132428Sgrehan /* Only sync the cache for non-kernel modules */ 265132428Sgrehan if (lf->id != 1) 266132428Sgrehan __syncicache(lf->address, lf->size); 267105469Smarcel return (0); 268105469Smarcel} 269105469Smarcel 270105469Smarcelint 271105469Smarcelelf_cpu_unload_file(linker_file_t lf __unused) 272105469Smarcel{ 273105469Smarcel 274105469Smarcel return (0); 275105469Smarcel} 276209975Snwhitehorn#endif 277