2 * Copyright (c) 2000-2002 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@
25 #include <mach_debug.h>
26 #include <mach_ldebug.h>
28 #include <mach/kern_return.h>
29 #include <mach/thread_status.h>
30 #include <mach/vm_param.h>
32 #include <kern/counters.h>
33 #include <kern/cpu_data.h>
34 #include <kern/mach_param.h>
35 #include <kern/task.h>
36 #include <kern/thread.h>
37 #include <kern/thread_swap.h>
38 #include <kern/sched_prim.h>
39 #include <kern/misc_protos.h>
40 #include <kern/assert.h>
42 #include <ipc/ipc_port.h>
43 #include <vm/vm_kern.h>
46 #include <i386/thread.h>
47 #include <i386/eflags.h>
48 #include <i386/proc_reg.h>
51 #include <i386/user_ldt.h>
53 #include <i386/iopb_entries.h>
54 #include <i386/machdep_call.h>
56 #include <sys/syscall.h>
57 #include <sys/ktrace.h>
79 struct i386_saved_state
*
89 unsigned int get_msr_exportmask(void);
91 unsigned int get_msr_nbits(void);
93 unsigned int get_msr_rbits(void);
98 * Return the user stack pointer from the machine
99 * dependent thread state info.
105 thread_state_t tstate
,
107 vm_offset_t
*user_stack
,
111 struct i386_saved_state
*state
;
112 i386_thread_state_t
*state25
;
119 case i386_THREAD_STATE
: /* FIXME */
120 state25
= (i386_thread_state_t
*) tstate
;
122 *user_stack
= state25
->esp
;
123 if (customstack
&& state25
->esp
)
129 case i386_NEW_THREAD_STATE
:
130 if (count
< i386_NEW_THREAD_STATE_COUNT
)
131 return (KERN_INVALID_ARGUMENT
);
133 state
= (struct i386_saved_state
*) tstate
;
137 /* If a valid user stack is specified, use it. */
140 if (customstack
&& uesp
)
146 return (KERN_INVALID_ARGUMENT
);
149 return (KERN_SUCCESS
);
156 thread_state_t tstate
,
158 vm_offset_t
*entry_point
161 struct i386_saved_state
*state
;
162 i386_thread_state_t
*state25
;
167 if (*entry_point
== 0)
168 *entry_point
= VM_MIN_ADDRESS
;
171 case i386_THREAD_STATE
:
172 state25
= (i386_thread_state_t
*) tstate
;
173 *entry_point
= state25
->eip
? state25
->eip
: VM_MIN_ADDRESS
;
176 case i386_NEW_THREAD_STATE
:
177 if (count
< i386_THREAD_STATE_COUNT
)
178 return (KERN_INVALID_ARGUMENT
);
180 state
= (struct i386_saved_state
*) tstate
;
183 * If a valid entry point is specified, use it.
185 *entry_point
= state
->eip
? state
->eip
: VM_MIN_ADDRESS
;
190 return (KERN_SUCCESS
);
193 struct i386_saved_state
*
194 get_user_regs(thread_act_t th
)
197 return(USER_REGS(th
));
199 printf("[get_user_regs: thread does not have pcb]");
205 * Duplicate parent state in child
214 struct i386_saved_state
*parent_state
, *child_state
;
215 struct i386_machine_state
*ims
;
216 struct i386_float_state floatregs
;
219 /* Save the FPU state */
220 if ((pcb_t
)(per_proc_info
[cpu_number()].fpu_pcb
) == parent
->mact
.pcb
) {
221 fp_state_save(parent
);
225 if (child
->mact
.pcb
== NULL
226 || parent
->mact
.pcb
== NULL
) {
227 panic("[thread_dup, child (%x) or parent (%x) is NULL!]",
228 child
->mact
.pcb
, parent
->mact
.pcb
);
232 /* Copy over the i386_saved_state registers */
233 child
->mact
.pcb
->iss
= parent
->mact
.pcb
->iss
;
235 /* Check to see if parent is using floating point
236 * and if so, copy the registers to the child
237 * FIXME - make sure this works.
240 if (parent
->mact
.pcb
->ims
.ifps
) {
241 if (fpu_get_state(parent
, &floatregs
) == KERN_SUCCESS
)
242 fpu_set_state(child
, &floatregs
);
245 /* FIXME - should a user specified LDT, TSS and V86 info
246 * be duplicated as well?? - probably not.
251 * FIXME - thread_set_child
254 void thread_set_child(thread_act_t child
, int pid
);
256 thread_set_child(thread_act_t child
, int pid
)
258 child
->mact
.pcb
->iss
.eax
= pid
;
259 child
->mact
.pcb
->iss
.edx
= 1;
260 child
->mact
.pcb
->iss
.efl
&= ~EFL_CF
;
262 void thread_set_parent(thread_act_t parent
, int pid
);
264 thread_set_parent(thread_act_t parent
, int pid
)
266 parent
->mact
.pcb
->iss
.eax
= pid
;
267 parent
->mact
.pcb
->iss
.edx
= 0;
268 parent
->mact
.pcb
->iss
.efl
&= ~EFL_CF
;
274 * Move pages from one kernel virtual address to another.
275 * Both addresses are assumed to reside in the Sysmap,
276 * and size must be a multiple of the page size.
280 register caddr_t from
,
284 pmap_movepage((unsigned long)from
, (unsigned long)to
, (vm_size_t
)size
);
288 * System Call handling code
291 #define ERESTART -1 /* restart syscall */
292 #define EJUSTRETURN -2 /* don't modify regs, just return */
294 struct sysent
{ /* system call table */
295 unsigned short sy_narg
; /* number of args */
296 char sy_parallel
; /* can execute in parallel */
297 char sy_funnel
; /* funnel type */
298 unsigned long (*sy_call
)(void *, void *, int *); /* implementing function */
302 #define KERNEL_FUNNEL 1
303 #define NETWORK_FUNNEL 2
305 extern funnel_t
* kernel_flock
;
306 extern funnel_t
* network_flock
;
308 extern struct sysent sysent
[];
310 int set_bsduthreadargs (thread_act_t
, struct i386_saved_state
*, void *);
312 void * get_bsduthreadarg(thread_act_t
);
314 void unix_syscall(struct i386_saved_state
*);
317 unix_syscall_return(int error
)
321 struct i386_saved_state
*regs
;
323 struct proc
*current_proc();
326 struct sysent
*callp
;
329 thread
= current_act();
330 rval
= (int *)get_bsduthreadrval(thread
);
333 regs
= USER_REGS(thread
);
335 /* reconstruct code for tracing before blasting eax */
337 params
= (vm_offset_t
) ((caddr_t
)regs
->uesp
+ sizeof (int));
338 callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
339 if (callp
== sysent
) {
340 code
= fuword(params
);
343 if (error
== ERESTART
) {
346 else if (error
!= EJUSTRETURN
) {
349 regs
->efl
|= EFL_CF
; /* carry bit */
350 } else { /* (not error) */
353 regs
->efl
&= ~EFL_CF
;
357 ktrsysret(p
, code
, error
, rval
[0], callp
->sy_funnel
);
359 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_END
,
360 error
, rval
[0], rval
[1], 0, 0);
362 if (callp
->sy_funnel
!= NO_FUNNEL
) {
363 assert(thread_funnel_get() == THR_FUNNEL_NULL
);
364 (void) thread_funnel_set(current_thread()->funnel_lock
, FALSE
);
367 thread_exception_return();
373 unix_syscall(struct i386_saved_state
*regs
)
378 struct sysent
*callp
;
385 struct proc
*current_proc();
387 thread
= current_act();
389 rval
= (int *)get_bsduthreadrval(thread
);
391 //printf("[scall : eax %x]", regs->eax);
393 params
= (vm_offset_t
) ((caddr_t
)regs
->uesp
+ sizeof (int));
394 callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
395 if (callp
== sysent
) {
396 code
= fuword(params
);
397 params
+= sizeof (int);
398 callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
401 vt
= get_bsduthreadarg(thread
);
403 if ((nargs
= (callp
->sy_narg
* sizeof (int))) &&
404 (error
= copyin((char *) params
, (char *)vt
, nargs
)) != 0) {
407 thread_exception_return();
414 funnel_type
= callp
->sy_funnel
;
415 if(funnel_type
== KERNEL_FUNNEL
)
416 (void) thread_funnel_set(kernel_flock
, TRUE
);
417 else if (funnel_type
== NETWORK_FUNNEL
)
418 (void) thread_funnel_set(network_flock
, TRUE
);
420 set_bsduthreadargs(thread
, regs
, NULL
);
422 if (callp
->sy_narg
> 8)
423 panic("unix_syscall max arg count exceeded (%d)", callp
->sy_narg
);
425 ktrsyscall(p
, code
, callp
->sy_narg
, vt
, funnel_type
);
429 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_START
,
430 *ip
, *(ip
+1), *(ip
+2), *(ip
+3), 0);
433 error
= (*(callp
->sy_call
))(p
, (void *) vt
, rval
);
436 /* May be needed with vfork changes */
437 regs
= USER_REGS(thread
);
439 if (error
== ERESTART
) {
442 else if (error
!= EJUSTRETURN
) {
445 regs
->efl
|= EFL_CF
; /* carry bit */
446 } else { /* (not error) */
449 regs
->efl
&= ~EFL_CF
;
453 ktrsysret(p
, code
, error
, rval
[0], funnel_type
);
455 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_END
,
456 error
, rval
[0], rval
[1], 0, 0);
458 if(funnel_type
!= NO_FUNNEL
)
459 (void) thread_funnel_set(current_thread()->funnel_lock
, FALSE
);
461 thread_exception_return();
467 machdep_syscall( struct i386_saved_state
*regs
)
470 machdep_call_t
*entry
;
473 struct proc
*current_proc();
476 if (trapno
< 0 || trapno
>= machdep_call_count
) {
477 regs
->eax
= (unsigned int)kern_invalid();
479 thread_exception_return();
483 entry
= &machdep_call_table
[trapno
];
484 nargs
= entry
->nargs
;
489 if (copyin((char *) regs
->uesp
+ sizeof (int),
491 nargs
* sizeof (int))) {
493 regs
->eax
= KERN_INVALID_ADDRESS
;
495 thread_exception_return();
512 "r" (&args
[nargs
- 1]),
514 : "ax", "cx", "dx", "sp");
517 regs
->eax
= (unsigned int)(*entry
->routine
)();
519 if (current_thread()->funnel_lock
)
520 (void) thread_funnel_set(current_thread()->funnel_lock
, FALSE
);
522 thread_exception_return();
528 thread_set_cthread_self(int self
)
530 current_act()->mact
.pcb
->cthread_self
= (unsigned int)self
;
532 return (KERN_SUCCESS
);
536 thread_get_cthread_self(void)
538 return ((kern_return_t
)current_act()->mact
.pcb
->cthread_self
);
542 mach25_syscall(struct i386_saved_state
*regs
)
544 printf("*** Atttempt to execute a Mach 2.5 system call at EIP=%x EAX=%x(%d)\n",
545 regs
->eip
, regs
->eax
, -regs
->eax
);
549 #endif /* MACH_BSD */
551 #undef current_thread
555 return(current_thread_fast());