]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/bsd_ppc.c
d3afa89dc27af874c67b8ae3ddf61e3ab4f6f4a3
[apple/xnu.git] / osfmk / ppc / bsd_ppc.c
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 #include <mach/mach_types.h>
23 #include <mach/exception_types.h>
24 #include <mach/error.h>
25 #include <kern/counters.h>
26 #include <kern/syscall_sw.h>
27 #include <kern/task.h>
28 #include <kern/thread.h>
29 #include <ppc/thread.h>
30 #include <kern/thread_act.h>
31 #include <ppc/thread_act.h>
32 #include <ppc/asm.h>
33 #include <ppc/proc_reg.h>
34 #include <ppc/trap.h>
35 #include <ppc/exception.h>
36 #include <kern/assert.h>
37
38 #include <sys/syscall.h>
39 #include <sys/ktrace.h>
40 #include <sys/kdebug.h>
41 struct proc;
42
43 #define ERESTART -1 /* restart syscall */
44 #define EJUSTRETURN -2 /* don't modify regs, just return */
45
46 struct unix_syscallargs {
47 int flavor;
48 int r3;
49 int arg1, arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9;
50 };
51 struct sysent { /* system call table */
52 unsigned short sy_narg; /* number of args */
53 char sy_parallel; /* can execute in parallel */
54 char sy_funnel; /* funnel type */
55 unsigned long (*sy_call)(void *, void *, int *); /* implementing function */
56 };
57
58 #define KERNEL_FUNNEL 1
59 #define NETWORK_FUNNEL 2
60
61 extern funnel_t * kernel_flock;
62 extern funnel_t * network_flock;
63
64 extern struct sysent sysent[];
65
66 void *get_bsdtask_info(
67 task_t);
68
69 int set_bsduthreadargs (
70 thread_act_t, struct pcb *,
71 struct unix_syscallargs *);
72
73 void * get_bsduthreadarg(
74 thread_act_t);
75
76 void
77 unix_syscall(
78 struct pcb * pcb,
79 int, int, int, int, int, int, int );
80
81 /*
82 * Function: unix_syscall
83 *
84 * Inputs: pcb - pointer to Process Control Block
85 * arg1 - arguments to mach system calls
86 * arg2
87 * arg3
88 * arg4
89 * arg5
90 * arg6
91 * arg7
92 *
93 * Outputs: none
94 */
95 void
96 unix_syscall(
97 struct pcb * pcb,
98 int arg1,
99 int arg2,
100 int arg3,
101 int arg4,
102 int arg5,
103 int arg6,
104 int arg7
105 )
106 {
107 struct ppc_saved_state *regs;
108 thread_act_t thread;
109 struct sysent *callp;
110 int nargs, error;
111 unsigned short code;
112 struct proc *p;
113 void *vt;
114 int * vtint;
115 int *rval;
116 int funnel_type;
117 struct proc *current_proc();
118
119 struct unix_syscallargs sarg;
120 extern int nsysent;
121
122 regs = &pcb->ss;
123 code = regs->r0;
124
125 thread = current_act();
126 p = current_proc();
127 rval = (int *)get_bsduthreadrval(thread);
128
129 /*
130 * Set up call pointer
131 */
132 callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
133
134 sarg. flavor = (callp == sysent)? 1: 0;
135 if (sarg.flavor) {
136 code = regs->r3;
137 callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
138 } else
139 sarg. r3 = regs->r3;
140
141 if (code != 180) {
142 if (sarg.flavor)
143 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
144 arg1, arg2, arg3, arg4, 0);
145 else
146 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
147 sarg.r3, arg1, arg2, arg3, 0);
148 }
149 sarg.arg1 = arg1;
150 sarg.arg2 = arg2;
151 sarg.arg3 = arg3;
152 sarg.arg4 = arg4;
153 sarg.arg5 = arg5;
154 sarg.arg6 = arg6;
155 sarg.arg7 = arg7;
156
157 if(callp->sy_funnel == NETWORK_FUNNEL) {
158 (void) thread_funnel_set(network_flock, TRUE);
159 } else {
160 (void) thread_funnel_set(kernel_flock, TRUE);
161 }
162
163 set_bsduthreadargs(thread,pcb,&sarg);
164
165 if (callp->sy_narg > 8)
166 panic("unix_syscall: max arg count exceeded");
167
168 rval[0] = 0;
169
170 /*
171 * r4 is volatile, if we set it to regs->r4 here the child
172 * will have parents r4 after execve
173 */
174 rval[1] = 0;
175
176 error = 0; /* Start with a good value */
177
178 /*
179 ** the PPC runtime calls cerror after every unix system call, so
180 ** assume no error and adjust the "pc" to skip this call.
181 ** It will be set back to the cerror call if an error is detected.
182 */
183 regs->srr0 += 4;
184 vt = get_bsduthreadarg(thread);
185 counter_always(c_syscalls_unix++);
186 current_task()->syscalls_unix++;
187
188 ktrsyscall(p, code, callp->sy_narg, vt);
189
190 error = (*(callp->sy_call))(p, (void *)vt, rval);
191
192 regs = find_user_regs(thread);
193 if (regs == (struct ppc_saved_state *)0)
194 panic("No user savearea while returning from system call");
195
196 if (error == ERESTART) {
197 regs->srr0 -= 8;
198 } else if (error != EJUSTRETURN) {
199 if (error) {
200 regs->r3 = error;
201 /* set the "pc" to execute cerror routine */
202 regs->srr0 -= 4;
203 } else { /* (not error) */
204 regs->r3 = rval[0];
205 regs->r4 = rval[1];
206 }
207 }
208 /* else (error == EJUSTRETURN) { nothing } */
209
210 ktrsysret(p, code, error, rval[0]);
211
212 (void) thread_funnel_set(current_thread()->funnel_lock, FALSE);
213
214 if (code != 180) {
215 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
216 error, rval[0], rval[1], 0, 0);
217 }
218
219 thread_exception_return();
220 /* NOTREACHED */
221 }
222
223 unix_syscall_return(error)
224 {
225 struct ppc_saved_state *regs;
226 thread_act_t thread;
227 struct sysent *callp;
228 int nargs;
229 unsigned short code;
230 int *rval;
231 struct proc *p;
232 void *vt;
233 int * vtint;
234 struct pcb *pcb;
235 struct proc *current_proc();
236
237 struct unix_syscallargs sarg;
238 extern int nsysent;
239
240 thread = current_act();
241 p = current_proc();
242 rval = (int *)get_bsduthreadrval(thread);
243 pcb = thread->mact.pcb;
244 regs = &pcb->ss;
245
246 if (thread_funnel_get() == THR_FUNNEL_NULL)
247 panic("Unix syscall return without funnel held");
248
249 /*
250 * Get index into sysent table
251 */
252 code = regs->r0;
253
254 if (error == ERESTART) {
255 regs->srr0 -= 8;
256 } else if (error != EJUSTRETURN) {
257 if (error) {
258 regs->r3 = error;
259 /* set the "pc" to execute cerror routine */
260 regs->srr0 -= 4;
261 } else { /* (not error) */
262 regs->r3 = rval[0];
263 regs->r4 = rval[1];
264 }
265 }
266 /* else (error == EJUSTRETURN) { nothing } */
267
268 ktrsysret(p, code, error, rval[0]);
269
270 (void) thread_funnel_set(current_thread()->funnel_lock, FALSE);
271
272 if (code != 180) {
273 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
274 error, rval[0], rval[1], 0, 0);
275 }
276
277 thread_exception_return();
278 /* NOTREACHED */
279 }
280