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