]>
git.saurik.com Git - apple/xnu.git/blob - bsd/dev/ppc/systemcalls.c
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 #include <kern/task.h>
24 #include <kern/thread.h>
25 #include <kern/assert.h>
26 #include <kern/clock.h>
27 #include <kern/locks.h>
28 #include <kern/sched_prim.h>
29 #include <mach/machine/thread_status.h>
30 #include <ppc/savearea.h>
32 #include <sys/kernel.h>
34 #include <sys/proc_internal.h>
35 #include <sys/syscall.h>
36 #include <sys/systm.h>
38 #include <sys/errno.h>
39 #include <sys/ktrace.h>
40 #include <sys/kdebug.h>
41 #include <sys/sysent.h>
42 #include <sys/sysproto.h>
43 #include <sys/kauth.h>
45 #include <bsm/audit_kernel.h>
48 unix_syscall(struct savearea
*regs
);
50 unix_syscall_return(int error
);
52 extern struct savearea
*
56 extern void enter_funnel_section(funnel_t
*funnel_lock
);
57 extern void exit_funnel_section(void);
60 * Function: unix_syscall
62 * Inputs: regs - pointer to Process Control Block
67 unix_syscall(struct savearea
*regs
)
70 struct uthread
*uthread
;
77 unsigned int cancel_enable
;
79 flavor
= (((unsigned int)regs
->save_r0
) == 0)? 1: 0;
86 if (kdebug_enable
&& (code
!= 180)) {
88 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_START
,
89 regs
->save_r4
, regs
->save_r5
, regs
->save_r6
, regs
->save_r7
, 0);
91 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_START
,
92 regs
->save_r3
, regs
->save_r4
, regs
->save_r5
, regs
->save_r6
, 0);
94 thread_act
= current_thread();
95 uthread
= get_bsdthread_info(thread_act
);
97 if (!(uthread
->uu_flag
& UT_VFORK
))
98 proc
= (struct proc
*)get_bsdtask_info(current_task());
100 proc
= current_proc();
103 * Delayed binding of thread credential to process credential, if we
104 * are not running with an explicitly set thread credential.
106 if (uthread
->uu_ucred
!= proc
->p_ucred
&&
107 (uthread
->uu_flag
& UT_SETUID
) == 0) {
108 kauth_cred_t old
= uthread
->uu_ucred
;
110 uthread
->uu_ucred
= proc
->p_ucred
;
111 kauth_cred_ref(uthread
->uu_ucred
);
114 kauth_cred_rele(old
);
117 uthread
->uu_ar0
= (int *)regs
;
119 callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
121 if (callp
->sy_narg
!= 0) {
125 if (IS_64BIT_PROCESS(proc
)) {
126 /* XXX Turn 64 bit unsafe calls into nosys() */
127 if (callp
->sy_funnel
& UNSAFE_64BIT
) {
131 mungerp
= callp
->sy_arg_munge64
;
134 mungerp
= callp
->sy_arg_munge32
;
137 regsp
= (void *) ®s
->save_r3
;
139 /* indirect system call consumes an argument so only 7 are supported */
140 if (callp
->sy_narg
> 7) {
144 regsp
= (void *) ®s
->save_r4
;
146 /* call syscall argument munger to copy in arguments (see xnu/bsd/dev/ppc/munge.s) */
147 (*mungerp
)(regsp
, (void *) &uthread
->uu_arg
[0]);
151 cancel_enable
= callp
->sy_cancel
;
153 if (cancel_enable
== _SYSCALL_CANCEL_NONE
) {
154 uthread
->uu_flag
|= UT_NOTCANCELPT
;
156 if((uthread
->uu_flag
& (UT_CANCELDISABLE
| UT_CANCEL
| UT_CANCELED
)) == UT_CANCEL
) {
157 if (cancel_enable
== _SYSCALL_CANCEL_PRE
) {
158 /* system call cancelled; return to handle cancellation */
159 regs
->save_r3
= (long long)EINTR
;
160 thread_exception_return();
163 thread_abort_safely(thread_act
);
168 funnel_type
= (int)(callp
->sy_funnel
& FUNNEL_MASK
);
169 if (funnel_type
== KERNEL_FUNNEL
)
170 enter_funnel_section(kernel_flock
);
172 uthread
->uu_rval
[0] = 0;
175 * r4 is volatile, if we set it to regs->save_r4 here the child
176 * will have parents r4 after execve
178 uthread
->uu_rval
[1] = 0;
183 * PPC runtime calls cerror after every unix system call, so
184 * assume no error and adjust the "pc" to skip this call.
185 * It will be set back to the cerror call if an error is detected.
187 regs
->save_srr0
+= 4;
189 if (KTRPOINT(proc
, KTR_SYSCALL
))
190 ktrsyscall(proc
, code
, callp
->sy_narg
, uthread
->uu_arg
);
193 uthread
->uu_iocount
= 0;
194 uthread
->uu_vpindex
= 0;
196 AUDIT_SYSCALL_ENTER(code
, proc
, uthread
);
197 error
= (*(callp
->sy_call
))(proc
, (void *)uthread
->uu_arg
, &(uthread
->uu_rval
[0]));
198 AUDIT_SYSCALL_EXIT(error
, proc
, uthread
);
201 if (uthread
->uu_iocount
)
202 joe_debug("system call returned with uu_iocount != 0");
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 /* off_t returns 64 bits split across two registers for 32 bit */
225 /* process and in one register for 64 bit process */
226 if (IS_64BIT_PROCESS(proc
)) {
227 u_int64_t
*retp
= (u_int64_t
*)&uthread
->uu_rval
[0];
228 regs
->save_r3
= *retp
;
232 regs
->save_r3
= uthread
->uu_rval
[0];
233 regs
->save_r4
= uthread
->uu_rval
[1];
236 case _SYSCALL_RET_ADDR_T
:
237 case _SYSCALL_RET_SIZE_T
:
238 case _SYSCALL_RET_SSIZE_T
:
239 /* the variable length return types (user_addr_t, user_ssize_t,
240 * and user_size_t) are always the largest possible size in the
241 * kernel (we use uu_rval[0] and [1] as one 64 bit value).
244 user_addr_t
*retp
= (user_addr_t
*)&uthread
->uu_rval
[0];
245 regs
->save_r3
= *retp
;
249 case _SYSCALL_RET_NONE
:
252 panic("unix_syscall: unknown return type");
257 /* else (error == EJUSTRETURN) { nothing } */
260 if (KTRPOINT(proc
, KTR_SYSRET
)) {
261 switch(callp
->sy_return_type
) {
262 case _SYSCALL_RET_ADDR_T
:
263 case _SYSCALL_RET_SIZE_T
:
264 case _SYSCALL_RET_SSIZE_T
:
266 * Trace the value of the least significant bits,
267 * until we can revise the ktrace API safely.
269 ktrsysret(proc
, code
, error
, uthread
->uu_rval
[1]);
272 ktrsysret(proc
, code
, error
, uthread
->uu_rval
[0]);
277 if (cancel_enable
== _SYSCALL_CANCEL_NONE
)
278 uthread
->uu_flag
&= ~UT_NOTCANCELPT
;
280 exit_funnel_section();
282 if (uthread
->uu_lowpri_delay
) {
284 * task is marked as a low priority I/O type
285 * and the I/O we issued while in this system call
286 * collided with normal I/O operations... we'll
287 * delay in order to mitigate the impact of this
288 * task on the normal operation of the system
290 IOSleep(uthread
->uu_lowpri_delay
);
291 uthread
->uu_lowpri_delay
= 0;
293 if (kdebug_enable
&& (code
!= 180)) {
295 if (callp
->sy_return_type
== _SYSCALL_RET_SSIZE_T
)
296 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_END
,
297 error
, uthread
->uu_rval
[1], 0, 0, 0);
299 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_END
,
300 error
, uthread
->uu_rval
[0], uthread
->uu_rval
[1], 0, 0);
303 thread_exception_return();
308 unix_syscall_return(int error
)
311 struct uthread
*uthread
;
313 struct savearea
*regs
;
315 struct sysent
*callp
;
317 unsigned int cancel_enable
;
319 thread_act
= current_thread();
320 proc
= current_proc();
321 uthread
= get_bsdthread_info(thread_act
);
323 regs
= find_user_regs(thread_act
);
325 if (regs
->save_r0
!= 0)
326 code
= regs
->save_r0
;
328 code
= regs
->save_r3
;
330 callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
333 * Get index into sysent table
335 if (error
== ERESTART
) {
336 regs
->save_srr0
-= 8;
337 } else if (error
!= EJUSTRETURN
) {
339 regs
->save_r3
= (long long)error
;
340 /* set the "pc" to execute cerror routine */
341 regs
->save_srr0
-= 4;
342 } else { /* (not error) */
343 switch (callp
->sy_return_type
) {
344 case _SYSCALL_RET_INT_T
:
345 regs
->save_r3
= uthread
->uu_rval
[0];
346 regs
->save_r4
= uthread
->uu_rval
[1];
348 case _SYSCALL_RET_UINT_T
:
349 regs
->save_r3
= ((u_int
)uthread
->uu_rval
[0]);
350 regs
->save_r4
= ((u_int
)uthread
->uu_rval
[1]);
352 case _SYSCALL_RET_OFF_T
:
353 /* off_t returns 64 bits split across two registers for 32 bit */
354 /* process and in one register for 64 bit process */
355 if (IS_64BIT_PROCESS(proc
)) {
356 u_int64_t
*retp
= (u_int64_t
*)&uthread
->uu_rval
[0];
357 regs
->save_r3
= *retp
;
360 regs
->save_r3
= uthread
->uu_rval
[0];
361 regs
->save_r4
= uthread
->uu_rval
[1];
364 case _SYSCALL_RET_ADDR_T
:
365 case _SYSCALL_RET_SIZE_T
:
366 case _SYSCALL_RET_SSIZE_T
:
367 /* the variable length return types (user_addr_t, user_ssize_t,
368 * and user_size_t) are always the largest possible size in the
369 * kernel (we use uu_rval[0] and [1] as one 64 bit value).
372 u_int64_t
*retp
= (u_int64_t
*)&uthread
->uu_rval
[0];
373 regs
->save_r3
= *retp
;
376 case _SYSCALL_RET_NONE
:
379 panic("unix_syscall: unknown return type");
384 /* else (error == EJUSTRETURN) { nothing } */
386 if (KTRPOINT(proc
, KTR_SYSRET
)) {
387 switch(callp
->sy_return_type
) {
388 case _SYSCALL_RET_ADDR_T
:
389 case _SYSCALL_RET_SIZE_T
:
390 case _SYSCALL_RET_SSIZE_T
:
392 * Trace the value of the least significant bits,
393 * until we can revise the ktrace API safely.
395 ktrsysret(proc
, code
, error
, uthread
->uu_rval
[1]);
398 ktrsysret(proc
, code
, error
, uthread
->uu_rval
[0]);
403 cancel_enable
= callp
->sy_cancel
;
405 if (cancel_enable
== _SYSCALL_CANCEL_NONE
)
406 uthread
->uu_flag
&= ~UT_NOTCANCELPT
;
408 exit_funnel_section();
410 if (uthread
->uu_lowpri_delay
) {
412 * task is marked as a low priority I/O type
413 * and the I/O we issued while in this system call
414 * collided with normal I/O operations... we'll
415 * delay in order to mitigate the impact of this
416 * task on the normal operation of the system
418 IOSleep(uthread
->uu_lowpri_delay
);
419 uthread
->uu_lowpri_delay
= 0;
421 if (kdebug_enable
&& (code
!= 180)) {
422 if (callp
->sy_return_type
== _SYSCALL_RET_SSIZE_T
)
423 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_END
,
424 error
, uthread
->uu_rval
[1], 0, 0, 0);
426 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_END
,
427 error
, uthread
->uu_rval
[0], uthread
->uu_rval
[1], 0, 0);
430 thread_exception_return();
435 * Time of day and interval timer support.
437 * These routines provide the kernel entry points to get and set
438 * the time-of-day and per-process interval timers. Subroutines
439 * here provide support for adding and subtracting timeval structures
440 * and decrementing interval timers, optionally reloading the interval
441 * timers when they expire.
443 /* NOTE THIS implementation is for ppc architectures only.
444 * It is infrequently called, since the commpage intercepts
445 * most calls in user mode.
447 * XXX Y2038 bug because of assumed return of 32 bit seconds value, and
448 * XXX first parameter to clock_gettimeofday()
451 ppc_gettimeofday(__unused
struct proc
*p
,
452 register struct ppc_gettimeofday_args
*uap
,
456 extern lck_spin_t
* tz_slock
;
459 clock_gettimeofday(&retval
[0], &retval
[1]);
464 lck_spin_lock(tz_slock
);
466 lck_spin_unlock(tz_slock
);
467 error
= copyout((caddr_t
)<z
, uap
->tzp
, sizeof (tz
));
482 * WARNING - this is a temporary workaround for binary compatibility issues
483 * with anti-piracy software that relies on patching ptrace (3928003).
484 * This KPI will be removed in the system release after Tiger.
486 uintptr_t temp_patch_ptrace(uintptr_t new_ptrace
)
488 struct sysent
* callp
;
489 sy_call_t
* old_ptrace
;
494 enter_funnel_section(kernel_flock
);
496 old_ptrace
= callp
->sy_call
;
498 /* only allow one patcher of ptrace */
499 if (old_ptrace
== (sy_call_t
*) ptrace
) {
500 callp
->sy_call
= (sy_call_t
*) new_ptrace
;
505 exit_funnel_section( );
507 return((uintptr_t)old_ptrace
);
510 void temp_unpatch_ptrace(void)
512 struct sysent
* callp
;
514 enter_funnel_section(kernel_flock
);
516 callp
->sy_call
= (sy_call_t
*) ptrace
;
517 exit_funnel_section( );