]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/ppc/systemcalls.c
xnu-1228.15.4.tar.gz
[apple/xnu.git] / bsd / dev / ppc / systemcalls.c
1 /*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
30 * support for mandatory and extensible security protections. This notice
31 * is included in support of clause 2.2 (b) of the Apple Public License,
32 * Version 2.0.
33 */
34
35 #include <kern/task.h>
36 #include <kern/thread.h>
37 #include <kern/assert.h>
38 #include <kern/clock.h>
39 #include <kern/locks.h>
40 #include <kern/sched_prim.h>
41 #include <mach/machine/thread_status.h>
42 #include <mach/thread_act.h>
43 #include <ppc/savearea.h>
44
45 #include <sys/kernel.h>
46 #include <sys/vm.h>
47 #include <sys/proc_internal.h>
48 #include <sys/syscall.h>
49 #include <sys/systm.h>
50 #include <sys/user.h>
51 #include <sys/errno.h>
52 #include <sys/kdebug.h>
53 #include <sys/sysent.h>
54 #include <sys/sysproto.h>
55 #include <sys/kauth.h>
56
57 #include <bsm/audit_kernel.h>
58
59 #if CONFIG_DTRACE
60 extern int32_t dtrace_systrace_syscall(struct proc *, void *, int *);
61 extern void dtrace_systrace_syscall_return(unsigned short, int, int *);
62 #endif
63
64 extern void
65 unix_syscall(struct savearea *regs);
66
67 extern struct savearea *
68 find_user_regs(
69 thread_t act);
70
71 extern lck_spin_t * tz_slock;
72
73 /*
74 * Function: unix_syscall
75 *
76 * Inputs: regs - pointer to Process Control Block
77 *
78 * Outputs: none
79 */
80 void
81 unix_syscall(struct savearea *regs)
82 {
83 thread_t thread_act;
84 struct uthread *uthread;
85 struct proc *proc;
86 struct sysent *callp;
87 int error;
88 unsigned int code;
89 boolean_t flavor;
90
91 flavor = (((unsigned int)regs->save_r0) == 0)? 1: 0;
92
93 if (flavor)
94 code = regs->save_r3;
95 else
96 code = regs->save_r0;
97
98 if (kdebug_enable && (code != 180)) {
99 if (flavor)
100 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
101 regs->save_r4, regs->save_r5, regs->save_r6, regs->save_r7, 0);
102 else
103 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
104 regs->save_r3, regs->save_r4, regs->save_r5, regs->save_r6, 0);
105 }
106 thread_act = current_thread();
107 uthread = get_bsdthread_info(thread_act);
108
109 if (!(uthread->uu_flag & UT_VFORK))
110 proc = (struct proc *)get_bsdtask_info(current_task());
111 else
112 proc = current_proc();
113
114 /* Make sure there is a process associated with this task */
115 if (proc == NULL) {
116 regs->save_r3 = (long long)EPERM;
117 /* set the "pc" to execute cerror routine */
118 regs->save_srr0 -= 4;
119 task_terminate_internal(current_task());
120 thread_exception_return();
121 /* NOTREACHED */
122 }
123
124 /*
125 * Delayed binding of thread credential to process credential, if we
126 * are not running with an explicitly set thread credential.
127 */
128 kauth_cred_uthread_update(uthread, proc);
129
130 callp = (code >= NUM_SYSENT) ? &sysent[63] : &sysent[code];
131
132 if (callp->sy_narg != 0) {
133 void *regsp;
134 sy_munge_t *mungerp;
135
136 if (IS_64BIT_PROCESS(proc)) {
137 /* XXX Turn 64 bit unsafe calls into nosys() */
138 if (callp->sy_flags & UNSAFE_64BIT) {
139 callp = &sysent[63];
140 goto unsafe;
141 }
142 mungerp = callp->sy_arg_munge64;
143 }
144 else {
145 mungerp = callp->sy_arg_munge32;
146 }
147 if ( !flavor) {
148 regsp = (void *) &regs->save_r3;
149 } else {
150 /* indirect system call consumes an argument so only 7 are supported */
151 if (callp->sy_narg > 7) {
152 callp = &sysent[63];
153 goto unsafe;
154 }
155 regsp = (void *) &regs->save_r4;
156 }
157 /* call syscall argument munger to copy in arguments (see xnu/bsd/dev/ppc/munge.s) */
158 (*mungerp)(regsp, (void *) &uthread->uu_arg[0]);
159 }
160
161 unsafe:
162
163 uthread->uu_flag |= UT_NOTCANCELPT;
164
165 uthread->uu_rval[0] = 0;
166
167 /*
168 * r4 is volatile, if we set it to regs->save_r4 here the child
169 * will have parents r4 after execve
170 */
171 uthread->uu_rval[1] = 0;
172
173 error = 0;
174
175 /*
176 * PPC runtime calls cerror after every unix system call, so
177 * assume no error and adjust the "pc" to skip this call.
178 * It will be set back to the cerror call if an error is detected.
179 */
180 regs->save_srr0 += 4;
181
182 #ifdef JOE_DEBUG
183 uthread->uu_iocount = 0;
184 uthread->uu_vpindex = 0;
185 #endif
186 AUDIT_SYSCALL_ENTER(code, proc, uthread);
187 error = (*(callp->sy_call))(proc, (void *)uthread->uu_arg, &(uthread->uu_rval[0]));
188 AUDIT_SYSCALL_EXIT(code, proc, uthread, error);
189 #if CONFIG_MACF
190 mac_thread_userret(code, error, thread_act);
191 #endif
192
193
194 #ifdef JOE_DEBUG
195 if (uthread->uu_iocount)
196 joe_debug("system call returned with uu_iocount != 0");
197 #endif
198 #if CONFIG_DTRACE
199 uthread->t_dtrace_errno = error;
200 #endif /* CONFIG_DTRACE */
201
202 regs = find_user_regs(thread_act);
203
204 if (error == ERESTART) {
205 regs->save_srr0 -= 8;
206 } else if (error != EJUSTRETURN) {
207 if (error) {
208 regs->save_r3 = (long long)error;
209 /* set the "pc" to execute cerror routine */
210 regs->save_srr0 -= 4;
211 } else { /* (not error) */
212 switch (callp->sy_return_type) {
213 case _SYSCALL_RET_INT_T:
214 regs->save_r3 = uthread->uu_rval[0];
215 regs->save_r4 = uthread->uu_rval[1];
216 break;
217 case _SYSCALL_RET_UINT_T:
218 regs->save_r3 = ((u_int)uthread->uu_rval[0]);
219 regs->save_r4 = ((u_int)uthread->uu_rval[1]);
220 break;
221 case _SYSCALL_RET_OFF_T:
222 /* off_t returns 64 bits split across two registers for 32 bit */
223 /* process and in one register for 64 bit process */
224 if (IS_64BIT_PROCESS(proc)) {
225 u_int64_t *retp = (u_int64_t *)&uthread->uu_rval[0];
226 regs->save_r3 = *retp;
227 regs->save_r4 = 0;
228 }
229 else {
230 regs->save_r3 = uthread->uu_rval[0];
231 regs->save_r4 = uthread->uu_rval[1];
232 }
233 break;
234 case _SYSCALL_RET_ADDR_T:
235 case _SYSCALL_RET_SIZE_T:
236 case _SYSCALL_RET_SSIZE_T:
237 /* the variable length return types (user_addr_t, user_ssize_t,
238 * and user_size_t) are always the largest possible size in the
239 * kernel (we use uu_rval[0] and [1] as one 64 bit value).
240 */
241 {
242 user_addr_t *retp = (user_addr_t *)&uthread->uu_rval[0];
243 regs->save_r3 = *retp;
244 regs->save_r4 = 0;
245 }
246 break;
247 case _SYSCALL_RET_NONE:
248 break;
249 default:
250 panic("unix_syscall: unknown return type");
251 break;
252 }
253 }
254 }
255 /* else (error == EJUSTRETURN) { nothing } */
256
257
258 uthread->uu_flag &= ~UT_NOTCANCELPT;
259
260 /* panic if funnel is held */
261 syscall_exit_funnelcheck();
262
263 if (uthread->uu_lowpri_window) {
264 /*
265 * task is marked as a low priority I/O type
266 * and the I/O we issued while in this system call
267 * collided with normal I/O operations... we'll
268 * delay in order to mitigate the impact of this
269 * task on the normal operation of the system
270 */
271 throttle_lowpri_io(TRUE);
272 }
273 if (kdebug_enable && (code != 180)) {
274
275 if (callp->sy_return_type == _SYSCALL_RET_SSIZE_T)
276 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
277 error, uthread->uu_rval[1], 0, 0, 0);
278 else
279 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
280 error, uthread->uu_rval[0], uthread->uu_rval[1], 0, 0);
281 }
282
283 thread_exception_return();
284 /* NOTREACHED */
285 }
286
287 void
288 unix_syscall_return(int error)
289 {
290 thread_t thread_act;
291 struct uthread *uthread;
292 struct proc *proc;
293 struct savearea *regs;
294 unsigned int code;
295 struct sysent *callp;
296
297 thread_act = current_thread();
298 proc = current_proc();
299 uthread = get_bsdthread_info(thread_act);
300
301 regs = find_user_regs(thread_act);
302
303 if (regs->save_r0 != 0)
304 code = regs->save_r0;
305 else
306 code = regs->save_r3;
307
308 callp = (code >= NUM_SYSENT) ? &sysent[63] : &sysent[code];
309
310 #if CONFIG_DTRACE
311 if (callp->sy_call == dtrace_systrace_syscall)
312 dtrace_systrace_syscall_return( code, error, uthread->uu_rval );
313 #endif /* CONFIG_DTRACE */
314
315 /*
316 * Get index into sysent table
317 */
318 if (error == ERESTART) {
319 regs->save_srr0 -= 8;
320 } else if (error != EJUSTRETURN) {
321 if (error) {
322 regs->save_r3 = (long long)error;
323 /* set the "pc" to execute cerror routine */
324 regs->save_srr0 -= 4;
325 } else { /* (not error) */
326 switch (callp->sy_return_type) {
327 case _SYSCALL_RET_INT_T:
328 regs->save_r3 = uthread->uu_rval[0];
329 regs->save_r4 = uthread->uu_rval[1];
330 break;
331 case _SYSCALL_RET_UINT_T:
332 regs->save_r3 = ((u_int)uthread->uu_rval[0]);
333 regs->save_r4 = ((u_int)uthread->uu_rval[1]);
334 break;
335 case _SYSCALL_RET_OFF_T:
336 /* off_t returns 64 bits split across two registers for 32 bit */
337 /* process and in one register for 64 bit process */
338 if (IS_64BIT_PROCESS(proc)) {
339 u_int64_t *retp = (u_int64_t *)&uthread->uu_rval[0];
340 regs->save_r3 = *retp;
341 }
342 else {
343 regs->save_r3 = uthread->uu_rval[0];
344 regs->save_r4 = uthread->uu_rval[1];
345 }
346 break;
347 case _SYSCALL_RET_ADDR_T:
348 case _SYSCALL_RET_SIZE_T:
349 case _SYSCALL_RET_SSIZE_T:
350 /* the variable length return types (user_addr_t, user_ssize_t,
351 * and user_size_t) are always the largest possible size in the
352 * kernel (we use uu_rval[0] and [1] as one 64 bit value).
353 */
354 {
355 u_int64_t *retp = (u_int64_t *)&uthread->uu_rval[0];
356 regs->save_r3 = *retp;
357 }
358 break;
359 case _SYSCALL_RET_NONE:
360 break;
361 default:
362 panic("unix_syscall: unknown return type");
363 break;
364 }
365 }
366 }
367 /* else (error == EJUSTRETURN) { nothing } */
368
369
370 uthread->uu_flag &= ~UT_NOTCANCELPT;
371
372 /* panic if funnel is held */
373 syscall_exit_funnelcheck();
374
375 if (uthread->uu_lowpri_window) {
376 /*
377 * task is marked as a low priority I/O type
378 * and the I/O we issued while in this system call
379 * collided with normal I/O operations... we'll
380 * delay in order to mitigate the impact of this
381 * task on the normal operation of the system
382 */
383 throttle_lowpri_io(TRUE);
384 }
385 if (kdebug_enable && (code != 180)) {
386 if (callp->sy_return_type == _SYSCALL_RET_SSIZE_T)
387 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
388 error, uthread->uu_rval[1], 0, 0, 0);
389 else
390 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
391 error, uthread->uu_rval[0], uthread->uu_rval[1], 0, 0);
392 }
393
394 thread_exception_return();
395 /* NOTREACHED */
396 }
397
398 #ifdef JOE_DEBUG
399 joe_debug(char *p) {
400
401 printf("%s\n", p);
402 }
403 #endif