]>
git.saurik.com Git - apple/xnu.git/blob - bsd/dev/ppc/systemcalls.c
2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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,
35 #include <mach/mach_traps.h>
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>
47 #include <sys/kernel.h>
49 #include <sys/proc_internal.h>
50 #include <sys/syscall.h>
51 #include <sys/systm.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>
59 #include <security/audit/audit.h>
62 extern int32_t dtrace_systrace_syscall(struct proc
*, void *, int *);
63 extern void dtrace_systrace_syscall_return(unsigned short, int, int *);
67 unix_syscall(struct savearea
*regs
);
69 extern struct savearea
*
73 extern lck_spin_t
* tz_slock
;
76 * Function: unix_syscall
78 * Inputs: regs - pointer to Process Control Block
83 unix_syscall(struct savearea
*regs
)
86 struct uthread
*uthread
;
93 flavor
= (((unsigned int)regs
->save_r0
) == 0)? 1: 0;
100 if (kdebug_enable
&& (code
!= 180)) {
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);
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);
108 thread_act
= current_thread();
109 uthread
= get_bsdthread_info(thread_act
);
111 if (!(uthread
->uu_flag
& UT_VFORK
))
112 proc
= (struct proc
*)get_bsdtask_info(current_task());
114 proc
= current_proc();
116 /* Make sure there is a process associated with this task */
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();
127 * Delayed binding of thread credential to process credential, if we
128 * are not running with an explicitly set thread credential.
130 kauth_cred_uthread_update(uthread
, proc
);
132 callp
= (code
>= NUM_SYSENT
) ? &sysent
[63] : &sysent
[code
];
134 if (callp
->sy_narg
!= 0) {
138 if (IS_64BIT_PROCESS(proc
)) {
139 /* XXX Turn 64 bit unsafe calls into nosys() */
140 if (callp
->sy_flags
& UNSAFE_64BIT
) {
144 mungerp
= callp
->sy_arg_munge64
;
147 mungerp
= callp
->sy_arg_munge32
;
150 regsp
= (void *) ®s
->save_r3
;
152 /* indirect system call consumes an argument so only 7 are supported */
153 if (callp
->sy_narg
> 7) {
157 regsp
= (void *) ®s
->save_r4
;
159 /* call syscall argument munger to copy in arguments (see xnu/bsd/dev/ppc/munge.s) */
160 (*mungerp
)(regsp
, (void *) &uthread
->uu_arg
[0]);
165 uthread
->uu_flag
|= UT_NOTCANCELPT
;
167 uthread
->uu_rval
[0] = 0;
170 * r4 is volatile, if we set it to regs->save_r4 here the child
171 * will have parents r4 after execve
173 uthread
->uu_rval
[1] = 0;
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.
182 regs
->save_srr0
+= 4;
185 uthread
->uu_iocount
= 0;
186 uthread
->uu_vpindex
= 0;
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
);
192 mac_thread_userret(code
, error
, thread_act
);
197 if (uthread
->uu_iocount
)
198 printf("system call returned with uu_iocount != 0\n");
201 uthread
->t_dtrace_errno
= error
;
202 #endif /* CONFIG_DTRACE */
204 regs
= find_user_regs(thread_act
);
206 if (error
== ERESTART
) {
207 regs
->save_srr0
-= 8;
208 } else if (error
!= EJUSTRETURN
) {
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];
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]);
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
;
233 regs
->save_r3
= uthread
->uu_rval
[0];
234 regs
->save_r4
= uthread
->uu_rval
[1];
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).
245 user_addr_t
*retp
= (user_addr_t
*)&uthread
->uu_rval
[0];
246 regs
->save_r3
= *retp
;
250 case _SYSCALL_RET_NONE
:
253 panic("unix_syscall: unknown return type");
258 /* else (error == EJUSTRETURN) { nothing } */
261 uthread
->uu_flag
&= ~UT_NOTCANCELPT
;
263 /* panic if funnel is held */
264 syscall_exit_funnelcheck();
266 if (uthread
->uu_lowpri_window
) {
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
274 throttle_lowpri_io(TRUE
);
276 if (kdebug_enable
&& (code
!= 180)) {
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);
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);
286 thread_exception_return();
291 unix_syscall_return(int error
)
294 struct uthread
*uthread
;
296 struct savearea
*regs
;
298 struct sysent
*callp
;
300 thread_act
= current_thread();
301 proc
= current_proc();
302 uthread
= get_bsdthread_info(thread_act
);
304 regs
= find_user_regs(thread_act
);
306 if (regs
->save_r0
!= 0)
307 code
= regs
->save_r0
;
309 code
= regs
->save_r3
;
311 callp
= (code
>= NUM_SYSENT
) ? &sysent
[63] : &sysent
[code
];
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
);
320 * Get index into sysent table
322 if (error
== ERESTART
) {
323 regs
->save_srr0
-= 8;
324 } else if (error
!= EJUSTRETURN
) {
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];
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]);
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
;
348 regs
->save_r3
= uthread
->uu_rval
[0];
349 regs
->save_r4
= uthread
->uu_rval
[1];
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).
360 u_int64_t
*retp
= (u_int64_t
*)&uthread
->uu_rval
[0];
361 regs
->save_r3
= *retp
;
364 case _SYSCALL_RET_NONE
:
367 panic("unix_syscall: unknown return type");
372 /* else (error == EJUSTRETURN) { nothing } */
375 uthread
->uu_flag
&= ~UT_NOTCANCELPT
;
377 /* panic if funnel is held */
378 syscall_exit_funnelcheck();
380 if (uthread
->uu_lowpri_window
) {
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
388 throttle_lowpri_io(TRUE
);
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);
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);
399 thread_exception_return();
408 const uint32_t *arg32
;
411 arg32
= (const uint32_t *) in32
;
412 arg64
= (uint64_t *) out64
;
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) */
426 const uint32_t *arg32
;
429 arg32
= (const uint32_t *) in32
;
430 arg64
= (uint64_t *) out64
;
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) */