xref: /netbsd/sys/arch/arm/arm/syscall.c (revision 955ad518)
1 /*	$NetBSD: syscall.c,v 1.68 2021/02/01 19:31:34 skrll Exp $	*/
2 
3 /*-
4  * Copyright (c) 2000, 2003 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Charles M. Hannum.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1994-1998 Mark Brinicombe.
34  * Copyright (c) 1994 Brini.
35  * All rights reserved.
36  *
37  * This code is derived from software written for Brini by Mark Brinicombe
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. All advertising materials mentioning features or use of this software
48  *    must display the following acknowledgement:
49  *	This product includes software developed by Mark Brinicombe
50  *	for the NetBSD Project.
51  * 4. The name of the company nor the name of the author may be used to
52  *    endorse or promote products derived from this software without specific
53  *    prior written permission.
54  *
55  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
56  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
57  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
58  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
59  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
60  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
61  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65  * SUCH DAMAGE.
66  *
67  * syscall entry handling
68  *
69  * Created      : 09/11/94
70  */
71 
72 #include <sys/param.h>
73 
74 __KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.68 2021/02/01 19:31:34 skrll Exp $");
75 
76 #include <sys/cpu.h>
77 #include <sys/device.h>
78 #include <sys/errno.h>
79 #include <sys/kernel.h>
80 #include <sys/reboot.h>
81 #include <sys/signalvar.h>
82 #include <sys/syscall.h>
83 #include <sys/syscallvar.h>
84 #include <sys/systm.h>
85 #include <sys/ktrace.h>
86 
87 #include <uvm/uvm_extern.h>
88 
89 #include <machine/frame.h>
90 #include <arm/swi.h>
91 #include <arm/locore.h>
92 
93 void
swi_handler(trapframe_t * tf)94 swi_handler(trapframe_t *tf)
95 {
96 	lwp_t * const l = curlwp;
97 	uint32_t insn;
98 
99 	/*
100 	 * Enable interrupts if they were enabled before the exception.
101 	 * Since all syscalls *should* come from user mode it will always
102 	 * be safe to enable them, but check anyway.
103 	 */
104 	KASSERT(VALID_PSR(tf->tf_spsr));
105 	restore_interrupts(tf->tf_spsr & IF32_bits);
106 
107 #ifndef THUMB_CODE
108 	/*
109 	 * Make sure the program counter is correctly aligned so we
110 	 * don't take an alignment fault trying to read the opcode.
111 	 */
112 	if (__predict_false(((tf->tf_pc - INSN_SIZE) & 3) != 0)) {
113 		ksiginfo_t ksi;
114 		/* Give the user an illegal instruction signal. */
115 		KSI_INIT_TRAP(&ksi);
116 		ksi.ksi_signo = SIGILL;
117 		ksi.ksi_code = ILL_ILLOPC;
118 		ksi.ksi_addr = (uint32_t *)(intptr_t) (tf->tf_pc-INSN_SIZE);
119 #if 0
120 		/* maybe one day we'll do emulations */
121 		(*l->l_proc->p_emul->e_trapsignal)(l, &ksi);
122 #else
123 		trapsignal(l, &ksi);
124 #endif
125 		userret(l);
126 		return;
127 	}
128 #endif
129 
130 #ifdef THUMB_CODE
131 	if (tf->tf_spsr & PSR_T_bit) {
132 		insn = 0xef000000 | SWI_OS_NETBSD | tf->tf_r0;
133 		tf->tf_r0 = tf->tf_ip;
134 	}
135 	else
136 #endif
137 	{
138 		insn = read_insn(tf->tf_pc - INSN_SIZE, true);
139 	}
140 
141 	KASSERTMSG(tf == lwp_trapframe(l), "tf %p vs %p", tf, lwp_trapframe(l));
142 
143 #ifdef CPU_ARM7
144 	/*
145 	 * This code is only needed if we are including support for the ARM7
146 	 * core. Other CPUs do not need it but it does not hurt.
147 	 */
148 
149 	/*
150 	 * ARM700/ARM710 match sticks and sellotape job ...
151 	 *
152 	 * I know this affects GPS/VLSI ARM700/ARM710 + various ARM7500.
153 	 *
154 	 * On occasion data aborts are mishandled and end up calling
155 	 * the swi vector.
156 	 *
157 	 * If the instruction that caused the exception is not a SWI
158 	 * then we hit the bug.
159 	 */
160 	if ((insn & 0x0f000000) != 0x0f000000) {
161 		tf->tf_pc -= INSN_SIZE;
162 		curcpu()->ci_arm700bugcount.ev_count++;
163 		userret(l);
164 		return;
165 	}
166 #endif	/* CPU_ARM7 */
167 
168 	curcpu()->ci_data.cpu_nsyscall++;
169 
170 	LWP_CACHE_CREDS(l, l->l_proc);
171 	(*l->l_proc->p_md.md_syscall)(tf, l, insn);
172 }
173 
174 void syscall(struct trapframe *, lwp_t *, uint32_t);
175 
176 void
syscall_intern(struct proc * p)177 syscall_intern(struct proc *p)
178 {
179 	p->p_md.md_syscall = syscall;
180 }
181 
182 void
syscall(struct trapframe * tf,lwp_t * l,uint32_t insn)183 syscall(struct trapframe *tf, lwp_t *l, uint32_t insn)
184 {
185 	struct proc * const p = l->l_proc;
186 	const struct sysent *callp;
187 	int error;
188 	u_int nargs, off = 0;
189 	register_t *args;
190 	uint64_t copyargs64[sizeof(register_t) *
191 			    (2+SYS_MAXSYSARGS+1)/sizeof(uint64_t)];
192 	register_t *copyargs = (register_t *)copyargs64;
193 	register_t rval[2];
194 	ksiginfo_t ksi;
195 	const uint32_t os_mask = insn & SWI_OS_MASK;
196 	uint32_t code = insn & 0x000fffff;
197 
198 	/* test new official and old unofficial NetBSD ranges */
199 	if (__predict_false(os_mask != SWI_OS_NETBSD)
200 	    && __predict_false(os_mask != 0)) {
201 
202 		const uint32_t swi = __SHIFTOUT(insn, __BITS(23,0));
203 		if (swi == SWI_IMB || swi == SWI_IMBrange) {
204 			userret(l);
205 			return;
206 		}
207 
208 		/* Undefined so illegal instruction */
209 		KSI_INIT_TRAP(&ksi);
210 		ksi.ksi_signo = SIGILL;
211 		ksi.ksi_code = ILL_ILLTRP;
212 #ifdef THUMB_CODE
213 		if (tf->tf_spsr & PSR_T_bit)
214 			ksi.ksi_addr = (void *)(tf->tf_pc - THUMB_INSN_SIZE);
215 		else
216 #endif
217 			ksi.ksi_addr = (void *)(tf->tf_pc - INSN_SIZE);
218 		ksi.ksi_trap = insn;
219 		trapsignal(l, &ksi);
220 		userret(l);
221 		return;
222 	}
223 
224 	code &= (SYS_NSYSENT - 1);
225 
226 	if (__predict_false(code == SYS_syscall)) {
227 		off = 1;
228 		code = tf->tf_r0;
229 		code &= (SYS_NSYSENT - 1);
230 		if (__predict_false(code == SYS_syscall)) {
231 			error = EINVAL;
232 			goto bad;
233 		}
234 	}
235 
236 	callp = p->p_emul->e_sysent + code;
237 	nargs = callp->sy_narg;
238 
239 	if ((nargs+off) > 4) {
240 		args = copyargs;
241 		memcpy(args, &tf->tf_r0+off, (4-off) * sizeof(register_t));
242 		error = copyin((void *)tf->tf_usr_sp, args + 4 - off,
243 		    (nargs - 4 + off) * sizeof(register_t));
244 		if (error)
245 			goto bad;
246 	} else {
247 		args = &tf->tf_r0 + off;
248 	}
249 
250 	error = sy_invoke(callp, l, args, rval, code);
251 
252 	switch (error) {
253 	case 0:
254 		tf->tf_r0 = rval[0];
255 		tf->tf_r1 = rval[1];
256 
257 		tf->tf_spsr &= ~PSR_C_bit;	/* carry bit */
258 		break;
259 
260 	case ERESTART:
261 		/*
262 		 * Reconstruct the pc to point at the swi.
263 		 */
264 #ifdef THUMB_CODE
265 		if (tf->tf_spsr & PSR_T_bit)
266 			tf->tf_pc -= THUMB_INSN_SIZE;
267 		else
268 #endif
269 			tf->tf_pc -= INSN_SIZE;
270 		break;
271 
272 	case EJUSTRETURN:
273 		/* nothing to do */
274 		break;
275 
276 	default:
277 	bad:
278 		tf->tf_r0 = error;
279 		tf->tf_spsr |= PSR_C_bit;	/* carry bit */
280 		break;
281 	}
282 
283 	userret(l);
284 }
285 
286 void
md_child_return(struct lwp * l)287 md_child_return(struct lwp *l)
288 {
289 	struct trapframe * const tf = lwp_trapframe(l);
290 
291 	tf->tf_r0 = 0;
292 	tf->tf_spsr &= ~PSR_C_bit;	/* carry bit */
293 
294 	userret(l);
295 }
296 
297 /*
298  * Process the tail end of a posix_spawn() for the child.
299  */
300 void
cpu_spawn_return(struct lwp * l)301 cpu_spawn_return(struct lwp *l)
302 {
303 
304 	userret(l);
305 }
306