]> git.saurik.com Git - apple/xnu.git/blame - osfmk/i386/bsd_i386.c
xnu-517.7.7.tar.gz
[apple/xnu.git] / osfmk / i386 / bsd_i386.c
CommitLineData
1c79356b 1/*
9bccf70c 2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
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.
1c79356b 11 *
e5568f75
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22#ifdef MACH_BSD
23#include <cpus.h>
24#include <mach_rt.h>
25#include <mach_debug.h>
26#include <mach_ldebug.h>
27
28#include <mach/kern_return.h>
29#include <mach/thread_status.h>
30#include <mach/vm_param.h>
1c79356b
A
31
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>
41#include <kern/spl.h>
55e303ae 42#include <kern/syscall_sw.h>
1c79356b
A
43#include <ipc/ipc_port.h>
44#include <vm/vm_kern.h>
45#include <vm/pmap.h>
46
47#include <i386/thread.h>
48#include <i386/eflags.h>
49#include <i386/proc_reg.h>
50#include <i386/seg.h>
51#include <i386/tss.h>
52#include <i386/user_ldt.h>
53#include <i386/fpu.h>
54#include <i386/iopb_entries.h>
55#include <i386/machdep_call.h>
56
9bccf70c
A
57#include <sys/syscall.h>
58#include <sys/ktrace.h>
59struct proc;
1c79356b
A
60
61kern_return_t
62thread_userstack(
63 thread_t,
64 int,
65 thread_state_t,
66 unsigned int,
0b4e3aa0
A
67 vm_offset_t *,
68 int *
1c79356b
A
69);
70
71kern_return_t
72thread_entrypoint(
73 thread_t,
74 int,
75 thread_state_t,
76 unsigned int,
77 vm_offset_t *
78);
79
80struct i386_saved_state *
81get_user_regs(
82 thread_act_t);
83
1c79356b
A
84unsigned int get_msr_exportmask(void);
85
86unsigned int get_msr_nbits(void);
87
88unsigned int get_msr_rbits(void);
89
55e303ae
A
90kern_return_t
91thread_compose_cthread_desc(unsigned int addr, pcb_t pcb);
92
1c79356b
A
93/*
94 * thread_userstack:
95 *
96 * Return the user stack pointer from the machine
97 * dependent thread state info.
98 */
99kern_return_t
100thread_userstack(
101 thread_t thread,
102 int flavor,
103 thread_state_t tstate,
104 unsigned int count,
0b4e3aa0
A
105 vm_offset_t *user_stack,
106 int *customstack
1c79356b
A
107)
108{
109 struct i386_saved_state *state;
110 i386_thread_state_t *state25;
111 vm_offset_t uesp;
112
0b4e3aa0
A
113 if (customstack)
114 *customstack = 0;
9bccf70c 115
1c79356b
A
116 switch (flavor) {
117 case i386_THREAD_STATE: /* FIXME */
118 state25 = (i386_thread_state_t *) tstate;
9bccf70c
A
119 if (state25->esp)
120 *user_stack = state25->esp;
121 if (customstack && state25->esp)
122 *customstack = 1;
123 else
124 *customstack = 0;
1c79356b
A
125 break;
126
127 case i386_NEW_THREAD_STATE:
128 if (count < i386_NEW_THREAD_STATE_COUNT)
129 return (KERN_INVALID_ARGUMENT);
130 else {
131 state = (struct i386_saved_state *) tstate;
132 uesp = state->uesp;
133 }
134
9bccf70c
A
135 /* If a valid user stack is specified, use it. */
136 if (uesp)
137 *user_stack = uesp;
138 if (customstack && uesp)
139 *customstack = 1;
140 else
141 *customstack = 0;
1c79356b
A
142 break;
143 default :
144 return (KERN_INVALID_ARGUMENT);
145 }
146
147 return (KERN_SUCCESS);
148}
149
150kern_return_t
151thread_entrypoint(
152 thread_t thread,
153 int flavor,
154 thread_state_t tstate,
155 unsigned int count,
156 vm_offset_t *entry_point
157)
158{
159 struct i386_saved_state *state;
160 i386_thread_state_t *state25;
161
162 /*
163 * Set a default.
164 */
165 if (*entry_point == 0)
166 *entry_point = VM_MIN_ADDRESS;
167
168 switch (flavor) {
169 case i386_THREAD_STATE:
170 state25 = (i386_thread_state_t *) tstate;
171 *entry_point = state25->eip ? state25->eip: VM_MIN_ADDRESS;
172 break;
173
174 case i386_NEW_THREAD_STATE:
175 if (count < i386_THREAD_STATE_COUNT)
176 return (KERN_INVALID_ARGUMENT);
177 else {
178 state = (struct i386_saved_state *) tstate;
179
180 /*
181 * If a valid entry point is specified, use it.
182 */
183 *entry_point = state->eip ? state->eip: VM_MIN_ADDRESS;
184 }
185 break;
186 }
187
188 return (KERN_SUCCESS);
189}
190
191struct i386_saved_state *
192get_user_regs(thread_act_t th)
193{
194 if (th->mact.pcb)
195 return(USER_REGS(th));
196 else {
197 printf("[get_user_regs: thread does not have pcb]");
198 return NULL;
199 }
200}
201
202/*
203 * Duplicate parent state in child
204 * for U**X fork.
205 */
55e303ae
A
206kern_return_t
207machine_thread_dup(
1c79356b
A
208 thread_act_t parent,
209 thread_act_t child
210)
211{
212 struct i386_saved_state *parent_state, *child_state;
213 struct i386_machine_state *ims;
214 struct i386_float_state floatregs;
215
216#ifdef XXX
217 /* Save the FPU state */
218 if ((pcb_t)(per_proc_info[cpu_number()].fpu_pcb) == parent->mact.pcb) {
219 fp_state_save(parent);
220 }
221#endif
222
55e303ae
A
223 if (child->mact.pcb == NULL || parent->mact.pcb == NULL)
224 return (KERN_FAILURE);
1c79356b
A
225
226 /* Copy over the i386_saved_state registers */
227 child->mact.pcb->iss = parent->mact.pcb->iss;
228
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.
232 */
233
234 if (parent->mact.pcb->ims.ifps) {
235 if (fpu_get_state(parent, &floatregs) == KERN_SUCCESS)
236 fpu_set_state(child, &floatregs);
237 }
238
239 /* FIXME - should a user specified LDT, TSS and V86 info
240 * be duplicated as well?? - probably not.
241 */
55e303ae
A
242
243 return (KERN_SUCCESS);
1c79356b
A
244}
245
246/*
247 * FIXME - thread_set_child
248 */
249
250void thread_set_child(thread_act_t child, int pid);
251void
252thread_set_child(thread_act_t child, int pid)
253{
254 child->mact.pcb->iss.eax = pid;
255 child->mact.pcb->iss.edx = 1;
256 child->mact.pcb->iss.efl &= ~EFL_CF;
257}
0b4e3aa0
A
258void thread_set_parent(thread_act_t parent, int pid);
259void
260thread_set_parent(thread_act_t parent, int pid)
261{
262 parent->mact.pcb->iss.eax = pid;
263 parent->mact.pcb->iss.edx = 0;
264 parent->mact.pcb->iss.efl &= ~EFL_CF;
265}
1c79356b
A
266
267
268
269/*
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.
273 */
274void
275pagemove(
276 register caddr_t from,
277 register caddr_t to,
278 int size)
279{
280 pmap_movepage((unsigned long)from, (unsigned long)to, (vm_size_t)size);
281}
282
283/*
284 * System Call handling code
285 */
286
287#define ERESTART -1 /* restart syscall */
288#define EJUSTRETURN -2 /* don't modify regs, just return */
289
290struct 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 */
295};
296
9bccf70c 297#define NO_FUNNEL 0
1c79356b
A
298#define KERNEL_FUNNEL 1
299#define NETWORK_FUNNEL 2
300
301extern funnel_t * kernel_flock;
302extern funnel_t * network_flock;
303
304extern struct sysent sysent[];
305
1c79356b
A
306int set_bsduthreadargs (thread_act_t, struct i386_saved_state *, void *);
307
308void * get_bsduthreadarg(thread_act_t);
309
310void unix_syscall(struct i386_saved_state *);
311
312void
313unix_syscall_return(int error)
314{
0b4e3aa0
A
315 thread_act_t thread;
316 volatile int *rval;
317 struct i386_saved_state *regs;
9bccf70c
A
318 struct proc *p;
319 struct proc *current_proc();
320 unsigned short code;
321 vm_offset_t params;
322 struct sysent *callp;
323 extern int nsysent;
0b4e3aa0
A
324
325 thread = current_act();
326 rval = (int *)get_bsduthreadrval(thread);
9bccf70c 327 p = current_proc();
0b4e3aa0
A
328
329 regs = USER_REGS(thread);
330
9bccf70c
A
331 /* reconstruct code for tracing before blasting eax */
332 code = regs->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);
337 }
338
0b4e3aa0
A
339 if (error == ERESTART) {
340 regs->eip -= 7;
341 }
342 else if (error != EJUSTRETURN) {
343 if (error) {
344 regs->eax = error;
345 regs->efl |= EFL_CF; /* carry bit */
346 } else { /* (not error) */
347 regs->eax = rval[0];
348 regs->edx = rval[1];
349 regs->efl &= ~EFL_CF;
350 }
351 }
352
9bccf70c
A
353 ktrsysret(p, code, error, rval[0], callp->sy_funnel);
354
355 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
356 error, rval[0], rval[1], 0, 0);
357
55e303ae 358 if (callp->sy_funnel != NO_FUNNEL)
9bccf70c 359 (void) thread_funnel_set(current_thread()->funnel_lock, FALSE);
0b4e3aa0
A
360
361 thread_exception_return();
362 /* NOTREACHED */
1c79356b
A
363}
364
365
366void
367unix_syscall(struct i386_saved_state *regs)
368{
369 thread_act_t thread;
9bccf70c 370 void *vt;
1c79356b
A
371 unsigned short code;
372 struct sysent *callp;
373 int nargs, error;
0b4e3aa0 374 volatile int *rval;
9bccf70c 375 int funnel_type;
1c79356b
A
376 vm_offset_t params;
377 extern int nsysent;
9bccf70c
A
378 struct proc *p;
379 struct proc *current_proc();
1c79356b
A
380
381 thread = current_act();
0b4e3aa0 382 p = current_proc();
1c79356b
A
383 rval = (int *)get_bsduthreadrval(thread);
384
385 //printf("[scall : eax %x]", regs->eax);
386 code = 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];
393 }
394
395 vt = get_bsduthreadarg(thread);
396
397 if ((nargs = (callp->sy_narg * sizeof (int))) &&
398 (error = copyin((char *) params, (char *)vt , nargs)) != 0) {
399 regs->eax = error;
400 regs->efl |= EFL_CF;
401 thread_exception_return();
402 /* NOTREACHED */
403 }
404
405 rval[0] = 0;
406 rval[1] = regs->edx;
407
9bccf70c
A
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);
413
1c79356b
A
414 set_bsduthreadargs(thread, regs, NULL);
415
416 if (callp->sy_narg > 8)
417 panic("unix_syscall max arg count exceeded (%d)", callp->sy_narg);
418
9bccf70c
A
419 ktrsyscall(p, code, callp->sy_narg, vt, funnel_type);
420
421 {
422 int *ip = (int *)vt;
423 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_START,
424 *ip, *(ip+1), *(ip+2), *(ip+3), 0);
425 }
1c79356b 426
55e303ae 427 error = (*(callp->sy_call))(p, (void *) vt, (int *) &rval[0]);
1c79356b 428
0b4e3aa0
A
429#if 0
430 /* May be needed with vfork changes */
431 regs = USER_REGS(thread);
432#endif
1c79356b
A
433 if (error == ERESTART) {
434 regs->eip -= 7;
435 }
436 else if (error != EJUSTRETURN) {
437 if (error) {
438 regs->eax = error;
439 regs->efl |= EFL_CF; /* carry bit */
440 } else { /* (not error) */
441 regs->eax = rval[0];
442 regs->edx = rval[1];
443 regs->efl &= ~EFL_CF;
444 }
445 }
446
9bccf70c
A
447 ktrsysret(p, code, error, rval[0], funnel_type);
448
449 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END,
450 error, rval[0], rval[1], 0, 0);
451
452 if(funnel_type != NO_FUNNEL)
453 (void) thread_funnel_set(current_thread()->funnel_lock, FALSE);
1c79356b
A
454
455 thread_exception_return();
456 /* NOTREACHED */
457}
458
459
460void
461machdep_syscall( struct i386_saved_state *regs)
462{
463 int trapno, nargs;
464 machdep_call_t *entry;
465 thread_t thread;
9bccf70c
A
466 struct proc *p;
467 struct proc *current_proc();
1c79356b
A
468
469 trapno = regs->eax;
470 if (trapno < 0 || trapno >= machdep_call_count) {
471 regs->eax = (unsigned int)kern_invalid();
472
473 thread_exception_return();
474 /* NOTREACHED */
475 }
476
477 entry = &machdep_call_table[trapno];
478 nargs = entry->nargs;
479
480 if (nargs > 0) {
481 int args[nargs];
482
483 if (copyin((char *) regs->uesp + sizeof (int),
484 (char *) args,
485 nargs * sizeof (int))) {
486
487 regs->eax = KERN_INVALID_ADDRESS;
488
489 thread_exception_return();
490 /* NOTREACHED */
491 }
492
55e303ae
A
493 switch (nargs) {
494 case 1:
495 regs->eax = (*entry->routine)(args[0]);
496 break;
497 case 2:
498 regs->eax = (*entry->routine)(args[0],args[1]);
499 break;
500 case 3:
501 regs->eax = (*entry->routine)(args[0],args[1],args[2]);
502 break;
503 case 4:
504 regs->eax = (*entry->routine)(args[0],args[1],args[2],args[3]);
505 break;
506 default:
507 panic("machdep_syscall(): too many args");
508 }
1c79356b
A
509 }
510 else
55e303ae 511 regs->eax = (*entry->routine)();
1c79356b 512
55e303ae
A
513 if (current_thread()->funnel_lock)
514 (void) thread_funnel_set(current_thread()->funnel_lock, FALSE);
1c79356b
A
515
516 thread_exception_return();
517 /* NOTREACHED */
518}
519
520
55e303ae
A
521kern_return_t
522thread_compose_cthread_desc(unsigned int addr, pcb_t pcb)
523{
524 struct real_descriptor desc;
525 extern struct fake_descriptor *mp_ldt[];
526 struct real_descriptor *ldtp;
527 int mycpu = cpu_number();
528
529 ldtp = (struct real_descriptor *)mp_ldt[mycpu];
530 desc.limit_low = 1;
531 desc.limit_high = 0;
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);
540}
541
1c79356b
A
542kern_return_t
543thread_set_cthread_self(int self)
544{
545 current_act()->mact.pcb->cthread_self = (unsigned int)self;
546
547 return (KERN_SUCCESS);
548}
549
550kern_return_t
551thread_get_cthread_self(void)
552{
553 return ((kern_return_t)current_act()->mact.pcb->cthread_self);
554}
555
55e303ae
A
556kern_return_t
557thread_fast_set_cthread_self(int self)
558{
559 pcb_t pcb;
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);
564}
565
1c79356b
A
566void
567mach25_syscall(struct i386_saved_state *regs)
568{
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);
571 panic("FIXME!");
572}
1c79356b
A
573#endif /* MACH_BSD */
574
55e303ae
A
575
576/* This routine is called from assembly before each and every mach trap.
577 */
578
579extern unsigned int mach_call_start(unsigned int, unsigned int *);
580
581__private_extern__
582unsigned int
583mach_call_start(unsigned int call_number, unsigned int *args)
1c79356b 584{
55e303ae
A
585 int i, argc;
586 unsigned int kdarg[3];
587
588/* Always prepare to trace mach system calls */
589
590 kdarg[0]=0;
591 kdarg[1]=0;
592 kdarg[2]=0;
593
594 argc = mach_trap_table[call_number>>4].mach_trap_arg_count;
595
596 if (argc > 3)
597 argc = 3;
598
599 for (i=0; i < argc; i++)
600 kdarg[i] = (int)*(args + i);
601
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);
604
605 return call_number; /* pass this back thru */
606}
607
608/* This routine is called from assembly after each mach system call
609 */
610
611extern unsigned int mach_call_end(unsigned int, unsigned int);
612
613__private_extern__
614unsigned int
615mach_call_end(unsigned int call_number, unsigned int retval)
616{
617 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC,(call_number>>4)) | DBG_FUNC_END,
618 retval, 0, 0, 0, 0);
619 return retval; /* pass this back thru */
1c79356b 620}
55e303ae 621