]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/bsd_i386.c
a70d68ae3668ee7af40b9085d36e81044f049689
[apple/xnu.git] / osfmk / i386 / bsd_i386.c
1 /*
2 * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 #ifdef MACH_BSD
29 #include <mach_rt.h>
30 #include <mach_debug.h>
31 #include <mach_ldebug.h>
32
33 #include <mach/kern_return.h>
34 #include <mach/mach_traps.h>
35 #include <mach/thread_status.h>
36 #include <mach/vm_param.h>
37
38 #include <kern/counters.h>
39 #include <kern/cpu_data.h>
40 #include <kern/mach_param.h>
41 #include <kern/task.h>
42 #include <kern/thread.h>
43 #include <kern/sched_prim.h>
44 #include <kern/misc_protos.h>
45 #include <kern/assert.h>
46 #include <kern/debug.h>
47 #include <kern/spl.h>
48 #include <kern/syscall_sw.h>
49 #include <ipc/ipc_port.h>
50 #include <vm/vm_kern.h>
51 #include <vm/pmap.h>
52
53 #include <i386/cpu_number.h>
54 #include <i386/eflags.h>
55 #include <i386/proc_reg.h>
56 #include <i386/tss.h>
57 #include <i386/user_ldt.h>
58 #include <i386/fpu.h>
59 #include <i386/machdep_call.h>
60 #include <i386/vmparam.h>
61 #include <i386/mp_desc.h>
62 #include <i386/misc_protos.h>
63 #include <i386/thread.h>
64 #include <i386/trap.h>
65 #include <i386/seg.h>
66 #include <mach/i386/syscall_sw.h>
67 #include <sys/syscall.h>
68 #include <sys/kdebug.h>
69 #include <sys/errno.h>
70 #include <../bsd/sys/sysent.h>
71
72 #ifdef MACH_BSD
73 extern void mach_kauth_cred_uthread_update(void);
74 extern void throttle_lowpri_io(int);
75 #endif
76
77 void * find_user_regs(thread_t);
78
79 unsigned int get_msr_exportmask(void);
80
81 unsigned int get_msr_nbits(void);
82
83 unsigned int get_msr_rbits(void);
84
85 /*
86 * thread_userstack:
87 *
88 * Return the user stack pointer from the machine
89 * dependent thread state info.
90 */
91 kern_return_t
92 thread_userstack(
93 __unused thread_t thread,
94 int flavor,
95 thread_state_t tstate,
96 __unused unsigned int count,
97 mach_vm_offset_t *user_stack,
98 int *customstack
99 )
100 {
101 if (customstack)
102 *customstack = 0;
103
104 switch (flavor) {
105 case x86_THREAD_STATE32:
106 {
107 x86_thread_state32_t *state25;
108
109 state25 = (x86_thread_state32_t *) tstate;
110
111 if (state25->esp) {
112 *user_stack = state25->esp;
113 if (customstack)
114 *customstack = 1;
115 } else {
116 *user_stack = VM_USRSTACK32;
117 if (customstack)
118 *customstack = 0;
119 }
120 break;
121 }
122
123 case x86_THREAD_STATE64:
124 {
125 x86_thread_state64_t *state25;
126
127 state25 = (x86_thread_state64_t *) tstate;
128
129 if (state25->rsp) {
130 *user_stack = state25->rsp;
131 if (customstack)
132 *customstack = 1;
133 } else {
134 *user_stack = VM_USRSTACK64;
135 if (customstack)
136 *customstack = 0;
137 }
138 break;
139 }
140
141 default:
142 return (KERN_INVALID_ARGUMENT);
143 }
144
145 return (KERN_SUCCESS);
146 }
147
148 /*
149 * thread_userstackdefault:
150 *
151 * Return the default stack location for the
152 * thread, if otherwise unknown.
153 */
154 kern_return_t
155 thread_userstackdefault(
156 thread_t thread,
157 mach_vm_offset_t *default_user_stack)
158 {
159 if (thread_is_64bit(thread)) {
160 *default_user_stack = VM_USRSTACK64;
161 } else {
162 *default_user_stack = VM_USRSTACK32;
163 }
164 return (KERN_SUCCESS);
165 }
166
167 kern_return_t
168 thread_entrypoint(
169 __unused thread_t thread,
170 int flavor,
171 thread_state_t tstate,
172 __unused unsigned int count,
173 mach_vm_offset_t *entry_point
174 )
175 {
176 /*
177 * Set a default.
178 */
179 if (*entry_point == 0)
180 *entry_point = VM_MIN_ADDRESS;
181
182 switch (flavor) {
183 case x86_THREAD_STATE32:
184 {
185 x86_thread_state32_t *state25;
186
187 state25 = (i386_thread_state_t *) tstate;
188 *entry_point = state25->eip ? state25->eip: VM_MIN_ADDRESS;
189 break;
190 }
191
192 case x86_THREAD_STATE64:
193 {
194 x86_thread_state64_t *state25;
195
196 state25 = (x86_thread_state64_t *) tstate;
197 *entry_point = state25->rip ? state25->rip: VM_MIN_ADDRESS64;
198 break;
199 }
200 }
201 return (KERN_SUCCESS);
202 }
203
204 /*
205 * FIXME - thread_set_child
206 */
207
208 void thread_set_child(thread_t child, int pid);
209 void
210 thread_set_child(thread_t child, int pid)
211 {
212 pal_register_cache_state(child, DIRTY);
213
214 if (thread_is_64bit(child)) {
215 x86_saved_state64_t *iss64;
216
217 iss64 = USER_REGS64(child);
218
219 iss64->rax = pid;
220 iss64->rdx = 1;
221 iss64->isf.rflags &= ~EFL_CF;
222 } else {
223 x86_saved_state32_t *iss32;
224
225 iss32 = USER_REGS32(child);
226
227 iss32->eax = pid;
228 iss32->edx = 1;
229 iss32->efl &= ~EFL_CF;
230 }
231 }
232
233
234
235 /*
236 * System Call handling code
237 */
238
239 extern long fuword(vm_offset_t);
240
241
242
243 void
244 machdep_syscall(x86_saved_state_t *state)
245 {
246 int args[machdep_call_count];
247 int trapno;
248 int nargs;
249 const machdep_call_t *entry;
250 x86_saved_state32_t *regs;
251
252 assert(is_saved_state32(state));
253 regs = saved_state32(state);
254
255 trapno = regs->eax;
256 #if DEBUG_TRACE
257 kprintf("machdep_syscall(0x%08x) code=%d\n", regs, trapno);
258 #endif
259
260 DEBUG_KPRINT_SYSCALL_MDEP(
261 "machdep_syscall: trapno=%d\n", trapno);
262
263 if (trapno < 0 || trapno >= machdep_call_count) {
264 regs->eax = (unsigned int)kern_invalid(NULL);
265
266 thread_exception_return();
267 /* NOTREACHED */
268 }
269 entry = &machdep_call_table[trapno];
270 nargs = entry->nargs;
271
272 if (nargs != 0) {
273 if (copyin((user_addr_t) regs->uesp + sizeof (int),
274 (char *) args, (nargs * sizeof (int)))) {
275 regs->eax = KERN_INVALID_ADDRESS;
276
277 thread_exception_return();
278 /* NOTREACHED */
279 }
280 }
281 switch (nargs) {
282 case 0:
283 regs->eax = (*entry->routine.args_0)();
284 break;
285 case 1:
286 regs->eax = (*entry->routine.args_1)(args[0]);
287 break;
288 case 2:
289 regs->eax = (*entry->routine.args_2)(args[0],args[1]);
290 break;
291 case 3:
292 if (!entry->bsd_style)
293 regs->eax = (*entry->routine.args_3)(args[0],args[1],args[2]);
294 else {
295 int error;
296 uint32_t rval;
297
298 error = (*entry->routine.args_bsd_3)(&rval, args[0], args[1], args[2]);
299 if (error) {
300 regs->eax = error;
301 regs->efl |= EFL_CF; /* carry bit */
302 } else {
303 regs->eax = rval;
304 regs->efl &= ~EFL_CF;
305 }
306 }
307 break;
308 case 4:
309 regs->eax = (*entry->routine.args_4)(args[0], args[1], args[2], args[3]);
310 break;
311
312 default:
313 panic("machdep_syscall: too many args");
314 }
315
316 DEBUG_KPRINT_SYSCALL_MDEP("machdep_syscall: retval=%u\n", regs->eax);
317
318 throttle_lowpri_io(1);
319
320 thread_exception_return();
321 /* NOTREACHED */
322 }
323
324
325 void
326 machdep_syscall64(x86_saved_state_t *state)
327 {
328 int trapno;
329 const machdep_call_t *entry;
330 x86_saved_state64_t *regs;
331
332 assert(is_saved_state64(state));
333 regs = saved_state64(state);
334
335 trapno = (int)(regs->rax & SYSCALL_NUMBER_MASK);
336
337 DEBUG_KPRINT_SYSCALL_MDEP(
338 "machdep_syscall64: trapno=%d\n", trapno);
339
340 if (trapno < 0 || trapno >= machdep_call_count) {
341 regs->rax = (unsigned int)kern_invalid(NULL);
342
343 thread_exception_return();
344 /* NOTREACHED */
345 }
346 entry = &machdep_call_table64[trapno];
347
348 switch (entry->nargs) {
349 case 0:
350 regs->rax = (*entry->routine.args_0)();
351 break;
352 case 1:
353 regs->rax = (*entry->routine.args64_1)(regs->rdi);
354 break;
355 case 2:
356 regs->rax = (*entry->routine.args64_2)(regs->rdi, regs->rsi);
357 break;
358 default:
359 panic("machdep_syscall64: too many args");
360 }
361
362 DEBUG_KPRINT_SYSCALL_MDEP("machdep_syscall: retval=%llu\n", regs->rax);
363
364 throttle_lowpri_io(1);
365
366 thread_exception_return();
367 /* NOTREACHED */
368 }
369
370 #endif /* MACH_BSD */
371
372
373 typedef kern_return_t (*mach_call_t)(void *);
374
375 struct mach_call_args {
376 syscall_arg_t arg1;
377 syscall_arg_t arg2;
378 syscall_arg_t arg3;
379 syscall_arg_t arg4;
380 syscall_arg_t arg5;
381 syscall_arg_t arg6;
382 syscall_arg_t arg7;
383 syscall_arg_t arg8;
384 syscall_arg_t arg9;
385 };
386
387 static kern_return_t
388 mach_call_arg_munger32(uint32_t sp, struct mach_call_args *args, const mach_trap_t *trapp);
389
390
391 static kern_return_t
392 mach_call_arg_munger32(uint32_t sp, struct mach_call_args *args, const mach_trap_t *trapp)
393 {
394 if (copyin((user_addr_t)(sp + sizeof(int)), (char *)args, trapp->mach_trap_u32_words * sizeof (int)))
395 return KERN_INVALID_ARGUMENT;
396 #if CONFIG_REQUIRES_U32_MUNGING
397 trapp->mach_trap_arg_munge32(args);
398 #else
399 #error U32 mach traps on x86_64 kernel requires munging
400 #endif
401 return KERN_SUCCESS;
402 }
403
404
405 __private_extern__ void mach_call_munger(x86_saved_state_t *state);
406
407 extern const char *mach_syscall_name_table[];
408
409 void
410 mach_call_munger(x86_saved_state_t *state)
411 {
412 int argc;
413 int call_number;
414 mach_call_t mach_call;
415 kern_return_t retval;
416 struct mach_call_args args = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
417 x86_saved_state32_t *regs;
418
419 #if PROC_REF_DEBUG
420 struct uthread *ut = get_bsdthread_info(current_thread());
421
422 uthread_reset_proc_refcount(ut);
423 #endif
424
425 assert(is_saved_state32(state));
426 regs = saved_state32(state);
427
428 call_number = -(regs->eax);
429
430 DEBUG_KPRINT_SYSCALL_MACH(
431 "mach_call_munger: code=%d(%s)\n",
432 call_number, mach_syscall_name_table[call_number]);
433 #if DEBUG_TRACE
434 kprintf("mach_call_munger(0x%08x) code=%d\n", regs, call_number);
435 #endif
436
437 if (call_number < 0 || call_number >= mach_trap_count) {
438 i386_exception(EXC_SYSCALL, call_number, 1);
439 /* NOTREACHED */
440 }
441 mach_call = (mach_call_t)mach_trap_table[call_number].mach_trap_function;
442
443 if (mach_call == (mach_call_t)kern_invalid) {
444 DEBUG_KPRINT_SYSCALL_MACH(
445 "mach_call_munger: kern_invalid 0x%x\n", regs->eax);
446 i386_exception(EXC_SYSCALL, call_number, 1);
447 /* NOTREACHED */
448 }
449
450 argc = mach_trap_table[call_number].mach_trap_arg_count;
451 if (argc) {
452 retval = mach_call_arg_munger32(regs->uesp, &args, &mach_trap_table[call_number]);
453 if (retval != KERN_SUCCESS) {
454 regs->eax = retval;
455
456 DEBUG_KPRINT_SYSCALL_MACH(
457 "mach_call_munger: retval=0x%x\n", retval);
458
459 thread_exception_return();
460 /* NOTREACHED */
461 }
462 }
463
464 #ifdef MACH_BSD
465 mach_kauth_cred_uthread_update();
466 #endif
467
468 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
469 MACHDBG_CODE(DBG_MACH_EXCP_SC, (call_number)) | DBG_FUNC_START,
470 args.arg1, args.arg2, args.arg3, args.arg4, 0);
471
472 retval = mach_call(&args);
473
474 DEBUG_KPRINT_SYSCALL_MACH("mach_call_munger: retval=0x%x\n", retval);
475
476 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
477 MACHDBG_CODE(DBG_MACH_EXCP_SC,(call_number)) | DBG_FUNC_END,
478 retval, 0, 0, 0, 0);
479
480 regs->eax = retval;
481
482 throttle_lowpri_io(1);
483
484 #if PROC_REF_DEBUG
485 if (__improbable(uthread_get_proc_refcount(ut) != 0)) {
486 panic("system call returned with uu_proc_refcount != 0");
487 }
488 #endif
489
490 thread_exception_return();
491 /* NOTREACHED */
492 }
493
494
495 __private_extern__ void mach_call_munger64(x86_saved_state_t *regs);
496
497 void
498 mach_call_munger64(x86_saved_state_t *state)
499 {
500 int call_number;
501 int argc;
502 mach_call_t mach_call;
503 struct mach_call_args args = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
504 x86_saved_state64_t *regs;
505
506 #if PROC_REF_DEBUG
507 struct uthread *ut = get_bsdthread_info(current_thread());
508
509 uthread_reset_proc_refcount(ut);
510 #endif
511
512 assert(is_saved_state64(state));
513 regs = saved_state64(state);
514
515 call_number = (int)(regs->rax & SYSCALL_NUMBER_MASK);
516
517 DEBUG_KPRINT_SYSCALL_MACH(
518 "mach_call_munger64: code=%d(%s)\n",
519 call_number, mach_syscall_name_table[call_number]);
520
521 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
522 MACHDBG_CODE(DBG_MACH_EXCP_SC,(call_number)) | DBG_FUNC_START,
523 regs->rdi, regs->rsi, regs->rdx, regs->r10, 0);
524
525 if (call_number < 0 || call_number >= mach_trap_count) {
526 i386_exception(EXC_SYSCALL, regs->rax, 1);
527 /* NOTREACHED */
528 }
529 mach_call = (mach_call_t)mach_trap_table[call_number].mach_trap_function;
530
531 if (mach_call == (mach_call_t)kern_invalid) {
532 i386_exception(EXC_SYSCALL, regs->rax, 1);
533 /* NOTREACHED */
534 }
535 argc = mach_trap_table[call_number].mach_trap_arg_count;
536 if (argc) {
537 int args_in_regs = MIN(6, argc);
538
539 memcpy(&args.arg1, &regs->rdi, args_in_regs * sizeof(syscall_arg_t));
540
541 if (argc > 6) {
542 int copyin_count;
543
544 assert(argc <= 9);
545 copyin_count = (argc - 6) * (int)sizeof(syscall_arg_t);
546
547 if (copyin((user_addr_t)(regs->isf.rsp + sizeof(user_addr_t)), (char *)&args.arg7, copyin_count)) {
548 regs->rax = KERN_INVALID_ARGUMENT;
549
550 thread_exception_return();
551 /* NOTREACHED */
552 }
553 }
554 }
555
556 #ifdef MACH_BSD
557 mach_kauth_cred_uthread_update();
558 #endif
559
560 regs->rax = (uint64_t)mach_call((void *)&args);
561
562 DEBUG_KPRINT_SYSCALL_MACH( "mach_call_munger64: retval=0x%llx\n", regs->rax);
563
564 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
565 MACHDBG_CODE(DBG_MACH_EXCP_SC,(call_number)) | DBG_FUNC_END,
566 regs->rax, 0, 0, 0, 0);
567
568 throttle_lowpri_io(1);
569
570 #if PROC_REF_DEBUG
571 if (__improbable(uthread_get_proc_refcount(ut) != 0)) {
572 panic("system call returned with uu_proc_refcount != 0");
573 }
574 #endif
575
576 thread_exception_return();
577 /* NOTREACHED */
578 }
579
580
581 /*
582 * thread_setuserstack:
583 *
584 * Sets the user stack pointer into the machine
585 * dependent thread state info.
586 */
587 void
588 thread_setuserstack(
589 thread_t thread,
590 mach_vm_address_t user_stack)
591 {
592 pal_register_cache_state(thread, DIRTY);
593 if (thread_is_64bit(thread)) {
594 x86_saved_state64_t *iss64;
595
596 iss64 = USER_REGS64(thread);
597
598 iss64->isf.rsp = (uint64_t)user_stack;
599 } else {
600 x86_saved_state32_t *iss32;
601
602 iss32 = USER_REGS32(thread);
603
604 iss32->uesp = CAST_DOWN_EXPLICIT(unsigned int, user_stack);
605 }
606 }
607
608 /*
609 * thread_adjuserstack:
610 *
611 * Returns the adjusted user stack pointer from the machine
612 * dependent thread state info. Used for small (<2G) deltas.
613 */
614 uint64_t
615 thread_adjuserstack(
616 thread_t thread,
617 int adjust)
618 {
619 pal_register_cache_state(thread, DIRTY);
620 if (thread_is_64bit(thread)) {
621 x86_saved_state64_t *iss64;
622
623 iss64 = USER_REGS64(thread);
624
625 iss64->isf.rsp += adjust;
626
627 return iss64->isf.rsp;
628 } else {
629 x86_saved_state32_t *iss32;
630
631 iss32 = USER_REGS32(thread);
632
633 iss32->uesp += adjust;
634
635 return CAST_USER_ADDR_T(iss32->uesp);
636 }
637 }
638
639 /*
640 * thread_setentrypoint:
641 *
642 * Sets the user PC into the machine
643 * dependent thread state info.
644 */
645 void
646 thread_setentrypoint(thread_t thread, mach_vm_address_t entry)
647 {
648 pal_register_cache_state(thread, DIRTY);
649 if (thread_is_64bit(thread)) {
650 x86_saved_state64_t *iss64;
651
652 iss64 = USER_REGS64(thread);
653
654 iss64->isf.rip = (uint64_t)entry;
655 } else {
656 x86_saved_state32_t *iss32;
657
658 iss32 = USER_REGS32(thread);
659
660 iss32->eip = CAST_DOWN_EXPLICIT(unsigned int, entry);
661 }
662 }
663
664
665 kern_return_t
666 thread_setsinglestep(thread_t thread, int on)
667 {
668 pal_register_cache_state(thread, DIRTY);
669 if (thread_is_64bit(thread)) {
670 x86_saved_state64_t *iss64;
671
672 iss64 = USER_REGS64(thread);
673
674 if (on)
675 iss64->isf.rflags |= EFL_TF;
676 else
677 iss64->isf.rflags &= ~EFL_TF;
678 } else {
679 x86_saved_state32_t *iss32;
680
681 iss32 = USER_REGS32(thread);
682
683 if (on) {
684 iss32->efl |= EFL_TF;
685 /* Ensure IRET */
686 if (iss32->cs == SYSENTER_CS)
687 iss32->cs = SYSENTER_TF_CS;
688 }
689 else
690 iss32->efl &= ~EFL_TF;
691 }
692
693 return (KERN_SUCCESS);
694 }
695
696
697
698 /* XXX this should be a struct savearea so that CHUD will work better on x86 */
699 void *
700 find_user_regs(thread_t thread)
701 {
702 pal_register_cache_state(thread, DIRTY);
703 return USER_STATE(thread);
704 }
705
706 void *
707 get_user_regs(thread_t th)
708 {
709 pal_register_cache_state(th, DIRTY);
710 return(USER_STATE(th));
711 }
712
713 #if CONFIG_DTRACE
714 /*
715 * DTrace would like to have a peek at the kernel interrupt state, if available.
716 * Based on osfmk/chud/i386/chud_thread_i386.c:chudxnu_thread_get_state(), which see.
717 */
718 x86_saved_state_t *find_kern_regs(thread_t);
719
720 x86_saved_state_t *
721 find_kern_regs(thread_t thread)
722 {
723 if (thread == current_thread() &&
724 NULL != current_cpu_datap()->cpu_int_state &&
725 !(USER_STATE(thread) == current_cpu_datap()->cpu_int_state &&
726 current_cpu_datap()->cpu_interrupt_level == 1)) {
727
728 return current_cpu_datap()->cpu_int_state;
729 } else {
730 return NULL;
731 }
732 }
733
734 vm_offset_t dtrace_get_cpu_int_stack_top(void);
735
736 vm_offset_t
737 dtrace_get_cpu_int_stack_top(void)
738 {
739 return current_cpu_datap()->cpu_int_stack_top;
740 }
741 #endif