]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/bsd_i386.c
xnu-517.12.7.tar.gz
[apple/xnu.git] / osfmk / i386 / bsd_i386.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
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>
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>
42 #include <kern/syscall_sw.h>
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
57 #include <sys/syscall.h>
58 #include <sys/ktrace.h>
59 struct proc;
60
61 kern_return_t
62 thread_userstack(
63 thread_t,
64 int,
65 thread_state_t,
66 unsigned int,
67 vm_offset_t *,
68 int *
69 );
70
71 kern_return_t
72 thread_entrypoint(
73 thread_t,
74 int,
75 thread_state_t,
76 unsigned int,
77 vm_offset_t *
78 );
79
80 struct i386_saved_state *
81 get_user_regs(
82 thread_act_t);
83
84 unsigned int get_msr_exportmask(void);
85
86 unsigned int get_msr_nbits(void);
87
88 unsigned int get_msr_rbits(void);
89
90 kern_return_t
91 thread_compose_cthread_desc(unsigned int addr, pcb_t pcb);
92
93 /*
94 * thread_userstack:
95 *
96 * Return the user stack pointer from the machine
97 * dependent thread state info.
98 */
99 kern_return_t
100 thread_userstack(
101 thread_t thread,
102 int flavor,
103 thread_state_t tstate,
104 unsigned int count,
105 vm_offset_t *user_stack,
106 int *customstack
107 )
108 {
109 struct i386_saved_state *state;
110 i386_thread_state_t *state25;
111 vm_offset_t uesp;
112
113 if (customstack)
114 *customstack = 0;
115
116 switch (flavor) {
117 case i386_THREAD_STATE: /* FIXME */
118 state25 = (i386_thread_state_t *) tstate;
119 if (state25->esp)
120 *user_stack = state25->esp;
121 if (customstack && state25->esp)
122 *customstack = 1;
123 else
124 *customstack = 0;
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
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;
142 break;
143 default :
144 return (KERN_INVALID_ARGUMENT);
145 }
146
147 return (KERN_SUCCESS);
148 }
149
150 kern_return_t
151 thread_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
191 struct i386_saved_state *
192 get_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 */
206 kern_return_t
207 machine_thread_dup(
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
223 if (child->mact.pcb == NULL || parent->mact.pcb == NULL)
224 return (KERN_FAILURE);
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 */
242
243 return (KERN_SUCCESS);
244 }
245
246 /*
247 * FIXME - thread_set_child
248 */
249
250 void thread_set_child(thread_act_t child, int pid);
251 void
252 thread_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 }
258 void thread_set_parent(thread_act_t parent, int pid);
259 void
260 thread_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 }
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 */
274 void
275 pagemove(
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
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 */
295 };
296
297 #define NO_FUNNEL 0
298 #define KERNEL_FUNNEL 1
299 #define NETWORK_FUNNEL 2
300
301 extern funnel_t * kernel_flock;
302 extern funnel_t * network_flock;
303
304 extern struct sysent sysent[];
305
306 int set_bsduthreadargs (thread_act_t, struct i386_saved_state *, void *);
307
308 void * get_bsduthreadarg(thread_act_t);
309
310 void unix_syscall(struct i386_saved_state *);
311
312 void
313 unix_syscall_return(int error)
314 {
315 thread_act_t thread;
316 volatile int *rval;
317 struct i386_saved_state *regs;
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;
324
325 thread = current_act();
326 rval = (int *)get_bsduthreadrval(thread);
327 p = current_proc();
328
329 regs = USER_REGS(thread);
330
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
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
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
358 if (callp->sy_funnel != NO_FUNNEL)
359 (void) thread_funnel_set(current_thread()->funnel_lock, FALSE);
360
361 thread_exception_return();
362 /* NOTREACHED */
363 }
364
365
366 void
367 unix_syscall(struct i386_saved_state *regs)
368 {
369 thread_act_t thread;
370 void *vt;
371 unsigned short code;
372 struct sysent *callp;
373 int nargs, error;
374 volatile int *rval;
375 int funnel_type;
376 vm_offset_t params;
377 extern int nsysent;
378 struct proc *p;
379 struct proc *current_proc();
380
381 thread = current_act();
382 p = current_proc();
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
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
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
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 }
426
427 error = (*(callp->sy_call))(p, (void *) vt, (int *) &rval[0]);
428
429 #if 0
430 /* May be needed with vfork changes */
431 regs = USER_REGS(thread);
432 #endif
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
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);
454
455 thread_exception_return();
456 /* NOTREACHED */
457 }
458
459
460 void
461 machdep_syscall( struct i386_saved_state *regs)
462 {
463 int trapno, nargs;
464 machdep_call_t *entry;
465 thread_t thread;
466 struct proc *p;
467 struct proc *current_proc();
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
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 }
509 }
510 else
511 regs->eax = (*entry->routine)();
512
513 if (current_thread()->funnel_lock)
514 (void) thread_funnel_set(current_thread()->funnel_lock, FALSE);
515
516 thread_exception_return();
517 /* NOTREACHED */
518 }
519
520
521 kern_return_t
522 thread_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
542 kern_return_t
543 thread_set_cthread_self(int self)
544 {
545 current_act()->mact.pcb->cthread_self = (unsigned int)self;
546
547 return (KERN_SUCCESS);
548 }
549
550 kern_return_t
551 thread_get_cthread_self(void)
552 {
553 return ((kern_return_t)current_act()->mact.pcb->cthread_self);
554 }
555
556 kern_return_t
557 thread_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
566 void
567 mach25_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 }
573 #endif /* MACH_BSD */
574
575
576 /* This routine is called from assembly before each and every mach trap.
577 */
578
579 extern unsigned int mach_call_start(unsigned int, unsigned int *);
580
581 __private_extern__
582 unsigned int
583 mach_call_start(unsigned int call_number, unsigned int *args)
584 {
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
611 extern unsigned int mach_call_end(unsigned int, unsigned int);
612
613 __private_extern__
614 unsigned int
615 mach_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 */
620 }
621