xref: /openbsd/sys/arch/arm64/arm64/syscall.c (revision 5a38ef86)
1 /* $OpenBSD: syscall.c,v 1.9 2021/12/09 00:26:11 guenther Exp $ */
2 /*
3  * Copyright (c) 2015 Dale Rahn <drahn@dalerahn.com>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #include <sys/param.h>
18 #include <sys/systm.h>
19 #include <sys/proc.h>
20 #include <sys/signalvar.h>
21 #include <sys/user.h>
22 #include <sys/vnode.h>
23 #include <sys/signal.h>
24 #include <sys/syscall.h>
25 #include <sys/syscall_mi.h>
26 #include <sys/systm.h>
27 #include <sys/proc.h>
28 
29 #include <uvm/uvm_extern.h>
30 
31 #include <machine/vfp.h>
32 
33 #define MAXARGS 8
34 
35 void
36 svc_handler(trapframe_t *frame)
37 {
38 	struct proc *p = curproc;
39 	const struct sysent *callp;
40 	int code, error;
41 	u_int nap = 8, nargs;
42 	register_t *ap, *args, copyargs[MAXARGS], rval[2];
43 
44 	uvmexp.syscalls++;
45 
46 	/* Before enabling interrupts, save FPU state */
47 	vfp_save();
48 
49 	/* Re-enable interrupts if they were enabled previously */
50 	if (__predict_true((frame->tf_spsr & I_bit) == 0))
51 		intr_enable();
52 
53 	/* Skip over speculation-blocking barrier. */
54 	frame->tf_elr += 8;
55 
56 	code = frame->tf_x[8];
57 
58 	ap = &frame->tf_x[0];
59 
60 	switch (code) {
61 	case SYS_syscall:
62 		code = *ap++;
63 		nap--;
64 		break;
65         case SYS___syscall:
66 		code = *ap++;
67 		nap--;
68 		break;
69 	}
70 
71 	callp = sysent;
72 	if (code < 0 || code >= SYS_MAXSYSCALL)
73 		callp += SYS_syscall;
74 	else
75 		callp += code;
76 
77 	nargs = callp->sy_argsize / sizeof(register_t);
78 	if (nargs <= nap) {
79 		args = ap;
80 	} else {
81 		KASSERT(nargs <= MAXARGS);
82 		memcpy(copyargs, ap, nap * sizeof(register_t));
83 		if ((error = copyin((void *)frame->tf_sp, copyargs + nap,
84 		    (nargs - nap) * sizeof(register_t))))
85 			goto bad;
86 		args = copyargs;
87 	}
88 
89 	rval[0] = 0;
90 	rval[1] = frame->tf_x[1];
91 
92 	error = mi_syscall(p, code, callp, args, rval);
93 
94 	switch (error) {
95 	case 0:
96 		frame->tf_x[0] = rval[0];
97 		frame->tf_x[1] = rval[1];
98 
99 		frame->tf_spsr &= ~PSR_C;	/* carry bit */
100 		break;
101 
102 	case ERESTART:
103 		/*
104 		 * Reconstruct the pc to point at the svc.
105 		 */
106 		frame->tf_elr -= 12;
107 		break;
108 
109 	case EJUSTRETURN:
110 		/* nothing to do */
111 		break;
112 
113 	default:
114 	bad:
115 		frame->tf_x[0] = error;
116 		frame->tf_spsr |= PSR_C;	/* carry bit */
117 		break;
118 	}
119 
120 	mi_syscall_return(p, code, error, rval);
121 }
122 
123 void
124 child_return(void *arg)
125 {
126 	struct proc *p = arg;
127 	struct trapframe *frame = p->p_addr->u_pcb.pcb_tf;
128 
129 	frame->tf_x[0] = 0;
130 	frame->tf_x[1] = 1;
131 	frame->tf_spsr &= ~PSR_C;	/* carry bit */
132 
133 	KERNEL_UNLOCK();
134 
135 	mi_child_return(p);
136 }
137