1209950Snwhitehorn/*-
2209950Snwhitehorn * Copyright (C) 1995, 1996 Wolfgang Solfrank.
3209950Snwhitehorn * Copyright (C) 1995, 1996 TooLs GmbH.
4209950Snwhitehorn * All rights reserved.
5209950Snwhitehorn *
6209950Snwhitehorn * Redistribution and use in source and binary forms, with or without
7209950Snwhitehorn * modification, are permitted provided that the following conditions
8209950Snwhitehorn * are met:
9209950Snwhitehorn * 1. Redistributions of source code must retain the above copyright
10209950Snwhitehorn *    notice, this list of conditions and the following disclaimer.
11209950Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
12209950Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
13209950Snwhitehorn *    documentation and/or other materials provided with the distribution.
14209950Snwhitehorn * 3. All advertising materials mentioning features or use of this software
15209950Snwhitehorn *    must display the following acknowledgement:
16209950Snwhitehorn *      This product includes software developed by TooLs GmbH.
17209950Snwhitehorn * 4. The name of TooLs GmbH may not be used to endorse or promote products
18209950Snwhitehorn *    derived from this software without specific prior written permission.
19209950Snwhitehorn *
20209950Snwhitehorn * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21209950Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22209950Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23209950Snwhitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24209950Snwhitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25209950Snwhitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26209950Snwhitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27209950Snwhitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28209950Snwhitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29209950Snwhitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30209950Snwhitehorn */
31209950Snwhitehorn/*-
32209950Snwhitehorn * Copyright (C) 2001 Benno Rice
33209950Snwhitehorn * All rights reserved.
34209950Snwhitehorn *
35209950Snwhitehorn * Redistribution and use in source and binary forms, with or without
36209950Snwhitehorn * modification, are permitted provided that the following conditions
37209950Snwhitehorn * are met:
38209950Snwhitehorn * 1. Redistributions of source code must retain the above copyright
39209950Snwhitehorn *    notice, this list of conditions and the following disclaimer.
40209950Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
41209950Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
42209950Snwhitehorn *    documentation and/or other materials provided with the distribution.
43209950Snwhitehorn *
44209950Snwhitehorn * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
45209950Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
46209950Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
47209950Snwhitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48209950Snwhitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
49209950Snwhitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
50209950Snwhitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
51209950Snwhitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
52209950Snwhitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
53209950Snwhitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54209950Snwhitehorn *	$NetBSD: machdep.c,v 1.74.2.1 2000/11/01 16:13:48 tv Exp $
55209950Snwhitehorn */
56209950Snwhitehorn
57209950Snwhitehorn#include <sys/cdefs.h>
58209950Snwhitehorn__FBSDID("$FreeBSD: stable/11/sys/powerpc/powerpc/exec_machdep.c 341165 2018-11-28 21:19:58Z vangyzen $");
59209950Snwhitehorn
60209950Snwhitehorn#include "opt_compat.h"
61258259Snwhitehorn#include "opt_fpu_emu.h"
62209950Snwhitehorn
63209950Snwhitehorn#include <sys/param.h>
64209950Snwhitehorn#include <sys/proc.h>
65209950Snwhitehorn#include <sys/systm.h>
66209950Snwhitehorn#include <sys/bio.h>
67209950Snwhitehorn#include <sys/buf.h>
68209950Snwhitehorn#include <sys/bus.h>
69209950Snwhitehorn#include <sys/cons.h>
70209950Snwhitehorn#include <sys/cpu.h>
71209950Snwhitehorn#include <sys/exec.h>
72209950Snwhitehorn#include <sys/imgact.h>
73209950Snwhitehorn#include <sys/kernel.h>
74209950Snwhitehorn#include <sys/ktr.h>
75209950Snwhitehorn#include <sys/lock.h>
76209950Snwhitehorn#include <sys/malloc.h>
77209950Snwhitehorn#include <sys/mutex.h>
78209950Snwhitehorn#include <sys/signalvar.h>
79209950Snwhitehorn#include <sys/syscallsubr.h>
80209950Snwhitehorn#include <sys/syscall.h>
81209950Snwhitehorn#include <sys/sysent.h>
82209950Snwhitehorn#include <sys/sysproto.h>
83209950Snwhitehorn#include <sys/ucontext.h>
84209950Snwhitehorn#include <sys/uio.h>
85209950Snwhitehorn
86209950Snwhitehorn#include <machine/altivec.h>
87209950Snwhitehorn#include <machine/cpu.h>
88209950Snwhitehorn#include <machine/elf.h>
89209950Snwhitehorn#include <machine/fpu.h>
90209950Snwhitehorn#include <machine/pcb.h>
91209950Snwhitehorn#include <machine/reg.h>
92209950Snwhitehorn#include <machine/sigframe.h>
93209950Snwhitehorn#include <machine/trap.h>
94209950Snwhitehorn#include <machine/vmparam.h>
95209950Snwhitehorn
96258259Snwhitehorn#ifdef FPU_EMU
97258259Snwhitehorn#include <powerpc/fpu/fpu_extern.h>
98258259Snwhitehorn#endif
99258259Snwhitehorn
100209975Snwhitehorn#ifdef COMPAT_FREEBSD32
101209975Snwhitehorn#include <compat/freebsd32/freebsd32_signal.h>
102209975Snwhitehorn#include <compat/freebsd32/freebsd32_util.h>
103209975Snwhitehorn#include <compat/freebsd32/freebsd32_proto.h>
104209975Snwhitehorn
105209975Snwhitehorntypedef struct __ucontext32 {
106209975Snwhitehorn	sigset_t		uc_sigmask;
107209975Snwhitehorn	mcontext32_t		uc_mcontext;
108209975Snwhitehorn	uint32_t		uc_link;
109209975Snwhitehorn	struct sigaltstack32    uc_stack;
110209975Snwhitehorn	uint32_t		uc_flags;
111209975Snwhitehorn	uint32_t		__spare__[4];
112209975Snwhitehorn} ucontext32_t;
113209975Snwhitehorn
114209975Snwhitehornstruct sigframe32 {
115209975Snwhitehorn	ucontext32_t		sf_uc;
116209975Snwhitehorn	struct siginfo32	sf_si;
117209975Snwhitehorn};
118209975Snwhitehorn
119209975Snwhitehornstatic int	grab_mcontext32(struct thread *td, mcontext32_t *, int flags);
120209975Snwhitehorn#endif
121209975Snwhitehorn
122209950Snwhitehornstatic int	grab_mcontext(struct thread *, mcontext_t *, int);
123209950Snwhitehorn
124209950Snwhitehornvoid
125209950Snwhitehornsendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
126209950Snwhitehorn{
127209950Snwhitehorn	struct trapframe *tf;
128209950Snwhitehorn	struct sigacts *psp;
129209950Snwhitehorn	struct sigframe sf;
130209950Snwhitehorn	struct thread *td;
131209950Snwhitehorn	struct proc *p;
132209975Snwhitehorn	#ifdef COMPAT_FREEBSD32
133209975Snwhitehorn	struct siginfo32 siginfo32;
134209975Snwhitehorn	struct sigframe32 sf32;
135209975Snwhitehorn	#endif
136209950Snwhitehorn	size_t sfpsize;
137209950Snwhitehorn	caddr_t sfp, usfp;
138209950Snwhitehorn	int oonstack, rndfsize;
139209950Snwhitehorn	int sig;
140209950Snwhitehorn	int code;
141209950Snwhitehorn
142209950Snwhitehorn	td = curthread;
143209950Snwhitehorn	p = td->td_proc;
144209950Snwhitehorn	PROC_LOCK_ASSERT(p, MA_OWNED);
145209950Snwhitehorn
146209950Snwhitehorn	psp = p->p_sigacts;
147209950Snwhitehorn	mtx_assert(&psp->ps_mtx, MA_OWNED);
148209950Snwhitehorn	tf = td->td_frame;
149209950Snwhitehorn	oonstack = sigonstack(tf->fixreg[1]);
150209950Snwhitehorn
151209950Snwhitehorn	/*
152209950Snwhitehorn	 * Fill siginfo structure.
153209950Snwhitehorn	 */
154209950Snwhitehorn	ksi->ksi_info.si_signo = ksi->ksi_signo;
155209950Snwhitehorn	ksi->ksi_info.si_addr = (void *)((tf->exc == EXC_DSI) ?
156279601Snwhitehorn	    tf->dar : tf->srr0);
157209950Snwhitehorn
158209975Snwhitehorn	#ifdef COMPAT_FREEBSD32
159217896Sdchagin	if (SV_PROC_FLAG(p, SV_ILP32)) {
160209975Snwhitehorn		siginfo_to_siginfo32(&ksi->ksi_info, &siginfo32);
161209975Snwhitehorn		sig = siginfo32.si_signo;
162209975Snwhitehorn		code = siginfo32.si_code;
163209975Snwhitehorn		sfp = (caddr_t)&sf32;
164209975Snwhitehorn		sfpsize = sizeof(sf32);
165298860Spfg		rndfsize = roundup(sizeof(sf32), 16);
166209950Snwhitehorn
167209975Snwhitehorn		/*
168209975Snwhitehorn		 * Save user context
169209975Snwhitehorn		 */
170209950Snwhitehorn
171209975Snwhitehorn		memset(&sf32, 0, sizeof(sf32));
172209975Snwhitehorn		grab_mcontext32(td, &sf32.sf_uc.uc_mcontext, 0);
173209950Snwhitehorn
174209975Snwhitehorn		sf32.sf_uc.uc_sigmask = *mask;
175209975Snwhitehorn		sf32.sf_uc.uc_stack.ss_sp = (uintptr_t)td->td_sigstk.ss_sp;
176209975Snwhitehorn		sf32.sf_uc.uc_stack.ss_size = (uint32_t)td->td_sigstk.ss_size;
177209975Snwhitehorn		sf32.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
178209975Snwhitehorn		    ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
179209950Snwhitehorn
180209975Snwhitehorn		sf32.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
181209975Snwhitehorn	} else {
182209975Snwhitehorn	#endif
183209975Snwhitehorn		sig = ksi->ksi_signo;
184209975Snwhitehorn		code = ksi->ksi_code;
185209975Snwhitehorn		sfp = (caddr_t)&sf;
186209975Snwhitehorn		sfpsize = sizeof(sf);
187209975Snwhitehorn		#ifdef __powerpc64__
188209975Snwhitehorn		/*
189209975Snwhitehorn		 * 64-bit PPC defines a 288 byte scratch region
190209975Snwhitehorn		 * below the stack.
191209975Snwhitehorn		 */
192298860Spfg		rndfsize = 288 + roundup(sizeof(sf), 48);
193209975Snwhitehorn		#else
194298860Spfg		rndfsize = roundup(sizeof(sf), 16);
195209975Snwhitehorn		#endif
196209950Snwhitehorn
197209975Snwhitehorn		/*
198209975Snwhitehorn		 * Save user context
199209975Snwhitehorn		 */
200209975Snwhitehorn
201209975Snwhitehorn		memset(&sf, 0, sizeof(sf));
202209975Snwhitehorn		grab_mcontext(td, &sf.sf_uc.uc_mcontext, 0);
203209975Snwhitehorn
204209975Snwhitehorn		sf.sf_uc.uc_sigmask = *mask;
205209975Snwhitehorn		sf.sf_uc.uc_stack = td->td_sigstk;
206209975Snwhitehorn		sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
207209975Snwhitehorn		    ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
208209975Snwhitehorn
209209975Snwhitehorn		sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
210209975Snwhitehorn	#ifdef COMPAT_FREEBSD32
211209975Snwhitehorn	}
212209975Snwhitehorn	#endif
213209975Snwhitehorn
214209950Snwhitehorn	CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
215209950Snwhitehorn	     catcher, sig);
216209950Snwhitehorn
217209950Snwhitehorn	/*
218209950Snwhitehorn	 * Allocate and validate space for the signal handler context.
219209950Snwhitehorn	 */
220209950Snwhitehorn	if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
221209950Snwhitehorn	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
222295186Sjhibbits		usfp = (void *)(((uintptr_t)td->td_sigstk.ss_sp +
223295186Sjhibbits		   td->td_sigstk.ss_size - rndfsize) & ~0xFul);
224209950Snwhitehorn	} else {
225295186Sjhibbits		usfp = (void *)((tf->fixreg[1] - rndfsize) & ~0xFul);
226209950Snwhitehorn	}
227209950Snwhitehorn
228209950Snwhitehorn	/*
229209950Snwhitehorn	 * Save the floating-point state, if necessary, then copy it.
230209950Snwhitehorn	 */
231209950Snwhitehorn	/* XXX */
232209950Snwhitehorn
233209950Snwhitehorn	/*
234209950Snwhitehorn	 * Set up the registers to return to sigcode.
235209950Snwhitehorn	 *
236209950Snwhitehorn	 *   r1/sp - sigframe ptr
237209950Snwhitehorn	 *   lr    - sig function, dispatched to by blrl in trampoline
238209950Snwhitehorn	 *   r3    - sig number
239209950Snwhitehorn	 *   r4    - SIGINFO ? &siginfo : exception code
240209950Snwhitehorn	 *   r5    - user context
241209950Snwhitehorn	 *   srr0  - trampoline function addr
242209950Snwhitehorn	 */
243209950Snwhitehorn	tf->lr = (register_t)catcher;
244209950Snwhitehorn	tf->fixreg[1] = (register_t)usfp;
245209950Snwhitehorn	tf->fixreg[FIRSTARG] = sig;
246209975Snwhitehorn	#ifdef COMPAT_FREEBSD32
247209950Snwhitehorn	tf->fixreg[FIRSTARG+2] = (register_t)usfp +
248217896Sdchagin	    ((SV_PROC_FLAG(p, SV_ILP32)) ?
249209975Snwhitehorn	    offsetof(struct sigframe32, sf_uc) :
250212586Snwhitehorn	    offsetof(struct sigframe, sf_uc));
251209975Snwhitehorn	#else
252209975Snwhitehorn	tf->fixreg[FIRSTARG+2] = (register_t)usfp +
253209975Snwhitehorn	    offsetof(struct sigframe, sf_uc);
254209975Snwhitehorn	#endif
255209950Snwhitehorn	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
256209950Snwhitehorn		/*
257209950Snwhitehorn		 * Signal handler installed with SA_SIGINFO.
258209950Snwhitehorn		 */
259209975Snwhitehorn		#ifdef COMPAT_FREEBSD32
260217896Sdchagin		if (SV_PROC_FLAG(p, SV_ILP32)) {
261209975Snwhitehorn			sf32.sf_si = siginfo32;
262209950Snwhitehorn			tf->fixreg[FIRSTARG+1] = (register_t)usfp +
263209975Snwhitehorn			    offsetof(struct sigframe32, sf_si);
264209975Snwhitehorn			sf32.sf_si = siginfo32;
265209975Snwhitehorn		} else  {
266209975Snwhitehorn		#endif
267209975Snwhitehorn			tf->fixreg[FIRSTARG+1] = (register_t)usfp +
268209950Snwhitehorn			    offsetof(struct sigframe, sf_si);
269209950Snwhitehorn			sf.sf_si = ksi->ksi_info;
270209975Snwhitehorn		#ifdef COMPAT_FREEBSD32
271209975Snwhitehorn		}
272209975Snwhitehorn		#endif
273209950Snwhitehorn	} else {
274209950Snwhitehorn		/* Old FreeBSD-style arguments. */
275209950Snwhitehorn		tf->fixreg[FIRSTARG+1] = code;
276209950Snwhitehorn		tf->fixreg[FIRSTARG+3] = (tf->exc == EXC_DSI) ?
277279601Snwhitehorn		    tf->dar : tf->srr0;
278209950Snwhitehorn	}
279209950Snwhitehorn	mtx_unlock(&psp->ps_mtx);
280209950Snwhitehorn	PROC_UNLOCK(p);
281209950Snwhitehorn
282217400Skib	tf->srr0 = (register_t)p->p_sysent->sv_sigcode_base;
283209950Snwhitehorn
284209950Snwhitehorn	/*
285209950Snwhitehorn	 * copy the frame out to userland.
286209950Snwhitehorn	 */
287209950Snwhitehorn	if (copyout(sfp, usfp, sfpsize) != 0) {
288209950Snwhitehorn		/*
289209950Snwhitehorn		 * Process has trashed its stack. Kill it.
290209950Snwhitehorn		 */
291209950Snwhitehorn		CTR2(KTR_SIG, "sendsig: sigexit td=%p sfp=%p", td, sfp);
292209950Snwhitehorn		PROC_LOCK(p);
293209950Snwhitehorn		sigexit(td, SIGILL);
294209950Snwhitehorn	}
295209950Snwhitehorn
296209950Snwhitehorn	CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td,
297209950Snwhitehorn	     tf->srr0, tf->fixreg[1]);
298209950Snwhitehorn
299209950Snwhitehorn	PROC_LOCK(p);
300209950Snwhitehorn	mtx_lock(&psp->ps_mtx);
301209950Snwhitehorn}
302209950Snwhitehorn
303209950Snwhitehornint
304225617Skmacysys_sigreturn(struct thread *td, struct sigreturn_args *uap)
305209950Snwhitehorn{
306209950Snwhitehorn	ucontext_t uc;
307209950Snwhitehorn	int error;
308209950Snwhitehorn
309209950Snwhitehorn	CTR2(KTR_SIG, "sigreturn: td=%p ucp=%p", td, uap->sigcntxp);
310209950Snwhitehorn
311209950Snwhitehorn	if (copyin(uap->sigcntxp, &uc, sizeof(uc)) != 0) {
312209950Snwhitehorn		CTR1(KTR_SIG, "sigreturn: efault td=%p", td);
313209950Snwhitehorn		return (EFAULT);
314209950Snwhitehorn	}
315209950Snwhitehorn
316209950Snwhitehorn	error = set_mcontext(td, &uc.uc_mcontext);
317209950Snwhitehorn	if (error != 0)
318209950Snwhitehorn		return (error);
319209950Snwhitehorn
320209950Snwhitehorn	kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
321209950Snwhitehorn
322209950Snwhitehorn	CTR3(KTR_SIG, "sigreturn: return td=%p pc=%#x sp=%#x",
323209950Snwhitehorn	     td, uc.uc_mcontext.mc_srr0, uc.uc_mcontext.mc_gpr[1]);
324209950Snwhitehorn
325209950Snwhitehorn	return (EJUSTRETURN);
326209950Snwhitehorn}
327209950Snwhitehorn
328209950Snwhitehorn#ifdef COMPAT_FREEBSD4
329209950Snwhitehornint
330209950Snwhitehornfreebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap)
331209950Snwhitehorn{
332209950Snwhitehorn
333225617Skmacy	return sys_sigreturn(td, (struct sigreturn_args *)uap);
334209950Snwhitehorn}
335209950Snwhitehorn#endif
336209950Snwhitehorn
337209950Snwhitehorn/*
338209950Snwhitehorn * Construct a PCB from a trapframe. This is called from kdb_trap() where
339209950Snwhitehorn * we want to start a backtrace from the function that caused us to enter
340209950Snwhitehorn * the debugger. We have the context in the trapframe, but base the trace
341209950Snwhitehorn * on the PCB. The PCB doesn't have to be perfect, as long as it contains
342209950Snwhitehorn * enough for a backtrace.
343209950Snwhitehorn */
344209950Snwhitehornvoid
345209950Snwhitehornmakectx(struct trapframe *tf, struct pcb *pcb)
346209950Snwhitehorn{
347209950Snwhitehorn
348209950Snwhitehorn	pcb->pcb_lr = tf->srr0;
349209950Snwhitehorn	pcb->pcb_sp = tf->fixreg[1];
350209950Snwhitehorn}
351209950Snwhitehorn
352209950Snwhitehorn/*
353209950Snwhitehorn * get_mcontext/sendsig helper routine that doesn't touch the
354209950Snwhitehorn * proc lock
355209950Snwhitehorn */
356209950Snwhitehornstatic int
357209950Snwhitehorngrab_mcontext(struct thread *td, mcontext_t *mcp, int flags)
358209950Snwhitehorn{
359209950Snwhitehorn	struct pcb *pcb;
360279189Snwhitehorn	int i;
361209950Snwhitehorn
362209950Snwhitehorn	pcb = td->td_pcb;
363209950Snwhitehorn
364209950Snwhitehorn	memset(mcp, 0, sizeof(mcontext_t));
365209950Snwhitehorn
366209950Snwhitehorn	mcp->mc_vers = _MC_VERSION;
367209950Snwhitehorn	mcp->mc_flags = 0;
368209950Snwhitehorn	memcpy(&mcp->mc_frame, td->td_frame, sizeof(struct trapframe));
369209950Snwhitehorn	if (flags & GET_MC_CLEAR_RET) {
370209950Snwhitehorn		mcp->mc_gpr[3] = 0;
371209950Snwhitehorn		mcp->mc_gpr[4] = 0;
372209950Snwhitehorn	}
373209950Snwhitehorn
374209950Snwhitehorn	/*
375209950Snwhitehorn	 * This assumes that floating-point context is *not* lazy,
376209950Snwhitehorn	 * so if the thread has used FP there would have been a
377209950Snwhitehorn	 * FP-unavailable exception that would have set things up
378209950Snwhitehorn	 * correctly.
379209950Snwhitehorn	 */
380258257Snwhitehorn	if (pcb->pcb_flags & PCB_FPREGS) {
381258257Snwhitehorn		if (pcb->pcb_flags & PCB_FPU) {
382258257Snwhitehorn			KASSERT(td == curthread,
383258257Snwhitehorn				("get_mcontext: fp save not curthread"));
384258257Snwhitehorn			critical_enter();
385258257Snwhitehorn			save_fpu(td);
386258257Snwhitehorn			critical_exit();
387258257Snwhitehorn		}
388209950Snwhitehorn		mcp->mc_flags |= _MC_FP_VALID;
389209950Snwhitehorn		memcpy(&mcp->mc_fpscr, &pcb->pcb_fpu.fpscr, sizeof(double));
390279189Snwhitehorn		for (i = 0; i < 32; i++)
391279189Snwhitehorn			memcpy(&mcp->mc_fpreg[i], &pcb->pcb_fpu.fpr[i].fpr,
392279189Snwhitehorn			    sizeof(double));
393209950Snwhitehorn	}
394209950Snwhitehorn
395279937Snwhitehorn	if (pcb->pcb_flags & PCB_VSX) {
396279937Snwhitehorn		for (i = 0; i < 32; i++)
397279937Snwhitehorn			memcpy(&mcp->mc_vsxfpreg[i],
398279937Snwhitehorn			    &pcb->pcb_fpu.fpr[i].vsr[2], sizeof(double));
399279937Snwhitehorn	}
400279937Snwhitehorn
401209950Snwhitehorn	/*
402209950Snwhitehorn	 * Repeat for Altivec context
403209950Snwhitehorn	 */
404209950Snwhitehorn
405209950Snwhitehorn	if (pcb->pcb_flags & PCB_VEC) {
406209950Snwhitehorn		KASSERT(td == curthread,
407209950Snwhitehorn			("get_mcontext: fp save not curthread"));
408209950Snwhitehorn		critical_enter();
409209950Snwhitehorn		save_vec(td);
410209950Snwhitehorn		critical_exit();
411209950Snwhitehorn		mcp->mc_flags |= _MC_AV_VALID;
412209950Snwhitehorn		mcp->mc_vscr  = pcb->pcb_vec.vscr;
413209950Snwhitehorn		mcp->mc_vrsave =  pcb->pcb_vec.vrsave;
414209950Snwhitehorn		memcpy(mcp->mc_avec, pcb->pcb_vec.vr, sizeof(mcp->mc_avec));
415209950Snwhitehorn	}
416209950Snwhitehorn
417209950Snwhitehorn	mcp->mc_len = sizeof(*mcp);
418209950Snwhitehorn
419209950Snwhitehorn	return (0);
420209950Snwhitehorn}
421209950Snwhitehorn
422209950Snwhitehornint
423209950Snwhitehornget_mcontext(struct thread *td, mcontext_t *mcp, int flags)
424209950Snwhitehorn{
425209950Snwhitehorn	int error;
426209950Snwhitehorn
427209950Snwhitehorn	error = grab_mcontext(td, mcp, flags);
428209950Snwhitehorn	if (error == 0) {
429209950Snwhitehorn		PROC_LOCK(curthread->td_proc);
430209950Snwhitehorn		mcp->mc_onstack = sigonstack(td->td_frame->fixreg[1]);
431209950Snwhitehorn		PROC_UNLOCK(curthread->td_proc);
432209950Snwhitehorn	}
433209950Snwhitehorn
434209950Snwhitehorn	return (error);
435209950Snwhitehorn}
436209950Snwhitehorn
437209950Snwhitehornint
438278001Skibset_mcontext(struct thread *td, mcontext_t *mcp)
439209950Snwhitehorn{
440209950Snwhitehorn	struct pcb *pcb;
441209950Snwhitehorn	struct trapframe *tf;
442234115Snwhitehorn	register_t tls;
443279189Snwhitehorn	int i;
444209950Snwhitehorn
445209950Snwhitehorn	pcb = td->td_pcb;
446209950Snwhitehorn	tf = td->td_frame;
447209950Snwhitehorn
448209950Snwhitehorn	if (mcp->mc_vers != _MC_VERSION || mcp->mc_len != sizeof(*mcp))
449209950Snwhitehorn		return (EINVAL);
450209950Snwhitehorn
451209950Snwhitehorn	/*
452209950Snwhitehorn	 * Don't let the user set privileged MSR bits
453209950Snwhitehorn	 */
454209950Snwhitehorn	if ((mcp->mc_srr1 & PSL_USERSTATIC) != (tf->srr1 & PSL_USERSTATIC)) {
455209950Snwhitehorn		return (EINVAL);
456209950Snwhitehorn	}
457209950Snwhitehorn
458234115Snwhitehorn	/* Copy trapframe, preserving TLS pointer across context change */
459234115Snwhitehorn	if (SV_PROC_FLAG(td->td_proc, SV_LP64))
460234115Snwhitehorn		tls = tf->fixreg[13];
461234115Snwhitehorn	else
462234115Snwhitehorn		tls = tf->fixreg[2];
463209950Snwhitehorn	memcpy(tf, mcp->mc_frame, sizeof(mcp->mc_frame));
464234115Snwhitehorn	if (SV_PROC_FLAG(td->td_proc, SV_LP64))
465234115Snwhitehorn		tf->fixreg[13] = tls;
466234115Snwhitehorn	else
467234115Snwhitehorn		tf->fixreg[2] = tls;
468209950Snwhitehorn
469209950Snwhitehorn	if (mcp->mc_flags & _MC_FP_VALID) {
470258257Snwhitehorn		/* enable_fpu() will happen lazily on a fault */
471258257Snwhitehorn		pcb->pcb_flags |= PCB_FPREGS;
472209950Snwhitehorn		memcpy(&pcb->pcb_fpu.fpscr, &mcp->mc_fpscr, sizeof(double));
473279189Snwhitehorn		bzero(pcb->pcb_fpu.fpr, sizeof(pcb->pcb_fpu.fpr));
474279937Snwhitehorn		for (i = 0; i < 32; i++) {
475279189Snwhitehorn			memcpy(&pcb->pcb_fpu.fpr[i].fpr, &mcp->mc_fpreg[i],
476279189Snwhitehorn			    sizeof(double));
477279937Snwhitehorn			memcpy(&pcb->pcb_fpu.fpr[i].vsr[2],
478279937Snwhitehorn			    &mcp->mc_vsxfpreg[i], sizeof(double));
479279937Snwhitehorn		}
480209950Snwhitehorn	}
481209950Snwhitehorn
482209950Snwhitehorn	if (mcp->mc_flags & _MC_AV_VALID) {
483209950Snwhitehorn		if ((pcb->pcb_flags & PCB_VEC) != PCB_VEC) {
484209950Snwhitehorn			critical_enter();
485209950Snwhitehorn			enable_vec(td);
486209950Snwhitehorn			critical_exit();
487209950Snwhitehorn		}
488209950Snwhitehorn		pcb->pcb_vec.vscr = mcp->mc_vscr;
489209950Snwhitehorn		pcb->pcb_vec.vrsave = mcp->mc_vrsave;
490209950Snwhitehorn		memcpy(pcb->pcb_vec.vr, mcp->mc_avec, sizeof(mcp->mc_avec));
491209950Snwhitehorn	}
492209950Snwhitehorn
493209950Snwhitehorn	return (0);
494209950Snwhitehorn}
495209950Snwhitehorn
496209950Snwhitehorn/*
497209950Snwhitehorn * Set set up registers on exec.
498209950Snwhitehorn */
499209950Snwhitehornvoid
500209950Snwhitehornexec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
501209950Snwhitehorn{
502209950Snwhitehorn	struct trapframe	*tf;
503209950Snwhitehorn	register_t		argc;
504209950Snwhitehorn
505209950Snwhitehorn	tf = trapframe(td);
506209950Snwhitehorn	bzero(tf, sizeof *tf);
507209975Snwhitehorn	#ifdef __powerpc64__
508209975Snwhitehorn	tf->fixreg[1] = -roundup(-stack + 48, 16);
509209975Snwhitehorn	#else
510209950Snwhitehorn	tf->fixreg[1] = -roundup(-stack + 8, 16);
511209975Snwhitehorn	#endif
512209950Snwhitehorn
513209950Snwhitehorn	/*
514209950Snwhitehorn	 * Set up arguments for _start():
515209950Snwhitehorn	 *	_start(argc, argv, envp, obj, cleanup, ps_strings);
516209950Snwhitehorn	 *
517209950Snwhitehorn	 * Notes:
518209950Snwhitehorn	 *	- obj and cleanup are the auxilliary and termination
519209950Snwhitehorn	 *	  vectors.  They are fixed up by ld.elf_so.
520209950Snwhitehorn	 *	- ps_strings is a NetBSD extention, and will be
521209950Snwhitehorn	 * 	  ignored by executables which are strictly
522209950Snwhitehorn	 *	  compliant with the SVR4 ABI.
523209950Snwhitehorn	 *
524209950Snwhitehorn	 * XXX We have to set both regs and retval here due to different
525209950Snwhitehorn	 * XXX calling convention in trap.c and init_main.c.
526209950Snwhitehorn	 */
527209950Snwhitehorn
528209950Snwhitehorn	/* Collect argc from the user stack */
529209950Snwhitehorn	argc = fuword((void *)stack);
530209950Snwhitehorn
531209950Snwhitehorn        /*
532209950Snwhitehorn         * XXX PG: these get overwritten in the syscall return code.
533209950Snwhitehorn         * execve() should return EJUSTRETURN, like it does on NetBSD.
534209950Snwhitehorn         * Emulate by setting the syscall return value cells. The
535209950Snwhitehorn         * registers still have to be set for init's fork trampoline.
536209950Snwhitehorn         */
537209950Snwhitehorn        td->td_retval[0] = argc;
538209950Snwhitehorn        td->td_retval[1] = stack + sizeof(register_t);
539209950Snwhitehorn	tf->fixreg[3] = argc;
540209950Snwhitehorn	tf->fixreg[4] = stack + sizeof(register_t);
541209950Snwhitehorn	tf->fixreg[5] = stack + (2 + argc)*sizeof(register_t);
542209950Snwhitehorn	tf->fixreg[6] = 0;				/* auxillary vector */
543209950Snwhitehorn	tf->fixreg[7] = 0;				/* termination vector */
544209950Snwhitehorn	tf->fixreg[8] = (register_t)imgp->ps_strings;	/* NetBSD extension */
545209950Snwhitehorn
546291211Snwhitehorn	tf->srr0 = imgp->entry_addr;
547209975Snwhitehorn	#ifdef __powerpc64__
548291211Snwhitehorn	tf->fixreg[12] = imgp->entry_addr;
549209975Snwhitehorn	tf->srr1 = PSL_SF | PSL_USERSET | PSL_FE_DFLT;
550209975Snwhitehorn	if (mfmsr() & PSL_HV)
551209975Snwhitehorn		tf->srr1 |= PSL_HV;
552209975Snwhitehorn	#else
553209950Snwhitehorn	tf->srr1 = PSL_USERSET | PSL_FE_DFLT;
554209975Snwhitehorn	#endif
555209950Snwhitehorn	td->td_pcb->pcb_flags = 0;
556209950Snwhitehorn}
557209950Snwhitehorn
558209975Snwhitehorn#ifdef COMPAT_FREEBSD32
559209975Snwhitehornvoid
560209975Snwhitehornppc32_setregs(struct thread *td, struct image_params *imgp, u_long stack)
561209975Snwhitehorn{
562209975Snwhitehorn	struct trapframe	*tf;
563209975Snwhitehorn	uint32_t		argc;
564209950Snwhitehorn
565209975Snwhitehorn	tf = trapframe(td);
566209975Snwhitehorn	bzero(tf, sizeof *tf);
567209975Snwhitehorn	tf->fixreg[1] = -roundup(-stack + 8, 16);
568209975Snwhitehorn
569209975Snwhitehorn	argc = fuword32((void *)stack);
570209975Snwhitehorn
571209975Snwhitehorn        td->td_retval[0] = argc;
572209975Snwhitehorn        td->td_retval[1] = stack + sizeof(uint32_t);
573209975Snwhitehorn	tf->fixreg[3] = argc;
574209975Snwhitehorn	tf->fixreg[4] = stack + sizeof(uint32_t);
575209975Snwhitehorn	tf->fixreg[5] = stack + (2 + argc)*sizeof(uint32_t);
576209975Snwhitehorn	tf->fixreg[6] = 0;				/* auxillary vector */
577209975Snwhitehorn	tf->fixreg[7] = 0;				/* termination vector */
578209975Snwhitehorn	tf->fixreg[8] = (register_t)imgp->ps_strings;	/* NetBSD extension */
579209975Snwhitehorn
580209975Snwhitehorn	tf->srr0 = imgp->entry_addr;
581257115Snwhitehorn	tf->srr1 = PSL_USERSET | PSL_FE_DFLT;
582209975Snwhitehorn	tf->srr1 &= ~PSL_SF;
583209975Snwhitehorn	if (mfmsr() & PSL_HV)
584209975Snwhitehorn		tf->srr1 |= PSL_HV;
585209975Snwhitehorn	td->td_pcb->pcb_flags = 0;
586209975Snwhitehorn}
587209975Snwhitehorn#endif
588209975Snwhitehorn
589209950Snwhitehornint
590209950Snwhitehornfill_regs(struct thread *td, struct reg *regs)
591209950Snwhitehorn{
592209950Snwhitehorn	struct trapframe *tf;
593209950Snwhitehorn
594209950Snwhitehorn	tf = td->td_frame;
595209950Snwhitehorn	memcpy(regs, tf, sizeof(struct reg));
596209950Snwhitehorn
597209950Snwhitehorn	return (0);
598209950Snwhitehorn}
599209950Snwhitehorn
600209950Snwhitehornint
601209950Snwhitehornfill_dbregs(struct thread *td, struct dbreg *dbregs)
602209950Snwhitehorn{
603209950Snwhitehorn	/* No debug registers on PowerPC */
604209950Snwhitehorn	return (ENOSYS);
605209950Snwhitehorn}
606209950Snwhitehorn
607209950Snwhitehornint
608209950Snwhitehornfill_fpregs(struct thread *td, struct fpreg *fpregs)
609209950Snwhitehorn{
610209950Snwhitehorn	struct pcb *pcb;
611295132Sjhb	int i;
612209950Snwhitehorn
613209950Snwhitehorn	pcb = td->td_pcb;
614209950Snwhitehorn
615258257Snwhitehorn	if ((pcb->pcb_flags & PCB_FPREGS) == 0)
616209950Snwhitehorn		memset(fpregs, 0, sizeof(struct fpreg));
617295132Sjhb	else {
618295132Sjhb		memcpy(&fpregs->fpscr, &pcb->pcb_fpu.fpscr, sizeof(double));
619295132Sjhb		for (i = 0; i < 32; i++)
620295132Sjhb			memcpy(&fpregs->fpreg[i], &pcb->pcb_fpu.fpr[i].fpr,
621295132Sjhb			    sizeof(double));
622295132Sjhb	}
623209950Snwhitehorn
624209950Snwhitehorn	return (0);
625209950Snwhitehorn}
626209950Snwhitehorn
627209950Snwhitehornint
628209950Snwhitehornset_regs(struct thread *td, struct reg *regs)
629209950Snwhitehorn{
630209950Snwhitehorn	struct trapframe *tf;
631209950Snwhitehorn
632209950Snwhitehorn	tf = td->td_frame;
633209950Snwhitehorn	memcpy(tf, regs, sizeof(struct reg));
634209950Snwhitehorn
635209950Snwhitehorn	return (0);
636209950Snwhitehorn}
637209950Snwhitehorn
638209950Snwhitehornint
639209950Snwhitehornset_dbregs(struct thread *td, struct dbreg *dbregs)
640209950Snwhitehorn{
641209950Snwhitehorn	/* No debug registers on PowerPC */
642209950Snwhitehorn	return (ENOSYS);
643209950Snwhitehorn}
644209950Snwhitehorn
645209950Snwhitehornint
646209950Snwhitehornset_fpregs(struct thread *td, struct fpreg *fpregs)
647209950Snwhitehorn{
648209950Snwhitehorn	struct pcb *pcb;
649295132Sjhb	int i;
650209950Snwhitehorn
651209950Snwhitehorn	pcb = td->td_pcb;
652258257Snwhitehorn	pcb->pcb_flags |= PCB_FPREGS;
653295132Sjhb	memcpy(&pcb->pcb_fpu.fpscr, &fpregs->fpscr, sizeof(double));
654295132Sjhb	for (i = 0; i < 32; i++) {
655295132Sjhb		memcpy(&pcb->pcb_fpu.fpr[i].fpr, &fpregs->fpreg[i],
656295132Sjhb		    sizeof(double));
657295132Sjhb	}
658209950Snwhitehorn
659209950Snwhitehorn	return (0);
660209950Snwhitehorn}
661209950Snwhitehorn
662209975Snwhitehorn#ifdef COMPAT_FREEBSD32
663209975Snwhitehornint
664209975Snwhitehornset_regs32(struct thread *td, struct reg32 *regs)
665209975Snwhitehorn{
666209975Snwhitehorn	struct trapframe *tf;
667209975Snwhitehorn	int i;
668209950Snwhitehorn
669209975Snwhitehorn	tf = td->td_frame;
670209975Snwhitehorn	for (i = 0; i < 32; i++)
671209975Snwhitehorn		tf->fixreg[i] = regs->fixreg[i];
672209975Snwhitehorn	tf->lr = regs->lr;
673209975Snwhitehorn	tf->cr = regs->cr;
674209975Snwhitehorn	tf->xer = regs->xer;
675209975Snwhitehorn	tf->ctr = regs->ctr;
676209975Snwhitehorn	tf->srr0 = regs->pc;
677209950Snwhitehorn
678209975Snwhitehorn	return (0);
679209975Snwhitehorn}
680209975Snwhitehorn
681209975Snwhitehornint
682209975Snwhitehornfill_regs32(struct thread *td, struct reg32 *regs)
683209975Snwhitehorn{
684209975Snwhitehorn	struct trapframe *tf;
685209975Snwhitehorn	int i;
686209975Snwhitehorn
687209975Snwhitehorn	tf = td->td_frame;
688209975Snwhitehorn	for (i = 0; i < 32; i++)
689209975Snwhitehorn		regs->fixreg[i] = tf->fixreg[i];
690209975Snwhitehorn	regs->lr = tf->lr;
691209975Snwhitehorn	regs->cr = tf->cr;
692209975Snwhitehorn	regs->xer = tf->xer;
693209975Snwhitehorn	regs->ctr = tf->ctr;
694209975Snwhitehorn	regs->pc = tf->srr0;
695209975Snwhitehorn
696209975Snwhitehorn	return (0);
697209975Snwhitehorn}
698209975Snwhitehorn
699209975Snwhitehornstatic int
700209975Snwhitehorngrab_mcontext32(struct thread *td, mcontext32_t *mcp, int flags)
701209975Snwhitehorn{
702209975Snwhitehorn	mcontext_t mcp64;
703209975Snwhitehorn	int i, error;
704209975Snwhitehorn
705209975Snwhitehorn	error = grab_mcontext(td, &mcp64, flags);
706209975Snwhitehorn	if (error != 0)
707209975Snwhitehorn		return (error);
708209975Snwhitehorn
709209975Snwhitehorn	mcp->mc_vers = mcp64.mc_vers;
710209975Snwhitehorn	mcp->mc_flags = mcp64.mc_flags;
711209975Snwhitehorn	mcp->mc_onstack = mcp64.mc_onstack;
712209975Snwhitehorn	mcp->mc_len = mcp64.mc_len;
713209975Snwhitehorn	memcpy(mcp->mc_avec,mcp64.mc_avec,sizeof(mcp64.mc_avec));
714209975Snwhitehorn	memcpy(mcp->mc_av,mcp64.mc_av,sizeof(mcp64.mc_av));
715209975Snwhitehorn	for (i = 0; i < 42; i++)
716209975Snwhitehorn		mcp->mc_frame[i] = mcp64.mc_frame[i];
717209975Snwhitehorn	memcpy(mcp->mc_fpreg,mcp64.mc_fpreg,sizeof(mcp64.mc_fpreg));
718279937Snwhitehorn	memcpy(mcp->mc_vsxfpreg,mcp64.mc_vsxfpreg,sizeof(mcp64.mc_vsxfpreg));
719209975Snwhitehorn
720209975Snwhitehorn	return (0);
721209975Snwhitehorn}
722209975Snwhitehorn
723209975Snwhitehornstatic int
724209975Snwhitehornget_mcontext32(struct thread *td, mcontext32_t *mcp, int flags)
725209975Snwhitehorn{
726209975Snwhitehorn	int error;
727209975Snwhitehorn
728209975Snwhitehorn	error = grab_mcontext32(td, mcp, flags);
729209975Snwhitehorn	if (error == 0) {
730209975Snwhitehorn		PROC_LOCK(curthread->td_proc);
731209975Snwhitehorn		mcp->mc_onstack = sigonstack(td->td_frame->fixreg[1]);
732209975Snwhitehorn		PROC_UNLOCK(curthread->td_proc);
733209975Snwhitehorn	}
734209975Snwhitehorn
735209975Snwhitehorn	return (error);
736209975Snwhitehorn}
737209975Snwhitehorn
738209975Snwhitehornstatic int
739278001Skibset_mcontext32(struct thread *td, mcontext32_t *mcp)
740209975Snwhitehorn{
741209975Snwhitehorn	mcontext_t mcp64;
742209975Snwhitehorn	int i, error;
743209975Snwhitehorn
744209975Snwhitehorn	mcp64.mc_vers = mcp->mc_vers;
745209975Snwhitehorn	mcp64.mc_flags = mcp->mc_flags;
746209975Snwhitehorn	mcp64.mc_onstack = mcp->mc_onstack;
747209975Snwhitehorn	mcp64.mc_len = mcp->mc_len;
748209975Snwhitehorn	memcpy(mcp64.mc_avec,mcp->mc_avec,sizeof(mcp64.mc_avec));
749209975Snwhitehorn	memcpy(mcp64.mc_av,mcp->mc_av,sizeof(mcp64.mc_av));
750209975Snwhitehorn	for (i = 0; i < 42; i++)
751209975Snwhitehorn		mcp64.mc_frame[i] = mcp->mc_frame[i];
752261095Sjhibbits	mcp64.mc_srr1 |= (td->td_frame->srr1 & 0xFFFFFFFF00000000ULL);
753209975Snwhitehorn	memcpy(mcp64.mc_fpreg,mcp->mc_fpreg,sizeof(mcp64.mc_fpreg));
754279937Snwhitehorn	memcpy(mcp64.mc_vsxfpreg,mcp->mc_vsxfpreg,sizeof(mcp64.mc_vsxfpreg));
755209975Snwhitehorn
756209975Snwhitehorn	error = set_mcontext(td, &mcp64);
757209975Snwhitehorn
758209975Snwhitehorn	return (error);
759209975Snwhitehorn}
760209975Snwhitehorn#endif
761209975Snwhitehorn
762209975Snwhitehorn#ifdef COMPAT_FREEBSD32
763209975Snwhitehornint
764209975Snwhitehornfreebsd32_sigreturn(struct thread *td, struct freebsd32_sigreturn_args *uap)
765209975Snwhitehorn{
766209975Snwhitehorn	ucontext32_t uc;
767209975Snwhitehorn	int error;
768209975Snwhitehorn
769209975Snwhitehorn	CTR2(KTR_SIG, "sigreturn: td=%p ucp=%p", td, uap->sigcntxp);
770209975Snwhitehorn
771209975Snwhitehorn	if (copyin(uap->sigcntxp, &uc, sizeof(uc)) != 0) {
772209975Snwhitehorn		CTR1(KTR_SIG, "sigreturn: efault td=%p", td);
773209975Snwhitehorn		return (EFAULT);
774209975Snwhitehorn	}
775209975Snwhitehorn
776209975Snwhitehorn	error = set_mcontext32(td, &uc.uc_mcontext);
777209975Snwhitehorn	if (error != 0)
778209975Snwhitehorn		return (error);
779209975Snwhitehorn
780209975Snwhitehorn	kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
781209975Snwhitehorn
782209975Snwhitehorn	CTR3(KTR_SIG, "sigreturn: return td=%p pc=%#x sp=%#x",
783209975Snwhitehorn	     td, uc.uc_mcontext.mc_srr0, uc.uc_mcontext.mc_gpr[1]);
784209975Snwhitehorn
785209975Snwhitehorn	return (EJUSTRETURN);
786209975Snwhitehorn}
787209975Snwhitehorn
788209975Snwhitehorn/*
789209975Snwhitehorn * The first two fields of a ucontext_t are the signal mask and the machine
790209975Snwhitehorn * context.  The next field is uc_link; we want to avoid destroying the link
791209975Snwhitehorn * when copying out contexts.
792209975Snwhitehorn */
793209975Snwhitehorn#define	UC32_COPY_SIZE	offsetof(ucontext32_t, uc_link)
794209975Snwhitehorn
795209975Snwhitehornint
796209975Snwhitehornfreebsd32_getcontext(struct thread *td, struct freebsd32_getcontext_args *uap)
797209975Snwhitehorn{
798209975Snwhitehorn	ucontext32_t uc;
799209975Snwhitehorn	int ret;
800209975Snwhitehorn
801209975Snwhitehorn	if (uap->ucp == NULL)
802209975Snwhitehorn		ret = EINVAL;
803209975Snwhitehorn	else {
804341165Svangyzen		bzero(&uc, sizeof(uc));
805209975Snwhitehorn		get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET);
806209975Snwhitehorn		PROC_LOCK(td->td_proc);
807209975Snwhitehorn		uc.uc_sigmask = td->td_sigmask;
808209975Snwhitehorn		PROC_UNLOCK(td->td_proc);
809209975Snwhitehorn		ret = copyout(&uc, uap->ucp, UC32_COPY_SIZE);
810209975Snwhitehorn	}
811209975Snwhitehorn	return (ret);
812209975Snwhitehorn}
813209975Snwhitehorn
814209975Snwhitehornint
815209975Snwhitehornfreebsd32_setcontext(struct thread *td, struct freebsd32_setcontext_args *uap)
816209975Snwhitehorn{
817209975Snwhitehorn	ucontext32_t uc;
818209975Snwhitehorn	int ret;
819209975Snwhitehorn
820209975Snwhitehorn	if (uap->ucp == NULL)
821209975Snwhitehorn		ret = EINVAL;
822209975Snwhitehorn	else {
823209975Snwhitehorn		ret = copyin(uap->ucp, &uc, UC32_COPY_SIZE);
824209975Snwhitehorn		if (ret == 0) {
825209975Snwhitehorn			ret = set_mcontext32(td, &uc.uc_mcontext);
826209975Snwhitehorn			if (ret == 0) {
827209975Snwhitehorn				kern_sigprocmask(td, SIG_SETMASK,
828209975Snwhitehorn				    &uc.uc_sigmask, NULL, 0);
829209975Snwhitehorn			}
830209975Snwhitehorn		}
831209975Snwhitehorn	}
832209975Snwhitehorn	return (ret == 0 ? EJUSTRETURN : ret);
833209975Snwhitehorn}
834209975Snwhitehorn
835209975Snwhitehornint
836209975Snwhitehornfreebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap)
837209975Snwhitehorn{
838209975Snwhitehorn	ucontext32_t uc;
839209975Snwhitehorn	int ret;
840209975Snwhitehorn
841209975Snwhitehorn	if (uap->oucp == NULL || uap->ucp == NULL)
842209975Snwhitehorn		ret = EINVAL;
843209975Snwhitehorn	else {
844341165Svangyzen		bzero(&uc, sizeof(uc));
845209975Snwhitehorn		get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET);
846209975Snwhitehorn		PROC_LOCK(td->td_proc);
847209975Snwhitehorn		uc.uc_sigmask = td->td_sigmask;
848209975Snwhitehorn		PROC_UNLOCK(td->td_proc);
849209975Snwhitehorn		ret = copyout(&uc, uap->oucp, UC32_COPY_SIZE);
850209975Snwhitehorn		if (ret == 0) {
851209975Snwhitehorn			ret = copyin(uap->ucp, &uc, UC32_COPY_SIZE);
852209975Snwhitehorn			if (ret == 0) {
853209975Snwhitehorn				ret = set_mcontext32(td, &uc.uc_mcontext);
854209975Snwhitehorn				if (ret == 0) {
855209975Snwhitehorn					kern_sigprocmask(td, SIG_SETMASK,
856209975Snwhitehorn					    &uc.uc_sigmask, NULL, 0);
857209975Snwhitehorn				}
858209975Snwhitehorn			}
859209975Snwhitehorn		}
860209975Snwhitehorn	}
861209975Snwhitehorn	return (ret == 0 ? EJUSTRETURN : ret);
862209975Snwhitehorn}
863209975Snwhitehorn
864209975Snwhitehorn#endif
865209975Snwhitehorn
866209950Snwhitehornvoid
867209950Snwhitehorncpu_set_syscall_retval(struct thread *td, int error)
868209950Snwhitehorn{
869209950Snwhitehorn	struct proc *p;
870209950Snwhitehorn	struct trapframe *tf;
871209950Snwhitehorn	int fixup;
872209950Snwhitehorn
873209950Snwhitehorn	if (error == EJUSTRETURN)
874209950Snwhitehorn		return;
875209950Snwhitehorn
876209950Snwhitehorn	p = td->td_proc;
877209950Snwhitehorn	tf = td->td_frame;
878209950Snwhitehorn
879209975Snwhitehorn	if (tf->fixreg[0] == SYS___syscall &&
880217896Sdchagin	    (SV_PROC_FLAG(p, SV_ILP32))) {
881209950Snwhitehorn		int code = tf->fixreg[FIRSTARG + 1];
882209950Snwhitehorn		if (p->p_sysent->sv_mask)
883209950Snwhitehorn			code &= p->p_sysent->sv_mask;
884296861Sbz		fixup = (
885296861Sbz#if defined(COMPAT_FREEBSD6) && defined(SYS_freebsd6_lseek)
886296861Sbz		    code != SYS_freebsd6_lseek &&
887296861Sbz#endif
888296861Sbz		    code != SYS_lseek) ?  1 : 0;
889209950Snwhitehorn	} else
890209950Snwhitehorn		fixup = 0;
891209950Snwhitehorn
892209950Snwhitehorn	switch (error) {
893209950Snwhitehorn	case 0:
894209950Snwhitehorn		if (fixup) {
895209950Snwhitehorn			/*
896209950Snwhitehorn			 * 64-bit return, 32-bit syscall. Fixup byte order
897209950Snwhitehorn			 */
898209950Snwhitehorn			tf->fixreg[FIRSTARG] = 0;
899209950Snwhitehorn			tf->fixreg[FIRSTARG + 1] = td->td_retval[0];
900209950Snwhitehorn		} else {
901209950Snwhitehorn			tf->fixreg[FIRSTARG] = td->td_retval[0];
902209950Snwhitehorn			tf->fixreg[FIRSTARG + 1] = td->td_retval[1];
903209950Snwhitehorn		}
904209950Snwhitehorn		tf->cr &= ~0x10000000;		/* Unset summary overflow */
905209950Snwhitehorn		break;
906209950Snwhitehorn	case ERESTART:
907209950Snwhitehorn		/*
908209950Snwhitehorn		 * Set user's pc back to redo the system call.
909209950Snwhitehorn		 */
910209950Snwhitehorn		tf->srr0 -= 4;
911209950Snwhitehorn		break;
912209950Snwhitehorn	default:
913300415Sdchagin		tf->fixreg[FIRSTARG] = SV_ABI_ERRNO(p, error);
914209950Snwhitehorn		tf->cr |= 0x10000000;		/* Set summary overflow */
915209950Snwhitehorn		break;
916209950Snwhitehorn	}
917209950Snwhitehorn}
918209950Snwhitehorn
919209950Snwhitehorn/*
920209950Snwhitehorn * Threading functions
921209950Snwhitehorn */
922209950Snwhitehornvoid
923209950Snwhitehorncpu_thread_exit(struct thread *td)
924209950Snwhitehorn{
925209950Snwhitehorn}
926209950Snwhitehorn
927209950Snwhitehornvoid
928209950Snwhitehorncpu_thread_clean(struct thread *td)
929209950Snwhitehorn{
930209950Snwhitehorn}
931209950Snwhitehorn
932209950Snwhitehornvoid
933209950Snwhitehorncpu_thread_alloc(struct thread *td)
934209950Snwhitehorn{
935209950Snwhitehorn	struct pcb *pcb;
936209950Snwhitehorn
937209950Snwhitehorn	pcb = (struct pcb *)((td->td_kstack + td->td_kstack_pages * PAGE_SIZE -
938209950Snwhitehorn	    sizeof(struct pcb)) & ~0x2fUL);
939209950Snwhitehorn	td->td_pcb = pcb;
940209950Snwhitehorn	td->td_frame = (struct trapframe *)pcb - 1;
941209950Snwhitehorn}
942209950Snwhitehorn
943209950Snwhitehornvoid
944209950Snwhitehorncpu_thread_free(struct thread *td)
945209950Snwhitehorn{
946209950Snwhitehorn}
947209950Snwhitehorn
948209950Snwhitehornint
949209950Snwhitehorncpu_set_user_tls(struct thread *td, void *tls_base)
950209950Snwhitehorn{
951209950Snwhitehorn
952217896Sdchagin	if (SV_PROC_FLAG(td->td_proc, SV_LP64))
953209975Snwhitehorn		td->td_frame->fixreg[13] = (register_t)tls_base + 0x7010;
954209975Snwhitehorn	else
955209975Snwhitehorn		td->td_frame->fixreg[2] = (register_t)tls_base + 0x7008;
956209950Snwhitehorn	return (0);
957209950Snwhitehorn}
958209950Snwhitehorn
959209950Snwhitehornvoid
960301961Skibcpu_copy_thread(struct thread *td, struct thread *td0)
961209950Snwhitehorn{
962209950Snwhitehorn	struct pcb *pcb2;
963209950Snwhitehorn	struct trapframe *tf;
964209950Snwhitehorn	struct callframe *cf;
965209950Snwhitehorn
966209950Snwhitehorn	pcb2 = td->td_pcb;
967209950Snwhitehorn
968209950Snwhitehorn	/* Copy the upcall pcb */
969209950Snwhitehorn	bcopy(td0->td_pcb, pcb2, sizeof(*pcb2));
970209950Snwhitehorn
971209950Snwhitehorn	/* Create a stack for the new thread */
972209950Snwhitehorn	tf = td->td_frame;
973209950Snwhitehorn	bcopy(td0->td_frame, tf, sizeof(struct trapframe));
974209950Snwhitehorn	tf->fixreg[FIRSTARG] = 0;
975209950Snwhitehorn	tf->fixreg[FIRSTARG + 1] = 0;
976209950Snwhitehorn	tf->cr &= ~0x10000000;
977209950Snwhitehorn
978209950Snwhitehorn	/* Set registers for trampoline to user mode. */
979209950Snwhitehorn	cf = (struct callframe *)tf - 1;
980209950Snwhitehorn	memset(cf, 0, sizeof(struct callframe));
981209950Snwhitehorn	cf->cf_func = (register_t)fork_return;
982209950Snwhitehorn	cf->cf_arg0 = (register_t)td;
983209950Snwhitehorn	cf->cf_arg1 = (register_t)tf;
984209950Snwhitehorn
985209950Snwhitehorn	pcb2->pcb_sp = (register_t)cf;
986291442Snwhitehorn	#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1)
987209975Snwhitehorn	pcb2->pcb_lr = ((register_t *)fork_trampoline)[0];
988209975Snwhitehorn	pcb2->pcb_toc = ((register_t *)fork_trampoline)[1];
989209975Snwhitehorn	#else
990209950Snwhitehorn	pcb2->pcb_lr = (register_t)fork_trampoline;
991291442Snwhitehorn	pcb2->pcb_context[0] = pcb2->pcb_lr;
992209975Snwhitehorn	#endif
993209975Snwhitehorn	pcb2->pcb_cpu.aim.usr_vsid = 0;
994209950Snwhitehorn
995209950Snwhitehorn	/* Setup to release spin count in fork_exit(). */
996209950Snwhitehorn	td->td_md.md_spinlock_count = 1;
997209950Snwhitehorn	td->td_md.md_saved_msr = PSL_KERNSET;
998209950Snwhitehorn}
999209950Snwhitehorn
1000209950Snwhitehornvoid
1001301961Skibcpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
1002301961Skib    stack_t *stack)
1003209950Snwhitehorn{
1004209950Snwhitehorn	struct trapframe *tf;
1005209950Snwhitehorn	uintptr_t sp;
1006209950Snwhitehorn
1007209950Snwhitehorn	tf = td->td_frame;
1008209950Snwhitehorn	/* align stack and alloc space for frame ptr and saved LR */
1009209975Snwhitehorn	#ifdef __powerpc64__
1010209975Snwhitehorn	sp = ((uintptr_t)stack->ss_sp + stack->ss_size - 48) &
1011209975Snwhitehorn	    ~0x1f;
1012209975Snwhitehorn	#else
1013209950Snwhitehorn	sp = ((uintptr_t)stack->ss_sp + stack->ss_size - 8) &
1014209950Snwhitehorn	    ~0x1f;
1015209975Snwhitehorn	#endif
1016209950Snwhitehorn	bzero(tf, sizeof(struct trapframe));
1017209950Snwhitehorn
1018209950Snwhitehorn	tf->fixreg[1] = (register_t)sp;
1019209950Snwhitehorn	tf->fixreg[3] = (register_t)arg;
1020217896Sdchagin	if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
1021209975Snwhitehorn		tf->srr0 = (register_t)entry;
1022257115Snwhitehorn		tf->srr1 = PSL_USERSET | PSL_FE_DFLT;
1023220597Snwhitehorn		#ifdef __powerpc64__
1024220597Snwhitehorn		tf->srr1 &= ~PSL_SF;
1025220597Snwhitehorn		#endif
1026209975Snwhitehorn	} else {
1027209975Snwhitehorn	    #ifdef __powerpc64__
1028209975Snwhitehorn		register_t entry_desc[3];
1029209975Snwhitehorn		(void)copyin((void *)entry, entry_desc, sizeof(entry_desc));
1030209975Snwhitehorn		tf->srr0 = entry_desc[0];
1031209975Snwhitehorn		tf->fixreg[2] = entry_desc[1];
1032209975Snwhitehorn		tf->fixreg[11] = entry_desc[2];
1033257116Snwhitehorn		tf->srr1 = PSL_SF | PSL_USERSET | PSL_FE_DFLT;
1034209975Snwhitehorn	    #endif
1035209975Snwhitehorn	}
1036209950Snwhitehorn
1037209975Snwhitehorn	#ifdef __powerpc64__
1038209975Snwhitehorn	if (mfmsr() & PSL_HV)
1039209975Snwhitehorn		tf->srr1 |= PSL_HV;
1040209975Snwhitehorn	#endif
1041209950Snwhitehorn	td->td_pcb->pcb_flags = 0;
1042209950Snwhitehorn
1043209950Snwhitehorn	td->td_retval[0] = (register_t)entry;
1044209950Snwhitehorn	td->td_retval[1] = 0;
1045209950Snwhitehorn}
1046209950Snwhitehorn
1047258259Snwhitehornint
1048258259Snwhitehornppc_instr_emulate(struct trapframe *frame, struct pcb *pcb)
1049258259Snwhitehorn{
1050258259Snwhitehorn	uint32_t instr;
1051258259Snwhitehorn	int reg, sig;
1052258259Snwhitehorn
1053258259Snwhitehorn	instr = fuword32((void *)frame->srr0);
1054258259Snwhitehorn	sig = SIGILL;
1055258259Snwhitehorn
1056258259Snwhitehorn	if ((instr & 0xfc1fffff) == 0x7c1f42a6) {	/* mfpvr */
1057258259Snwhitehorn		reg = (instr & ~0xfc1fffff) >> 21;
1058258259Snwhitehorn		frame->fixreg[reg] = mfpvr();
1059258259Snwhitehorn		frame->srr0 += 4;
1060258259Snwhitehorn		return (0);
1061258259Snwhitehorn	}
1062258259Snwhitehorn
1063258259Snwhitehorn	if ((instr & 0xfc000ffe) == 0x7c0004ac) {	/* various sync */
1064258259Snwhitehorn		powerpc_sync(); /* Do a heavy-weight sync */
1065258259Snwhitehorn		frame->srr0 += 4;
1066258259Snwhitehorn		return (0);
1067258259Snwhitehorn	}
1068258259Snwhitehorn
1069258259Snwhitehorn#ifdef FPU_EMU
1070258259Snwhitehorn	if (!(pcb->pcb_flags & PCB_FPREGS)) {
1071258259Snwhitehorn		bzero(&pcb->pcb_fpu, sizeof(pcb->pcb_fpu));
1072258259Snwhitehorn		pcb->pcb_flags |= PCB_FPREGS;
1073258259Snwhitehorn	}
1074295132Sjhb	sig = fpu_emulate(frame, &pcb->pcb_fpu);
1075258259Snwhitehorn#endif
1076258259Snwhitehorn
1077258259Snwhitehorn	return (sig);
1078258259Snwhitehorn}
1079258259Snwhitehorn
1080