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