xref: /netbsd/sys/arch/arm/arm/syscall.c (revision 6550d01e)
1 /*	$NetBSD: syscall.c,v 1.51 2010/12/20 00:25:26 matt 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.51 2010/12/20 00:25:26 matt Exp $");
75 
76 #include "opt_sa.h"
77 
78 #include <sys/device.h>
79 #include <sys/errno.h>
80 #include <sys/kernel.h>
81 #include <sys/reboot.h>
82 #include <sys/signalvar.h>
83 #include <sys/syscall.h>
84 #include <sys/syscallvar.h>
85 #include <sys/systm.h>
86 #include <sys/ktrace.h>
87 
88 #include <uvm/uvm_extern.h>
89 
90 #include <sys/savar.h>
91 #include <machine/cpu.h>
92 #include <machine/frame.h>
93 #include <machine/pcb.h>
94 #include <arm/swi.h>
95 
96 #ifdef acorn26
97 #include <machine/machdep.h>
98 #endif
99 
100 void
101 swi_handler(trapframe_t *frame)
102 {
103 	lwp_t *l = curlwp;
104 	struct pcb *pcb;
105 	uint32_t insn;
106 
107 	/*
108 	 * Enable interrupts if they were enabled before the exception.
109 	 * Since all syscalls *should* come from user mode it will always
110 	 * be safe to enable them, but check anyway.
111 	 */
112 #ifdef acorn26
113 	if ((frame->tf_r15 & R15_IRQ_DISABLE) == 0)
114 		int_on();
115 #else
116 	KASSERT((frame->tf_spsr & IF32_bits) == 0);
117 	restore_interrupts(frame->tf_spsr & IF32_bits);
118 #endif
119 
120 #ifdef acorn26
121 	frame->tf_pc += INSN_SIZE;
122 #endif
123 
124 #ifdef KERN_SA
125 	if (__predict_false((l->l_savp)
126             && (l->l_savp->savp_pflags & SAVP_FLAG_DELIVERING)))
127 		l->l_savp->savp_pflags &= ~SAVP_FLAG_DELIVERING;
128 #endif
129 
130 #ifndef THUMB_CODE
131 	/*
132 	 * Make sure the program counter is correctly aligned so we
133 	 * don't take an alignment fault trying to read the opcode.
134 	 */
135 	if (__predict_false(((frame->tf_pc - INSN_SIZE) & 3) != 0)) {
136 		ksiginfo_t ksi;
137 		/* Give the user an illegal instruction signal. */
138 		KSI_INIT_TRAP(&ksi);
139 		ksi.ksi_signo = SIGILL;
140 		ksi.ksi_code = ILL_ILLOPC;
141 		ksi.ksi_addr = (uint32_t *)(intptr_t) (frame->tf_pc-INSN_SIZE);
142 #if 0
143 		/* maybe one day we'll do emulations */
144 		(*l->l_proc->p_emul->e_trapsignal)(l, &ksi);
145 #else
146 		trapsignal(l, &ksi);
147 #endif
148 		userret(l);
149 		return;
150 	}
151 #endif
152 
153 #ifdef THUMB_CODE
154 	if (frame->tf_spsr & PSR_T_bit) {
155 		/* Map a Thumb SWI onto the bottom 256 ARM SWIs.  */
156 		insn = fusword((void *)(frame->tf_pc - THUMB_INSN_SIZE));
157 		if (insn & 0x00ff)
158 			insn = (insn & 0x00ff) | 0xef000000;
159 		else
160 			insn = frame->tf_ip | 0xef000000;
161 	}
162 	else
163 #endif
164 	{
165 	/* XXX fuword? */
166 #ifdef __PROG32
167 		insn = *(uint32_t *)(frame->tf_pc - INSN_SIZE);
168 #else
169 		insn = *(uint32_t *)((frame->tf_r15 & R15_PC) - INSN_SIZE);
170 #endif
171 	}
172 
173 	pcb = lwp_getpcb(l);
174 	pcb->pcb_tf = frame;
175 
176 #ifdef CPU_ARM7
177 	/*
178 	 * This code is only needed if we are including support for the ARM7
179 	 * core. Other CPUs do not need it but it does not hurt.
180 	 */
181 
182 	/*
183 	 * ARM700/ARM710 match sticks and sellotape job ...
184 	 *
185 	 * I know this affects GPS/VLSI ARM700/ARM710 + various ARM7500.
186 	 *
187 	 * On occasion data aborts are mishandled and end up calling
188 	 * the swi vector.
189 	 *
190 	 * If the instruction that caused the exception is not a SWI
191 	 * then we hit the bug.
192 	 */
193 	if ((insn & 0x0f000000) != 0x0f000000) {
194 		frame->tf_pc -= INSN_SIZE;
195 		curcpu()->ci_arm700bugcount.ev_count++;
196 		userret(l);
197 		return;
198 	}
199 #endif	/* CPU_ARM7 */
200 
201 	curcpu()->ci_data.cpu_nsyscall++;
202 
203 	LWP_CACHE_CREDS(l, l->l_proc);
204 	(*l->l_proc->p_md.md_syscall)(frame, l, insn);
205 }
206 
207 void syscall(struct trapframe *, lwp_t *, uint32_t);
208 
209 void
210 syscall_intern(struct proc *p)
211 {
212 	p->p_md.md_syscall = syscall;
213 }
214 
215 void
216 syscall(struct trapframe *frame, lwp_t *l, uint32_t insn)
217 {
218 	struct proc * const p = l->l_proc;
219 	const struct sysent *callp;
220 	int error;
221 	u_int nargs;
222 	register_t *args;
223 	register_t copyargs[2+SYS_MAXSYSARGS];
224 	register_t rval[2];
225 	ksiginfo_t ksi;
226 	const uint32_t os_mask = insn & SWI_OS_MASK;
227 	uint32_t code = insn & 0x000fffff;
228 
229 	/* test new official and old unofficial NetBSD ranges */
230 	if (__predict_false(os_mask != SWI_OS_NETBSD)
231 	    && __predict_false(os_mask != 0)) {
232 		if (os_mask == SWI_OS_ARM
233 		    && (code == SWI_IMB || code == SWI_IMBrange)) {
234 			userret(l);
235 			return;
236 		}
237 
238 		/* Undefined so illegal instruction */
239 		KSI_INIT_TRAP(&ksi);
240 		ksi.ksi_signo = SIGILL;
241 		ksi.ksi_code = ILL_ILLTRP;
242 #ifdef THUMB_CODE
243 		if (frame->tf_spsr & PSR_T_bit)
244 			ksi.ksi_addr = (void *)(frame->tf_pc - THUMB_INSN_SIZE);
245 		else
246 #endif
247 			ksi.ksi_addr = (void *)(frame->tf_pc - INSN_SIZE);
248 		ksi.ksi_trap = insn;
249 		trapsignal(l, &ksi);
250 		userret(l);
251 		return;
252 	}
253 
254 	code &= (SYS_NSYSENT - 1);
255 	callp = p->p_emul->e_sysent + code;
256 	nargs = callp->sy_narg;
257 	if (nargs > 4) {
258 		args = copyargs;
259 		memcpy(args, &frame->tf_r0, 4 * sizeof(register_t));
260 		error = copyin((void *)frame->tf_usr_sp, args + 4,
261 		    (nargs - 4) * sizeof(register_t));
262 		if (error)
263 			goto bad;
264 	} else {
265 		args = &frame->tf_r0;
266 	}
267 
268 	if (!__predict_false(p->p_trace_enabled)
269 	    || __predict_false(callp->sy_flags & SYCALL_INDIRECT)
270 	    || (error = trace_enter(code, args, nargs)) == 0) {
271 		rval[0] = 0;
272 		rval[1] = 0;
273 		error = (*callp->sy_call)(l, args, rval);
274 	}
275 
276 	if (__predict_false(p->p_trace_enabled)
277 	    || !__predict_false(callp->sy_flags & SYCALL_INDIRECT))
278 		trace_exit(code, rval, error);
279 
280 	switch (error) {
281 	case 0:
282 		frame->tf_r0 = rval[0];
283 		frame->tf_r1 = rval[1];
284 
285 #ifdef __PROG32
286 		frame->tf_spsr &= ~PSR_C_bit;	/* carry bit */
287 #else
288 		frame->tf_r15 &= ~R15_FLAG_C;	/* carry bit */
289 #endif
290 		break;
291 
292 	case ERESTART:
293 		/*
294 		 * Reconstruct the pc to point at the swi.
295 		 */
296 #ifdef THUMB_CODE
297 		if (frame->tf_spsr & PSR_T_bit)
298 			frame->tf_pc -= THUMB_INSN_SIZE;
299 		else
300 #endif
301 			frame->tf_pc -= INSN_SIZE;
302 		break;
303 
304 	case EJUSTRETURN:
305 		/* nothing to do */
306 		break;
307 
308 	default:
309 	bad:
310 		frame->tf_r0 = error;
311 #ifdef __PROG32
312 		frame->tf_spsr |= PSR_C_bit;	/* carry bit */
313 #else
314 		frame->tf_r15 |= R15_FLAG_C;	/* carry bit */
315 #endif
316 		break;
317 	}
318 
319 	userret(l);
320 }
321 
322 void
323 child_return(void *arg)
324 {
325 	lwp_t *l = arg;
326 	struct pcb *pcb = lwp_getpcb(l);
327 	struct trapframe *frame = pcb->pcb_tf;
328 
329 	frame->tf_r0 = 0;
330 #ifdef __PROG32
331 	frame->tf_spsr &= ~PSR_C_bit;	/* carry bit */
332 #else
333 	frame->tf_r15 &= ~R15_FLAG_C;	/* carry bit */
334 #endif
335 
336 	userret(l);
337 	ktrsysret(SYS_fork, 0, 0);
338 }
339