2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
28 #include <mach_debug.h>
29 #include <mach_ldebug.h>
31 #include <mach/kern_return.h>
32 #include <mach/thread_status.h>
33 #include <mach/vm_param.h>
35 #include <kern/counters.h>
36 #include <kern/cpu_data.h>
37 #include <kern/mach_param.h>
38 #include <kern/task.h>
39 #include <kern/thread.h>
40 #include <kern/thread_swap.h>
41 #include <kern/sched_prim.h>
42 #include <kern/misc_protos.h>
43 #include <kern/assert.h>
45 #include <ipc/ipc_port.h>
46 #include <vm/vm_kern.h>
49 #include <i386/thread.h>
50 #include <i386/eflags.h>
51 #include <i386/proc_reg.h>
54 #include <i386/user_ldt.h>
56 #include <i386/iopb_entries.h>
57 #include <i386/machdep_call.h>
59 #include <sys/syscall.h>
60 #include <sys/ktrace.h>
82 struct i386_saved_state
*
92 unsigned int get_msr_exportmask(void);
94 unsigned int get_msr_nbits(void);
96 unsigned int get_msr_rbits(void);
101 * Return the user stack pointer from the machine
102 * dependent thread state info.
108 thread_state_t tstate
,
110 vm_offset_t
*user_stack
,
114 struct i386_saved_state
*state
;
115 i386_thread_state_t
*state25
;
122 case i386_THREAD_STATE
: /* FIXME */
123 state25
= (i386_thread_state_t
*) tstate
;
125 *user_stack
= state25
->esp
;
126 if (customstack
&& state25
->esp
)
132 case i386_NEW_THREAD_STATE
:
133 if (count
< i386_NEW_THREAD_STATE_COUNT
)
134 return (KERN_INVALID_ARGUMENT
);
136 state
= (struct i386_saved_state
*) tstate
;
140 /* If a valid user stack is specified, use it. */
143 if (customstack
&& uesp
)
149 return (KERN_INVALID_ARGUMENT
);
152 return (KERN_SUCCESS
);
159 thread_state_t tstate
,
161 vm_offset_t
*entry_point
164 struct i386_saved_state
*state
;
165 i386_thread_state_t
*state25
;
170 if (*entry_point
== 0)
171 *entry_point
= VM_MIN_ADDRESS
;
174 case i386_THREAD_STATE
:
175 state25
= (i386_thread_state_t
*) tstate
;
176 *entry_point
= state25
->eip
? state25
->eip
: VM_MIN_ADDRESS
;
179 case i386_NEW_THREAD_STATE
:
180 if (count
< i386_THREAD_STATE_COUNT
)
181 return (KERN_INVALID_ARGUMENT
);
183 state
= (struct i386_saved_state
*) tstate
;
186 * If a valid entry point is specified, use it.
188 *entry_point
= state
->eip
? state
->eip
: VM_MIN_ADDRESS
;
193 return (KERN_SUCCESS
);
196 struct i386_saved_state
*
197 get_user_regs(thread_act_t th
)
200 return(USER_REGS(th
));
202 printf("[get_user_regs: thread does not have pcb]");
208 * Duplicate parent state in child
217 struct i386_saved_state
*parent_state
, *child_state
;
218 struct i386_machine_state
*ims
;
219 struct i386_float_state floatregs
;
222 /* Save the FPU state */
223 if ((pcb_t
)(per_proc_info
[cpu_number()].fpu_pcb
) == parent
->mact
.pcb
) {
224 fp_state_save(parent
);
228 if (child
->mact
.pcb
== NULL
229 || parent
->mact
.pcb
== NULL
) {
230 panic("[thread_dup, child (%x) or parent (%x) is NULL!]",
231 child
->mact
.pcb
, parent
->mact
.pcb
);
235 /* Copy over the i386_saved_state registers */
236 child
->mact
.pcb
->iss
= parent
->mact
.pcb
->iss
;
238 /* Check to see if parent is using floating point
239 * and if so, copy the registers to the child
240 * FIXME - make sure this works.
243 if (parent
->mact
.pcb
->ims
.ifps
) {
244 if (fpu_get_state(parent
, &floatregs
) == KERN_SUCCESS
)
245 fpu_set_state(child
, &floatregs
);
248 /* FIXME - should a user specified LDT, TSS and V86 info
249 * be duplicated as well?? - probably not.
254 * FIXME - thread_set_child
257 void thread_set_child(thread_act_t child
, int pid
);
259 thread_set_child(thread_act_t child
, int pid
)
261 child
->mact
.pcb
->iss
.eax
= pid
;
262 child
->mact
.pcb
->iss
.edx
= 1;
263 child
->mact
.pcb
->iss
.efl
&= ~EFL_CF
;
265 void thread_set_parent(thread_act_t parent
, int pid
);
267 thread_set_parent(thread_act_t parent
, int pid
)
269 parent
->mact
.pcb
->iss
.eax
= pid
;
270 parent
->mact
.pcb
->iss
.edx
= 0;
271 parent
->mact
.pcb
->iss
.efl
&= ~EFL_CF
;
277 * Move pages from one kernel virtual address to another.
278 * Both addresses are assumed to reside in the Sysmap,
279 * and size must be a multiple of the page size.
283 register caddr_t from
,
287 pmap_movepage((unsigned long)from
, (unsigned long)to
, (vm_size_t
)size
);
291 * System Call handling code
294 #define ERESTART -1 /* restart syscall */
295 #define EJUSTRETURN -2 /* don't modify regs, just return */
297 struct sysent
{ /* system call table */
298 unsigned short sy_narg
; /* number of args */
299 char sy_parallel
; /* can execute in parallel */
300 char sy_funnel
; /* funnel type */
301 unsigned long (*sy_call
)(void *, void *, int *); /* implementing function */
305 #define KERNEL_FUNNEL 1
306 #define NETWORK_FUNNEL 2
308 extern funnel_t
* kernel_flock
;
309 extern funnel_t
* network_flock
;
311 extern struct sysent sysent
[];
313 int set_bsduthreadargs (thread_act_t
, struct i386_saved_state
*, void *);
315 void * get_bsduthreadarg(thread_act_t
);
317 void unix_syscall(struct i386_saved_state
*);
320 unix_syscall_return(int error
)
324 struct i386_saved_state
*regs
;
326 struct proc
*current_proc();
329 struct sysent
*callp
;
332 thread
= current_act();
333 rval
= (int *)get_bsduthreadrval(thread
);
336 regs
= USER_REGS(thread
);
338 /* reconstruct code for tracing before blasting eax */
340 params
= (vm_offset_t
) ((caddr_t
)regs
->uesp
+ sizeof (int));
341 callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
342 if (callp
== sysent
) {
343 code
= fuword(params
);
346 if (error
== ERESTART
) {
349 else if (error
!= EJUSTRETURN
) {
352 regs
->efl
|= EFL_CF
; /* carry bit */
353 } else { /* (not error) */
356 regs
->efl
&= ~EFL_CF
;
360 ktrsysret(p
, code
, error
, rval
[0], callp
->sy_funnel
);
362 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_END
,
363 error
, rval
[0], rval
[1], 0, 0);
365 if (callp
->sy_funnel
!= NO_FUNNEL
) {
366 assert(thread_funnel_get() == THR_FUNNEL_NULL
);
367 (void) thread_funnel_set(current_thread()->funnel_lock
, FALSE
);
370 thread_exception_return();
376 unix_syscall(struct i386_saved_state
*regs
)
381 struct sysent
*callp
;
388 struct proc
*current_proc();
390 thread
= current_act();
392 rval
= (int *)get_bsduthreadrval(thread
);
394 //printf("[scall : eax %x]", regs->eax);
396 params
= (vm_offset_t
) ((caddr_t
)regs
->uesp
+ sizeof (int));
397 callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
398 if (callp
== sysent
) {
399 code
= fuword(params
);
400 params
+= sizeof (int);
401 callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
404 vt
= get_bsduthreadarg(thread
);
406 if ((nargs
= (callp
->sy_narg
* sizeof (int))) &&
407 (error
= copyin((char *) params
, (char *)vt
, nargs
)) != 0) {
410 thread_exception_return();
417 funnel_type
= callp
->sy_funnel
;
418 if(funnel_type
== KERNEL_FUNNEL
)
419 (void) thread_funnel_set(kernel_flock
, TRUE
);
420 else if (funnel_type
== NETWORK_FUNNEL
)
421 (void) thread_funnel_set(network_flock
, TRUE
);
423 set_bsduthreadargs(thread
, regs
, NULL
);
425 if (callp
->sy_narg
> 8)
426 panic("unix_syscall max arg count exceeded (%d)", callp
->sy_narg
);
428 ktrsyscall(p
, code
, callp
->sy_narg
, vt
, funnel_type
);
432 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_START
,
433 *ip
, *(ip
+1), *(ip
+2), *(ip
+3), 0);
436 error
= (*(callp
->sy_call
))(p
, (void *) vt
, rval
);
439 /* May be needed with vfork changes */
440 regs
= USER_REGS(thread
);
442 if (error
== ERESTART
) {
445 else if (error
!= EJUSTRETURN
) {
448 regs
->efl
|= EFL_CF
; /* carry bit */
449 } else { /* (not error) */
452 regs
->efl
&= ~EFL_CF
;
456 ktrsysret(p
, code
, error
, rval
[0], funnel_type
);
458 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_END
,
459 error
, rval
[0], rval
[1], 0, 0);
461 if(funnel_type
!= NO_FUNNEL
)
462 (void) thread_funnel_set(current_thread()->funnel_lock
, FALSE
);
464 thread_exception_return();
470 machdep_syscall( struct i386_saved_state
*regs
)
473 machdep_call_t
*entry
;
476 struct proc
*current_proc();
479 if (trapno
< 0 || trapno
>= machdep_call_count
) {
480 regs
->eax
= (unsigned int)kern_invalid();
482 thread_exception_return();
486 entry
= &machdep_call_table
[trapno
];
487 nargs
= entry
->nargs
;
492 if (copyin((char *) regs
->uesp
+ sizeof (int),
494 nargs
* sizeof (int))) {
496 regs
->eax
= KERN_INVALID_ADDRESS
;
498 thread_exception_return();
515 "r" (&args
[nargs
- 1]),
517 : "ax", "cx", "dx", "sp");
520 regs
->eax
= (unsigned int)(*entry
->routine
)();
522 if (current_thread()->funnel_lock
)
523 (void) thread_funnel_set(current_thread()->funnel_lock
, FALSE
);
525 thread_exception_return();
531 thread_set_cthread_self(int self
)
533 current_act()->mact
.pcb
->cthread_self
= (unsigned int)self
;
535 return (KERN_SUCCESS
);
539 thread_get_cthread_self(void)
541 return ((kern_return_t
)current_act()->mact
.pcb
->cthread_self
);
545 mach25_syscall(struct i386_saved_state
*regs
)
547 printf("*** Atttempt to execute a Mach 2.5 system call at EIP=%x EAX=%x(%d)\n",
548 regs
->eip
, regs
->eax
, -regs
->eax
);
552 #endif /* MACH_BSD */
554 #undef current_thread
558 return(current_thread_fast());