]>
git.saurik.com Git - apple/xnu.git/blob - bsd/dev/ppc/systemcalls.c
2 * Copyright (c) 2000-2005 Apple Computer, 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 #include <kern/task.h>
30 #include <kern/thread.h>
31 #include <kern/assert.h>
32 #include <kern/clock.h>
33 #include <kern/locks.h>
34 #include <kern/sched_prim.h>
35 #include <mach/machine/thread_status.h>
36 #include <ppc/savearea.h>
38 #include <sys/kernel.h>
40 #include <sys/proc_internal.h>
41 #include <sys/syscall.h>
42 #include <sys/systm.h>
44 #include <sys/errno.h>
45 #include <sys/ktrace.h>
46 #include <sys/kdebug.h>
47 #include <sys/sysent.h>
48 #include <sys/sysproto.h>
49 #include <sys/kauth.h>
51 #include <bsm/audit_kernel.h>
54 unix_syscall(struct savearea
*regs
);
56 unix_syscall_return(int error
);
58 extern struct savearea
*
62 extern void enter_funnel_section(funnel_t
*funnel_lock
);
63 extern void exit_funnel_section(void);
66 * Function: unix_syscall
68 * Inputs: regs - pointer to Process Control Block
73 unix_syscall(struct savearea
*regs
)
76 struct uthread
*uthread
;
83 unsigned int cancel_enable
;
85 flavor
= (((unsigned int)regs
->save_r0
) == 0)? 1: 0;
92 if (kdebug_enable
&& (code
!= 180)) {
94 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_START
,
95 regs
->save_r4
, regs
->save_r5
, regs
->save_r6
, regs
->save_r7
, 0);
97 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_START
,
98 regs
->save_r3
, regs
->save_r4
, regs
->save_r5
, regs
->save_r6
, 0);
100 thread_act
= current_thread();
101 uthread
= get_bsdthread_info(thread_act
);
103 if (!(uthread
->uu_flag
& UT_VFORK
))
104 proc
= (struct proc
*)get_bsdtask_info(current_task());
106 proc
= current_proc();
108 /* Make sure there is a process associated with this task */
110 regs
->save_r3
= (long long)EPERM
;
111 /* set the "pc" to execute cerror routine */
112 regs
->save_srr0
-= 4;
113 task_terminate_internal(current_task());
114 thread_exception_return();
119 * Delayed binding of thread credential to process credential, if we
120 * are not running with an explicitly set thread credential.
122 if (uthread
->uu_ucred
!= proc
->p_ucred
&&
123 (uthread
->uu_flag
& UT_SETUID
) == 0) {
124 kauth_cred_t old
= uthread
->uu_ucred
;
125 uthread
->uu_ucred
= kauth_cred_proc_ref(proc
);
126 if (IS_VALID_CRED(old
))
127 kauth_cred_unref(&old
);
130 callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
132 if (callp
->sy_narg
!= 0) {
136 if (IS_64BIT_PROCESS(proc
)) {
137 /* XXX Turn 64 bit unsafe calls into nosys() */
138 if (callp
->sy_funnel
& UNSAFE_64BIT
) {
142 mungerp
= callp
->sy_arg_munge64
;
145 mungerp
= callp
->sy_arg_munge32
;
148 regsp
= (void *) ®s
->save_r3
;
150 /* indirect system call consumes an argument so only 7 are supported */
151 if (callp
->sy_narg
> 7) {
155 regsp
= (void *) ®s
->save_r4
;
157 /* call syscall argument munger to copy in arguments (see xnu/bsd/dev/ppc/munge.s) */
158 (*mungerp
)(regsp
, (void *) &uthread
->uu_arg
[0]);
162 cancel_enable
= callp
->sy_cancel
;
164 if (cancel_enable
== _SYSCALL_CANCEL_NONE
) {
165 uthread
->uu_flag
|= UT_NOTCANCELPT
;
167 if((uthread
->uu_flag
& (UT_CANCELDISABLE
| UT_CANCEL
| UT_CANCELED
)) == UT_CANCEL
) {
168 if (cancel_enable
== _SYSCALL_CANCEL_PRE
) {
169 /* system call cancelled; return to handle cancellation */
170 regs
->save_r3
= (long long)EINTR
;
171 thread_exception_return();
174 thread_abort_safely(thread_act
);
179 funnel_type
= (int)(callp
->sy_funnel
& FUNNEL_MASK
);
180 if (funnel_type
== KERNEL_FUNNEL
)
181 enter_funnel_section(kernel_flock
);
183 uthread
->uu_rval
[0] = 0;
186 * r4 is volatile, if we set it to regs->save_r4 here the child
187 * will have parents r4 after execve
189 uthread
->uu_rval
[1] = 0;
194 * PPC runtime calls cerror after every unix system call, so
195 * assume no error and adjust the "pc" to skip this call.
196 * It will be set back to the cerror call if an error is detected.
198 regs
->save_srr0
+= 4;
200 if (KTRPOINT(proc
, KTR_SYSCALL
))
201 ktrsyscall(proc
, code
, callp
->sy_narg
, uthread
->uu_arg
);
204 uthread
->uu_iocount
= 0;
205 uthread
->uu_vpindex
= 0;
207 AUDIT_SYSCALL_ENTER(code
, proc
, uthread
);
208 error
= (*(callp
->sy_call
))(proc
, (void *)uthread
->uu_arg
, &(uthread
->uu_rval
[0]));
209 AUDIT_SYSCALL_EXIT(error
, proc
, uthread
);
212 if (uthread
->uu_iocount
)
213 joe_debug("system call returned with uu_iocount != 0");
215 regs
= find_user_regs(thread_act
);
217 if (error
== ERESTART
) {
218 regs
->save_srr0
-= 8;
219 } else if (error
!= EJUSTRETURN
) {
221 regs
->save_r3
= (long long)error
;
222 /* set the "pc" to execute cerror routine */
223 regs
->save_srr0
-= 4;
224 } else { /* (not error) */
225 switch (callp
->sy_return_type
) {
226 case _SYSCALL_RET_INT_T
:
227 regs
->save_r3
= uthread
->uu_rval
[0];
228 regs
->save_r4
= uthread
->uu_rval
[1];
230 case _SYSCALL_RET_UINT_T
:
231 regs
->save_r3
= ((u_int
)uthread
->uu_rval
[0]);
232 regs
->save_r4
= ((u_int
)uthread
->uu_rval
[1]);
234 case _SYSCALL_RET_OFF_T
:
235 /* off_t returns 64 bits split across two registers for 32 bit */
236 /* process and in one register for 64 bit process */
237 if (IS_64BIT_PROCESS(proc
)) {
238 u_int64_t
*retp
= (u_int64_t
*)&uthread
->uu_rval
[0];
239 regs
->save_r3
= *retp
;
243 regs
->save_r3
= uthread
->uu_rval
[0];
244 regs
->save_r4
= uthread
->uu_rval
[1];
247 case _SYSCALL_RET_ADDR_T
:
248 case _SYSCALL_RET_SIZE_T
:
249 case _SYSCALL_RET_SSIZE_T
:
250 /* the variable length return types (user_addr_t, user_ssize_t,
251 * and user_size_t) are always the largest possible size in the
252 * kernel (we use uu_rval[0] and [1] as one 64 bit value).
255 user_addr_t
*retp
= (user_addr_t
*)&uthread
->uu_rval
[0];
256 regs
->save_r3
= *retp
;
260 case _SYSCALL_RET_NONE
:
263 panic("unix_syscall: unknown return type");
268 /* else (error == EJUSTRETURN) { nothing } */
271 if (KTRPOINT(proc
, KTR_SYSRET
)) {
272 switch(callp
->sy_return_type
) {
273 case _SYSCALL_RET_ADDR_T
:
274 case _SYSCALL_RET_SIZE_T
:
275 case _SYSCALL_RET_SSIZE_T
:
277 * Trace the value of the least significant bits,
278 * until we can revise the ktrace API safely.
280 ktrsysret(proc
, code
, error
, uthread
->uu_rval
[1]);
283 ktrsysret(proc
, code
, error
, uthread
->uu_rval
[0]);
288 if (cancel_enable
== _SYSCALL_CANCEL_NONE
)
289 uthread
->uu_flag
&= ~UT_NOTCANCELPT
;
291 exit_funnel_section();
293 if (uthread
->uu_lowpri_delay
) {
295 * task is marked as a low priority I/O type
296 * and the I/O we issued while in this system call
297 * collided with normal I/O operations... we'll
298 * delay in order to mitigate the impact of this
299 * task on the normal operation of the system
301 IOSleep(uthread
->uu_lowpri_delay
);
302 uthread
->uu_lowpri_delay
= 0;
304 if (kdebug_enable
&& (code
!= 180)) {
306 if (callp
->sy_return_type
== _SYSCALL_RET_SSIZE_T
)
307 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_END
,
308 error
, uthread
->uu_rval
[1], 0, 0, 0);
310 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_END
,
311 error
, uthread
->uu_rval
[0], uthread
->uu_rval
[1], 0, 0);
314 thread_exception_return();
319 unix_syscall_return(int error
)
322 struct uthread
*uthread
;
324 struct savearea
*regs
;
326 struct sysent
*callp
;
327 unsigned int cancel_enable
;
329 thread_act
= current_thread();
330 proc
= current_proc();
331 uthread
= get_bsdthread_info(thread_act
);
333 regs
= find_user_regs(thread_act
);
335 if (regs
->save_r0
!= 0)
336 code
= regs
->save_r0
;
338 code
= regs
->save_r3
;
340 callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
343 * Get index into sysent table
345 if (error
== ERESTART
) {
346 regs
->save_srr0
-= 8;
347 } else if (error
!= EJUSTRETURN
) {
349 regs
->save_r3
= (long long)error
;
350 /* set the "pc" to execute cerror routine */
351 regs
->save_srr0
-= 4;
352 } else { /* (not error) */
353 switch (callp
->sy_return_type
) {
354 case _SYSCALL_RET_INT_T
:
355 regs
->save_r3
= uthread
->uu_rval
[0];
356 regs
->save_r4
= uthread
->uu_rval
[1];
358 case _SYSCALL_RET_UINT_T
:
359 regs
->save_r3
= ((u_int
)uthread
->uu_rval
[0]);
360 regs
->save_r4
= ((u_int
)uthread
->uu_rval
[1]);
362 case _SYSCALL_RET_OFF_T
:
363 /* off_t returns 64 bits split across two registers for 32 bit */
364 /* process and in one register for 64 bit process */
365 if (IS_64BIT_PROCESS(proc
)) {
366 u_int64_t
*retp
= (u_int64_t
*)&uthread
->uu_rval
[0];
367 regs
->save_r3
= *retp
;
370 regs
->save_r3
= uthread
->uu_rval
[0];
371 regs
->save_r4
= uthread
->uu_rval
[1];
374 case _SYSCALL_RET_ADDR_T
:
375 case _SYSCALL_RET_SIZE_T
:
376 case _SYSCALL_RET_SSIZE_T
:
377 /* the variable length return types (user_addr_t, user_ssize_t,
378 * and user_size_t) are always the largest possible size in the
379 * kernel (we use uu_rval[0] and [1] as one 64 bit value).
382 u_int64_t
*retp
= (u_int64_t
*)&uthread
->uu_rval
[0];
383 regs
->save_r3
= *retp
;
386 case _SYSCALL_RET_NONE
:
389 panic("unix_syscall: unknown return type");
394 /* else (error == EJUSTRETURN) { nothing } */
396 if (KTRPOINT(proc
, KTR_SYSRET
)) {
397 switch(callp
->sy_return_type
) {
398 case _SYSCALL_RET_ADDR_T
:
399 case _SYSCALL_RET_SIZE_T
:
400 case _SYSCALL_RET_SSIZE_T
:
402 * Trace the value of the least significant bits,
403 * until we can revise the ktrace API safely.
405 ktrsysret(proc
, code
, error
, uthread
->uu_rval
[1]);
408 ktrsysret(proc
, code
, error
, uthread
->uu_rval
[0]);
413 cancel_enable
= callp
->sy_cancel
;
415 if (cancel_enable
== _SYSCALL_CANCEL_NONE
)
416 uthread
->uu_flag
&= ~UT_NOTCANCELPT
;
418 exit_funnel_section();
420 if (uthread
->uu_lowpri_delay
) {
422 * task is marked as a low priority I/O type
423 * and the I/O we issued while in this system call
424 * collided with normal I/O operations... we'll
425 * delay in order to mitigate the impact of this
426 * task on the normal operation of the system
428 IOSleep(uthread
->uu_lowpri_delay
);
429 uthread
->uu_lowpri_delay
= 0;
431 if (kdebug_enable
&& (code
!= 180)) {
432 if (callp
->sy_return_type
== _SYSCALL_RET_SSIZE_T
)
433 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_END
,
434 error
, uthread
->uu_rval
[1], 0, 0, 0);
436 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_END
,
437 error
, uthread
->uu_rval
[0], uthread
->uu_rval
[1], 0, 0);
440 thread_exception_return();