1 /*        $NetBSD: syscall.c,v 1.69 2023/10/05 19:41:03 ad 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.69 2023/10/05 19:41:03 ad 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           (*l->l_proc->p_md.md_syscall)(tf, l, insn);
171 }
172 
173 void syscall(struct trapframe *, lwp_t *, uint32_t);
174 
175 void
syscall_intern(struct proc * p)176 syscall_intern(struct proc *p)
177 {
178           p->p_md.md_syscall = syscall;
179 }
180 
181 void
syscall(struct trapframe * tf,lwp_t * l,uint32_t insn)182 syscall(struct trapframe *tf, lwp_t *l, uint32_t insn)
183 {
184           struct proc * const p = l->l_proc;
185           const struct sysent *callp;
186           int error;
187           u_int nargs, off = 0;
188           register_t *args;
189           uint64_t copyargs64[sizeof(register_t) *
190                                   (2+SYS_MAXSYSARGS+1)/sizeof(uint64_t)];
191           register_t *copyargs = (register_t *)copyargs64;
192           register_t rval[2];
193           ksiginfo_t ksi;
194           const uint32_t os_mask = insn & SWI_OS_MASK;
195           uint32_t code = insn & 0x000fffff;
196 
197           /* test new official and old unofficial NetBSD ranges */
198           if (__predict_false(os_mask != SWI_OS_NETBSD)
199               && __predict_false(os_mask != 0)) {
200 
201                     const uint32_t swi = __SHIFTOUT(insn, __BITS(23,0));
202                     if (swi == SWI_IMB || swi == SWI_IMBrange) {
203                               userret(l);
204                               return;
205                     }
206 
207                     /* Undefined so illegal instruction */
208                     KSI_INIT_TRAP(&ksi);
209                     ksi.ksi_signo = SIGILL;
210                     ksi.ksi_code = ILL_ILLTRP;
211 #ifdef THUMB_CODE
212                     if (tf->tf_spsr & PSR_T_bit)
213                               ksi.ksi_addr = (void *)(tf->tf_pc - THUMB_INSN_SIZE);
214                     else
215 #endif
216                               ksi.ksi_addr = (void *)(tf->tf_pc - INSN_SIZE);
217                     ksi.ksi_trap = insn;
218                     trapsignal(l, &ksi);
219                     userret(l);
220                     return;
221           }
222 
223           code &= (SYS_NSYSENT - 1);
224 
225           if (__predict_false(code == SYS_syscall)) {
226                     off = 1;
227                     code = tf->tf_r0;
228                     code &= (SYS_NSYSENT - 1);
229                     if (__predict_false(code == SYS_syscall)) {
230                               error = EINVAL;
231                               goto bad;
232                     }
233           }
234 
235           callp = p->p_emul->e_sysent + code;
236           nargs = callp->sy_narg;
237 
238           if ((nargs+off) > 4) {
239                     args = copyargs;
240                     memcpy(args, &tf->tf_r0+off, (4-off) * sizeof(register_t));
241                     error = copyin((void *)tf->tf_usr_sp, args + 4 - off,
242                         (nargs - 4 + off) * sizeof(register_t));
243                     if (error)
244                               goto bad;
245           } else {
246                     args = &tf->tf_r0 + off;
247           }
248 
249           error = sy_invoke(callp, l, args, rval, code);
250 
251           switch (error) {
252           case 0:
253                     tf->tf_r0 = rval[0];
254                     tf->tf_r1 = rval[1];
255 
256                     tf->tf_spsr &= ~PSR_C_bit;    /* carry bit */
257                     break;
258 
259           case ERESTART:
260                     /*
261                      * Reconstruct the pc to point at the swi.
262                      */
263 #ifdef THUMB_CODE
264                     if (tf->tf_spsr & PSR_T_bit)
265                               tf->tf_pc -= THUMB_INSN_SIZE;
266                     else
267 #endif
268                               tf->tf_pc -= INSN_SIZE;
269                     break;
270 
271           case EJUSTRETURN:
272                     /* nothing to do */
273                     break;
274 
275           default:
276           bad:
277                     tf->tf_r0 = error;
278                     tf->tf_spsr |= PSR_C_bit;     /* carry bit */
279                     break;
280           }
281 
282           userret(l);
283 }
284 
285 void
md_child_return(struct lwp * l)286 md_child_return(struct lwp *l)
287 {
288           struct trapframe * const tf = lwp_trapframe(l);
289 
290           tf->tf_r0 = 0;
291           tf->tf_spsr &= ~PSR_C_bit;    /* carry bit */
292 
293           userret(l);
294 }
295 
296 /*
297  * Process the tail end of a posix_spawn() for the child.
298  */
299 void
cpu_spawn_return(struct lwp * l)300 cpu_spawn_return(struct lwp *l)
301 {
302 
303           userret(l);
304 }
305