]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/bsd_ppc.c
xnu-201.tar.gz
[apple/xnu.git] / osfmk / ppc / bsd_ppc.c
1 /*
2 * Copyright (c) 2000 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/kdebug.h>
39
40 #define ERESTART -1 /* restart syscall */
41 #define EJUSTRETURN -2 /* don't modify regs, just return */
42
43 struct unix_syscallargs {
44 int flavor;
45 int r3;
46 int arg1, arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9;
47 };
48 struct sysent { /* system call table */
49 unsigned short sy_narg; /* number of args */
50 char sy_parallel; /* can execute in parallel */
51 char sy_funnel; /* funnel type */
52 unsigned long (*sy_call)(void *, void *, int *); /* implementing function */
53 };
54
55 #define KERNEL_FUNNEL 1
56 #define NETWORK_FUNNEL 2
57
58 extern funnel_t * kernel_flock;
59 extern funnel_t * network_flock;
60
61 extern struct sysent sysent[];
62
63 void *get_bsdtask_info(
64 task_t);
65
66 int set_bsduthreadargs (
67 thread_act_t, struct pcb *,
68 struct unix_syscallargs *);
69
70 void * get_bsduthreadarg(
71 thread_act_t);
72
73 void
74 unix_syscall(
75 struct pcb * pcb,
76 int, int, int, int, int, int, int );
77
78 /*
79 * Function: unix_syscall
80 *
81 * Inputs: pcb - pointer to Process Control Block
82 * arg1 - arguments to mach system calls
83 * arg2
84 * arg3
85 * arg4
86 * arg5
87 * arg6
88 * arg7
89 *
90 * Outputs: none
91 */
92 void
93 unix_syscall(
94 struct pcb * pcb,
95 int arg1,
96 int arg2,
97 int arg3,
98 int arg4,
99 int arg5,
100 int arg6,
101 int arg7
102 )
103 {
104 struct ppc_saved_state *regs;
105 thread_act_t thread;
106 struct sysent *callp;
107 int nargs, error;
108 unsigned short code;
109 void * p, *vt;
110 int * vtint;
111 int *rval;
112 int funnel_type;
113
114 struct unix_syscallargs sarg;
115 extern int nsysent;
116
117
118 regs = &pcb->ss;
119 code = regs->r0;
120
121 thread = current_act();
122 p = current_proc();
123 rval = (int *)get_bsduthreadrval(thread);
124
125 /*
126 ** Get index into sysent table
127 */
128
129
130 /*
131 ** Set up call pointer
132 */
133 callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
134
135 sarg. flavor = (callp == sysent)? 1: 0;
136 if (sarg.flavor) {
137 code = regs->r3;
138 callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
139
140 }
141 else
142 sarg. r3 = regs->r3;
143
144 if (code != 180) {
145 if (sarg.flavor)
146 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
147 arg1, arg2, arg3, arg4, 0);
148 else
149 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
150 sarg.r3, arg1, arg2, arg3, 0);
151 }
152 sarg. arg1 = arg1;
153 sarg. arg2 = arg2;
154 sarg. arg3 = arg3;
155 sarg. arg4 = arg4;
156 sarg. arg5 = arg5;
157 sarg. arg6 = arg6;
158 sarg. arg7 = arg7;
159
160 if(callp->sy_funnel == NETWORK_FUNNEL) {
161 (void) thread_funnel_set(network_flock, TRUE);
162 }
163 else {
164 (void) thread_funnel_set(kernel_flock, TRUE);
165 }
166
167 set_bsduthreadargs(thread,pcb,&sarg);
168
169
170 if (callp->sy_narg > 8)
171 panic("unix_syscall: max arg count exceeded");
172
173 rval[0] = 0;
174
175 /* r4 is volatile, if we set it to regs->r4 here the child
176 * will have parents r4 after execve */
177 rval[1] = 0;
178
179 error = 0; /* Start with a good value */
180
181 /*
182 ** the PPC runtime calls cerror after every unix system call, so
183 ** assume no error and adjust the "pc" to skip this call.
184 ** It will be set back to the cerror call if an error is detected.
185 */
186 regs->srr0 += 4;
187 vt = get_bsduthreadarg(thread);
188 counter_always(c_syscalls_unix++);
189 current_task()->syscalls_unix++;
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 }
199 else if (error != EJUSTRETURN) {
200 if (error)
201 {
202 regs->r3 = error;
203 /* set the "pc" to execute cerror routine */
204 regs->srr0 -= 4;
205 } else { /* (not error) */
206 regs->r3 = rval[0];
207 regs->r4 = rval[1];
208 }
209 }
210 /* else (error == EJUSTRETURN) { nothing } */
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 void * p, *vt;
232 int * vtint;
233 struct pcb *pcb;
234
235 struct unix_syscallargs sarg;
236 extern int nsysent;
237
238 thread = current_act();
239 p = current_proc();
240 rval = (int *)get_bsduthreadrval(thread);
241 pcb = thread->mact.pcb;
242 regs = &pcb->ss;
243
244 if (thread_funnel_get() == THR_FUNNEL_NULL)
245 panic("Unix syscall return without funnel held");
246
247 /*
248 ** Get index into sysent table
249 */
250 code = regs->r0;
251
252 if (error == ERESTART) {
253 regs->srr0 -= 8;
254 }
255 else if (error != EJUSTRETURN) {
256 if (error)
257 {
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 (void) thread_funnel_set(current_thread()->funnel_lock, FALSE);
269
270 if (code != 180) {
271 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
272 error, rval[0], rval[1], 0, 0);
273 }
274
275 thread_exception_return();
276 /* NOTREACHED */
277 }
278