- ** the PPC runtime calls cerror after every unix system call, so
- ** assume no error and adjust the "pc" to skip this call.
- ** It will be set back to the cerror call if an error is detected.
- */
- regs->srr0 += 4;
- vt = get_bsduthreadarg(thread);
- p = ((struct proc *)get_bsdtask_info(current_task()));
- error = (*(callp->sy_call))(p, (caddr_t)vt, rval);
-
- if (error == ERESTART) {
- regs->srr0 -= 8;
- }
- else if (error != EJUSTRETURN) {
- if (error)
- {
- regs->r3 = error;
- /* set the "pc" to execute cerror routine */
- regs->srr0 -= 4;
- } else { /* (not error) */
- regs->r3 = rval[0];
- regs->r4 = rval[1];
- }
- }
- /* else (error == EJUSTRETURN) { nothing } */
-
- thread_exception_return();
- /* NOTREACHED */
-
+ * Get index into sysent table
+ */
+ if (error == ERESTART) {
+ regs->save_srr0 -= 8;
+ } else if (error != EJUSTRETURN) {
+ if (error) {
+ regs->save_r3 = (long long)error;
+ /* set the "pc" to execute cerror routine */
+ regs->save_srr0 -= 4;
+ } else { /* (not error) */
+ switch (callp->sy_return_type) {
+ case _SYSCALL_RET_INT_T:
+ regs->save_r3 = uthread->uu_rval[0];
+ regs->save_r4 = uthread->uu_rval[1];
+ break;
+ case _SYSCALL_RET_UINT_T:
+ regs->save_r3 = ((u_int)uthread->uu_rval[0]);
+ regs->save_r4 = ((u_int)uthread->uu_rval[1]);
+ break;
+ case _SYSCALL_RET_OFF_T:
+ /* off_t returns 64 bits split across two registers for 32 bit */
+ /* process and in one register for 64 bit process */
+ if (IS_64BIT_PROCESS(proc)) {
+ u_int64_t *retp = (u_int64_t *)&uthread->uu_rval[0];
+ regs->save_r3 = *retp;
+ }
+ else {
+ regs->save_r3 = uthread->uu_rval[0];
+ regs->save_r4 = uthread->uu_rval[1];
+ }
+ break;
+ case _SYSCALL_RET_ADDR_T:
+ case _SYSCALL_RET_SIZE_T:
+ case _SYSCALL_RET_SSIZE_T:
+ /* the variable length return types (user_addr_t, user_ssize_t,
+ * and user_size_t) are always the largest possible size in the
+ * kernel (we use uu_rval[0] and [1] as one 64 bit value).
+ */
+ {
+ u_int64_t *retp = (u_int64_t *)&uthread->uu_rval[0];
+ regs->save_r3 = *retp;
+ }
+ break;
+ case _SYSCALL_RET_NONE:
+ break;
+ default:
+ panic("unix_syscall: unknown return type");
+ break;
+ }
+ }
+ }
+ /* else (error == EJUSTRETURN) { nothing } */
+
+ if (KTRPOINT(proc, KTR_SYSRET)) {
+ switch(callp->sy_return_type) {
+ case _SYSCALL_RET_ADDR_T:
+ case _SYSCALL_RET_SIZE_T:
+ case _SYSCALL_RET_SSIZE_T:
+ /*
+ * Trace the value of the least significant bits,
+ * until we can revise the ktrace API safely.
+ */
+ ktrsysret(proc, code, error, uthread->uu_rval[1]);
+ break;
+ default:
+ ktrsysret(proc, code, error, uthread->uu_rval[0]);
+ break;
+ }
+ }
+
+ cancel_enable = callp->sy_cancel;
+
+ if (cancel_enable == _SYSCALL_CANCEL_NONE)
+ uthread->uu_flag &= ~UT_NOTCANCELPT;
+
+ exit_funnel_section();
+
+ if (uthread->uu_lowpri_delay) {
+ /*
+ * task is marked as a low priority I/O type
+ * and the I/O we issued while in this system call
+ * collided with normal I/O operations... we'll
+ * delay in order to mitigate the impact of this
+ * task on the normal operation of the system
+ */
+ IOSleep(uthread->uu_lowpri_delay);
+ uthread->uu_lowpri_delay = 0;
+ }
+ if (kdebug_enable && (code != 180)) {
+ if (callp->sy_return_type == _SYSCALL_RET_SSIZE_T)
+ KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
+ error, uthread->uu_rval[1], 0, 0, 0);
+ else
+ KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
+ error, uthread->uu_rval[0], uthread->uu_rval[1], 0, 0);
+ }
+
+ thread_exception_return();
+ /* NOTREACHED */