elf32_machdep.c revision 133464
1142215Sglebius/*-
2142215Sglebius * Copyright 1996-1998 John D. Polstra.
3142215Sglebius * All rights reserved.
4142215Sglebius *
5142215Sglebius * Redistribution and use in source and binary forms, with or without
6142215Sglebius * modification, are permitted provided that the following conditions
7142215Sglebius * are met:
8142215Sglebius * 1. Redistributions of source code must retain the above copyright
9142215Sglebius *    notice, this list of conditions and the following disclaimer.
10142215Sglebius * 2. Redistributions in binary form must reproduce the above copyright
11142215Sglebius *    notice, this list of conditions and the following disclaimer in the
12142215Sglebius *    documentation and/or other materials provided with the distribution.
13142215Sglebius *
14142215Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15142215Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16142215Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17142215Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18142215Sglebius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19142215Sglebius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20142215Sglebius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21142215Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22142215Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23142215Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24142215Sglebius *
25142215Sglebius * $FreeBSD: head/sys/powerpc/powerpc/elf_machdep.c 133464 2004-08-11 02:35:06Z marcel $
26142215Sglebius */
27142215Sglebius
28142215Sglebius#include <sys/param.h>
29142215Sglebius#include <sys/kernel.h>
30142215Sglebius#include <sys/systm.h>
31142215Sglebius#include <sys/exec.h>
32142215Sglebius#include <sys/imgact.h>
33142215Sglebius#include <sys/malloc.h>
34142215Sglebius#include <sys/proc.h>
35142215Sglebius#include <sys/namei.h>
36142215Sglebius#include <sys/fcntl.h>
37142215Sglebius#include <sys/sysent.h>
38142215Sglebius#include <sys/imgact_elf.h>
39142215Sglebius#include <sys/syscall.h>
40142215Sglebius#include <sys/signalvar.h>
41142215Sglebius#include <sys/vnode.h>
42142215Sglebius#include <sys/linker.h>
43142215Sglebius
44142215Sglebius#include <vm/vm.h>
45142215Sglebius#include <vm/vm_param.h>
46142215Sglebius
47142215Sglebius#include <machine/cpu.h>
48142215Sglebius#include <machine/elf.h>
49142215Sglebius#include <machine/md_var.h>
50142215Sglebius
51142215Sglebiusstruct sysentvec elf32_freebsd_sysvec = {
52142215Sglebius	SYS_MAXSYSCALL,
53142215Sglebius	sysent,
54142215Sglebius	0,
55142224Sglebius	0,
56142215Sglebius	NULL,
57142215Sglebius	0,
58142215Sglebius	NULL,
59142215Sglebius	NULL,
60142215Sglebius	__elfN(freebsd_fixup),
61142215Sglebius	sendsig,
62142224Sglebius	sigcode,
63142215Sglebius	&szsigcode,
64142215Sglebius	NULL,
65142215Sglebius	"FreeBSD ELF32",
66142215Sglebius	__elfN(coredump),
67142215Sglebius	NULL,
68142215Sglebius	MINSIGSTKSZ,
69142215Sglebius	PAGE_SIZE,
70142215Sglebius	VM_MIN_ADDRESS,
71142215Sglebius	VM_MAXUSER_ADDRESS,
72142215Sglebius	USRSTACK,
73142215Sglebius	PS_STRINGS,
74142215Sglebius	VM_PROT_ALL,
75142215Sglebius	exec_copyout_strings,
76142215Sglebius	exec_setregs,
77142215Sglebius	NULL
78142215Sglebius};
79142215Sglebius
80142215Sglebiusstatic Elf32_Brandinfo freebsd_brand_info = {
81142215Sglebius						ELFOSABI_FREEBSD,
82142215Sglebius						EM_PPC,
83142215Sglebius						"FreeBSD",
84142215Sglebius						NULL,
85142215Sglebius						"/libexec/ld-elf.so.1",
86142215Sglebius						&elf32_freebsd_sysvec,
87142215Sglebius						NULL,
88142215Sglebius					  };
89142215Sglebius
90142215SglebiusSYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY,
91142215Sglebius	(sysinit_cfunc_t) elf32_insert_brand_entry,
92142215Sglebius	&freebsd_brand_info);
93142215Sglebius
94142215Sglebiusstatic Elf32_Brandinfo freebsd_brand_oinfo = {
95142215Sglebius						ELFOSABI_FREEBSD,
96142215Sglebius						EM_PPC,
97142215Sglebius						"FreeBSD",
98142215Sglebius						NULL,
99203486Sru						"/usr/libexec/ld-elf.so.1",
100142215Sglebius						&elf32_freebsd_sysvec,
101142215Sglebius						NULL,
102142215Sglebius					  };
103142215Sglebius
104142215SglebiusSYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY,
105142215Sglebius	(sysinit_cfunc_t) elf32_insert_brand_entry,
106142215Sglebius	&freebsd_brand_oinfo);
107142215Sglebius
108142215Sglebius
109142215Sglebiusvoid
110142215Sglebiuself32_dump_thread(struct thread *td __unused, void *dst __unused,
111142215Sglebius    size_t *off __unused)
112142215Sglebius{
113142215Sglebius}
114142215Sglebius
115142215Sglebius
116142215Sglebius/* Process one elf relocation with addend. */
117142215Sglebiusstatic int
118142215Sglebiuself_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
119142215Sglebius    int type, int local, elf_lookup_fn lookup)
120142215Sglebius{
121142215Sglebius	Elf_Addr *where;
122142215Sglebius	Elf_Half *hwhere;
123142215Sglebius	Elf_Addr addr;
124142215Sglebius	Elf_Addr addend;
125142215Sglebius	Elf_Word rtype, symidx;
126142215Sglebius	const Elf_Rela *rela;
127142215Sglebius
128142215Sglebius	switch (type) {
129142215Sglebius	case ELF_RELOC_REL:
130142215Sglebius		panic("PPC only supports RELA relocations");
131142215Sglebius		break;
132142215Sglebius	case ELF_RELOC_RELA:
133142215Sglebius		rela = (const Elf_Rela *)data;
134142215Sglebius		where = (Elf_Addr *) (relocbase + rela->r_offset);
135142215Sglebius		hwhere = (Elf_Half *) (relocbase + rela->r_offset);
136142215Sglebius		addend = rela->r_addend;
137142215Sglebius		rtype = ELF_R_TYPE(rela->r_info);
138142215Sglebius		symidx = ELF_R_SYM(rela->r_info);
139142215Sglebius		break;
140142215Sglebius	default:
141142215Sglebius		panic("elf_reloc: unknown relocation mode %d\n", type);
142142215Sglebius	}
143142215Sglebius
144142215Sglebius	switch (rtype) {
145142215Sglebius
146142215Sglebius       	case R_PPC_NONE:
147142215Sglebius	       	break;
148142215Sglebius
149142215Sglebius	case R_PPC_ADDR32: /* word32 S + A */
150142215Sglebius       		addr = lookup(lf, symidx, 1);
151142215Sglebius	       	if (addr == 0)
152142215Sglebius	       		return -1;
153142215Sglebius		addr += addend;
154142215Sglebius	       	*where = addr;
155142215Sglebius	       	break;
156142215Sglebius
157142215Sglebius       	case R_PPC_ADDR16_LO: /* #lo(S) */
158142215Sglebius		addr = lookup(lf, symidx, 1);
159142215Sglebius		if (addr == 0)
160142215Sglebius			return -1;
161142215Sglebius		/*
162142215Sglebius		 * addend values are sometimes relative to sections
163142215Sglebius		 * (i.e. .rodata) in rela, where in reality they
164142215Sglebius		 * are relative to relocbase. Detect this condition.
165142215Sglebius		 */
166142215Sglebius		if (addr > relocbase && addr <= (relocbase + addend))
167142215Sglebius			addr = relocbase + addend;
168142215Sglebius		else
169142215Sglebius			addr += addend;
170142215Sglebius		*hwhere = addr & 0xffff;
171142215Sglebius		break;
172142215Sglebius
173142215Sglebius	case R_PPC_ADDR16_HA: /* #ha(S) */
174142215Sglebius		addr = lookup(lf, symidx, 1);
175142215Sglebius		if (addr == 0)
176142215Sglebius			return -1;
177142215Sglebius		/*
178142215Sglebius		 * addend values are sometimes relative to sections
179142215Sglebius		 * (i.e. .rodata) in rela, where in reality they
180142215Sglebius		 * are relative to relocbase. Detect this condition.
181142215Sglebius		 */
182142215Sglebius		if (addr > relocbase && addr <= (relocbase + addend))
183142215Sglebius			addr = relocbase + addend;
184142215Sglebius		else
185142215Sglebius			addr += addend;
186142215Sglebius	       	*hwhere = ((addr >> 16) + ((addr & 0x8000) ? 1 : 0))
187142224Sglebius		    & 0xffff;
188142215Sglebius		break;
189142215Sglebius
190142215Sglebius	case R_PPC_RELATIVE: /* word32 B + A */
191142215Sglebius       		*where = relocbase + addend;
192142215Sglebius	       	break;
193142215Sglebius
194142215Sglebius	default:
195142215Sglebius       		printf("kldload: unexpected relocation type %d\n",
196142215Sglebius	       	    (int) rtype);
197142215Sglebius		return -1;
198142215Sglebius	}
199142215Sglebius	return(0);
200142215Sglebius}
201
202int
203elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
204    elf_lookup_fn lookup)
205{
206
207	return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
208}
209
210int
211elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
212    int type, elf_lookup_fn lookup)
213{
214
215	return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
216}
217
218int
219elf_cpu_load_file(linker_file_t lf)
220{
221	/* Only sync the cache for non-kernel modules */
222	if (lf->id != 1)
223		__syncicache(lf->address, lf->size);
224	return (0);
225}
226
227int
228elf_cpu_unload_file(linker_file_t lf __unused)
229{
230
231	return (0);
232}
233