1 /* $NetBSD: syscall.c,v 1.13 2023/10/05 19:41:03 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas of 3am Software Foundry. 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 #include <sys/param.h> 33 #include <sys/cpu.h> 34 #include <sys/ktrace.h> 35 #include <sys/proc.h> 36 #include <sys/reboot.h> 37 #include <sys/systm.h> 38 #include <sys/lwp.h> 39 #include <sys/syscallvar.h> 40 41 #include <uvm/uvm_extern.h> 42 43 #include <aarch64/userret.h> 44 #include <aarch64/frame.h> 45 #include <aarch64/machdep.h> 46 #include <aarch64/armreg.h> 47 48 #ifndef NARGREG 49 #define NARGREG 8 /* 8 args are in registers */ 50 #endif 51 #define MOREARGS(sp) ((const void *)(uintptr_t)(sp)) /* more args go here */ 52 53 #ifndef EMULNAME 54 #include <sys/syscall.h> 55 56 #define SYSCALL_INDIRECT_CODE_REG 17 /* netbsd/aarch64 use x17 */ 57 58 #define EMULNAME(x) (x) 59 #define EMULNAMEU(x) (x) 60 61 __KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.13 2023/10/05 19:41:03 ad Exp $"); 62 63 void 64 cpu_spawn_return(struct lwp *l) 65 { 66 67 userret(l); 68 } 69 70 void 71 md_child_return(struct lwp *l) 72 { 73 struct trapframe * const tf = lwp_trapframe(l); 74 75 tf->tf_reg[0] = 0; 76 tf->tf_reg[1] = 1; 77 tf->tf_spsr &= ~NZCV_C; 78 l->l_md.md_cpacr = CPACR_FPEN_NONE; 79 80 userret(l); 81 } 82 #endif 83 84 static void EMULNAME(syscall)(struct trapframe *); 85 86 void 87 EMULNAME(syscall)(struct trapframe *tf) 88 { 89 struct lwp * const l = curlwp; 90 struct proc * const p = l->l_proc; 91 register_t rval[2]; 92 register_t args[10]; 93 int error; 94 95 curcpu()->ci_data.cpu_nsyscall++; /* XXX unsafe curcpu() */ 96 97 register_t *params = (void *)tf->tf_reg; 98 size_t nargs = NARGREG; 99 #ifdef SYSCALL_CODE_REG 100 /* 101 * mov x<SYSCALL_CODE_REG>, #<syscall_no> 102 * svc #<optional> 103 */ 104 size_t code = tf->tf_reg[SYSCALL_CODE_REG]; 105 #if (SYSCALL_CODE_REG == 0) 106 params++; 107 #endif 108 #else /* SYSCALL_CODE_REG */ 109 /* 110 * svc #<syscall_no> 111 */ 112 size_t code = tf->tf_esr & 0xffff; 113 #endif /* SYSCALL_CODE_REG */ 114 115 #ifndef SYSCALL_NO_INDIRECT 116 switch (code) { 117 case EMULNAMEU(SYS_syscall): 118 case EMULNAMEU(SYS___syscall): 119 #if (SYSCALL_INDIRECT_CODE_REG == 0) 120 code = *params++; 121 nargs -= 1; 122 #else 123 code = tf->tf_reg[SYSCALL_INDIRECT_CODE_REG]; 124 #endif 125 /* 126 * code is first argument, 127 * followed by actual args. 128 */ 129 break; 130 default: 131 break; 132 } 133 #endif /* !SYSCALL_NO_INDIRECT */ 134 135 code &= EMULNAMEU(SYS_NSYSENT) - 1; 136 const struct sysent * const callp = p->p_emul->e_sysent + code; 137 138 if (__predict_false(callp->sy_narg > nargs)) { 139 const size_t diff = callp->sy_narg - nargs; 140 memcpy(args, params, nargs * sizeof(params[0])); 141 error = copyin(MOREARGS(tf->tf_sp), &args[nargs], 142 diff * sizeof(register_t)); 143 if (error) 144 goto bad; 145 params = args; 146 } 147 148 rval[0] = 0; 149 rval[1] = tf->tf_reg[1]; 150 error = sy_invoke(callp, l, params, rval, code); 151 152 if (__predict_true(error == 0)) { 153 tf->tf_reg[0] = rval[0]; 154 #ifndef SYSCALL_NO_RVAL1 155 tf->tf_reg[1] = rval[1]; 156 #endif 157 tf->tf_spsr &= ~NZCV_C; 158 } else { 159 switch (error) { 160 case ERESTART: 161 /* 162 * Set user's pc back to redo the system call. 163 */ 164 tf->tf_pc -= 4; 165 break; 166 case EJUSTRETURN: 167 /* nothing to do */ 168 break; 169 default: 170 bad: 171 #ifndef __HAVE_MINIMAL_EMUL 172 if (p->p_emul->e_errno) 173 error = p->p_emul->e_errno[error]; 174 #elif defined(SYSCALL_EMUL_ERRNO) 175 error = SYSCALL_EMUL_ERRNO(error); 176 #endif 177 tf->tf_reg[0] = error; 178 tf->tf_spsr |= NZCV_C; 179 break; 180 } 181 } 182 183 userret(l); 184 } 185 186 void EMULNAME(syscall_intern)(struct proc *); 187 188 void 189 EMULNAME(syscall_intern)(struct proc *p) 190 { 191 192 p->p_md.md_syscall = EMULNAME(syscall); 193 } 194