]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/ppc/systemcalls.c
xnu-1504.7.4.tar.gz
[apple/xnu.git] / bsd / dev / ppc / systemcalls.c
1 /*
2 * Copyright (c) 2000-2008 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 <mach/mach_traps.h>
36
37 #include <kern/task.h>
38 #include <kern/thread.h>
39 #include <kern/assert.h>
40 #include <kern/clock.h>
41 #include <kern/locks.h>
42 #include <kern/sched_prim.h>
43 #include <mach/machine/thread_status.h>
44 #include <mach/thread_act.h>
45 #include <ppc/savearea.h>
46
47 #include <sys/kernel.h>
48 #include <sys/vm.h>
49 #include <sys/proc_internal.h>
50 #include <sys/syscall.h>
51 #include <sys/systm.h>
52 #include <sys/user.h>
53 #include <sys/errno.h>
54 #include <sys/kdebug.h>
55 #include <sys/sysent.h>
56 #include <sys/sysproto.h>
57 #include <sys/kauth.h>
58
59 #include <security/audit/audit.h>
60
61 #if CONFIG_DTRACE
62 extern int32_t dtrace_systrace_syscall(struct proc *, void *, int *);
63 extern void dtrace_systrace_syscall_return(unsigned short, int, int *);
64 #endif
65
66 extern void
67 unix_syscall(struct savearea *regs);
68
69 extern struct savearea *
70 find_user_regs(
71 thread_t act);
72
73 extern lck_spin_t * tz_slock;
74
75 /*
76 * Function: unix_syscall
77 *
78 * Inputs: regs - pointer to Process Control Block
79 *
80 * Outputs: none
81 */
82 void
83 unix_syscall(struct savearea *regs)
84 {
85 thread_t thread_act;
86 struct uthread *uthread;
87 struct proc *proc;
88 struct sysent *callp;
89 int error;
90 unsigned int code;
91 boolean_t flavor;
92
93 flavor = (((unsigned int)regs->save_r0) == 0)? 1: 0;
94
95 if (flavor)
96 code = regs->save_r3;
97 else
98 code = regs->save_r0;
99
100 if (kdebug_enable && (code != 180)) {
101 if (flavor)
102 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
103 regs->save_r4, regs->save_r5, regs->save_r6, regs->save_r7, 0);
104 else
105 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
106 regs->save_r3, regs->save_r4, regs->save_r5, regs->save_r6, 0);
107 }
108 thread_act = current_thread();
109 uthread = get_bsdthread_info(thread_act);
110
111 if (!(uthread->uu_flag & UT_VFORK))
112 proc = (struct proc *)get_bsdtask_info(current_task());
113 else
114 proc = current_proc();
115
116 /* Make sure there is a process associated with this task */
117 if (proc == NULL) {
118 regs->save_r3 = (long long)EPERM;
119 /* set the "pc" to execute cerror routine */
120 regs->save_srr0 -= 4;
121 task_terminate_internal(current_task());
122 thread_exception_return();
123 /* NOTREACHED */
124 }
125
126 /*
127 * Delayed binding of thread credential to process credential, if we
128 * are not running with an explicitly set thread credential.
129 */
130 kauth_cred_uthread_update(uthread, proc);
131
132 callp = (code >= NUM_SYSENT) ? &sysent[63] : &sysent[code];
133
134 if (callp->sy_narg != 0) {
135 void *regsp;
136 sy_munge_t *mungerp;
137
138 if (IS_64BIT_PROCESS(proc)) {
139 /* XXX Turn 64 bit unsafe calls into nosys() */
140 if (callp->sy_flags & UNSAFE_64BIT) {
141 callp = &sysent[63];
142 goto unsafe;
143 }
144 mungerp = callp->sy_arg_munge64;
145 }
146 else {
147 mungerp = callp->sy_arg_munge32;
148 }
149 if ( !flavor) {
150 regsp = (void *) &regs->save_r3;
151 } else {
152 /* indirect system call consumes an argument so only 7 are supported */
153 if (callp->sy_narg > 7) {
154 callp = &sysent[63];
155 goto unsafe;
156 }
157 regsp = (void *) &regs->save_r4;
158 }
159 /* call syscall argument munger to copy in arguments (see xnu/bsd/dev/ppc/munge.s) */
160 (*mungerp)(regsp, (void *) &uthread->uu_arg[0]);
161 }
162
163 unsafe:
164
165 uthread->uu_flag |= UT_NOTCANCELPT;
166
167 uthread->uu_rval[0] = 0;
168
169 /*
170 * r4 is volatile, if we set it to regs->save_r4 here the child
171 * will have parents r4 after execve
172 */
173 uthread->uu_rval[1] = 0;
174
175 error = 0;
176
177 /*
178 * PPC runtime calls cerror after every unix system call, so
179 * assume no error and adjust the "pc" to skip this call.
180 * It will be set back to the cerror call if an error is detected.
181 */
182 regs->save_srr0 += 4;
183
184 #ifdef JOE_DEBUG
185 uthread->uu_iocount = 0;
186 uthread->uu_vpindex = 0;
187 #endif
188 AUDIT_SYSCALL_ENTER(code, proc, uthread);
189 error = (*(callp->sy_call))(proc, (void *)uthread->uu_arg, &(uthread->uu_rval[0]));
190 AUDIT_SYSCALL_EXIT(code, proc, uthread, error);
191 #if CONFIG_MACF
192 mac_thread_userret(code, error, thread_act);
193 #endif
194
195
196 #ifdef JOE_DEBUG
197 if (uthread->uu_iocount)
198 printf("system call returned with uu_iocount != 0\n");
199 #endif
200 #if CONFIG_DTRACE
201 uthread->t_dtrace_errno = error;
202 #endif /* CONFIG_DTRACE */
203
204 regs = find_user_regs(thread_act);
205
206 if (error == ERESTART) {
207 regs->save_srr0 -= 8;
208 } else if (error != EJUSTRETURN) {
209 if (error) {
210 regs->save_r3 = (long long)error;
211 /* set the "pc" to execute cerror routine */
212 regs->save_srr0 -= 4;
213 } else { /* (not error) */
214 switch (callp->sy_return_type) {
215 case _SYSCALL_RET_INT_T:
216 regs->save_r3 = uthread->uu_rval[0];
217 regs->save_r4 = uthread->uu_rval[1];
218 break;
219 case _SYSCALL_RET_UINT_T:
220 regs->save_r3 = ((u_int)uthread->uu_rval[0]);
221 regs->save_r4 = ((u_int)uthread->uu_rval[1]);
222 break;
223 case _SYSCALL_RET_OFF_T:
224 case _SYSCALL_RET_UINT64_T:
225 /* return 64 bits split across two registers for 32 bit */
226 /* process and in one register for 64 bit process */
227 if (IS_64BIT_PROCESS(proc)) {
228 u_int64_t *retp = (u_int64_t *)&uthread->uu_rval[0];
229 regs->save_r3 = *retp;
230 regs->save_r4 = 0;
231 }
232 else {
233 regs->save_r3 = uthread->uu_rval[0];
234 regs->save_r4 = uthread->uu_rval[1];
235 }
236 break;
237 case _SYSCALL_RET_ADDR_T:
238 case _SYSCALL_RET_SIZE_T:
239 case _SYSCALL_RET_SSIZE_T:
240 /* the variable length return types (user_addr_t, user_ssize_t,
241 * and user_size_t) are always the largest possible size in the
242 * kernel (we use uu_rval[0] and [1] as one 64 bit value).
243 */
244 {
245 user_addr_t *retp = (user_addr_t *)&uthread->uu_rval[0];
246 regs->save_r3 = *retp;
247 regs->save_r4 = 0;
248 }
249 break;
250 case _SYSCALL_RET_NONE:
251 break;
252 default:
253 panic("unix_syscall: unknown return type");
254 break;
255 }
256 }
257 }
258 /* else (error == EJUSTRETURN) { nothing } */
259
260
261 uthread->uu_flag &= ~UT_NOTCANCELPT;
262
263 /* panic if funnel is held */
264 syscall_exit_funnelcheck();
265
266 if (uthread->uu_lowpri_window) {
267 /*
268 * task is marked as a low priority I/O type
269 * and the I/O we issued while in this system call
270 * collided with normal I/O operations... we'll
271 * delay in order to mitigate the impact of this
272 * task on the normal operation of the system
273 */
274 throttle_lowpri_io(TRUE);
275 }
276 if (kdebug_enable && (code != 180)) {
277
278 if (callp->sy_return_type == _SYSCALL_RET_SSIZE_T)
279 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
280 error, uthread->uu_rval[1], 0, proc->p_pid, 0);
281 else
282 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
283 error, uthread->uu_rval[0], uthread->uu_rval[1], proc->p_pid, 0);
284 }
285
286 thread_exception_return();
287 /* NOTREACHED */
288 }
289
290 void
291 unix_syscall_return(int error)
292 {
293 thread_t thread_act;
294 struct uthread *uthread;
295 struct proc *proc;
296 struct savearea *regs;
297 unsigned int code;
298 struct sysent *callp;
299
300 thread_act = current_thread();
301 proc = current_proc();
302 uthread = get_bsdthread_info(thread_act);
303
304 regs = find_user_regs(thread_act);
305
306 if (regs->save_r0 != 0)
307 code = regs->save_r0;
308 else
309 code = regs->save_r3;
310
311 callp = (code >= NUM_SYSENT) ? &sysent[63] : &sysent[code];
312
313 #if CONFIG_DTRACE
314 if (callp->sy_call == dtrace_systrace_syscall)
315 dtrace_systrace_syscall_return( code, error, uthread->uu_rval );
316 #endif /* CONFIG_DTRACE */
317 AUDIT_SYSCALL_EXIT(code, proc, uthread, error);
318
319 /*
320 * Get index into sysent table
321 */
322 if (error == ERESTART) {
323 regs->save_srr0 -= 8;
324 } else if (error != EJUSTRETURN) {
325 if (error) {
326 regs->save_r3 = (long long)error;
327 /* set the "pc" to execute cerror routine */
328 regs->save_srr0 -= 4;
329 } else { /* (not error) */
330 switch (callp->sy_return_type) {
331 case _SYSCALL_RET_INT_T:
332 regs->save_r3 = uthread->uu_rval[0];
333 regs->save_r4 = uthread->uu_rval[1];
334 break;
335 case _SYSCALL_RET_UINT_T:
336 regs->save_r3 = ((u_int)uthread->uu_rval[0]);
337 regs->save_r4 = ((u_int)uthread->uu_rval[1]);
338 break;
339 case _SYSCALL_RET_OFF_T:
340 case _SYSCALL_RET_UINT64_T:
341 /* return 64 bits split across two registers for 32 bit */
342 /* process and in one register for 64 bit process */
343 if (IS_64BIT_PROCESS(proc)) {
344 u_int64_t *retp = (u_int64_t *)&uthread->uu_rval[0];
345 regs->save_r3 = *retp;
346 }
347 else {
348 regs->save_r3 = uthread->uu_rval[0];
349 regs->save_r4 = uthread->uu_rval[1];
350 }
351 break;
352 case _SYSCALL_RET_ADDR_T:
353 case _SYSCALL_RET_SIZE_T:
354 case _SYSCALL_RET_SSIZE_T:
355 /* the variable length return types (user_addr_t, user_ssize_t,
356 * and user_size_t) are always the largest possible size in the
357 * kernel (we use uu_rval[0] and [1] as one 64 bit value).
358 */
359 {
360 u_int64_t *retp = (u_int64_t *)&uthread->uu_rval[0];
361 regs->save_r3 = *retp;
362 }
363 break;
364 case _SYSCALL_RET_NONE:
365 break;
366 default:
367 panic("unix_syscall: unknown return type");
368 break;
369 }
370 }
371 }
372 /* else (error == EJUSTRETURN) { nothing } */
373
374
375 uthread->uu_flag &= ~UT_NOTCANCELPT;
376
377 /* panic if funnel is held */
378 syscall_exit_funnelcheck();
379
380 if (uthread->uu_lowpri_window) {
381 /*
382 * task is marked as a low priority I/O type
383 * and the I/O we issued while in this system call
384 * collided with normal I/O operations... we'll
385 * delay in order to mitigate the impact of this
386 * task on the normal operation of the system
387 */
388 throttle_lowpri_io(TRUE);
389 }
390 if (kdebug_enable && (code != 180)) {
391 if (callp->sy_return_type == _SYSCALL_RET_SSIZE_T)
392 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
393 error, uthread->uu_rval[1], 0, proc->p_pid, 0);
394 else
395 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
396 error, uthread->uu_rval[0], uthread->uu_rval[1], proc->p_pid, 0);
397 }
398
399 thread_exception_return();
400 /* NOTREACHED */
401 }
402
403 void
404 munge_lwww(
405 const void *in32,
406 void *out64)
407 {
408 const uint32_t *arg32;
409 uint64_t *arg64;
410
411 arg32 = (const uint32_t *) in32;
412 arg64 = (uint64_t *) out64;
413
414 arg64[3] = arg32[9]; /* lwwW */
415 arg64[2] = arg32[7]; /* lwWw */
416 arg64[1] = arg32[5]; /* lWww */
417 arg64[0] = ((uint64_t) arg32[1]) << 32; /* Lwww (hi) */
418 arg64[0] |= (uint64_t) arg32[3]; /* Lwww (lo) */
419 }
420
421 void
422 munge_lw(
423 const void *in32,
424 void *out64)
425 {
426 const uint32_t *arg32;
427 uint64_t *arg64;
428
429 arg32 = (const uint32_t *) in32;
430 arg64 = (uint64_t *) out64;
431
432 arg64[1] = arg32[5]; /* lW */
433 arg64[0] = ((uint64_t) arg32[1]) << 32; /* Lw (hi) */
434 arg64[0] |= (uint64_t) arg32[3]; /* Lw (lo) */
435 }