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 <kern/syscall_sw.h>
43 #include <ipc/ipc_port.h>
44 #include <vm/vm_kern.h>
47 #include <i386/thread.h>
48 #include <i386/eflags.h>
49 #include <i386/proc_reg.h>
52 #include <i386/user_ldt.h>
54 #include <i386/iopb_entries.h>
55 #include <i386/machdep_call.h>
57 #include <sys/syscall.h>
58 #include <sys/ktrace.h>
80 struct i386_saved_state
*
84 unsigned int get_msr_exportmask(void);
86 unsigned int get_msr_nbits(void);
88 unsigned int get_msr_rbits(void);
91 thread_compose_cthread_desc(unsigned int addr
, pcb_t pcb
);
96 * Return the user stack pointer from the machine
97 * dependent thread state info.
103 thread_state_t tstate
,
105 vm_offset_t
*user_stack
,
109 struct i386_saved_state
*state
;
110 i386_thread_state_t
*state25
;
117 case i386_THREAD_STATE
: /* FIXME */
118 state25
= (i386_thread_state_t
*) tstate
;
120 *user_stack
= state25
->esp
;
121 if (customstack
&& state25
->esp
)
127 case i386_NEW_THREAD_STATE
:
128 if (count
< i386_NEW_THREAD_STATE_COUNT
)
129 return (KERN_INVALID_ARGUMENT
);
131 state
= (struct i386_saved_state
*) tstate
;
135 /* If a valid user stack is specified, use it. */
138 if (customstack
&& uesp
)
144 return (KERN_INVALID_ARGUMENT
);
147 return (KERN_SUCCESS
);
154 thread_state_t tstate
,
156 vm_offset_t
*entry_point
159 struct i386_saved_state
*state
;
160 i386_thread_state_t
*state25
;
165 if (*entry_point
== 0)
166 *entry_point
= VM_MIN_ADDRESS
;
169 case i386_THREAD_STATE
:
170 state25
= (i386_thread_state_t
*) tstate
;
171 *entry_point
= state25
->eip
? state25
->eip
: VM_MIN_ADDRESS
;
174 case i386_NEW_THREAD_STATE
:
175 if (count
< i386_THREAD_STATE_COUNT
)
176 return (KERN_INVALID_ARGUMENT
);
178 state
= (struct i386_saved_state
*) tstate
;
181 * If a valid entry point is specified, use it.
183 *entry_point
= state
->eip
? state
->eip
: VM_MIN_ADDRESS
;
188 return (KERN_SUCCESS
);
191 struct i386_saved_state
*
192 get_user_regs(thread_act_t th
)
195 return(USER_REGS(th
));
197 printf("[get_user_regs: thread does not have pcb]");
203 * Duplicate parent state in child
212 struct i386_saved_state
*parent_state
, *child_state
;
213 struct i386_machine_state
*ims
;
214 struct i386_float_state floatregs
;
217 /* Save the FPU state */
218 if ((pcb_t
)(per_proc_info
[cpu_number()].fpu_pcb
) == parent
->mact
.pcb
) {
219 fp_state_save(parent
);
223 if (child
->mact
.pcb
== NULL
|| parent
->mact
.pcb
== NULL
)
224 return (KERN_FAILURE
);
226 /* Copy over the i386_saved_state registers */
227 child
->mact
.pcb
->iss
= parent
->mact
.pcb
->iss
;
229 /* Check to see if parent is using floating point
230 * and if so, copy the registers to the child
231 * FIXME - make sure this works.
234 if (parent
->mact
.pcb
->ims
.ifps
) {
235 if (fpu_get_state(parent
, &floatregs
) == KERN_SUCCESS
)
236 fpu_set_state(child
, &floatregs
);
239 /* FIXME - should a user specified LDT, TSS and V86 info
240 * be duplicated as well?? - probably not.
243 return (KERN_SUCCESS
);
247 * FIXME - thread_set_child
250 void thread_set_child(thread_act_t child
, int pid
);
252 thread_set_child(thread_act_t child
, int pid
)
254 child
->mact
.pcb
->iss
.eax
= pid
;
255 child
->mact
.pcb
->iss
.edx
= 1;
256 child
->mact
.pcb
->iss
.efl
&= ~EFL_CF
;
258 void thread_set_parent(thread_act_t parent
, int pid
);
260 thread_set_parent(thread_act_t parent
, int pid
)
262 parent
->mact
.pcb
->iss
.eax
= pid
;
263 parent
->mact
.pcb
->iss
.edx
= 0;
264 parent
->mact
.pcb
->iss
.efl
&= ~EFL_CF
;
270 * Move pages from one kernel virtual address to another.
271 * Both addresses are assumed to reside in the Sysmap,
272 * and size must be a multiple of the page size.
276 register caddr_t from
,
280 pmap_movepage((unsigned long)from
, (unsigned long)to
, (vm_size_t
)size
);
284 * System Call handling code
287 #define ERESTART -1 /* restart syscall */
288 #define EJUSTRETURN -2 /* don't modify regs, just return */
290 struct sysent
{ /* system call table */
291 unsigned short sy_narg
; /* number of args */
292 char sy_parallel
; /* can execute in parallel */
293 char sy_funnel
; /* funnel type */
294 unsigned long (*sy_call
)(void *, void *, int *); /* implementing function */
298 #define KERNEL_FUNNEL 1
299 #define NETWORK_FUNNEL 2
301 extern funnel_t
* kernel_flock
;
302 extern funnel_t
* network_flock
;
304 extern struct sysent sysent
[];
306 int set_bsduthreadargs (thread_act_t
, struct i386_saved_state
*, void *);
308 void * get_bsduthreadarg(thread_act_t
);
310 void unix_syscall(struct i386_saved_state
*);
313 unix_syscall_return(int error
)
317 struct i386_saved_state
*regs
;
319 struct proc
*current_proc();
322 struct sysent
*callp
;
325 thread
= current_act();
326 rval
= (int *)get_bsduthreadrval(thread
);
329 regs
= USER_REGS(thread
);
331 /* reconstruct code for tracing before blasting eax */
333 params
= (vm_offset_t
) ((caddr_t
)regs
->uesp
+ sizeof (int));
334 callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
335 if (callp
== sysent
) {
336 code
= fuword(params
);
339 if (error
== ERESTART
) {
342 else if (error
!= EJUSTRETURN
) {
345 regs
->efl
|= EFL_CF
; /* carry bit */
346 } else { /* (not error) */
349 regs
->efl
&= ~EFL_CF
;
353 ktrsysret(p
, code
, error
, rval
[0], callp
->sy_funnel
);
355 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_END
,
356 error
, rval
[0], rval
[1], 0, 0);
358 if (callp
->sy_funnel
!= NO_FUNNEL
)
359 (void) thread_funnel_set(current_thread()->funnel_lock
, FALSE
);
361 thread_exception_return();
367 unix_syscall(struct i386_saved_state
*regs
)
372 struct sysent
*callp
;
379 struct proc
*current_proc();
381 thread
= current_act();
383 rval
= (int *)get_bsduthreadrval(thread
);
385 //printf("[scall : eax %x]", regs->eax);
387 params
= (vm_offset_t
) ((caddr_t
)regs
->uesp
+ sizeof (int));
388 callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
389 if (callp
== sysent
) {
390 code
= fuword(params
);
391 params
+= sizeof (int);
392 callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
395 vt
= get_bsduthreadarg(thread
);
397 if ((nargs
= (callp
->sy_narg
* sizeof (int))) &&
398 (error
= copyin((char *) params
, (char *)vt
, nargs
)) != 0) {
401 thread_exception_return();
408 funnel_type
= callp
->sy_funnel
;
409 if(funnel_type
== KERNEL_FUNNEL
)
410 (void) thread_funnel_set(kernel_flock
, TRUE
);
411 else if (funnel_type
== NETWORK_FUNNEL
)
412 (void) thread_funnel_set(network_flock
, TRUE
);
414 set_bsduthreadargs(thread
, regs
, NULL
);
416 if (callp
->sy_narg
> 8)
417 panic("unix_syscall max arg count exceeded (%d)", callp
->sy_narg
);
419 ktrsyscall(p
, code
, callp
->sy_narg
, vt
, funnel_type
);
423 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_START
,
424 *ip
, *(ip
+1), *(ip
+2), *(ip
+3), 0);
427 error
= (*(callp
->sy_call
))(p
, (void *) vt
, (int *) &rval
[0]);
430 /* May be needed with vfork changes */
431 regs
= USER_REGS(thread
);
433 if (error
== ERESTART
) {
436 else if (error
!= EJUSTRETURN
) {
439 regs
->efl
|= EFL_CF
; /* carry bit */
440 } else { /* (not error) */
443 regs
->efl
&= ~EFL_CF
;
447 ktrsysret(p
, code
, error
, rval
[0], funnel_type
);
449 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC
, code
) | DBG_FUNC_END
,
450 error
, rval
[0], rval
[1], 0, 0);
452 if(funnel_type
!= NO_FUNNEL
)
453 (void) thread_funnel_set(current_thread()->funnel_lock
, FALSE
);
455 thread_exception_return();
461 machdep_syscall( struct i386_saved_state
*regs
)
464 machdep_call_t
*entry
;
467 struct proc
*current_proc();
470 if (trapno
< 0 || trapno
>= machdep_call_count
) {
471 regs
->eax
= (unsigned int)kern_invalid();
473 thread_exception_return();
477 entry
= &machdep_call_table
[trapno
];
478 nargs
= entry
->nargs
;
483 if (copyin((char *) regs
->uesp
+ sizeof (int),
485 nargs
* sizeof (int))) {
487 regs
->eax
= KERN_INVALID_ADDRESS
;
489 thread_exception_return();
495 regs
->eax
= (*entry
->routine
)(args
[0]);
498 regs
->eax
= (*entry
->routine
)(args
[0],args
[1]);
501 regs
->eax
= (*entry
->routine
)(args
[0],args
[1],args
[2]);
504 regs
->eax
= (*entry
->routine
)(args
[0],args
[1],args
[2],args
[3]);
507 panic("machdep_syscall(): too many args");
511 regs
->eax
= (*entry
->routine
)();
513 if (current_thread()->funnel_lock
)
514 (void) thread_funnel_set(current_thread()->funnel_lock
, FALSE
);
516 thread_exception_return();
522 thread_compose_cthread_desc(unsigned int addr
, pcb_t pcb
)
524 struct real_descriptor desc
;
525 extern struct fake_descriptor
*mp_ldt
[];
526 struct real_descriptor
*ldtp
;
527 int mycpu
= cpu_number();
529 ldtp
= (struct real_descriptor
*)mp_ldt
[mycpu
];
532 desc
.base_low
= addr
& 0xffff;
533 desc
.base_med
= (addr
>> 16) & 0xff;
534 desc
.base_high
= (addr
>> 24) & 0xff;
535 desc
.access
= ACC_P
|ACC_PL_U
|ACC_DATA_W
;
536 desc
.granularity
= SZ_32
|SZ_G
;
537 pcb
->cthread_desc
= desc
;
538 ldtp
[sel_idx(USER_CTHREAD
)] = desc
;
539 return(KERN_SUCCESS
);
543 thread_set_cthread_self(int self
)
545 current_act()->mact
.pcb
->cthread_self
= (unsigned int)self
;
547 return (KERN_SUCCESS
);
551 thread_get_cthread_self(void)
553 return ((kern_return_t
)current_act()->mact
.pcb
->cthread_self
);
557 thread_fast_set_cthread_self(int self
)
560 pcb
= (pcb_t
)current_act()->mact
.pcb
;
561 thread_compose_cthread_desc((unsigned int)self
, pcb
);
562 pcb
->cthread_self
= (unsigned int)self
; /* preserve old func too */
563 return (USER_CTHREAD
);
567 mach25_syscall(struct i386_saved_state
*regs
)
569 printf("*** Atttempt to execute a Mach 2.5 system call at EIP=%x EAX=%x(%d)\n",
570 regs
->eip
, regs
->eax
, -regs
->eax
);
573 #endif /* MACH_BSD */
576 /* This routine is called from assembly before each and every mach trap.
579 extern unsigned int mach_call_start(unsigned int, unsigned int *);
583 mach_call_start(unsigned int call_number
, unsigned int *args
)
586 unsigned int kdarg
[3];
588 /* Always prepare to trace mach system calls */
594 argc
= mach_trap_table
[call_number
>>4].mach_trap_arg_count
;
599 for (i
=0; i
< argc
; i
++)
600 kdarg
[i
] = (int)*(args
+ i
);
602 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC
, (call_number
>>4)) | DBG_FUNC_START
,
603 kdarg
[0], kdarg
[1], kdarg
[2], 0, 0);
605 return call_number
; /* pass this back thru */
608 /* This routine is called from assembly after each mach system call
611 extern unsigned int mach_call_end(unsigned int, unsigned int);
615 mach_call_end(unsigned int call_number
, unsigned int retval
)
617 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC
,(call_number
>>4)) | DBG_FUNC_END
,
619 return retval
; /* pass this back thru */