xref: /freebsd/sys/riscv/riscv/exec_machdep.c (revision fdafd315)
1aba66031SKonstantin Belousov /*-
2aba66031SKonstantin Belousov  * Copyright (c) 2014 Andrew Turner
3aba66031SKonstantin Belousov  * Copyright (c) 2015-2017 Ruslan Bukin <br@bsdpad.com>
4aba66031SKonstantin Belousov  * All rights reserved.
5aba66031SKonstantin Belousov  *
6aba66031SKonstantin Belousov  * Portions of this software were developed by SRI International and the
7aba66031SKonstantin Belousov  * University of Cambridge Computer Laboratory under DARPA/AFRL contract
8aba66031SKonstantin Belousov  * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
9aba66031SKonstantin Belousov  *
10aba66031SKonstantin Belousov  * Portions of this software were developed by the University of Cambridge
11aba66031SKonstantin Belousov  * Computer Laboratory as part of the CTSRD Project, with support from the
12aba66031SKonstantin Belousov  * UK Higher Education Innovation Fund (HEIF).
13aba66031SKonstantin Belousov  *
14aba66031SKonstantin Belousov  * Redistribution and use in source and binary forms, with or without
15aba66031SKonstantin Belousov  * modification, are permitted provided that the following conditions
16aba66031SKonstantin Belousov  * are met:
17aba66031SKonstantin Belousov  * 1. Redistributions of source code must retain the above copyright
18aba66031SKonstantin Belousov  *    notice, this list of conditions and the following disclaimer.
19aba66031SKonstantin Belousov  * 2. Redistributions in binary form must reproduce the above copyright
20aba66031SKonstantin Belousov  *    notice, this list of conditions and the following disclaimer in the
21aba66031SKonstantin Belousov  *    documentation and/or other materials provided with the distribution.
22aba66031SKonstantin Belousov  *
23aba66031SKonstantin Belousov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24aba66031SKonstantin Belousov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25aba66031SKonstantin Belousov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26aba66031SKonstantin Belousov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27aba66031SKonstantin Belousov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28aba66031SKonstantin Belousov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29aba66031SKonstantin Belousov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30aba66031SKonstantin Belousov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31aba66031SKonstantin Belousov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32aba66031SKonstantin Belousov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33aba66031SKonstantin Belousov  * SUCH DAMAGE.
34aba66031SKonstantin Belousov  */
35aba66031SKonstantin Belousov 
36aba66031SKonstantin Belousov #include <sys/param.h>
37aba66031SKonstantin Belousov #include <sys/systm.h>
38aba66031SKonstantin Belousov #include <sys/exec.h>
39aba66031SKonstantin Belousov #include <sys/imgact.h>
40aba66031SKonstantin Belousov #include <sys/kdb.h>
41aba66031SKonstantin Belousov #include <sys/kernel.h>
42aba66031SKonstantin Belousov #include <sys/ktr.h>
43aba66031SKonstantin Belousov #include <sys/limits.h>
44aba66031SKonstantin Belousov #include <sys/lock.h>
45aba66031SKonstantin Belousov #include <sys/mutex.h>
46aba66031SKonstantin Belousov #include <sys/proc.h>
47aba66031SKonstantin Belousov #include <sys/ptrace.h>
48aba66031SKonstantin Belousov #include <sys/reg.h>
49aba66031SKonstantin Belousov #include <sys/rwlock.h>
50aba66031SKonstantin Belousov #include <sys/sched.h>
51aba66031SKonstantin Belousov #include <sys/signalvar.h>
52aba66031SKonstantin Belousov #include <sys/syscallsubr.h>
53aba66031SKonstantin Belousov #include <sys/sysent.h>
54aba66031SKonstantin Belousov #include <sys/sysproto.h>
55aba66031SKonstantin Belousov #include <sys/ucontext.h>
56aba66031SKonstantin Belousov 
57aba66031SKonstantin Belousov #include <machine/cpu.h>
58c32b6c74SMitchell Horne #include <machine/fpe.h>
59aba66031SKonstantin Belousov #include <machine/kdb.h>
60aba66031SKonstantin Belousov #include <machine/pcb.h>
61aba66031SKonstantin Belousov #include <machine/pte.h>
62aba66031SKonstantin Belousov #include <machine/riscvreg.h>
63aba66031SKonstantin Belousov #include <machine/sbi.h>
64aba66031SKonstantin Belousov #include <machine/trap.h>
65aba66031SKonstantin Belousov 
66706f4a81SMark Johnston #include <vm/vm.h>
67706f4a81SMark Johnston #include <vm/vm_param.h>
68706f4a81SMark Johnston #include <vm/pmap.h>
69706f4a81SMark Johnston #include <vm/vm_map.h>
70706f4a81SMark Johnston 
71aba66031SKonstantin Belousov static void get_fpcontext(struct thread *td, mcontext_t *mcp);
72aba66031SKonstantin Belousov static void set_fpcontext(struct thread *td, mcontext_t *mcp);
73aba66031SKonstantin Belousov 
740987dc5bSWarner Losh _Static_assert(sizeof(mcontext_t) == 864, "mcontext_t size incorrect");
750987dc5bSWarner Losh _Static_assert(sizeof(ucontext_t) == 936, "ucontext_t size incorrect");
760987dc5bSWarner Losh _Static_assert(sizeof(siginfo_t) == 80, "siginfo_t size incorrect");
770987dc5bSWarner Losh 
78aba66031SKonstantin Belousov int
fill_regs(struct thread * td,struct reg * regs)79aba66031SKonstantin Belousov fill_regs(struct thread *td, struct reg *regs)
80aba66031SKonstantin Belousov {
81aba66031SKonstantin Belousov 	struct trapframe *frame;
82aba66031SKonstantin Belousov 
83aba66031SKonstantin Belousov 	frame = td->td_frame;
84aba66031SKonstantin Belousov 	regs->sepc = frame->tf_sepc;
85aba66031SKonstantin Belousov 	regs->sstatus = frame->tf_sstatus;
86aba66031SKonstantin Belousov 	regs->ra = frame->tf_ra;
87aba66031SKonstantin Belousov 	regs->sp = frame->tf_sp;
88aba66031SKonstantin Belousov 	regs->gp = frame->tf_gp;
89aba66031SKonstantin Belousov 	regs->tp = frame->tf_tp;
90aba66031SKonstantin Belousov 
91aba66031SKonstantin Belousov 	memcpy(regs->t, frame->tf_t, sizeof(regs->t));
92aba66031SKonstantin Belousov 	memcpy(regs->s, frame->tf_s, sizeof(regs->s));
93aba66031SKonstantin Belousov 	memcpy(regs->a, frame->tf_a, sizeof(regs->a));
94aba66031SKonstantin Belousov 
95aba66031SKonstantin Belousov 	return (0);
96aba66031SKonstantin Belousov }
97aba66031SKonstantin Belousov 
98aba66031SKonstantin Belousov int
set_regs(struct thread * td,struct reg * regs)99aba66031SKonstantin Belousov set_regs(struct thread *td, struct reg *regs)
100aba66031SKonstantin Belousov {
101aba66031SKonstantin Belousov 	struct trapframe *frame;
102aba66031SKonstantin Belousov 
103aba66031SKonstantin Belousov 	frame = td->td_frame;
104aba66031SKonstantin Belousov 	frame->tf_sepc = regs->sepc;
105aba66031SKonstantin Belousov 	frame->tf_ra = regs->ra;
106aba66031SKonstantin Belousov 	frame->tf_sp = regs->sp;
107aba66031SKonstantin Belousov 	frame->tf_gp = regs->gp;
108aba66031SKonstantin Belousov 	frame->tf_tp = regs->tp;
109aba66031SKonstantin Belousov 
110aba66031SKonstantin Belousov 	memcpy(frame->tf_t, regs->t, sizeof(frame->tf_t));
111aba66031SKonstantin Belousov 	memcpy(frame->tf_s, regs->s, sizeof(frame->tf_s));
112aba66031SKonstantin Belousov 	memcpy(frame->tf_a, regs->a, sizeof(frame->tf_a));
113aba66031SKonstantin Belousov 
114aba66031SKonstantin Belousov 	return (0);
115aba66031SKonstantin Belousov }
116aba66031SKonstantin Belousov 
117aba66031SKonstantin Belousov int
fill_fpregs(struct thread * td,struct fpreg * regs)118aba66031SKonstantin Belousov fill_fpregs(struct thread *td, struct fpreg *regs)
119aba66031SKonstantin Belousov {
120aba66031SKonstantin Belousov 	struct pcb *pcb;
121aba66031SKonstantin Belousov 
122aba66031SKonstantin Belousov 	pcb = td->td_pcb;
123aba66031SKonstantin Belousov 
124aba66031SKonstantin Belousov 	if ((pcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
125aba66031SKonstantin Belousov 		/*
126aba66031SKonstantin Belousov 		 * If we have just been running FPE instructions we will
127aba66031SKonstantin Belousov 		 * need to save the state to memcpy it below.
128aba66031SKonstantin Belousov 		 */
129aba66031SKonstantin Belousov 		if (td == curthread)
130aba66031SKonstantin Belousov 			fpe_state_save(td);
131aba66031SKonstantin Belousov 
132aba66031SKonstantin Belousov 		memcpy(regs->fp_x, pcb->pcb_x, sizeof(regs->fp_x));
133aba66031SKonstantin Belousov 		regs->fp_fcsr = pcb->pcb_fcsr;
134aba66031SKonstantin Belousov 	} else
135aba66031SKonstantin Belousov 		memset(regs, 0, sizeof(*regs));
136aba66031SKonstantin Belousov 
137aba66031SKonstantin Belousov 	return (0);
138aba66031SKonstantin Belousov }
139aba66031SKonstantin Belousov 
140aba66031SKonstantin Belousov int
set_fpregs(struct thread * td,struct fpreg * regs)141aba66031SKonstantin Belousov set_fpregs(struct thread *td, struct fpreg *regs)
142aba66031SKonstantin Belousov {
143aba66031SKonstantin Belousov 	struct trapframe *frame;
144aba66031SKonstantin Belousov 	struct pcb *pcb;
145aba66031SKonstantin Belousov 
146aba66031SKonstantin Belousov 	frame = td->td_frame;
147aba66031SKonstantin Belousov 	pcb = td->td_pcb;
148aba66031SKonstantin Belousov 
149aba66031SKonstantin Belousov 	memcpy(pcb->pcb_x, regs->fp_x, sizeof(regs->fp_x));
150aba66031SKonstantin Belousov 	pcb->pcb_fcsr = regs->fp_fcsr;
151aba66031SKonstantin Belousov 	pcb->pcb_fpflags |= PCB_FP_STARTED;
152aba66031SKonstantin Belousov 	frame->tf_sstatus &= ~SSTATUS_FS_MASK;
153aba66031SKonstantin Belousov 	frame->tf_sstatus |= SSTATUS_FS_CLEAN;
154aba66031SKonstantin Belousov 
155aba66031SKonstantin Belousov 	return (0);
156aba66031SKonstantin Belousov }
157aba66031SKonstantin Belousov 
158aba66031SKonstantin Belousov int
fill_dbregs(struct thread * td,struct dbreg * regs)159aba66031SKonstantin Belousov fill_dbregs(struct thread *td, struct dbreg *regs)
160aba66031SKonstantin Belousov {
161aba66031SKonstantin Belousov 
162aba66031SKonstantin Belousov 	panic("fill_dbregs");
163aba66031SKonstantin Belousov }
164aba66031SKonstantin Belousov 
165aba66031SKonstantin Belousov int
set_dbregs(struct thread * td,struct dbreg * regs)166aba66031SKonstantin Belousov set_dbregs(struct thread *td, struct dbreg *regs)
167aba66031SKonstantin Belousov {
168aba66031SKonstantin Belousov 
169aba66031SKonstantin Belousov 	panic("set_dbregs");
170aba66031SKonstantin Belousov }
171aba66031SKonstantin Belousov 
172aba66031SKonstantin Belousov void
exec_setregs(struct thread * td,struct image_params * imgp,uintptr_t stack)173aba66031SKonstantin Belousov exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
174aba66031SKonstantin Belousov {
175aba66031SKonstantin Belousov 	struct trapframe *tf;
176aba66031SKonstantin Belousov 	struct pcb *pcb;
177aba66031SKonstantin Belousov 
178aba66031SKonstantin Belousov 	tf = td->td_frame;
179aba66031SKonstantin Belousov 	pcb = td->td_pcb;
180aba66031SKonstantin Belousov 
181aba66031SKonstantin Belousov 	memset(tf, 0, sizeof(struct trapframe));
182aba66031SKonstantin Belousov 
183aba66031SKonstantin Belousov 	tf->tf_a[0] = stack;
184aba66031SKonstantin Belousov 	tf->tf_sp = STACKALIGN(stack);
185aba66031SKonstantin Belousov 	tf->tf_ra = imgp->entry_addr;
186aba66031SKonstantin Belousov 	tf->tf_sepc = imgp->entry_addr;
187aba66031SKonstantin Belousov 
188aba66031SKonstantin Belousov 	pcb->pcb_fpflags &= ~PCB_FP_STARTED;
189aba66031SKonstantin Belousov }
190aba66031SKonstantin Belousov 
191aba66031SKonstantin Belousov /* Sanity check these are the same size, they will be memcpy'd to and from */
192aba66031SKonstantin Belousov CTASSERT(sizeof(((struct trapframe *)0)->tf_a) ==
193aba66031SKonstantin Belousov     sizeof((struct gpregs *)0)->gp_a);
194aba66031SKonstantin Belousov CTASSERT(sizeof(((struct trapframe *)0)->tf_s) ==
195aba66031SKonstantin Belousov     sizeof((struct gpregs *)0)->gp_s);
196aba66031SKonstantin Belousov CTASSERT(sizeof(((struct trapframe *)0)->tf_t) ==
197aba66031SKonstantin Belousov     sizeof((struct gpregs *)0)->gp_t);
198aba66031SKonstantin Belousov CTASSERT(sizeof(((struct trapframe *)0)->tf_a) ==
199aba66031SKonstantin Belousov     sizeof((struct reg *)0)->a);
200aba66031SKonstantin Belousov CTASSERT(sizeof(((struct trapframe *)0)->tf_s) ==
201aba66031SKonstantin Belousov     sizeof((struct reg *)0)->s);
202aba66031SKonstantin Belousov CTASSERT(sizeof(((struct trapframe *)0)->tf_t) ==
203aba66031SKonstantin Belousov     sizeof((struct reg *)0)->t);
204aba66031SKonstantin Belousov 
205aba66031SKonstantin Belousov int
get_mcontext(struct thread * td,mcontext_t * mcp,int clear_ret)206aba66031SKonstantin Belousov get_mcontext(struct thread *td, mcontext_t *mcp, int clear_ret)
207aba66031SKonstantin Belousov {
208aba66031SKonstantin Belousov 	struct trapframe *tf = td->td_frame;
209aba66031SKonstantin Belousov 
210aba66031SKonstantin Belousov 	memcpy(mcp->mc_gpregs.gp_t, tf->tf_t, sizeof(mcp->mc_gpregs.gp_t));
211aba66031SKonstantin Belousov 	memcpy(mcp->mc_gpregs.gp_s, tf->tf_s, sizeof(mcp->mc_gpregs.gp_s));
212aba66031SKonstantin Belousov 	memcpy(mcp->mc_gpregs.gp_a, tf->tf_a, sizeof(mcp->mc_gpregs.gp_a));
213aba66031SKonstantin Belousov 
214aba66031SKonstantin Belousov 	if (clear_ret & GET_MC_CLEAR_RET) {
215aba66031SKonstantin Belousov 		mcp->mc_gpregs.gp_a[0] = 0;
216aba66031SKonstantin Belousov 		mcp->mc_gpregs.gp_t[0] = 0; /* clear syscall error */
217aba66031SKonstantin Belousov 	}
218aba66031SKonstantin Belousov 
219aba66031SKonstantin Belousov 	mcp->mc_gpregs.gp_ra = tf->tf_ra;
220aba66031SKonstantin Belousov 	mcp->mc_gpregs.gp_sp = tf->tf_sp;
221aba66031SKonstantin Belousov 	mcp->mc_gpregs.gp_gp = tf->tf_gp;
222aba66031SKonstantin Belousov 	mcp->mc_gpregs.gp_tp = tf->tf_tp;
223aba66031SKonstantin Belousov 	mcp->mc_gpregs.gp_sepc = tf->tf_sepc;
224aba66031SKonstantin Belousov 	mcp->mc_gpregs.gp_sstatus = tf->tf_sstatus;
225aba66031SKonstantin Belousov 	get_fpcontext(td, mcp);
226aba66031SKonstantin Belousov 
227aba66031SKonstantin Belousov 	return (0);
228aba66031SKonstantin Belousov }
229aba66031SKonstantin Belousov 
230aba66031SKonstantin Belousov int
set_mcontext(struct thread * td,mcontext_t * mcp)231aba66031SKonstantin Belousov set_mcontext(struct thread *td, mcontext_t *mcp)
232aba66031SKonstantin Belousov {
233aba66031SKonstantin Belousov 	struct trapframe *tf;
234aba66031SKonstantin Belousov 
235aba66031SKonstantin Belousov 	tf = td->td_frame;
236aba66031SKonstantin Belousov 
237aba66031SKonstantin Belousov 	/*
238aba66031SKonstantin Belousov 	 * Permit changes to the USTATUS bits of SSTATUS.
239aba66031SKonstantin Belousov 	 *
240aba66031SKonstantin Belousov 	 * Ignore writes to read-only bits (SD, XS).
241aba66031SKonstantin Belousov 	 *
242aba66031SKonstantin Belousov 	 * Ignore writes to the FS field as set_fpcontext() will set
243aba66031SKonstantin Belousov 	 * it explicitly.
244aba66031SKonstantin Belousov 	 */
245aba66031SKonstantin Belousov 	if (((mcp->mc_gpregs.gp_sstatus ^ tf->tf_sstatus) &
246aba66031SKonstantin Belousov 	    ~(SSTATUS_SD | SSTATUS_XS_MASK | SSTATUS_FS_MASK | SSTATUS_UPIE |
247aba66031SKonstantin Belousov 	    SSTATUS_UIE)) != 0)
248aba66031SKonstantin Belousov 		return (EINVAL);
249aba66031SKonstantin Belousov 
250aba66031SKonstantin Belousov 	memcpy(tf->tf_t, mcp->mc_gpregs.gp_t, sizeof(tf->tf_t));
251aba66031SKonstantin Belousov 	memcpy(tf->tf_s, mcp->mc_gpregs.gp_s, sizeof(tf->tf_s));
252aba66031SKonstantin Belousov 	memcpy(tf->tf_a, mcp->mc_gpregs.gp_a, sizeof(tf->tf_a));
253aba66031SKonstantin Belousov 
254aba66031SKonstantin Belousov 	tf->tf_ra = mcp->mc_gpregs.gp_ra;
255aba66031SKonstantin Belousov 	tf->tf_sp = mcp->mc_gpregs.gp_sp;
256aba66031SKonstantin Belousov 	tf->tf_gp = mcp->mc_gpregs.gp_gp;
257aba66031SKonstantin Belousov 	tf->tf_sepc = mcp->mc_gpregs.gp_sepc;
258aba66031SKonstantin Belousov 	tf->tf_sstatus = mcp->mc_gpregs.gp_sstatus;
259aba66031SKonstantin Belousov 	set_fpcontext(td, mcp);
260aba66031SKonstantin Belousov 
261aba66031SKonstantin Belousov 	return (0);
262aba66031SKonstantin Belousov }
263aba66031SKonstantin Belousov 
264aba66031SKonstantin Belousov static void
get_fpcontext(struct thread * td,mcontext_t * mcp)265aba66031SKonstantin Belousov get_fpcontext(struct thread *td, mcontext_t *mcp)
266aba66031SKonstantin Belousov {
267aba66031SKonstantin Belousov 	struct pcb *curpcb;
268aba66031SKonstantin Belousov 
269aba66031SKonstantin Belousov 	critical_enter();
270aba66031SKonstantin Belousov 
271aba66031SKonstantin Belousov 	curpcb = curthread->td_pcb;
272aba66031SKonstantin Belousov 
273aba66031SKonstantin Belousov 	KASSERT(td->td_pcb == curpcb, ("Invalid fpe pcb"));
274aba66031SKonstantin Belousov 
275aba66031SKonstantin Belousov 	if ((curpcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
276aba66031SKonstantin Belousov 		/*
277aba66031SKonstantin Belousov 		 * If we have just been running FPE instructions we will
278aba66031SKonstantin Belousov 		 * need to save the state to memcpy it below.
279aba66031SKonstantin Belousov 		 */
280aba66031SKonstantin Belousov 		fpe_state_save(td);
281aba66031SKonstantin Belousov 
282aba66031SKonstantin Belousov 		KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
283aba66031SKonstantin Belousov 		    ("Non-userspace FPE flags set in get_fpcontext"));
284aba66031SKonstantin Belousov 		memcpy(mcp->mc_fpregs.fp_x, curpcb->pcb_x,
285aba66031SKonstantin Belousov 		    sizeof(mcp->mc_fpregs.fp_x));
286aba66031SKonstantin Belousov 		mcp->mc_fpregs.fp_fcsr = curpcb->pcb_fcsr;
287aba66031SKonstantin Belousov 		mcp->mc_fpregs.fp_flags = curpcb->pcb_fpflags;
288aba66031SKonstantin Belousov 		mcp->mc_flags |= _MC_FP_VALID;
289aba66031SKonstantin Belousov 	}
290aba66031SKonstantin Belousov 
291aba66031SKonstantin Belousov 	critical_exit();
292aba66031SKonstantin Belousov }
293aba66031SKonstantin Belousov 
294aba66031SKonstantin Belousov static void
set_fpcontext(struct thread * td,mcontext_t * mcp)295aba66031SKonstantin Belousov set_fpcontext(struct thread *td, mcontext_t *mcp)
296aba66031SKonstantin Belousov {
297aba66031SKonstantin Belousov 	struct pcb *curpcb;
298aba66031SKonstantin Belousov 
299aba66031SKonstantin Belousov 	td->td_frame->tf_sstatus &= ~SSTATUS_FS_MASK;
300aba66031SKonstantin Belousov 	td->td_frame->tf_sstatus |= SSTATUS_FS_OFF;
301aba66031SKonstantin Belousov 
302aba66031SKonstantin Belousov 	critical_enter();
303aba66031SKonstantin Belousov 
304aba66031SKonstantin Belousov 	if ((mcp->mc_flags & _MC_FP_VALID) != 0) {
305aba66031SKonstantin Belousov 		curpcb = curthread->td_pcb;
306aba66031SKonstantin Belousov 		/* FPE usage is enabled, override registers. */
307aba66031SKonstantin Belousov 		memcpy(curpcb->pcb_x, mcp->mc_fpregs.fp_x,
308aba66031SKonstantin Belousov 		    sizeof(mcp->mc_fpregs.fp_x));
309aba66031SKonstantin Belousov 		curpcb->pcb_fcsr = mcp->mc_fpregs.fp_fcsr;
310aba66031SKonstantin Belousov 		curpcb->pcb_fpflags = mcp->mc_fpregs.fp_flags & PCB_FP_USERMASK;
311aba66031SKonstantin Belousov 		td->td_frame->tf_sstatus |= SSTATUS_FS_CLEAN;
312aba66031SKonstantin Belousov 	}
313aba66031SKonstantin Belousov 
314aba66031SKonstantin Belousov 	critical_exit();
315aba66031SKonstantin Belousov }
316aba66031SKonstantin Belousov 
317aba66031SKonstantin Belousov int
sys_sigreturn(struct thread * td,struct sigreturn_args * uap)318aba66031SKonstantin Belousov sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
319aba66031SKonstantin Belousov {
320aba66031SKonstantin Belousov 	ucontext_t uc;
321aba66031SKonstantin Belousov 	int error;
322aba66031SKonstantin Belousov 
323aba66031SKonstantin Belousov 	if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
324aba66031SKonstantin Belousov 		return (EFAULT);
325aba66031SKonstantin Belousov 
326aba66031SKonstantin Belousov 	error = set_mcontext(td, &uc.uc_mcontext);
327aba66031SKonstantin Belousov 	if (error != 0)
328aba66031SKonstantin Belousov 		return (error);
329aba66031SKonstantin Belousov 
330aba66031SKonstantin Belousov 	/* Restore signal mask. */
331aba66031SKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
332aba66031SKonstantin Belousov 
333aba66031SKonstantin Belousov 	return (EJUSTRETURN);
334aba66031SKonstantin Belousov }
335aba66031SKonstantin Belousov 
336aba66031SKonstantin Belousov void
sendsig(sig_t catcher,ksiginfo_t * ksi,sigset_t * mask)337aba66031SKonstantin Belousov sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
338aba66031SKonstantin Belousov {
339aba66031SKonstantin Belousov 	struct sigframe *fp, frame;
340aba66031SKonstantin Belousov 	struct sysentvec *sysent;
341aba66031SKonstantin Belousov 	struct trapframe *tf;
342aba66031SKonstantin Belousov 	struct sigacts *psp;
343aba66031SKonstantin Belousov 	struct thread *td;
344aba66031SKonstantin Belousov 	struct proc *p;
345aba66031SKonstantin Belousov 	int onstack;
346aba66031SKonstantin Belousov 	int sig;
347aba66031SKonstantin Belousov 
348aba66031SKonstantin Belousov 	td = curthread;
349aba66031SKonstantin Belousov 	p = td->td_proc;
350aba66031SKonstantin Belousov 	PROC_LOCK_ASSERT(p, MA_OWNED);
351aba66031SKonstantin Belousov 
352aba66031SKonstantin Belousov 	sig = ksi->ksi_signo;
353aba66031SKonstantin Belousov 	psp = p->p_sigacts;
354aba66031SKonstantin Belousov 	mtx_assert(&psp->ps_mtx, MA_OWNED);
355aba66031SKonstantin Belousov 
356aba66031SKonstantin Belousov 	tf = td->td_frame;
357aba66031SKonstantin Belousov 	onstack = sigonstack(tf->tf_sp);
358aba66031SKonstantin Belousov 
359aba66031SKonstantin Belousov 	CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
360aba66031SKonstantin Belousov 	    catcher, sig);
361aba66031SKonstantin Belousov 
362aba66031SKonstantin Belousov 	/* Allocate and validate space for the signal handler context. */
363aba66031SKonstantin Belousov 	if ((td->td_pflags & TDP_ALTSTACK) != 0 && !onstack &&
364aba66031SKonstantin Belousov 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
365aba66031SKonstantin Belousov 		fp = (struct sigframe *)((uintptr_t)td->td_sigstk.ss_sp +
366aba66031SKonstantin Belousov 		    td->td_sigstk.ss_size);
367aba66031SKonstantin Belousov 	} else {
368aba66031SKonstantin Belousov 		fp = (struct sigframe *)td->td_frame->tf_sp;
369aba66031SKonstantin Belousov 	}
370aba66031SKonstantin Belousov 
371aba66031SKonstantin Belousov 	/* Make room, keeping the stack aligned */
372aba66031SKonstantin Belousov 	fp--;
373aba66031SKonstantin Belousov 	fp = (struct sigframe *)STACKALIGN(fp);
374aba66031SKonstantin Belousov 
375aba66031SKonstantin Belousov 	/* Fill in the frame to copy out */
376aba66031SKonstantin Belousov 	bzero(&frame, sizeof(frame));
377aba66031SKonstantin Belousov 	get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
378aba66031SKonstantin Belousov 	frame.sf_si = ksi->ksi_info;
379aba66031SKonstantin Belousov 	frame.sf_uc.uc_sigmask = *mask;
380aba66031SKonstantin Belousov 	frame.sf_uc.uc_stack = td->td_sigstk;
381aba66031SKonstantin Belousov 	frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ?
382aba66031SKonstantin Belousov 	    (onstack ? SS_ONSTACK : 0) : SS_DISABLE;
383aba66031SKonstantin Belousov 	mtx_unlock(&psp->ps_mtx);
384aba66031SKonstantin Belousov 	PROC_UNLOCK(td->td_proc);
385aba66031SKonstantin Belousov 
386aba66031SKonstantin Belousov 	/* Copy the sigframe out to the user's stack. */
387aba66031SKonstantin Belousov 	if (copyout(&frame, fp, sizeof(*fp)) != 0) {
388aba66031SKonstantin Belousov 		/* Process has trashed its stack. Kill it. */
389aba66031SKonstantin Belousov 		CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
390aba66031SKonstantin Belousov 		PROC_LOCK(p);
391aba66031SKonstantin Belousov 		sigexit(td, SIGILL);
392aba66031SKonstantin Belousov 	}
393aba66031SKonstantin Belousov 
394aba66031SKonstantin Belousov 	tf->tf_a[0] = sig;
395aba66031SKonstantin Belousov 	tf->tf_a[1] = (register_t)&fp->sf_si;
396aba66031SKonstantin Belousov 	tf->tf_a[2] = (register_t)&fp->sf_uc;
397aba66031SKonstantin Belousov 
398aba66031SKonstantin Belousov 	tf->tf_sepc = (register_t)catcher;
399aba66031SKonstantin Belousov 	tf->tf_sp = (register_t)fp;
400aba66031SKonstantin Belousov 
401aba66031SKonstantin Belousov 	sysent = p->p_sysent;
402361971fbSKornel Dulęba 	if (PROC_HAS_SHP(p))
403f6ac79fbSKornel Dulęba 		tf->tf_ra = (register_t)PROC_SIGCODE(p);
404aba66031SKonstantin Belousov 	else
405706f4a81SMark Johnston 		tf->tf_ra = (register_t)(PROC_PS_STRINGS(p) -
406aba66031SKonstantin Belousov 		    *(sysent->sv_szsigcode));
407aba66031SKonstantin Belousov 
408aba66031SKonstantin Belousov 	CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_sepc,
409aba66031SKonstantin Belousov 	    tf->tf_sp);
410aba66031SKonstantin Belousov 
411aba66031SKonstantin Belousov 	PROC_LOCK(p);
412aba66031SKonstantin Belousov 	mtx_lock(&psp->ps_mtx);
413aba66031SKonstantin Belousov }
414