xref: /src/sys/arm64/arm64/exec_machdep.c (revision e9a697bf20ccbb2a19f6ad01fa3e0c14e0390847)
1b4ae6b16SKonstantin Belousov /*-
2b4ae6b16SKonstantin Belousov  * Copyright (c) 2014 Andrew Turner
3b4ae6b16SKonstantin Belousov  * All rights reserved.
4b4ae6b16SKonstantin Belousov  *
5b4ae6b16SKonstantin Belousov  * Redistribution and use in source and binary forms, with or without
6b4ae6b16SKonstantin Belousov  * modification, are permitted provided that the following conditions
7b4ae6b16SKonstantin Belousov  * are met:
8b4ae6b16SKonstantin Belousov  * 1. Redistributions of source code must retain the above copyright
9b4ae6b16SKonstantin Belousov  *    notice, this list of conditions and the following disclaimer.
10b4ae6b16SKonstantin Belousov  * 2. Redistributions in binary form must reproduce the above copyright
11b4ae6b16SKonstantin Belousov  *    notice, this list of conditions and the following disclaimer in the
12b4ae6b16SKonstantin Belousov  *    documentation and/or other materials provided with the distribution.
13b4ae6b16SKonstantin Belousov  *
14b4ae6b16SKonstantin Belousov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15b4ae6b16SKonstantin Belousov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16b4ae6b16SKonstantin Belousov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17b4ae6b16SKonstantin Belousov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18b4ae6b16SKonstantin Belousov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19b4ae6b16SKonstantin Belousov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20b4ae6b16SKonstantin Belousov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21b4ae6b16SKonstantin Belousov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22b4ae6b16SKonstantin Belousov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23b4ae6b16SKonstantin Belousov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24b4ae6b16SKonstantin Belousov  * SUCH DAMAGE.
25b4ae6b16SKonstantin Belousov  *
26b4ae6b16SKonstantin Belousov  */
27b4ae6b16SKonstantin Belousov 
28b4ae6b16SKonstantin Belousov #include <sys/param.h>
29b4ae6b16SKonstantin Belousov #include <sys/systm.h>
30b4ae6b16SKonstantin Belousov #include <sys/exec.h>
31b4ae6b16SKonstantin Belousov #include <sys/imgact.h>
32b4ae6b16SKonstantin Belousov #include <sys/kdb.h>
33b4ae6b16SKonstantin Belousov #include <sys/kernel.h>
34b4ae6b16SKonstantin Belousov #include <sys/ktr.h>
35b4ae6b16SKonstantin Belousov #include <sys/limits.h>
36b4ae6b16SKonstantin Belousov #include <sys/lock.h>
37b4ae6b16SKonstantin Belousov #include <sys/mutex.h>
38b4ae6b16SKonstantin Belousov #include <sys/proc.h>
39b4ae6b16SKonstantin Belousov #include <sys/ptrace.h>
40b4ae6b16SKonstantin Belousov #include <sys/reg.h>
41b4ae6b16SKonstantin Belousov #include <sys/rwlock.h>
42b4ae6b16SKonstantin Belousov #include <sys/signalvar.h>
43b4ae6b16SKonstantin Belousov #include <sys/syscallsubr.h>
44b4ae6b16SKonstantin Belousov #include <sys/sysent.h>
45b4ae6b16SKonstantin Belousov #include <sys/sysproto.h>
46b4ae6b16SKonstantin Belousov #include <sys/ucontext.h>
47b4ae6b16SKonstantin Belousov 
48b4ae6b16SKonstantin Belousov #include <vm/vm.h>
49b4ae6b16SKonstantin Belousov #include <vm/vm_param.h>
50361971fbSKornel Dulęba #include <vm/pmap.h>
51361971fbSKornel Dulęba #include <vm/vm_map.h>
52b4ae6b16SKonstantin Belousov 
53b4ae6b16SKonstantin Belousov #include <machine/armreg.h>
544c6c27d3SAndrew Turner #include <machine/elf.h>
55b4ae6b16SKonstantin Belousov #include <machine/kdb.h>
56b4ae6b16SKonstantin Belousov #include <machine/md_var.h>
57b4ae6b16SKonstantin Belousov #include <machine/pcb.h>
58b4ae6b16SKonstantin Belousov 
59b4ae6b16SKonstantin Belousov #ifdef VFP
60b4ae6b16SKonstantin Belousov #include <machine/vfp.h>
61b4ae6b16SKonstantin Belousov #endif
62b4ae6b16SKonstantin Belousov 
63a9e77eb7SAndrew Turner #define	CTX_SIZE_SVE(buf_size)					\
64a9e77eb7SAndrew Turner     roundup2(sizeof(struct sve_context) + (buf_size),		\
65a9e77eb7SAndrew Turner       _Alignof(struct sve_context))
66a9e77eb7SAndrew Turner 
673988ca5aSWarner Losh _Static_assert(sizeof(mcontext_t) == 880, "mcontext_t size incorrect");
683988ca5aSWarner Losh _Static_assert(sizeof(ucontext_t) == 960, "ucontext_t size incorrect");
693988ca5aSWarner Losh _Static_assert(sizeof(siginfo_t) == 80, "siginfo_t size incorrect");
703988ca5aSWarner Losh 
71b4ae6b16SKonstantin Belousov static void get_fpcontext(struct thread *td, mcontext_t *mcp);
72b4ae6b16SKonstantin Belousov static void set_fpcontext(struct thread *td, mcontext_t *mcp);
73b4ae6b16SKonstantin Belousov 
74b4ae6b16SKonstantin Belousov int
fill_regs(struct thread * td,struct reg * regs)75b4ae6b16SKonstantin Belousov fill_regs(struct thread *td, struct reg *regs)
76b4ae6b16SKonstantin Belousov {
77b4ae6b16SKonstantin Belousov 	struct trapframe *frame;
78b4ae6b16SKonstantin Belousov 
79b4ae6b16SKonstantin Belousov 	frame = td->td_frame;
80b4ae6b16SKonstantin Belousov 	regs->sp = frame->tf_sp;
81b4ae6b16SKonstantin Belousov 	regs->lr = frame->tf_lr;
82b4ae6b16SKonstantin Belousov 	regs->elr = frame->tf_elr;
83b4ae6b16SKonstantin Belousov 	regs->spsr = frame->tf_spsr;
84b4ae6b16SKonstantin Belousov 
85b4ae6b16SKonstantin Belousov 	memcpy(regs->x, frame->tf_x, sizeof(regs->x));
86b4ae6b16SKonstantin Belousov 
87b4ae6b16SKonstantin Belousov #ifdef COMPAT_FREEBSD32
88b4ae6b16SKonstantin Belousov 	/*
89b4ae6b16SKonstantin Belousov 	 * We may be called here for a 32bits process, if we're using a
90b4ae6b16SKonstantin Belousov 	 * 64bits debugger. If so, put PC and SPSR where it expects it.
91b4ae6b16SKonstantin Belousov 	 */
92b4ae6b16SKonstantin Belousov 	if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
93b4ae6b16SKonstantin Belousov 		regs->x[15] = frame->tf_elr;
94b4ae6b16SKonstantin Belousov 		regs->x[16] = frame->tf_spsr;
95b4ae6b16SKonstantin Belousov 	}
96b4ae6b16SKonstantin Belousov #endif
97b4ae6b16SKonstantin Belousov 	return (0);
98b4ae6b16SKonstantin Belousov }
99b4ae6b16SKonstantin Belousov 
100b4ae6b16SKonstantin Belousov int
set_regs(struct thread * td,struct reg * regs)101b4ae6b16SKonstantin Belousov set_regs(struct thread *td, struct reg *regs)
102b4ae6b16SKonstantin Belousov {
103b4ae6b16SKonstantin Belousov 	struct trapframe *frame;
104b4ae6b16SKonstantin Belousov 
105b4ae6b16SKonstantin Belousov 	frame = td->td_frame;
106b4ae6b16SKonstantin Belousov 	frame->tf_sp = regs->sp;
107b4ae6b16SKonstantin Belousov 	frame->tf_lr = regs->lr;
108b4ae6b16SKonstantin Belousov 
109b4ae6b16SKonstantin Belousov 	memcpy(frame->tf_x, regs->x, sizeof(frame->tf_x));
110b4ae6b16SKonstantin Belousov 
111b4ae6b16SKonstantin Belousov #ifdef COMPAT_FREEBSD32
112b4ae6b16SKonstantin Belousov 	if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
113b4ae6b16SKonstantin Belousov 		/*
114b4ae6b16SKonstantin Belousov 		 * We may be called for a 32bits process if we're using
115b4ae6b16SKonstantin Belousov 		 * a 64bits debugger. If so, get PC and SPSR from where
116b4ae6b16SKonstantin Belousov 		 * it put it.
117b4ae6b16SKonstantin Belousov 		 */
118b4ae6b16SKonstantin Belousov 		frame->tf_elr = regs->x[15];
11931cf95ceSAndrew Turner 		frame->tf_spsr &= ~PSR_SETTABLE_32;
12031cf95ceSAndrew Turner 		frame->tf_spsr |= regs->x[16] & PSR_SETTABLE_32;
12131cf95ceSAndrew Turner 		/* Don't allow userspace to ask to continue single stepping.
12231cf95ceSAndrew Turner 		 * The SPSR.SS field doesn't exist when the EL1 is AArch32.
12331cf95ceSAndrew Turner 		 * As the SPSR.DIT field has moved in its place don't
12431cf95ceSAndrew Turner 		 * allow userspace to set the SPSR.SS field.
12531cf95ceSAndrew Turner 		 */
126b4ae6b16SKonstantin Belousov 	} else
127b4ae6b16SKonstantin Belousov #endif
128b4ae6b16SKonstantin Belousov 	{
129b4ae6b16SKonstantin Belousov 		frame->tf_elr = regs->elr;
1304a06b28aSAndrew Turner 		/*
1314a06b28aSAndrew Turner 		 * frame->tf_spsr and regs->spsr on FreeBSD 13 was 32-bit
1324a06b28aSAndrew Turner 		 * where from 14 they are 64 bit. As PSR_SETTABLE_64 clears
1334a06b28aSAndrew Turner 		 * the upper 32 bits no compatibility handling is needed,
1344a06b28aSAndrew Turner 		 * however if this is ever not the case we will need to add
1354a06b28aSAndrew Turner 		 * these, similar to how it is done in set_mcontext.
1364a06b28aSAndrew Turner 		 */
13731cf95ceSAndrew Turner 		frame->tf_spsr &= ~PSR_SETTABLE_64;
13831cf95ceSAndrew Turner 		frame->tf_spsr |= regs->spsr & PSR_SETTABLE_64;
13931cf95ceSAndrew Turner 		/* Enable single stepping if userspace asked fot it */
14031cf95ceSAndrew Turner 		if ((frame->tf_spsr & PSR_SS) != 0) {
14131cf95ceSAndrew Turner 			td->td_pcb->pcb_flags |= PCB_SINGLE_STEP;
14231cf95ceSAndrew Turner 
14331cf95ceSAndrew Turner 			WRITE_SPECIALREG(mdscr_el1,
14431cf95ceSAndrew Turner 			    READ_SPECIALREG(mdscr_el1) | MDSCR_SS);
14531cf95ceSAndrew Turner 			isb();
14631cf95ceSAndrew Turner 		}
147b4ae6b16SKonstantin Belousov 	}
148b4ae6b16SKonstantin Belousov 	return (0);
149b4ae6b16SKonstantin Belousov }
150b4ae6b16SKonstantin Belousov 
151b4ae6b16SKonstantin Belousov int
fill_fpregs(struct thread * td,struct fpreg * regs)152b4ae6b16SKonstantin Belousov fill_fpregs(struct thread *td, struct fpreg *regs)
153b4ae6b16SKonstantin Belousov {
154b4ae6b16SKonstantin Belousov #ifdef VFP
155b4ae6b16SKonstantin Belousov 	struct pcb *pcb;
156b4ae6b16SKonstantin Belousov 
157b4ae6b16SKonstantin Belousov 	pcb = td->td_pcb;
158b4ae6b16SKonstantin Belousov 	if ((pcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
159b4ae6b16SKonstantin Belousov 		/*
160b4ae6b16SKonstantin Belousov 		 * If we have just been running VFP instructions we will
161b4ae6b16SKonstantin Belousov 		 * need to save the state to memcpy it below.
162b4ae6b16SKonstantin Belousov 		 */
163b4ae6b16SKonstantin Belousov 		if (td == curthread)
164b4ae6b16SKonstantin Belousov 			vfp_save_state(td, pcb);
16595dd6974SAndrew Turner 	}
166b4ae6b16SKonstantin Belousov 
167b4ae6b16SKonstantin Belousov 	KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate,
168b4ae6b16SKonstantin Belousov 	    ("Called fill_fpregs while the kernel is using the VFP"));
169b4ae6b16SKonstantin Belousov 	memcpy(regs->fp_q, pcb->pcb_fpustate.vfp_regs,
170b4ae6b16SKonstantin Belousov 	    sizeof(regs->fp_q));
171b4ae6b16SKonstantin Belousov 	regs->fp_cr = pcb->pcb_fpustate.vfp_fpcr;
172b4ae6b16SKonstantin Belousov 	regs->fp_sr = pcb->pcb_fpustate.vfp_fpsr;
17395dd6974SAndrew Turner #else
174b4ae6b16SKonstantin Belousov 	memset(regs, 0, sizeof(*regs));
17595dd6974SAndrew Turner #endif
176b4ae6b16SKonstantin Belousov 	return (0);
177b4ae6b16SKonstantin Belousov }
178b4ae6b16SKonstantin Belousov 
179b4ae6b16SKonstantin Belousov int
set_fpregs(struct thread * td,struct fpreg * regs)180b4ae6b16SKonstantin Belousov set_fpregs(struct thread *td, struct fpreg *regs)
181b4ae6b16SKonstantin Belousov {
182b4ae6b16SKonstantin Belousov #ifdef VFP
183b4ae6b16SKonstantin Belousov 	struct pcb *pcb;
184b4ae6b16SKonstantin Belousov 
185b4ae6b16SKonstantin Belousov 	pcb = td->td_pcb;
186b4ae6b16SKonstantin Belousov 	KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate,
187b4ae6b16SKonstantin Belousov 	    ("Called set_fpregs while the kernel is using the VFP"));
188b4ae6b16SKonstantin Belousov 	memcpy(pcb->pcb_fpustate.vfp_regs, regs->fp_q, sizeof(regs->fp_q));
189b4ae6b16SKonstantin Belousov 	pcb->pcb_fpustate.vfp_fpcr = regs->fp_cr;
190b4ae6b16SKonstantin Belousov 	pcb->pcb_fpustate.vfp_fpsr = regs->fp_sr;
191b4ae6b16SKonstantin Belousov #endif
192b4ae6b16SKonstantin Belousov 	return (0);
193b4ae6b16SKonstantin Belousov }
194b4ae6b16SKonstantin Belousov 
195b4ae6b16SKonstantin Belousov int
fill_dbregs(struct thread * td,struct dbreg * regs)196b4ae6b16SKonstantin Belousov fill_dbregs(struct thread *td, struct dbreg *regs)
197b4ae6b16SKonstantin Belousov {
198b4ae6b16SKonstantin Belousov 	struct debug_monitor_state *monitor;
199f820b6edSAndrew Turner 	uint64_t dfr0;
200b4ae6b16SKonstantin Belousov 	int i;
201b4ae6b16SKonstantin Belousov 	uint8_t debug_ver, nbkpts, nwtpts;
202b4ae6b16SKonstantin Belousov 
203b4ae6b16SKonstantin Belousov 	memset(regs, 0, sizeof(*regs));
204b4ae6b16SKonstantin Belousov 
205f820b6edSAndrew Turner 	/*
206f820b6edSAndrew Turner 	 * Read these the Debug Feature Register 0 to get info we need.
207f820b6edSAndrew Turner 	 * It will be identical on FreeBSD and Linux, so there is no need
208f820b6edSAndrew Turner 	 * to check which the target is.
209f820b6edSAndrew Turner 	 */
210f820b6edSAndrew Turner 	if (!get_user_reg(ID_AA64DFR0_EL1, &dfr0, true)) {
211f820b6edSAndrew Turner 		debug_ver = ID_AA64DFR0_DebugVer_8;
212f820b6edSAndrew Turner 		nbkpts = 0;
213f820b6edSAndrew Turner 		nwtpts = 0;
214f820b6edSAndrew Turner 	} else {
215f820b6edSAndrew Turner 		debug_ver = ID_AA64DFR0_DebugVer_VAL(dfr0) >>
216f820b6edSAndrew Turner 		    ID_AA64DFR0_DebugVer_SHIFT;
217f820b6edSAndrew Turner 		nbkpts = ID_AA64DFR0_BRPs_VAL(dfr0) >> ID_AA64DFR0_BRPs_SHIFT;
218f820b6edSAndrew Turner 		nwtpts = ID_AA64DFR0_WRPs_VAL(dfr0) >> ID_AA64DFR0_WRPs_SHIFT;
219f820b6edSAndrew Turner 	}
220b4ae6b16SKonstantin Belousov 
221b4ae6b16SKonstantin Belousov 	/*
222b4ae6b16SKonstantin Belousov 	 * The BRPs field contains the number of breakpoints - 1. Armv8-A
223b4ae6b16SKonstantin Belousov 	 * allows the hardware to provide 2-16 breakpoints so this won't
224b4ae6b16SKonstantin Belousov 	 * overflow an 8 bit value. The same applies to the WRPs field.
225b4ae6b16SKonstantin Belousov 	 */
226b4ae6b16SKonstantin Belousov 	nbkpts++;
227b4ae6b16SKonstantin Belousov 	nwtpts++;
228b4ae6b16SKonstantin Belousov 
229b4ae6b16SKonstantin Belousov 	regs->db_debug_ver = debug_ver;
230b4ae6b16SKonstantin Belousov 	regs->db_nbkpts = nbkpts;
231b4ae6b16SKonstantin Belousov 	regs->db_nwtpts = nwtpts;
232b4ae6b16SKonstantin Belousov 
233b4ae6b16SKonstantin Belousov 	monitor = &td->td_pcb->pcb_dbg_regs;
234b4ae6b16SKonstantin Belousov 	if ((monitor->dbg_flags & DBGMON_ENABLED) != 0) {
235b4ae6b16SKonstantin Belousov 		for (i = 0; i < nbkpts; i++) {
236b4ae6b16SKonstantin Belousov 			regs->db_breakregs[i].dbr_addr = monitor->dbg_bvr[i];
237b4ae6b16SKonstantin Belousov 			regs->db_breakregs[i].dbr_ctrl = monitor->dbg_bcr[i];
238b4ae6b16SKonstantin Belousov 		}
239b4ae6b16SKonstantin Belousov 		for (i = 0; i < nwtpts; i++) {
240b4ae6b16SKonstantin Belousov 			regs->db_watchregs[i].dbw_addr = monitor->dbg_wvr[i];
241b4ae6b16SKonstantin Belousov 			regs->db_watchregs[i].dbw_ctrl = monitor->dbg_wcr[i];
242b4ae6b16SKonstantin Belousov 		}
243b4ae6b16SKonstantin Belousov 	}
244b4ae6b16SKonstantin Belousov 
245b4ae6b16SKonstantin Belousov 	return (0);
246b4ae6b16SKonstantin Belousov }
247b4ae6b16SKonstantin Belousov 
248b4ae6b16SKonstantin Belousov int
set_dbregs(struct thread * td,struct dbreg * regs)249b4ae6b16SKonstantin Belousov set_dbregs(struct thread *td, struct dbreg *regs)
250b4ae6b16SKonstantin Belousov {
251b4ae6b16SKonstantin Belousov 	struct debug_monitor_state *monitor;
252b4ae6b16SKonstantin Belousov 	uint64_t addr;
253b4ae6b16SKonstantin Belousov 	uint32_t ctrl;
254b4ae6b16SKonstantin Belousov 	int i;
255b4ae6b16SKonstantin Belousov 
256b4ae6b16SKonstantin Belousov 	monitor = &td->td_pcb->pcb_dbg_regs;
257b4ae6b16SKonstantin Belousov 	monitor->dbg_enable_count = 0;
258b4ae6b16SKonstantin Belousov 
259b4ae6b16SKonstantin Belousov 	for (i = 0; i < DBG_BRP_MAX; i++) {
260b4ae6b16SKonstantin Belousov 		addr = regs->db_breakregs[i].dbr_addr;
261b4ae6b16SKonstantin Belousov 		ctrl = regs->db_breakregs[i].dbr_ctrl;
262b4ae6b16SKonstantin Belousov 
263b4ae6b16SKonstantin Belousov 		/*
264b4ae6b16SKonstantin Belousov 		 * Don't let the user set a breakpoint on a kernel or
265b4ae6b16SKonstantin Belousov 		 * non-canonical user address.
266b4ae6b16SKonstantin Belousov 		 */
267b4ae6b16SKonstantin Belousov 		if (addr >= VM_MAXUSER_ADDRESS)
268b4ae6b16SKonstantin Belousov 			return (EINVAL);
269b4ae6b16SKonstantin Belousov 
270b4ae6b16SKonstantin Belousov 		/*
271b4ae6b16SKonstantin Belousov 		 * The lowest 2 bits are ignored, so record the effective
272b4ae6b16SKonstantin Belousov 		 * address.
273b4ae6b16SKonstantin Belousov 		 */
274b4ae6b16SKonstantin Belousov 		addr = rounddown2(addr, 4);
275b4ae6b16SKonstantin Belousov 
276b4ae6b16SKonstantin Belousov 		/*
277b4ae6b16SKonstantin Belousov 		 * Some control fields are ignored, and other bits reserved.
278b4ae6b16SKonstantin Belousov 		 * Only unlinked, address-matching breakpoints are supported.
279b4ae6b16SKonstantin Belousov 		 *
280b4ae6b16SKonstantin Belousov 		 * XXX: fields that appear unvalidated, such as BAS, have
281b4ae6b16SKonstantin Belousov 		 * constrained undefined behaviour. If the user mis-programs
282b4ae6b16SKonstantin Belousov 		 * these, there is no risk to the system.
283b4ae6b16SKonstantin Belousov 		 */
284664640baSAndrew Turner 		ctrl &= DBGBCR_EN | DBGBCR_PMC | DBGBCR_BAS;
285664640baSAndrew Turner 		if ((ctrl & DBGBCR_EN) != 0) {
286b4ae6b16SKonstantin Belousov 			/* Only target EL0. */
287664640baSAndrew Turner 			if ((ctrl & DBGBCR_PMC) != DBGBCR_PMC_EL0)
288b4ae6b16SKonstantin Belousov 				return (EINVAL);
289b4ae6b16SKonstantin Belousov 
290b4ae6b16SKonstantin Belousov 			monitor->dbg_enable_count++;
291b4ae6b16SKonstantin Belousov 		}
292b4ae6b16SKonstantin Belousov 
293b4ae6b16SKonstantin Belousov 		monitor->dbg_bvr[i] = addr;
294b4ae6b16SKonstantin Belousov 		monitor->dbg_bcr[i] = ctrl;
295b4ae6b16SKonstantin Belousov 	}
296b4ae6b16SKonstantin Belousov 
297b4ae6b16SKonstantin Belousov 	for (i = 0; i < DBG_WRP_MAX; i++) {
298b4ae6b16SKonstantin Belousov 		addr = regs->db_watchregs[i].dbw_addr;
299b4ae6b16SKonstantin Belousov 		ctrl = regs->db_watchregs[i].dbw_ctrl;
300b4ae6b16SKonstantin Belousov 
301b4ae6b16SKonstantin Belousov 		/*
302b4ae6b16SKonstantin Belousov 		 * Don't let the user set a watchpoint on a kernel or
303b4ae6b16SKonstantin Belousov 		 * non-canonical user address.
304b4ae6b16SKonstantin Belousov 		 */
305b4ae6b16SKonstantin Belousov 		if (addr >= VM_MAXUSER_ADDRESS)
306b4ae6b16SKonstantin Belousov 			return (EINVAL);
307b4ae6b16SKonstantin Belousov 
308b4ae6b16SKonstantin Belousov 		/*
309b4ae6b16SKonstantin Belousov 		 * Some control fields are ignored, and other bits reserved.
310b4ae6b16SKonstantin Belousov 		 * Only unlinked watchpoints are supported.
311b4ae6b16SKonstantin Belousov 		 */
312664640baSAndrew Turner 		ctrl &= DBGWCR_EN | DBGWCR_PAC | DBGWCR_LSC | DBGWCR_BAS |
313664640baSAndrew Turner 		    DBGWCR_MASK;
314b4ae6b16SKonstantin Belousov 
315664640baSAndrew Turner 		if ((ctrl & DBGWCR_EN) != 0) {
316b4ae6b16SKonstantin Belousov 			/* Only target EL0. */
317664640baSAndrew Turner 			if ((ctrl & DBGWCR_PAC) != DBGWCR_PAC_EL0)
318b4ae6b16SKonstantin Belousov 				return (EINVAL);
319b4ae6b16SKonstantin Belousov 
320b4ae6b16SKonstantin Belousov 			/* Must set at least one of the load/store bits. */
321664640baSAndrew Turner 			if ((ctrl & DBGWCR_LSC) == 0)
322b4ae6b16SKonstantin Belousov 				return (EINVAL);
323b4ae6b16SKonstantin Belousov 
324b4ae6b16SKonstantin Belousov 			/*
325b4ae6b16SKonstantin Belousov 			 * When specifying the address range with BAS, the MASK
326b4ae6b16SKonstantin Belousov 			 * field must be zero.
327b4ae6b16SKonstantin Belousov 			 */
328664640baSAndrew Turner 			if ((ctrl & DBGWCR_BAS) != DBGWCR_BAS &&
329664640baSAndrew Turner 			    (ctrl & DBGWCR_MASK) != 0)
330b4ae6b16SKonstantin Belousov 				return (EINVAL);
331b4ae6b16SKonstantin Belousov 
332b4ae6b16SKonstantin Belousov 			monitor->dbg_enable_count++;
333b4ae6b16SKonstantin Belousov 		}
334b4ae6b16SKonstantin Belousov 		monitor->dbg_wvr[i] = addr;
335b4ae6b16SKonstantin Belousov 		monitor->dbg_wcr[i] = ctrl;
336b4ae6b16SKonstantin Belousov 	}
337b4ae6b16SKonstantin Belousov 
338b4ae6b16SKonstantin Belousov 	if (monitor->dbg_enable_count > 0)
339b4ae6b16SKonstantin Belousov 		monitor->dbg_flags |= DBGMON_ENABLED;
340b4ae6b16SKonstantin Belousov 
341b4ae6b16SKonstantin Belousov 	return (0);
342b4ae6b16SKonstantin Belousov }
343b4ae6b16SKonstantin Belousov 
344b4ae6b16SKonstantin Belousov #ifdef COMPAT_FREEBSD32
345b4ae6b16SKonstantin Belousov int
fill_regs32(struct thread * td,struct reg32 * regs)346b4ae6b16SKonstantin Belousov fill_regs32(struct thread *td, struct reg32 *regs)
347b4ae6b16SKonstantin Belousov {
348b4ae6b16SKonstantin Belousov 	int i;
349b4ae6b16SKonstantin Belousov 	struct trapframe *tf;
350b4ae6b16SKonstantin Belousov 
351b4ae6b16SKonstantin Belousov 	tf = td->td_frame;
352b4ae6b16SKonstantin Belousov 	for (i = 0; i < 13; i++)
353b4ae6b16SKonstantin Belousov 		regs->r[i] = tf->tf_x[i];
354b4ae6b16SKonstantin Belousov 	/* For arm32, SP is r13 and LR is r14 */
355b4ae6b16SKonstantin Belousov 	regs->r_sp = tf->tf_x[13];
356b4ae6b16SKonstantin Belousov 	regs->r_lr = tf->tf_x[14];
357b4ae6b16SKonstantin Belousov 	regs->r_pc = tf->tf_elr;
358b4ae6b16SKonstantin Belousov 	regs->r_cpsr = tf->tf_spsr;
359b4ae6b16SKonstantin Belousov 
360b4ae6b16SKonstantin Belousov 	return (0);
361b4ae6b16SKonstantin Belousov }
362b4ae6b16SKonstantin Belousov 
363b4ae6b16SKonstantin Belousov int
set_regs32(struct thread * td,struct reg32 * regs)364b4ae6b16SKonstantin Belousov set_regs32(struct thread *td, struct reg32 *regs)
365b4ae6b16SKonstantin Belousov {
366b4ae6b16SKonstantin Belousov 	int i;
367b4ae6b16SKonstantin Belousov 	struct trapframe *tf;
368b4ae6b16SKonstantin Belousov 
369b4ae6b16SKonstantin Belousov 	tf = td->td_frame;
370b4ae6b16SKonstantin Belousov 	for (i = 0; i < 13; i++)
371b4ae6b16SKonstantin Belousov 		tf->tf_x[i] = regs->r[i];
372b4ae6b16SKonstantin Belousov 	/* For arm 32, SP is r13 an LR is r14 */
373b4ae6b16SKonstantin Belousov 	tf->tf_x[13] = regs->r_sp;
374b4ae6b16SKonstantin Belousov 	tf->tf_x[14] = regs->r_lr;
375b4ae6b16SKonstantin Belousov 	tf->tf_elr = regs->r_pc;
37631cf95ceSAndrew Turner 	tf->tf_spsr &= ~PSR_SETTABLE_32;
37731cf95ceSAndrew Turner 	tf->tf_spsr |= regs->r_cpsr & PSR_SETTABLE_32;
378b4ae6b16SKonstantin Belousov 
379b4ae6b16SKonstantin Belousov 	return (0);
380b4ae6b16SKonstantin Belousov }
381b4ae6b16SKonstantin Belousov 
382b4ae6b16SKonstantin Belousov /* XXX fill/set dbregs/fpregs are stubbed on 32-bit arm. */
383b4ae6b16SKonstantin Belousov int
fill_fpregs32(struct thread * td,struct fpreg32 * regs)384b4ae6b16SKonstantin Belousov fill_fpregs32(struct thread *td, struct fpreg32 *regs)
385b4ae6b16SKonstantin Belousov {
386b4ae6b16SKonstantin Belousov 
387b4ae6b16SKonstantin Belousov 	memset(regs, 0, sizeof(*regs));
388b4ae6b16SKonstantin Belousov 	return (0);
389b4ae6b16SKonstantin Belousov }
390b4ae6b16SKonstantin Belousov 
391b4ae6b16SKonstantin Belousov int
set_fpregs32(struct thread * td,struct fpreg32 * regs)392b4ae6b16SKonstantin Belousov set_fpregs32(struct thread *td, struct fpreg32 *regs)
393b4ae6b16SKonstantin Belousov {
394b4ae6b16SKonstantin Belousov 
395b4ae6b16SKonstantin Belousov 	return (0);
396b4ae6b16SKonstantin Belousov }
397b4ae6b16SKonstantin Belousov 
398b4ae6b16SKonstantin Belousov int
fill_dbregs32(struct thread * td,struct dbreg32 * regs)399b4ae6b16SKonstantin Belousov fill_dbregs32(struct thread *td, struct dbreg32 *regs)
400b4ae6b16SKonstantin Belousov {
401b4ae6b16SKonstantin Belousov 
402b4ae6b16SKonstantin Belousov 	memset(regs, 0, sizeof(*regs));
403b4ae6b16SKonstantin Belousov 	return (0);
404b4ae6b16SKonstantin Belousov }
405b4ae6b16SKonstantin Belousov 
406b4ae6b16SKonstantin Belousov int
set_dbregs32(struct thread * td,struct dbreg32 * regs)407b4ae6b16SKonstantin Belousov set_dbregs32(struct thread *td, struct dbreg32 *regs)
408b4ae6b16SKonstantin Belousov {
409b4ae6b16SKonstantin Belousov 
410b4ae6b16SKonstantin Belousov 	return (0);
411b4ae6b16SKonstantin Belousov }
412b4ae6b16SKonstantin Belousov #endif
413b4ae6b16SKonstantin Belousov 
414b4ae6b16SKonstantin Belousov void
exec_setregs(struct thread * td,struct image_params * imgp,uintptr_t stack)415b4ae6b16SKonstantin Belousov exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
416b4ae6b16SKonstantin Belousov {
417b4ae6b16SKonstantin Belousov 	struct trapframe *tf = td->td_frame;
418b4ae6b16SKonstantin Belousov 	struct pcb *pcb = td->td_pcb;
4194c6c27d3SAndrew Turner 	uint64_t new_tcr, tcr;
420b4ae6b16SKonstantin Belousov 
421b4ae6b16SKonstantin Belousov 	memset(tf, 0, sizeof(struct trapframe));
422b4ae6b16SKonstantin Belousov 
423b4ae6b16SKonstantin Belousov 	tf->tf_x[0] = stack;
424b4ae6b16SKonstantin Belousov 	tf->tf_sp = STACKALIGN(stack);
425b4ae6b16SKonstantin Belousov 	tf->tf_lr = imgp->entry_addr;
426b4ae6b16SKonstantin Belousov 	tf->tf_elr = imgp->entry_addr;
427b4ae6b16SKonstantin Belousov 
428b4ae6b16SKonstantin Belousov 	td->td_pcb->pcb_tpidr_el0 = 0;
429b4ae6b16SKonstantin Belousov 	td->td_pcb->pcb_tpidrro_el0 = 0;
430b4ae6b16SKonstantin Belousov 	WRITE_SPECIALREG(tpidrro_el0, 0);
431b4ae6b16SKonstantin Belousov 	WRITE_SPECIALREG(tpidr_el0, 0);
432b4ae6b16SKonstantin Belousov 
433b4ae6b16SKonstantin Belousov #ifdef VFP
434b4ae6b16SKonstantin Belousov 	vfp_reset_state(td, pcb);
435b4ae6b16SKonstantin Belousov #endif
436b4ae6b16SKonstantin Belousov 
437b4ae6b16SKonstantin Belousov 	/*
438b4ae6b16SKonstantin Belousov 	 * Clear debug register state. It is not applicable to the new process.
439b4ae6b16SKonstantin Belousov 	 */
440b4ae6b16SKonstantin Belousov 	bzero(&pcb->pcb_dbg_regs, sizeof(pcb->pcb_dbg_regs));
44185b7c566SAndrew Turner 
4424c6c27d3SAndrew Turner 	/* If the process is new enough enable TBI */
4434c6c27d3SAndrew Turner 	if (td->td_proc->p_osrel >= TBI_VERSION)
4444c6c27d3SAndrew Turner 		new_tcr = TCR_TBI0;
4454c6c27d3SAndrew Turner 	else
4464c6c27d3SAndrew Turner 		new_tcr = 0;
4474c6c27d3SAndrew Turner 	td->td_proc->p_md.md_tcr = new_tcr;
4484c6c27d3SAndrew Turner 
4494c6c27d3SAndrew Turner 	/* TODO: should create a pmap function for this... */
4504c6c27d3SAndrew Turner 	tcr = READ_SPECIALREG(tcr_el1);
4514c6c27d3SAndrew Turner 	if ((tcr & MD_TCR_FIELDS) != new_tcr) {
4524c6c27d3SAndrew Turner 		uint64_t asid;
4534c6c27d3SAndrew Turner 
4544c6c27d3SAndrew Turner 		tcr &= ~MD_TCR_FIELDS;
4554c6c27d3SAndrew Turner 		tcr |= new_tcr;
4564c6c27d3SAndrew Turner 		WRITE_SPECIALREG(tcr_el1, tcr);
4574c6c27d3SAndrew Turner 		isb();
4584c6c27d3SAndrew Turner 
4594c6c27d3SAndrew Turner 		/*
4604c6c27d3SAndrew Turner 		 * TCR_EL1.TBI0 is permitted to be cached in the TLB, so
4614c6c27d3SAndrew Turner 		 * we need to perform a TLB invalidation.
4624c6c27d3SAndrew Turner 		 */
4634c6c27d3SAndrew Turner 		asid = READ_SPECIALREG(ttbr0_el1) & TTBR_ASID_MASK;
4644c6c27d3SAndrew Turner 		__asm __volatile(
4654c6c27d3SAndrew Turner 		    "tlbi aside1is, %0		\n"
4664c6c27d3SAndrew Turner 		    "dsb ish			\n"
4674c6c27d3SAndrew Turner 		    "isb			\n"
4684c6c27d3SAndrew Turner 		    : : "r" (asid));
4694c6c27d3SAndrew Turner 	}
4704c6c27d3SAndrew Turner 
47185b7c566SAndrew Turner 	/* Generate new pointer authentication keys */
47285b7c566SAndrew Turner 	ptrauth_exec(td);
473b4ae6b16SKonstantin Belousov }
474b4ae6b16SKonstantin Belousov 
475b4ae6b16SKonstantin Belousov /* Sanity check these are the same size, they will be memcpy'd to and from */
476b4ae6b16SKonstantin Belousov CTASSERT(sizeof(((struct trapframe *)0)->tf_x) ==
477b4ae6b16SKonstantin Belousov     sizeof((struct gpregs *)0)->gp_x);
478b4ae6b16SKonstantin Belousov CTASSERT(sizeof(((struct trapframe *)0)->tf_x) ==
479b4ae6b16SKonstantin Belousov     sizeof((struct reg *)0)->x);
480b4ae6b16SKonstantin Belousov 
481b4ae6b16SKonstantin Belousov int
get_mcontext(struct thread * td,mcontext_t * mcp,int clear_ret)482b4ae6b16SKonstantin Belousov get_mcontext(struct thread *td, mcontext_t *mcp, int clear_ret)
483b4ae6b16SKonstantin Belousov {
484b4ae6b16SKonstantin Belousov 	struct trapframe *tf = td->td_frame;
485b4ae6b16SKonstantin Belousov 
486b4ae6b16SKonstantin Belousov 	if (clear_ret & GET_MC_CLEAR_RET) {
487b4ae6b16SKonstantin Belousov 		mcp->mc_gpregs.gp_x[0] = 0;
488b4ae6b16SKonstantin Belousov 		mcp->mc_gpregs.gp_spsr = tf->tf_spsr & ~PSR_C;
489b4ae6b16SKonstantin Belousov 	} else {
490b4ae6b16SKonstantin Belousov 		mcp->mc_gpregs.gp_x[0] = tf->tf_x[0];
491b4ae6b16SKonstantin Belousov 		mcp->mc_gpregs.gp_spsr = tf->tf_spsr;
492b4ae6b16SKonstantin Belousov 	}
493b4ae6b16SKonstantin Belousov 
494b4ae6b16SKonstantin Belousov 	memcpy(&mcp->mc_gpregs.gp_x[1], &tf->tf_x[1],
495b4ae6b16SKonstantin Belousov 	    sizeof(mcp->mc_gpregs.gp_x[1]) * (nitems(mcp->mc_gpregs.gp_x) - 1));
496b4ae6b16SKonstantin Belousov 
497b4ae6b16SKonstantin Belousov 	mcp->mc_gpregs.gp_sp = tf->tf_sp;
498b4ae6b16SKonstantin Belousov 	mcp->mc_gpregs.gp_lr = tf->tf_lr;
499b4ae6b16SKonstantin Belousov 	mcp->mc_gpregs.gp_elr = tf->tf_elr;
500b4ae6b16SKonstantin Belousov 	get_fpcontext(td, mcp);
501b4ae6b16SKonstantin Belousov 
502b4ae6b16SKonstantin Belousov 	return (0);
503b4ae6b16SKonstantin Belousov }
504b4ae6b16SKonstantin Belousov 
505b4ae6b16SKonstantin Belousov int
set_mcontext(struct thread * td,mcontext_t * mcp)506b4ae6b16SKonstantin Belousov set_mcontext(struct thread *td, mcontext_t *mcp)
507b4ae6b16SKonstantin Belousov {
5084a06b28aSAndrew Turner #define	PSR_13_MASK	0xfffffffful
5097e6437c0SAndrew Turner 	struct arm64_reg_context ctx;
510b4ae6b16SKonstantin Belousov 	struct trapframe *tf = td->td_frame;
511e45132e9SAndrew Turner 	struct pcb *pcb;
5122ecbbcc7SZachary Leaf 	uint64_t spsr;
5137e6437c0SAndrew Turner 	vm_offset_t addr;
514e45132e9SAndrew Turner 	int error, seen_types;
5157e6437c0SAndrew Turner 	bool done;
516b4ae6b16SKonstantin Belousov 
517b4ae6b16SKonstantin Belousov 	spsr = mcp->mc_gpregs.gp_spsr;
5184a06b28aSAndrew Turner #ifdef COMPAT_FREEBSD13
5194a06b28aSAndrew Turner 	if (td->td_proc->p_osrel < P_OSREL_ARM64_SPSR) {
5204a06b28aSAndrew Turner 		/*
5214a06b28aSAndrew Turner 		 * Before FreeBSD 14 gp_spsr was 32 bit. The size of mc_gpregs
5224a06b28aSAndrew Turner 		 * was identical because of padding so mask of the upper bits
5234a06b28aSAndrew Turner 		 * that may be invalid on earlier releases.
5244a06b28aSAndrew Turner 		 */
5254a06b28aSAndrew Turner 		spsr &= PSR_13_MASK;
5264a06b28aSAndrew Turner 	}
5274a06b28aSAndrew Turner #endif
5284a06b28aSAndrew Turner 
529b4ae6b16SKonstantin Belousov 	if ((spsr & PSR_M_MASK) != PSR_M_EL0t ||
530b4ae6b16SKonstantin Belousov 	    (spsr & PSR_AARCH32) != 0 ||
531b4ae6b16SKonstantin Belousov 	    (spsr & PSR_DAIF) != (td->td_frame->tf_spsr & PSR_DAIF))
532b4ae6b16SKonstantin Belousov 		return (EINVAL);
533b4ae6b16SKonstantin Belousov 
534b4ae6b16SKonstantin Belousov 	memcpy(tf->tf_x, mcp->mc_gpregs.gp_x, sizeof(tf->tf_x));
535b4ae6b16SKonstantin Belousov 
536b4ae6b16SKonstantin Belousov 	tf->tf_sp = mcp->mc_gpregs.gp_sp;
537b4ae6b16SKonstantin Belousov 	tf->tf_lr = mcp->mc_gpregs.gp_lr;
538b4ae6b16SKonstantin Belousov 	tf->tf_elr = mcp->mc_gpregs.gp_elr;
5394a06b28aSAndrew Turner #ifdef COMPAT_FREEBSD13
5404a06b28aSAndrew Turner 	if (td->td_proc->p_osrel < P_OSREL_ARM64_SPSR) {
5414a06b28aSAndrew Turner 		/* Keep the upper 32 bits of spsr on older releases */
5424a06b28aSAndrew Turner 		tf->tf_spsr &= ~PSR_13_MASK;
5434a06b28aSAndrew Turner 		tf->tf_spsr |= spsr;
5444a06b28aSAndrew Turner 	} else
5454a06b28aSAndrew Turner #endif
5464a06b28aSAndrew Turner 		tf->tf_spsr = spsr;
54731cf95ceSAndrew Turner 	if ((tf->tf_spsr & PSR_SS) != 0) {
54831cf95ceSAndrew Turner 		td->td_pcb->pcb_flags |= PCB_SINGLE_STEP;
54931cf95ceSAndrew Turner 
55031cf95ceSAndrew Turner 		WRITE_SPECIALREG(mdscr_el1,
55131cf95ceSAndrew Turner 		    READ_SPECIALREG(mdscr_el1) | MDSCR_SS);
55231cf95ceSAndrew Turner 		isb();
55331cf95ceSAndrew Turner 	}
5547e6437c0SAndrew Turner 
555b4ae6b16SKonstantin Belousov 	set_fpcontext(td, mcp);
556b4ae6b16SKonstantin Belousov 
5577e6437c0SAndrew Turner 	/* Read any register contexts we find */
5587e6437c0SAndrew Turner 	if (mcp->mc_ptr != 0) {
5597e6437c0SAndrew Turner 		addr = mcp->mc_ptr;
560e45132e9SAndrew Turner 		pcb = td->td_pcb;
5617e6437c0SAndrew Turner 
562e45132e9SAndrew Turner #define	CTX_TYPE_FLAG_SVE	(1 << 0)
563e45132e9SAndrew Turner 
564e45132e9SAndrew Turner 		seen_types = 0;
5657e6437c0SAndrew Turner 		done = false;
5667e6437c0SAndrew Turner 		do {
5677e6437c0SAndrew Turner 			if (!__is_aligned(addr,
5687e6437c0SAndrew Turner 			    _Alignof(struct arm64_reg_context)))
5697e6437c0SAndrew Turner 				return (EINVAL);
5707e6437c0SAndrew Turner 
5717e6437c0SAndrew Turner 			error = copyin((const void *)addr, &ctx, sizeof(ctx));
5727e6437c0SAndrew Turner 			if (error != 0)
5737e6437c0SAndrew Turner 				return (error);
5747e6437c0SAndrew Turner 
5757e6437c0SAndrew Turner 			switch (ctx.ctx_id) {
576e45132e9SAndrew Turner #ifdef VFP
577e45132e9SAndrew Turner 			case ARM64_CTX_SVE: {
578e45132e9SAndrew Turner 				struct sve_context sve_ctx;
579e45132e9SAndrew Turner 				size_t buf_size;
580e45132e9SAndrew Turner 
581e45132e9SAndrew Turner 				if ((seen_types & CTX_TYPE_FLAG_SVE) != 0)
582e45132e9SAndrew Turner 					return (EINVAL);
583e45132e9SAndrew Turner 				seen_types |= CTX_TYPE_FLAG_SVE;
584e45132e9SAndrew Turner 
585e45132e9SAndrew Turner 				if (pcb->pcb_svesaved == NULL)
586e45132e9SAndrew Turner 					return (EINVAL);
587e45132e9SAndrew Turner 
588e45132e9SAndrew Turner 				/* XXX: Check pcb_svesaved is valid */
589e45132e9SAndrew Turner 
590e45132e9SAndrew Turner 				buf_size = sve_buf_size(td);
591e45132e9SAndrew Turner 				/* Check the size is valid */
592a9e77eb7SAndrew Turner 				if (ctx.ctx_size != CTX_SIZE_SVE(buf_size))
593e45132e9SAndrew Turner 					return (EINVAL);
594e45132e9SAndrew Turner 
595e45132e9SAndrew Turner 				memset(pcb->pcb_svesaved, 0,
596e45132e9SAndrew Turner 				    sve_max_buf_size());
597e45132e9SAndrew Turner 
598e45132e9SAndrew Turner 				/* Copy the SVE registers from userspace */
599e45132e9SAndrew Turner 				if (copyin((void *)(addr + sizeof(sve_ctx)),
600e45132e9SAndrew Turner 				    pcb->pcb_svesaved, buf_size) != 0)
601e45132e9SAndrew Turner 					return (EINVAL);
602e45132e9SAndrew Turner 
603e45132e9SAndrew Turner 				pcb->pcb_fpflags |= PCB_FP_SVEVALID;
604e45132e9SAndrew Turner 				break;
605e45132e9SAndrew Turner 			}
606e45132e9SAndrew Turner #endif
6077e6437c0SAndrew Turner 			case ARM64_CTX_END:
6087e6437c0SAndrew Turner 				done = true;
6097e6437c0SAndrew Turner 				break;
6107e6437c0SAndrew Turner 			default:
6117e6437c0SAndrew Turner 				return (EINVAL);
6127e6437c0SAndrew Turner 			}
6137e6437c0SAndrew Turner 
6147e6437c0SAndrew Turner 			addr += ctx.ctx_size;
6157e6437c0SAndrew Turner 		} while (!done);
616e45132e9SAndrew Turner 
617e45132e9SAndrew Turner #undef CTX_TYPE_FLAG_SVE
6187e6437c0SAndrew Turner 	}
6197e6437c0SAndrew Turner 
620b4ae6b16SKonstantin Belousov 	return (0);
6214a06b28aSAndrew Turner #undef PSR_13_MASK
622b4ae6b16SKonstantin Belousov }
623b4ae6b16SKonstantin Belousov 
624b4ae6b16SKonstantin Belousov static void
get_fpcontext(struct thread * td,mcontext_t * mcp)625b4ae6b16SKonstantin Belousov get_fpcontext(struct thread *td, mcontext_t *mcp)
626b4ae6b16SKonstantin Belousov {
627b4ae6b16SKonstantin Belousov #ifdef VFP
628b4ae6b16SKonstantin Belousov 	struct pcb *curpcb;
629b4ae6b16SKonstantin Belousov 
63061f5462fSAndrew Turner 	MPASS(td == curthread);
631b4ae6b16SKonstantin Belousov 
632b4ae6b16SKonstantin Belousov 	curpcb = curthread->td_pcb;
633b4ae6b16SKonstantin Belousov 	if ((curpcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
634b4ae6b16SKonstantin Belousov 		/*
635b4ae6b16SKonstantin Belousov 		 * If we have just been running VFP instructions we will
636b4ae6b16SKonstantin Belousov 		 * need to save the state to memcpy it below.
637b4ae6b16SKonstantin Belousov 		 */
638b4ae6b16SKonstantin Belousov 		vfp_save_state(td, curpcb);
63961f5462fSAndrew Turner 	}
640b4ae6b16SKonstantin Belousov 
641b4ae6b16SKonstantin Belousov 	KASSERT(curpcb->pcb_fpusaved == &curpcb->pcb_fpustate,
642b4ae6b16SKonstantin Belousov 	    ("Called get_fpcontext while the kernel is using the VFP"));
643b4ae6b16SKonstantin Belousov 	KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
644b4ae6b16SKonstantin Belousov 	    ("Non-userspace FPU flags set in get_fpcontext"));
645b4ae6b16SKonstantin Belousov 	memcpy(mcp->mc_fpregs.fp_q, curpcb->pcb_fpustate.vfp_regs,
646b4ae6b16SKonstantin Belousov 	    sizeof(mcp->mc_fpregs.fp_q));
647b4ae6b16SKonstantin Belousov 	mcp->mc_fpregs.fp_cr = curpcb->pcb_fpustate.vfp_fpcr;
648b4ae6b16SKonstantin Belousov 	mcp->mc_fpregs.fp_sr = curpcb->pcb_fpustate.vfp_fpsr;
649b4ae6b16SKonstantin Belousov 	mcp->mc_fpregs.fp_flags = curpcb->pcb_fpflags;
650b4ae6b16SKonstantin Belousov 	mcp->mc_flags |= _MC_FP_VALID;
651b4ae6b16SKonstantin Belousov #endif
652b4ae6b16SKonstantin Belousov }
653b4ae6b16SKonstantin Belousov 
654b4ae6b16SKonstantin Belousov static void
set_fpcontext(struct thread * td,mcontext_t * mcp)655b4ae6b16SKonstantin Belousov set_fpcontext(struct thread *td, mcontext_t *mcp)
656b4ae6b16SKonstantin Belousov {
657b4ae6b16SKonstantin Belousov #ifdef VFP
658b4ae6b16SKonstantin Belousov 	struct pcb *curpcb;
659b4ae6b16SKonstantin Belousov 
660a85cf421SAndrew Turner 	MPASS(td == curthread);
661b4ae6b16SKonstantin Belousov 	if ((mcp->mc_flags & _MC_FP_VALID) != 0) {
662b4ae6b16SKonstantin Belousov 		curpcb = curthread->td_pcb;
663b4ae6b16SKonstantin Belousov 
664b4ae6b16SKonstantin Belousov 		/*
665b4ae6b16SKonstantin Belousov 		 * Discard any vfp state for the current thread, we
666b4ae6b16SKonstantin Belousov 		 * are about to override it.
667b4ae6b16SKonstantin Belousov 		 */
668a85cf421SAndrew Turner 		critical_enter();
669b4ae6b16SKonstantin Belousov 		vfp_discard(td);
670a85cf421SAndrew Turner 		critical_exit();
671b4ae6b16SKonstantin Belousov 
672b4ae6b16SKonstantin Belousov 		KASSERT(curpcb->pcb_fpusaved == &curpcb->pcb_fpustate,
673b4ae6b16SKonstantin Belousov 		    ("Called set_fpcontext while the kernel is using the VFP"));
674b4ae6b16SKonstantin Belousov 		memcpy(curpcb->pcb_fpustate.vfp_regs, mcp->mc_fpregs.fp_q,
675b4ae6b16SKonstantin Belousov 		    sizeof(mcp->mc_fpregs.fp_q));
676b4ae6b16SKonstantin Belousov 		curpcb->pcb_fpustate.vfp_fpcr = mcp->mc_fpregs.fp_cr;
677b4ae6b16SKonstantin Belousov 		curpcb->pcb_fpustate.vfp_fpsr = mcp->mc_fpregs.fp_sr;
678e45132e9SAndrew Turner 		curpcb->pcb_fpflags = mcp->mc_fpregs.fp_flags & PCB_FP_STARTED;
679b4ae6b16SKonstantin Belousov 	}
680b4ae6b16SKonstantin Belousov #endif
681b4ae6b16SKonstantin Belousov }
682b4ae6b16SKonstantin Belousov 
683b4ae6b16SKonstantin Belousov int
sys_sigreturn(struct thread * td,struct sigreturn_args * uap)684b4ae6b16SKonstantin Belousov sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
685b4ae6b16SKonstantin Belousov {
686b4ae6b16SKonstantin Belousov 	ucontext_t uc;
687b4ae6b16SKonstantin Belousov 	int error;
688b4ae6b16SKonstantin Belousov 
689b4ae6b16SKonstantin Belousov 	if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
690b4ae6b16SKonstantin Belousov 		return (EFAULT);
691b4ae6b16SKonstantin Belousov 
692332c4263SAndrew Turner 	/* Stop an interrupt from causing the sve state to be dropped */
693332c4263SAndrew Turner 	td->td_sa.code = -1;
694b4ae6b16SKonstantin Belousov 	error = set_mcontext(td, &uc.uc_mcontext);
695b4ae6b16SKonstantin Belousov 	if (error != 0)
696b4ae6b16SKonstantin Belousov 		return (error);
697b4ae6b16SKonstantin Belousov 
698e45132e9SAndrew Turner 	/*
699e45132e9SAndrew Turner 	 * Sync the VFP and SVE registers. To be backwards compatible we
700e45132e9SAndrew Turner 	 * use the VFP registers to restore the lower bits of the SVE
701e45132e9SAndrew Turner 	 * register it aliases.
702e45132e9SAndrew Turner 	 */
703e45132e9SAndrew Turner 	vfp_to_sve_sync(td);
704e45132e9SAndrew Turner 
705b4ae6b16SKonstantin Belousov 	/* Restore signal mask. */
706b4ae6b16SKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
707b4ae6b16SKonstantin Belousov 
708b4ae6b16SKonstantin Belousov 	return (EJUSTRETURN);
709b4ae6b16SKonstantin Belousov }
710b4ae6b16SKonstantin Belousov 
7117e6437c0SAndrew Turner static bool
sendsig_ctx_end(struct thread * td,vm_offset_t * addrp)7127e6437c0SAndrew Turner sendsig_ctx_end(struct thread *td, vm_offset_t *addrp)
7137e6437c0SAndrew Turner {
7147e6437c0SAndrew Turner 	struct arm64_reg_context end_ctx;
7157e6437c0SAndrew Turner 	vm_offset_t ctx_addr;
7167e6437c0SAndrew Turner 
7177e6437c0SAndrew Turner 	*addrp -= sizeof(end_ctx);
7187e6437c0SAndrew Turner 	ctx_addr = *addrp;
7197e6437c0SAndrew Turner 
7207e6437c0SAndrew Turner 	memset(&end_ctx, 0, sizeof(end_ctx));
7217e6437c0SAndrew Turner 	end_ctx.ctx_id = ARM64_CTX_END;
7227e6437c0SAndrew Turner 	end_ctx.ctx_size = sizeof(end_ctx);
7237e6437c0SAndrew Turner 
7247e6437c0SAndrew Turner 	if (copyout(&end_ctx, (void *)ctx_addr, sizeof(end_ctx)) != 0)
7257e6437c0SAndrew Turner 		return (false);
7267e6437c0SAndrew Turner 
7277e6437c0SAndrew Turner 	return (true);
7287e6437c0SAndrew Turner }
7297e6437c0SAndrew Turner 
730e45132e9SAndrew Turner static bool
sendsig_ctx_sve(struct thread * td,vm_offset_t * addrp)731e45132e9SAndrew Turner sendsig_ctx_sve(struct thread *td, vm_offset_t *addrp)
732e45132e9SAndrew Turner {
733e45132e9SAndrew Turner 	struct sve_context ctx;
734e45132e9SAndrew Turner 	struct pcb *pcb;
735a9e77eb7SAndrew Turner 	size_t buf_size, ctx_size;
736e45132e9SAndrew Turner 	vm_offset_t ctx_addr;
737e45132e9SAndrew Turner 
738e45132e9SAndrew Turner 	pcb = td->td_pcb;
739e45132e9SAndrew Turner 	/* Do nothing if sve hasn't started */
740e45132e9SAndrew Turner 	if (pcb->pcb_svesaved == NULL)
741e45132e9SAndrew Turner 		return (true);
742e45132e9SAndrew Turner 
743e45132e9SAndrew Turner 	MPASS(pcb->pcb_svesaved != NULL);
744e45132e9SAndrew Turner 
745e45132e9SAndrew Turner 	buf_size = sve_buf_size(td);
746a9e77eb7SAndrew Turner 	ctx_size = CTX_SIZE_SVE(buf_size);
747e45132e9SAndrew Turner 
748e45132e9SAndrew Turner 	/* Address for the full context */
749a9e77eb7SAndrew Turner 	*addrp -= ctx_size;
750e45132e9SAndrew Turner 	ctx_addr = *addrp;
751e45132e9SAndrew Turner 
752e45132e9SAndrew Turner 	memset(&ctx, 0, sizeof(ctx));
753e45132e9SAndrew Turner 	ctx.sve_ctx.ctx_id = ARM64_CTX_SVE;
754a9e77eb7SAndrew Turner 	ctx.sve_ctx.ctx_size = ctx_size;
755e45132e9SAndrew Turner 	ctx.sve_vector_len = pcb->pcb_sve_len;
756e45132e9SAndrew Turner 	ctx.sve_flags = 0;
757e45132e9SAndrew Turner 
758e45132e9SAndrew Turner 	/* Copy out the header and data */
759e45132e9SAndrew Turner 	if (copyout(&ctx, (void *)ctx_addr, sizeof(ctx)) != 0)
760e45132e9SAndrew Turner 		return (false);
761e45132e9SAndrew Turner 	if (copyout(pcb->pcb_svesaved, (void *)(ctx_addr + sizeof(ctx)),
762e45132e9SAndrew Turner 	    buf_size) != 0)
763e45132e9SAndrew Turner 		return (false);
764e45132e9SAndrew Turner 
765e45132e9SAndrew Turner 	return (true);
766e45132e9SAndrew Turner }
767e45132e9SAndrew Turner 
7687e6437c0SAndrew Turner typedef bool(*ctx_func)(struct thread *, vm_offset_t *);
7697e6437c0SAndrew Turner static const ctx_func ctx_funcs[] = {
7707e6437c0SAndrew Turner 	sendsig_ctx_end,	/* Must be first to end the linked list */
771e45132e9SAndrew Turner 	sendsig_ctx_sve,
7727e6437c0SAndrew Turner 	NULL,
7737e6437c0SAndrew Turner };
7747e6437c0SAndrew Turner 
775b4ae6b16SKonstantin Belousov void
sendsig(sig_t catcher,ksiginfo_t * ksi,sigset_t * mask)776b4ae6b16SKonstantin Belousov sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
777b4ae6b16SKonstantin Belousov {
778b4ae6b16SKonstantin Belousov 	struct thread *td;
779b4ae6b16SKonstantin Belousov 	struct proc *p;
780b4ae6b16SKonstantin Belousov 	struct trapframe *tf;
781b4ae6b16SKonstantin Belousov 	struct sigframe *fp, frame;
782b4ae6b16SKonstantin Belousov 	struct sigacts *psp;
7837e6437c0SAndrew Turner 	vm_offset_t addr;
784b4ae6b16SKonstantin Belousov 	int onstack, sig;
785b4ae6b16SKonstantin Belousov 
786b4ae6b16SKonstantin Belousov 	td = curthread;
787b4ae6b16SKonstantin Belousov 	p = td->td_proc;
788b4ae6b16SKonstantin Belousov 	PROC_LOCK_ASSERT(p, MA_OWNED);
789b4ae6b16SKonstantin Belousov 
790b4ae6b16SKonstantin Belousov 	sig = ksi->ksi_signo;
791b4ae6b16SKonstantin Belousov 	psp = p->p_sigacts;
792b4ae6b16SKonstantin Belousov 	mtx_assert(&psp->ps_mtx, MA_OWNED);
793b4ae6b16SKonstantin Belousov 
794b4ae6b16SKonstantin Belousov 	tf = td->td_frame;
795b4ae6b16SKonstantin Belousov 	onstack = sigonstack(tf->tf_sp);
796b4ae6b16SKonstantin Belousov 
797b4ae6b16SKonstantin Belousov 	CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
798b4ae6b16SKonstantin Belousov 	    catcher, sig);
799b4ae6b16SKonstantin Belousov 
800b4ae6b16SKonstantin Belousov 	/* Allocate and validate space for the signal handler context. */
801b4ae6b16SKonstantin Belousov 	if ((td->td_pflags & TDP_ALTSTACK) != 0 && !onstack &&
802b4ae6b16SKonstantin Belousov 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
8037e6437c0SAndrew Turner 		addr = ((uintptr_t)td->td_sigstk.ss_sp +
804b4ae6b16SKonstantin Belousov 		    td->td_sigstk.ss_size);
805b4ae6b16SKonstantin Belousov #if defined(COMPAT_43)
806b4ae6b16SKonstantin Belousov 		td->td_sigstk.ss_flags |= SS_ONSTACK;
807b4ae6b16SKonstantin Belousov #endif
808b4ae6b16SKonstantin Belousov 	} else {
8097e6437c0SAndrew Turner 		addr = td->td_frame->tf_sp;
810b4ae6b16SKonstantin Belousov 	}
811b4ae6b16SKonstantin Belousov 
812b4ae6b16SKonstantin Belousov 	/* Fill in the frame to copy out */
813b4ae6b16SKonstantin Belousov 	bzero(&frame, sizeof(frame));
814b4ae6b16SKonstantin Belousov 	get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
815b4ae6b16SKonstantin Belousov 	frame.sf_si = ksi->ksi_info;
816b4ae6b16SKonstantin Belousov 	frame.sf_uc.uc_sigmask = *mask;
817b4ae6b16SKonstantin Belousov 	frame.sf_uc.uc_stack = td->td_sigstk;
818b4ae6b16SKonstantin Belousov 	frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ?
819b4ae6b16SKonstantin Belousov 	    (onstack ? SS_ONSTACK : 0) : SS_DISABLE;
820b4ae6b16SKonstantin Belousov 	mtx_unlock(&psp->ps_mtx);
821b4ae6b16SKonstantin Belousov 	PROC_UNLOCK(td->td_proc);
822b4ae6b16SKonstantin Belousov 
8237e6437c0SAndrew Turner 	for (int i = 0; ctx_funcs[i] != NULL; i++) {
8247e6437c0SAndrew Turner 		if (!ctx_funcs[i](td, &addr)) {
8257e6437c0SAndrew Turner 			/* Process has trashed its stack. Kill it. */
8267e6437c0SAndrew Turner 			CTR4(KTR_SIG,
8277e6437c0SAndrew Turner 			    "sendsig: frame sigexit td=%p fp=%#lx func[%d]=%p",
8287e6437c0SAndrew Turner 			    td, addr, i, ctx_funcs[i]);
8297e6437c0SAndrew Turner 			PROC_LOCK(p);
8307e6437c0SAndrew Turner 			sigexit(td, SIGILL);
8317e6437c0SAndrew Turner 			/* NOTREACHED */
8327e6437c0SAndrew Turner 		}
8337e6437c0SAndrew Turner 	}
8347e6437c0SAndrew Turner 
8357e6437c0SAndrew Turner 	/* Point at the first context */
8367e6437c0SAndrew Turner 	frame.sf_uc.uc_mcontext.mc_ptr = addr;
8377e6437c0SAndrew Turner 
8387e6437c0SAndrew Turner 	/* Make room, keeping the stack aligned */
8397e6437c0SAndrew Turner 	fp = (struct sigframe *)addr;
8407e6437c0SAndrew Turner 	fp--;
841*e9a697bfSJohn Baldwin 	fp = STACKALIGN(fp);
8427e6437c0SAndrew Turner 
843b4ae6b16SKonstantin Belousov 	/* Copy the sigframe out to the user's stack. */
844b4ae6b16SKonstantin Belousov 	if (copyout(&frame, fp, sizeof(*fp)) != 0) {
845b4ae6b16SKonstantin Belousov 		/* Process has trashed its stack. Kill it. */
846b4ae6b16SKonstantin Belousov 		CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
847b4ae6b16SKonstantin Belousov 		PROC_LOCK(p);
848b4ae6b16SKonstantin Belousov 		sigexit(td, SIGILL);
849b4ae6b16SKonstantin Belousov 	}
850b4ae6b16SKonstantin Belousov 
851b4ae6b16SKonstantin Belousov 	tf->tf_x[0] = sig;
852b4ae6b16SKonstantin Belousov 	tf->tf_x[1] = (register_t)&fp->sf_si;
853b4ae6b16SKonstantin Belousov 	tf->tf_x[2] = (register_t)&fp->sf_uc;
854db3a1eecSAndrew Turner 	tf->tf_x[8] = (register_t)catcher;
855b4ae6b16SKonstantin Belousov 	tf->tf_sp = (register_t)fp;
856f6ac79fbSKornel Dulęba 	tf->tf_elr = (register_t)PROC_SIGCODE(p);
857b4ae6b16SKonstantin Belousov 
85831cf95ceSAndrew Turner 	/* Clear the single step flag while in the signal handler */
85931cf95ceSAndrew Turner 	if ((td->td_pcb->pcb_flags & PCB_SINGLE_STEP) != 0) {
86031cf95ceSAndrew Turner 		td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
86131cf95ceSAndrew Turner 		WRITE_SPECIALREG(mdscr_el1,
86231cf95ceSAndrew Turner 		    READ_SPECIALREG(mdscr_el1) & ~MDSCR_SS);
86331cf95ceSAndrew Turner 		isb();
86431cf95ceSAndrew Turner 	}
86531cf95ceSAndrew Turner 
866b4ae6b16SKonstantin Belousov 	CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr,
867b4ae6b16SKonstantin Belousov 	    tf->tf_sp);
868b4ae6b16SKonstantin Belousov 
869b4ae6b16SKonstantin Belousov 	PROC_LOCK(p);
870b4ae6b16SKonstantin Belousov 	mtx_lock(&psp->ps_mtx);
871b4ae6b16SKonstantin Belousov }
872