]> git.saurik.com Git - apple/xnu.git/blame - bsd/dev/i386/systemcalls.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / dev / i386 / systemcalls.c
CommitLineData
0c530ab8 1/*
39037602 2 * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
0c530ab8 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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
0c530ab8
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
0c530ab8
A
27 */
28#include <kern/task.h>
29#include <kern/thread.h>
30#include <kern/assert.h>
31#include <kern/clock.h>
32#include <kern/locks.h>
33#include <kern/sched_prim.h>
b0d623f7 34#include <kern/debug.h>
0c530ab8
A
35#include <mach/machine/thread_status.h>
36#include <mach/thread_act.h>
37
38#include <sys/kernel.h>
39#include <sys/vm.h>
40#include <sys/proc_internal.h>
41#include <sys/syscall.h>
42#include <sys/systm.h>
43#include <sys/user.h>
44#include <sys/errno.h>
0c530ab8
A
45#include <sys/kdebug.h>
46#include <sys/sysent.h>
47#include <sys/sysproto.h>
48#include <sys/kauth.h>
49#include <sys/systm.h>
cb323159 50#include <sys/bitstring.h>
0c530ab8 51
b0d623f7 52#include <security/audit/audit.h>
0c530ab8
A
53
54#include <i386/seg.h>
55#include <i386/machine_routines.h>
56#include <mach/i386/syscall_sw.h>
57
6d2010ae
A
58#include <machine/pal_routines.h>
59
cb323159
A
60#if CONFIG_MACF
61#include <security/mac_framework.h>
62#endif
63
2d21ac55
A
64#if CONFIG_DTRACE
65extern int32_t dtrace_systrace_syscall(struct proc *, void *, int *);
66extern void dtrace_systrace_syscall_return(unsigned short, int, int *);
67#endif
68
0c530ab8
A
69extern void unix_syscall(x86_saved_state_t *);
70extern void unix_syscall64(x86_saved_state_t *);
0c530ab8 71extern void *find_user_regs(thread_t);
0c530ab8 72
b0d623f7
A
73/* dynamically generated at build time based on syscalls.master */
74extern const char *syscallnames[];
75
3e170ce0 76#define code_is_kdebug_trace(code) (((code) == SYS_kdebug_trace) || \
0a7de745
A
77 ((code) == SYS_kdebug_trace64) || \
78 ((code) == SYS_kdebug_trace_string))
a1c7dba1 79
0c530ab8
A
80/*
81 * Function: unix_syscall
82 *
83 * Inputs: regs - pointer to i386 save area
84 *
85 * Outputs: none
86 */
39037602 87__attribute__((noreturn))
0c530ab8
A
88void
89unix_syscall(x86_saved_state_t *state)
90{
0a7de745
A
91 thread_t thread;
92 void *vt;
cb323159 93 unsigned int code, syscode;
f427ee49 94 const struct sysent *callp;
0a7de745
A
95
96 int error;
97 vm_offset_t params;
98 struct proc *p;
99 struct uthread *uthread;
100 x86_saved_state32_t *regs;
101 boolean_t is_vfork;
102 pid_t pid;
0c530ab8
A
103
104 assert(is_saved_state32(state));
105 regs = saved_state32(state);
2d21ac55 106#if DEBUG
0a7de745 107 if (regs->eax == 0x800) {
0c530ab8 108 thread_exception_return();
0a7de745 109 }
2d21ac55 110#endif
0c530ab8
A
111 thread = current_thread();
112 uthread = get_bsdthread_info(thread);
113
3e170ce0 114 uthread_reset_proc_refcount(uthread);
3e170ce0 115
0c530ab8 116 /* Get the approriate proc; may be different from task's for vfork() */
6d2010ae 117 is_vfork = uthread->uu_flag & UT_VFORK;
0a7de745 118 if (__improbable(is_vfork != 0)) {
0c530ab8 119 p = current_proc();
0a7de745 120 } else {
6d2010ae 121 p = (struct proc *)get_bsdtask_info(current_task());
0a7de745 122 }
0c530ab8 123
cb323159
A
124 code = regs->eax & I386_SYSCALL_NUMBER_MASK;
125 syscode = (code < nsysent) ? code : SYS_invalid;
b0d623f7 126 DEBUG_KPRINT_SYSCALL_UNIX("unix_syscall: code=%d(%s) eip=%u\n",
cb323159 127 code, syscallnames[syscode], (uint32_t)regs->eip);
0a7de745 128 params = (vm_offset_t) (regs->uesp + sizeof(int));
2d21ac55
A
129
130 regs->efl &= ~(EFL_CF);
131
cb323159 132 callp = &sysent[syscode];
0c530ab8 133
6d2010ae 134 if (__improbable(callp == sysent)) {
0c530ab8 135 code = fuword(params);
2d21ac55 136 params += sizeof(int);
cb323159
A
137 syscode = (code < nsysent) ? code : SYS_invalid;
138 callp = &sysent[syscode];
0c530ab8 139 }
2d21ac55 140
0c530ab8
A
141 vt = (void *)uthread->uu_arg;
142
2d21ac55 143 if (callp->sy_arg_bytes != 0) {
fe8ab488 144#if CONFIG_REQUIRES_U32_MUNGING
0a7de745 145 sy_munge_t *mungerp;
fe8ab488
A
146#else
147#error U32 syscalls on x86_64 kernel requires munging
148#endif
0a7de745 149 uint32_t nargs;
0c530ab8 150
0a7de745 151 assert((unsigned) callp->sy_arg_bytes <= sizeof(uthread->uu_arg));
39236c6e
A
152 nargs = callp->sy_arg_bytes;
153 error = copyin((user_addr_t) params, (char *) vt, nargs);
154 if (error) {
155 regs->eax = error;
156 regs->efl |= EFL_CF;
157 thread_exception_return();
158 /* NOTREACHED */
0c530ab8 159 }
2d21ac55 160
a1c7dba1 161 if (__probable(!code_is_kdebug_trace(code))) {
cb323159
A
162 uint32_t *uip = vt;
163 KDBG_RELEASE(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
164 uip[0], uip[1], uip[2], uip[3]);
0c530ab8 165 }
fe8ab488
A
166
167#if CONFIG_REQUIRES_U32_MUNGING
0c530ab8
A
168 mungerp = callp->sy_arg_munge32;
169
0a7de745 170 if (mungerp != NULL) {
fe8ab488 171 (*mungerp)(vt);
0a7de745 172 }
fe8ab488 173#endif
0a7de745 174 } else {
cb323159 175 KDBG_RELEASE(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START);
0a7de745 176 }
2d21ac55 177
0c530ab8
A
178 /*
179 * Delayed binding of thread credential to process credential, if we
180 * are not running with an explicitly set thread credential.
181 */
2d21ac55 182 kauth_cred_uthread_update(uthread, p);
0c530ab8
A
183
184 uthread->uu_rval[0] = 0;
fe8ab488 185 uthread->uu_rval[1] = 0;
2d21ac55 186 uthread->uu_flag |= UT_NOTCANCELPT;
fe8ab488 187 uthread->syscall_code = code;
743345f9 188 pid = proc_pid(p);
0c530ab8 189
2d21ac55 190#ifdef JOE_DEBUG
0a7de745
A
191 uthread->uu_iocount = 0;
192 uthread->uu_vpindex = 0;
2d21ac55 193#endif
0c530ab8 194
cb323159
A
195#if CONFIG_MACF
196 if (__improbable(p->syscall_filter_mask != NULL && !bitstr_test(p->syscall_filter_mask, syscode))) {
197 error = mac_proc_check_syscall_unix(p, syscode);
198 if (error) {
199 goto skip_syscall;
200 }
201 }
202#endif /* CONFIG_MACF */
203
0c530ab8
A
204 AUDIT_SYSCALL_ENTER(code, p, uthread);
205 error = (*(callp->sy_call))((void *) p, (void *) vt, &(uthread->uu_rval[0]));
fe8ab488 206 AUDIT_SYSCALL_EXIT(code, p, uthread, error);
2d21ac55 207
cb323159
A
208#if CONFIG_MACF
209skip_syscall:
210#endif /* CONFIG_MACF */
211
2d21ac55 212#ifdef JOE_DEBUG
0a7de745
A
213 if (uthread->uu_iocount) {
214 printf("system call returned with uu_iocount != 0\n");
215 }
2d21ac55
A
216#endif
217#if CONFIG_DTRACE
218 uthread->t_dtrace_errno = error;
219#endif /* CONFIG_DTRACE */
220
6d2010ae 221 if (__improbable(error == ERESTART)) {
0c530ab8
A
222 /*
223 * Move the user's pc back to repeat the syscall:
224 * 5 bytes for a sysenter, or 2 for an int 8x.
225 * The SYSENTER_TF_CS covers single-stepping over a sysenter
226 * - see debug trap handler in idt.s/idt64.s
227 */
b0d623f7 228
6d2010ae 229 pal_syscall_restart(thread, state);
0a7de745 230 } else if (error != EJUSTRETURN) {
6d2010ae 231 if (__improbable(error)) {
0a7de745
A
232 regs->eax = error;
233 regs->efl |= EFL_CF; /* carry bit */
0c530ab8 234 } else { /* (not error) */
0a7de745
A
235 /*
236 * We split retval across two registers, in case the
237 * syscall had a 64-bit return value, in which case
238 * eax/edx matches the function call ABI.
239 */
240 regs->eax = uthread->uu_rval[0];
241 regs->edx = uthread->uu_rval[1];
242 }
0c530ab8
A
243 }
244
b0d623f7
A
245 DEBUG_KPRINT_SYSCALL_UNIX(
246 "unix_syscall: error=%d retval=(%u,%u)\n",
247 error, regs->eax, regs->edx);
248
2d21ac55 249 uthread->uu_flag &= ~UT_NOTCANCELPT;
0a7de745 250 uthread->syscall_code = 0;
6d2010ae 251
5ba3f43e
A
252#if DEBUG || DEVELOPMENT
253 kern_allocation_name_t
254 prior __assert_only = thread_set_allocation_name(NULL);
255 assertf(prior == NULL, "thread_set_allocation_name(\"%s\") not cleared", kern_allocation_get_name(prior));
256#endif /* DEBUG || DEVELOPMENT */
257
6d2010ae 258 if (__improbable(uthread->uu_lowpri_window)) {
0a7de745 259 /*
0c530ab8
A
260 * task is marked as a low priority I/O type
261 * and the I/O we issued while in this system call
262 * collided with normal I/O operations... we'll
263 * delay in order to mitigate the impact of this
264 * task on the normal operation of the system
265 */
39236c6e 266 throttle_lowpri_io(1);
0c530ab8 267 }
0a7de745 268 if (__probable(!code_is_kdebug_trace(code))) {
cb323159
A
269 KDBG_RELEASE(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
270 error, uthread->uu_rval[0], uthread->uu_rval[1], pid);
0a7de745 271 }
b0d623f7 272
6d2010ae
A
273 if (__improbable(!is_vfork && callp->sy_call == (sy_call_t *)execve && !error)) {
274 pal_execve_return(thread);
275 }
0c530ab8 276
3e170ce0
A
277#if PROC_REF_DEBUG
278 if (__improbable(uthread_get_proc_refcount(uthread) != 0)) {
279 panic("system call returned with uu_proc_refcount != 0");
280 }
281#endif
282
0c530ab8
A
283 thread_exception_return();
284 /* NOTREACHED */
285}
286
39037602 287__attribute__((noreturn))
0c530ab8
A
288void
289unix_syscall64(x86_saved_state_t *state)
290{
0a7de745
A
291 thread_t thread;
292 void *vt;
cb323159 293 unsigned int code, syscode;
f427ee49 294 const struct sysent *callp;
0a7de745
A
295 int args_in_regs;
296 boolean_t args_start_at_rdi;
297 int error;
298 struct proc *p;
299 struct uthread *uthread;
0c530ab8 300 x86_saved_state64_t *regs;
0a7de745 301 pid_t pid;
0c530ab8
A
302
303 assert(is_saved_state64(state));
304 regs = saved_state64(state);
0a7de745
A
305#if DEBUG
306 if (regs->rax == 0x2000800) {
0c530ab8 307 thread_exception_return();
0a7de745 308 }
6d2010ae 309#endif
0c530ab8
A
310 thread = current_thread();
311 uthread = get_bsdthread_info(thread);
312
3e170ce0 313 uthread_reset_proc_refcount(uthread);
3e170ce0 314
0c530ab8 315 /* Get the approriate proc; may be different from task's for vfork() */
0a7de745 316 if (__probable(!(uthread->uu_flag & UT_VFORK))) {
0c530ab8 317 p = (struct proc *)get_bsdtask_info(current_task());
0a7de745 318 } else {
0c530ab8 319 p = current_proc();
0a7de745 320 }
0c530ab8
A
321
322 /* Verify that we are not being called from a task without a proc */
6d2010ae 323 if (__improbable(p == NULL)) {
0c530ab8
A
324 regs->rax = EPERM;
325 regs->isf.rflags |= EFL_CF;
326 task_terminate_internal(current_task());
327 thread_exception_return();
328 /* NOTREACHED */
329 }
0c530ab8 330
cb323159
A
331 code = regs->rax & SYSCALL_NUMBER_MASK;
332 syscode = (code < nsysent) ? code : SYS_invalid;
b0d623f7
A
333 DEBUG_KPRINT_SYSCALL_UNIX(
334 "unix_syscall64: code=%d(%s) rip=%llx\n",
cb323159
A
335 code, syscallnames[syscode], regs->isf.rip);
336 callp = &sysent[syscode];
fe8ab488
A
337
338 vt = (void *)uthread->uu_arg;
0c530ab8 339
6d2010ae 340 if (__improbable(callp == sysent)) {
0a7de745 341 /*
0c530ab8
A
342 * indirect system call... system call number
343 * passed as 'arg0'
344 */
cb323159
A
345 code = regs->rdi;
346 syscode = (code < nsysent) ? code : SYS_invalid;
347 callp = &sysent[syscode];
fe8ab488 348 args_start_at_rdi = FALSE;
0c530ab8 349 args_in_regs = 5;
fe8ab488
A
350 } else {
351 args_start_at_rdi = TRUE;
352 args_in_regs = 6;
0c530ab8
A
353 }
354
355 if (callp->sy_narg != 0) {
fe8ab488
A
356 assert(callp->sy_narg <= 8); /* size of uu_arg */
357
358 args_in_regs = MIN(args_in_regs, callp->sy_narg);
359 memcpy(vt, args_start_at_rdi ? &regs->rdi : &regs->rsi, args_in_regs * sizeof(syscall_arg_t));
360
a1c7dba1 361 if (!code_is_kdebug_trace(code)) {
cb323159 362 uint64_t *uip = vt;
0c530ab8 363
cb323159
A
364 KDBG_RELEASE(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
365 uip[0], uip[1], uip[2], uip[3]);
0c530ab8 366 }
0c530ab8 367
6d2010ae 368 if (__improbable(callp->sy_narg > args_in_regs)) {
2d21ac55 369 int copyin_count;
0c530ab8 370
fe8ab488 371 copyin_count = (callp->sy_narg - args_in_regs) * sizeof(syscall_arg_t);
0c530ab8 372
fe8ab488 373 error = copyin((user_addr_t)(regs->isf.rsp + sizeof(user_addr_t)), (char *)&uthread->uu_arg[args_in_regs], copyin_count);
0c530ab8 374 if (error) {
2d21ac55 375 regs->rax = error;
0c530ab8
A
376 regs->isf.rflags |= EFL_CF;
377 thread_exception_return();
378 /* NOTREACHED */
379 }
380 }
0a7de745 381 } else {
cb323159 382 KDBG_RELEASE(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START);
0a7de745 383 }
0c530ab8
A
384
385 /*
386 * Delayed binding of thread credential to process credential, if we
387 * are not running with an explicitly set thread credential.
388 */
2d21ac55 389 kauth_cred_uthread_update(uthread, p);
0c530ab8
A
390
391 uthread->uu_rval[0] = 0;
392 uthread->uu_rval[1] = 0;
2d21ac55 393 uthread->uu_flag |= UT_NOTCANCELPT;
fe8ab488 394 uthread->syscall_code = code;
743345f9 395 pid = proc_pid(p);
0c530ab8 396
6d2010ae 397#ifdef JOE_DEBUG
0a7de745
A
398 uthread->uu_iocount = 0;
399 uthread->uu_vpindex = 0;
6d2010ae 400#endif
0c530ab8 401
cb323159
A
402#if CONFIG_MACF
403 if (__improbable(p->syscall_filter_mask != NULL && !bitstr_test(p->syscall_filter_mask, syscode))) {
404 error = mac_proc_check_syscall_unix(p, syscode);
405 if (error) {
406 goto skip_syscall;
407 }
408 }
409#endif /* CONFIG_MACF */
410
0c530ab8 411 AUDIT_SYSCALL_ENTER(code, p, uthread);
fe8ab488
A
412 error = (*(callp->sy_call))((void *) p, vt, &(uthread->uu_rval[0]));
413 AUDIT_SYSCALL_EXIT(code, p, uthread, error);
2d21ac55 414
cb323159
A
415#if CONFIG_MACF
416skip_syscall:
417#endif /* CONFIG_MACF */
418
6d2010ae 419#ifdef JOE_DEBUG
0a7de745
A
420 if (uthread->uu_iocount) {
421 printf("system call returned with uu_iocount != 0\n");
422 }
6d2010ae
A
423#endif
424
2d21ac55
A
425#if CONFIG_DTRACE
426 uthread->t_dtrace_errno = error;
427#endif /* CONFIG_DTRACE */
0a7de745 428
6d2010ae 429 if (__improbable(error == ERESTART)) {
0c530ab8
A
430 /*
431 * all system calls come through via the syscall instruction
432 * in 64 bit mode... its 2 bytes in length
433 * move the user's pc back to repeat the syscall:
434 */
6d2010ae 435 pal_syscall_restart( thread, state );
0a7de745 436 } else if (error != EJUSTRETURN) {
6d2010ae 437 if (__improbable(error)) {
2d21ac55 438 regs->rax = error;
0a7de745 439 regs->isf.rflags |= EFL_CF; /* carry bit */
0c530ab8 440 } else { /* (not error) */
0c530ab8
A
441 switch (callp->sy_return_type) {
442 case _SYSCALL_RET_INT_T:
443 regs->rax = uthread->uu_rval[0];
444 regs->rdx = uthread->uu_rval[1];
445 break;
446 case _SYSCALL_RET_UINT_T:
447 regs->rax = ((u_int)uthread->uu_rval[0]);
448 regs->rdx = ((u_int)uthread->uu_rval[1]);
449 break;
450 case _SYSCALL_RET_OFF_T:
451 case _SYSCALL_RET_ADDR_T:
452 case _SYSCALL_RET_SIZE_T:
453 case _SYSCALL_RET_SSIZE_T:
d1ecb069 454 case _SYSCALL_RET_UINT64_T:
0a7de745 455 regs->rax = *((uint64_t *)(&uthread->uu_rval[0]));
0c530ab8
A
456 regs->rdx = 0;
457 break;
458 case _SYSCALL_RET_NONE:
459 break;
460 default:
461 panic("unix_syscall: unknown return type");
462 break;
463 }
464 regs->isf.rflags &= ~EFL_CF;
0a7de745 465 }
0c530ab8
A
466 }
467
b0d623f7
A
468 DEBUG_KPRINT_SYSCALL_UNIX(
469 "unix_syscall64: error=%d retval=(%llu,%llu)\n",
470 error, regs->rax, regs->rdx);
0a7de745 471
2d21ac55 472 uthread->uu_flag &= ~UT_NOTCANCELPT;
0a7de745 473 uthread->syscall_code = 0;
0c530ab8 474
5ba3f43e
A
475#if DEBUG || DEVELOPMENT
476 kern_allocation_name_t
477 prior __assert_only = thread_set_allocation_name(NULL);
478 assertf(prior == NULL, "thread_set_allocation_name(\"%s\") not cleared", kern_allocation_get_name(prior));
479#endif /* DEBUG || DEVELOPMENT */
480
6d2010ae 481 if (__improbable(uthread->uu_lowpri_window)) {
0a7de745 482 /*
0c530ab8
A
483 * task is marked as a low priority I/O type
484 * and the I/O we issued while in this system call
485 * collided with normal I/O operations... we'll
486 * delay in order to mitigate the impact of this
487 * task on the normal operation of the system
488 */
39236c6e 489 throttle_lowpri_io(1);
0c530ab8 490 }
0a7de745 491 if (__probable(!code_is_kdebug_trace(code))) {
cb323159
A
492 KDBG_RELEASE(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
493 error, uthread->uu_rval[0], uthread->uu_rval[1], pid);
0a7de745 494 }
0c530ab8 495
3e170ce0
A
496#if PROC_REF_DEBUG
497 if (__improbable(uthread_get_proc_refcount(uthread))) {
498 panic("system call returned with uu_proc_refcount != 0");
499 }
500#endif
501
0c530ab8
A
502 thread_exception_return();
503 /* NOTREACHED */
504}
505
506
507void
508unix_syscall_return(int error)
509{
0a7de745
A
510 thread_t thread;
511 struct uthread *uthread;
0c530ab8
A
512 struct proc *p;
513 unsigned int code;
f427ee49 514 const struct sysent *callp;
0c530ab8
A
515
516 thread = current_thread();
517 uthread = get_bsdthread_info(thread);
518
6d2010ae 519 pal_register_cache_state(thread, DIRTY);
b0d623f7 520
0c530ab8
A
521 p = current_proc();
522
523 if (proc_is64bit(p)) {
2d21ac55 524 x86_saved_state64_t *regs;
0c530ab8
A
525
526 regs = saved_state64(find_user_regs(thread));
527
fe8ab488 528 code = uthread->syscall_code;
39037602 529 callp = (code >= nsysent) ? &sysent[SYS_invalid] : &sysent[code];
0c530ab8 530
2d21ac55 531#if CONFIG_DTRACE
0a7de745 532 if (callp->sy_call == dtrace_systrace_syscall) {
2d21ac55 533 dtrace_systrace_syscall_return( code, error, uthread->uu_rval );
0a7de745 534 }
2d21ac55 535#endif /* CONFIG_DTRACE */
b0d623f7 536 AUDIT_SYSCALL_EXIT(code, p, uthread, error);
0c530ab8
A
537
538 if (error == ERESTART) {
2d21ac55 539 /*
6d2010ae 540 * repeat the syscall
0c530ab8 541 */
0a7de745
A
542 pal_syscall_restart( thread, find_user_regs(thread));
543 } else if (error != EJUSTRETURN) {
2d21ac55
A
544 if (error) {
545 regs->rax = error;
0a7de745 546 regs->isf.rflags |= EFL_CF; /* carry bit */
0c530ab8 547 } else { /* (not error) */
2d21ac55 548 switch (callp->sy_return_type) {
0c530ab8 549 case _SYSCALL_RET_INT_T:
2d21ac55 550 regs->rax = uthread->uu_rval[0];
0c530ab8
A
551 regs->rdx = uthread->uu_rval[1];
552 break;
553 case _SYSCALL_RET_UINT_T:
2d21ac55 554 regs->rax = ((u_int)uthread->uu_rval[0]);
0c530ab8
A
555 regs->rdx = ((u_int)uthread->uu_rval[1]);
556 break;
557 case _SYSCALL_RET_OFF_T:
558 case _SYSCALL_RET_ADDR_T:
559 case _SYSCALL_RET_SIZE_T:
560 case _SYSCALL_RET_SSIZE_T:
d1ecb069 561 case _SYSCALL_RET_UINT64_T:
2d21ac55 562 regs->rax = *((uint64_t *)(&uthread->uu_rval[0]));
0c530ab8
A
563 regs->rdx = 0;
564 break;
565 case _SYSCALL_RET_NONE:
2d21ac55 566 break;
0c530ab8 567 default:
2d21ac55 568 panic("unix_syscall: unknown return type");
0c530ab8
A
569 break;
570 }
571 regs->isf.rflags &= ~EFL_CF;
0a7de745 572 }
0c530ab8 573 }
b0d623f7
A
574 DEBUG_KPRINT_SYSCALL_UNIX(
575 "unix_syscall_return: error=%d retval=(%llu,%llu)\n",
576 error, regs->rax, regs->rdx);
0c530ab8 577 } else {
0a7de745 578 x86_saved_state32_t *regs;
0c530ab8
A
579
580 regs = saved_state32(find_user_regs(thread));
581
2d21ac55 582 regs->efl &= ~(EFL_CF);
fe8ab488
A
583
584 code = uthread->syscall_code;
39037602 585 callp = (code >= nsysent) ? &sysent[SYS_invalid] : &sysent[code];
2d21ac55
A
586
587#if CONFIG_DTRACE
0a7de745 588 if (callp->sy_call == dtrace_systrace_syscall) {
2d21ac55 589 dtrace_systrace_syscall_return( code, error, uthread->uu_rval );
0a7de745 590 }
2d21ac55 591#endif /* CONFIG_DTRACE */
b0d623f7 592 AUDIT_SYSCALL_EXIT(code, p, uthread, error);
0c530ab8 593
0c530ab8 594 if (error == ERESTART) {
0a7de745
A
595 pal_syscall_restart( thread, find_user_regs(thread));
596 } else if (error != EJUSTRETURN) {
2d21ac55
A
597 if (error) {
598 regs->eax = error;
0a7de745 599 regs->efl |= EFL_CF; /* carry bit */
0c530ab8 600 } else { /* (not error) */
2d21ac55 601 regs->eax = uthread->uu_rval[0];
0c530ab8 602 regs->edx = uthread->uu_rval[1];
0a7de745 603 }
0c530ab8 604 }
b0d623f7
A
605 DEBUG_KPRINT_SYSCALL_UNIX(
606 "unix_syscall_return: error=%d retval=(%u,%u)\n",
607 error, regs->eax, regs->edx);
0c530ab8 608 }
0c530ab8 609
0c530ab8 610
2d21ac55 611 uthread->uu_flag &= ~UT_NOTCANCELPT;
0c530ab8 612
5ba3f43e
A
613#if DEBUG || DEVELOPMENT
614 kern_allocation_name_t
615 prior __assert_only = thread_set_allocation_name(NULL);
616 assertf(prior == NULL, "thread_set_allocation_name(\"%s\") not cleared", kern_allocation_get_name(prior));
617#endif /* DEBUG || DEVELOPMENT */
618
593a1d5f 619 if (uthread->uu_lowpri_window) {
0a7de745 620 /*
0c530ab8
A
621 * task is marked as a low priority I/O type
622 * and the I/O we issued while in this system call
623 * collided with normal I/O operations... we'll
624 * delay in order to mitigate the impact of this
625 * task on the normal operation of the system
626 */
39236c6e 627 throttle_lowpri_io(1);
0c530ab8 628 }
0a7de745 629 if (!code_is_kdebug_trace(code)) {
cb323159
A
630 KDBG_RELEASE(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
631 error, uthread->uu_rval[0], uthread->uu_rval[1], p->p_pid);
0a7de745 632 }
0c530ab8
A
633
634 thread_exception_return();
635 /* NOTREACHED */
636}