xref: /netbsd-src/sys/arch/powerpc/powerpc/syscall.c (revision 68fa58437753598de948829082f591c269b48777)
1 /*	$NetBSD: syscall.c,v 1.58 2023/10/05 19:41:05 ad Exp $	*/
2 
3 /*
4  * Copyright (C) 2002 Matt Thomas
5  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
6  * Copyright (C) 1995, 1996 TooLs GmbH.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by TooLs GmbH.
20  * 4. The name of TooLs GmbH may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 /* DO NOT INCLUDE opt_compat_XXX.h */
36 /* If needed, they will be included by file that includes this one */
37 
38 #include <sys/param.h>
39 #include <sys/cpu.h>
40 #include <sys/ktrace.h>
41 #include <sys/proc.h>
42 #include <sys/reboot.h>
43 #include <sys/systm.h>
44 #include <sys/syscallvar.h>
45 
46 #include <uvm/uvm_extern.h>
47 
48 #include <powerpc/frame.h>
49 #include <powerpc/pcb.h>
50 #include <powerpc/userret.h>
51 
52 #define	FIRSTARG	3		/* first argument is in reg 3 */
53 #define	NARGREG		8		/* 8 args are in registers */
54 #define	MOREARGS(sp)	((void *)((uintptr_t)(sp) + 8)) /* more args go here */
55 
56 #ifndef EMULNAME
57 #include <sys/syscall.h>
58 
59 #define EMULNAME(x)	(x)
60 #define EMULNAMEU(x)	(x)
61 
62 __KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.58 2023/10/05 19:41:05 ad Exp $");
63 
64 void
md_child_return(struct lwp * l)65 md_child_return(struct lwp *l)
66 {
67 	struct trapframe * const tf = l->l_md.md_utf;
68 
69 	tf->tf_fixreg[FIRSTARG] = 0;
70 	tf->tf_fixreg[FIRSTARG + 1] = 1;
71 	tf->tf_cr &= ~0x10000000;
72 	tf->tf_srr1 &= ~(PSL_FP|PSL_VEC); /* Disable FP & AltiVec, as we can't
73 					   be them. */
74 }
75 #endif
76 
77 #include <powerpc/spr.h>
78 
79 static void EMULNAME(syscall)(struct trapframe *);
80 
81 void
EMULNAME(syscall)82 EMULNAME(syscall)(struct trapframe *tf)
83 {
84 	struct lwp * const l = curlwp;
85 	struct proc * const p = l->l_proc;
86 	const struct sysent *callp;
87 	size_t argsize;
88 	register_t code;
89 	register_t *params, rval[2];
90 	register_t args[10];
91 	int error;
92 	int n;
93 
94 	curcpu()->ci_ev_scalls.ev_count++;
95 
96 	code = tf->tf_fixreg[0];
97 	params = tf->tf_fixreg + FIRSTARG;
98 	n = NARGREG;
99 
100 	{
101 		switch (code) {
102 		case EMULNAMEU(SYS_syscall):
103 			/*
104 			 * code is first argument,
105 			 * followed by actual args.
106 			 */
107 			code = *params++;
108 			n -= 1;
109 			break;
110 #if !defined(COMPAT_LINUX)
111 		case EMULNAMEU(SYS___syscall):
112 			params++;
113 			code = *params++;
114 			n -= 2;
115 			break;
116 #endif
117 		default:
118 			break;
119 		}
120 
121 		code &= EMULNAMEU(SYS_NSYSENT) - 1;
122 		callp = p->p_emul->e_sysent + code;
123 	}
124 
125 	argsize = callp->sy_argsize;
126 
127 	if (argsize > n * sizeof(register_t)) {
128 		memcpy(args, params, n * sizeof(register_t));
129 		error = copyin(MOREARGS(tf->tf_fixreg[1]),
130 		    args + n,
131 		    argsize - n * sizeof(register_t));
132 		if (error)
133 			goto bad;
134 		params = args;
135 	}
136 
137 	error = sy_invoke(callp, l, params, rval, code);
138 
139 	if (__predict_true(error == 0)) {
140 		tf->tf_fixreg[FIRSTARG] = rval[0];
141 		tf->tf_fixreg[FIRSTARG + 1] = rval[1];
142 		tf->tf_cr &= ~0x10000000;
143 	} else {
144 		switch (error) {
145 		case ERESTART:
146 			/*
147 			 * Set user's pc back to redo the system call.
148 			 */
149 			tf->tf_srr0 -= 4;
150 			break;
151 		case EJUSTRETURN:
152 			/* nothing to do */
153 			break;
154 		default:
155 		bad:
156 			if (p->p_emul->e_errno)
157 				error = p->p_emul->e_errno[error];
158 			tf->tf_fixreg[FIRSTARG] = error;
159 			tf->tf_cr |= 0x10000000;
160 			break;
161 		}
162 	}
163 
164 	userret(l, tf);
165 }
166 
167 void EMULNAME(syscall_intern)(struct proc *);
168 
169 void
EMULNAME(syscall_intern)170 EMULNAME(syscall_intern)(struct proc *p)
171 {
172 
173 	p->p_md.md_syscall = EMULNAME(syscall);
174 }
175