]> git.saurik.com Git - apple/xnu.git/blame - osfmk/i386/pcb.c
xnu-517.3.15.tar.gz
[apple/xnu.git] / osfmk / i386 / pcb.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
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
13 * file.
14 *
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
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
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.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * @OSF_COPYRIGHT@
27 */
28/*
29 * Mach Operating System
30 * Copyright (c) 1991,1990 Carnegie Mellon University
31 * All Rights Reserved.
32 *
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
38 *
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
42 *
43 * Carnegie Mellon requests users of this software to return to
44 *
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
49 *
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
52 */
53
54#include <cpus.h>
55#include <mach_rt.h>
56#include <mach_debug.h>
57#include <mach_ldebug.h>
58
59#include <sys/kdebug.h>
60
61#include <mach/kern_return.h>
62#include <mach/thread_status.h>
63#include <mach/vm_param.h>
1c79356b
A
64
65#include <kern/counters.h>
66#include <kern/mach_param.h>
67#include <kern/task.h>
68#include <kern/thread.h>
69#include <kern/thread_act.h>
70#include <kern/thread_swap.h>
71#include <kern/sched_prim.h>
72#include <kern/misc_protos.h>
73#include <kern/assert.h>
74#include <kern/spl.h>
75#include <ipc/ipc_port.h>
76#include <vm/vm_kern.h>
77#include <vm/pmap.h>
78
79#include <i386/thread.h>
80#include <i386/eflags.h>
81#include <i386/proc_reg.h>
82#include <i386/seg.h>
83#include <i386/tss.h>
84#include <i386/user_ldt.h>
85#include <i386/fpu.h>
86#include <i386/iopb_entries.h>
87
55e303ae
A
88vm_offset_t active_stacks[NCPUS];
89vm_offset_t kernel_stack[NCPUS];
90thread_act_t active_kloaded[NCPUS];
91
1c79356b
A
92/*
93 * Maps state flavor to number of words in the state:
94 */
95unsigned int state_count[] = {
96 /* FLAVOR_LIST */ 0,
97 i386_NEW_THREAD_STATE_COUNT,
98 i386_FLOAT_STATE_COUNT,
99 i386_ISA_PORT_MAP_STATE_COUNT,
100 i386_V86_ASSIST_STATE_COUNT,
101 i386_REGS_SEGS_STATE_COUNT,
102 i386_THREAD_SYSCALL_STATE_COUNT,
103 /* THREAD_STATE_NONE */ 0,
104 i386_SAVED_STATE_COUNT,
105};
106
107/* Forward */
108
109void act_machine_throughcall(thread_act_t thr_act);
110extern thread_t Switch_context(
111 thread_t old,
112 void (*cont)(void),
113 thread_t new);
114extern void Thread_continue(void);
115extern void Load_context(
116 thread_t thread);
117
118/*
119 * consider_machine_collect:
120 *
121 * Try to collect machine-dependent pages
122 */
123void
124consider_machine_collect()
125{
126}
127
128void
129consider_machine_adjust()
130{
131}
132
133
134/*
135 * machine_kernel_stack_init:
136 *
137 * Initialize a kernel stack which has already been
138 * attached to its thread_activation.
139 */
140
141void
142machine_kernel_stack_init(
143 thread_t thread,
144 void (*start_pos)(thread_t))
145{
146 thread_act_t thr_act = thread->top_act;
147 vm_offset_t stack;
148
149 assert(thr_act);
150 stack = thread->kernel_stack;
151 assert(stack);
152
1c79356b
A
153 /*
154 * We want to run at start_pos, giving it as an argument
155 * the return value from Load_context/Switch_context.
156 * Thread_continue takes care of the mismatch between
157 * the argument-passing/return-value conventions.
158 * This function will not return normally,
159 * so we don`t have to worry about a return address.
160 */
161 STACK_IKS(stack)->k_eip = (int) Thread_continue;
162 STACK_IKS(stack)->k_ebx = (int) start_pos;
163 STACK_IKS(stack)->k_esp = (int) STACK_IEL(stack);
164
165 /*
166 * Point top of kernel stack to user`s registers.
167 */
168 STACK_IEL(stack)->saved_state = &thr_act->mact.pcb->iss;
169}
170
171
172#if NCPUS > 1
173#define curr_gdt(mycpu) (mp_gdt[mycpu])
55e303ae 174#define curr_ldt(mycpu) (mp_ldt[mycpu])
1c79356b
A
175#define curr_ktss(mycpu) (mp_ktss[mycpu])
176#else
177#define curr_gdt(mycpu) (gdt)
55e303ae 178#define curr_ldt(mycpu) (ldt)
1c79356b
A
179#define curr_ktss(mycpu) (&ktss)
180#endif
181
182#define gdt_desc_p(mycpu,sel) \
183 ((struct real_descriptor *)&curr_gdt(mycpu)[sel_idx(sel)])
184
185void
186act_machine_switch_pcb( thread_act_t new_act )
187{
188 pcb_t pcb = new_act->mact.pcb;
189 int mycpu;
1c79356b
A
190 register iopb_tss_t tss = pcb->ims.io_tss;
191 vm_offset_t pcb_stack_top;
55e303ae 192 register user_ldt_t ldt = pcb->ims.ldt;
1c79356b
A
193
194 assert(new_act->thread != NULL);
195 assert(new_act->thread->kernel_stack != 0);
196 STACK_IEL(new_act->thread->kernel_stack)->saved_state =
197 &new_act->mact.pcb->iss;
198
199 /*
200 * Save a pointer to the top of the "kernel" stack -
201 * actually the place in the PCB where a trap into
202 * kernel mode will push the registers.
203 * The location depends on V8086 mode. If we are
204 * not in V8086 mode, then a trap into the kernel
205 * won`t save the v86 segments, so we leave room.
206 */
207
208 pcb_stack_top = (pcb->iss.efl & EFL_VM)
209 ? (int) (&pcb->iss + 1)
210 : (int) (&pcb->iss.v86_segs);
211
212 mp_disable_preemption();
213 mycpu = cpu_number();
214
215 if (tss == 0) {
216 /*
217 * No per-thread IO permissions.
218 * Use standard kernel TSS.
219 */
220 if (!(gdt_desc_p(mycpu,KERNEL_TSS)->access & ACC_TSS_BUSY))
221 set_tr(KERNEL_TSS);
222 curr_ktss(mycpu)->esp0 = pcb_stack_top;
223 }
224 else {
225 /*
226 * Set the IO permissions. Use this thread`s TSS.
227 */
228 *gdt_desc_p(mycpu,USER_TSS)
229 = *(struct real_descriptor *)tss->iopb_desc;
230 tss->tss.esp0 = pcb_stack_top;
231 set_tr(USER_TSS);
232 gdt_desc_p(mycpu,KERNEL_TSS)->access &= ~ ACC_TSS_BUSY;
233 }
1c79356b 234
1c79356b
A
235 /*
236 * Set the thread`s LDT.
237 */
238 if (ldt == 0) {
55e303ae 239 struct real_descriptor *ldtp;
1c79356b
A
240 /*
241 * Use system LDT.
242 */
55e303ae
A
243 ldtp = (struct real_descriptor *)curr_ldt(mycpu);
244 ldtp[sel_idx(USER_CTHREAD)] = pcb->cthread_desc;
1c79356b
A
245 set_ldt(KERNEL_LDT);
246 }
247 else {
248 /*
249 * Thread has its own LDT.
250 */
251 *gdt_desc_p(mycpu,USER_LDT) = ldt->desc;
252 set_ldt(USER_LDT);
253 }
55e303ae 254
1c79356b
A
255 mp_enable_preemption();
256 /*
257 * Load the floating-point context, if necessary.
258 */
259 fpu_load_context(pcb);
260
261}
262
1c79356b
A
263/*
264 * Switch to the first thread on a CPU.
265 */
266void
55e303ae 267machine_load_context(
1c79356b
A
268 thread_t new)
269{
270 act_machine_switch_pcb(new->top_act);
271 Load_context(new);
272}
273
274/*
275 * Number of times we needed to swap an activation back in before
276 * switching to it.
277 */
278int switch_act_swapins = 0;
279
280/*
281 * machine_switch_act
282 *
283 * Machine-dependent details of activation switching. Called with
284 * RPC locks held and preemption disabled.
285 */
286void
287machine_switch_act(
288 thread_t thread,
289 thread_act_t old,
55e303ae 290 thread_act_t new)
1c79356b 291{
55e303ae
A
292 int cpu = cpu_number();
293
1c79356b
A
294 /*
295 * Switch the vm, ast and pcb context.
296 * Save FP registers if in use and set TS (task switch) bit.
297 */
298 fpu_save_context(thread);
299
300 active_stacks[cpu] = thread->kernel_stack;
301 ast_context(new, cpu);
302
303 PMAP_SWITCH_CONTEXT(old, new, cpu);
304 act_machine_switch_pcb(new);
305}
306
307/*
308 * Switch to a new thread.
309 * Save the old thread`s kernel state or continuation,
310 * and return it.
311 */
312thread_t
55e303ae 313machine_switch_context(
1c79356b
A
314 thread_t old,
315 void (*continuation)(void),
316 thread_t new)
317{
318 register thread_act_t old_act = old->top_act,
319 new_act = new->top_act;
320
321#if MACH_RT
55e303ae 322 assert(active_stacks[cpu_number()] == old_act->thread->kernel_stack);
1c79356b
A
323#endif
324 check_simple_locks();
325
326 /*
327 * Save FP registers if in use.
328 */
329 fpu_save_context(old);
330
1c79356b
A
331 /*
332 * Switch address maps if need be, even if not switching tasks.
333 * (A server activation may be "borrowing" a client map.)
334 */
335 {
336 int mycpu = cpu_number();
337
338 PMAP_SWITCH_CONTEXT(old_act, new_act, mycpu)
339 }
340
341 /*
342 * Load the rest of the user state for the new thread
343 */
344 act_machine_switch_pcb(new_act);
9bccf70c
A
345 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_SCHED) | DBG_FUNC_NONE,
346 (int)old, (int)new, old->sched_pri, new->sched_pri, 0);
55e303ae 347 old->continuation = NULL;
1c79356b
A
348 return(Switch_context(old, continuation, new));
349}
350
1c79356b
A
351/*
352 * act_machine_sv_free
353 * release saveareas associated with an act. if flag is true, release
354 * user level savearea(s) too, else don't
355 */
356void
357act_machine_sv_free(thread_act_t act, int flag)
358{
1c79356b
A
359}
360
361/*
362 * act_machine_set_state:
363 *
364 * Set the status of the specified thread. Called with "appropriate"
365 * thread-related locks held (see act_lock_thread()), so
366 * thr_act->thread is guaranteed not to change.
367 */
368
369kern_return_t
55e303ae 370machine_thread_set_state(
1c79356b
A
371 thread_act_t thr_act,
372 thread_flavor_t flavor,
373 thread_state_t tstate,
374 mach_msg_type_number_t count)
375{
55e303ae 376 int kernel_act = 0;
1c79356b
A
377
378 switch (flavor) {
379 case THREAD_SYSCALL_STATE:
380 {
381 register struct thread_syscall_state *state;
382 register struct i386_saved_state *saved_state = USER_REGS(thr_act);
383
384 state = (struct thread_syscall_state *) tstate;
385 saved_state->eax = state->eax;
386 saved_state->edx = state->edx;
387 if (kernel_act)
388 saved_state->efl = state->efl;
389 else
390 saved_state->efl = (state->efl & ~EFL_USER_CLEAR) | EFL_USER_SET;
391 saved_state->eip = state->eip;
392 saved_state->uesp = state->esp;
393 break;
394 }
395
396 case i386_SAVED_STATE:
397 {
398 register struct i386_saved_state *state;
399 register struct i386_saved_state *saved_state;
400
401 if (count < i386_SAVED_STATE_COUNT) {
402 return(KERN_INVALID_ARGUMENT);
403 }
404
405 state = (struct i386_saved_state *) tstate;
406
407 saved_state = USER_REGS(thr_act);
408
409 /*
410 * General registers
411 */
412 saved_state->edi = state->edi;
413 saved_state->esi = state->esi;
414 saved_state->ebp = state->ebp;
415 saved_state->uesp = state->uesp;
416 saved_state->ebx = state->ebx;
417 saved_state->edx = state->edx;
418 saved_state->ecx = state->ecx;
419 saved_state->eax = state->eax;
420 saved_state->eip = state->eip;
421 if (kernel_act)
422 saved_state->efl = state->efl;
423 else
424 saved_state->efl = (state->efl & ~EFL_USER_CLEAR)
425 | EFL_USER_SET;
426
427 /*
428 * Segment registers. Set differently in V8086 mode.
429 */
430 if (state->efl & EFL_VM) {
431 /*
432 * Set V8086 mode segment registers.
433 */
434 saved_state->cs = state->cs & 0xffff;
435 saved_state->ss = state->ss & 0xffff;
436 saved_state->v86_segs.v86_ds = state->ds & 0xffff;
437 saved_state->v86_segs.v86_es = state->es & 0xffff;
438 saved_state->v86_segs.v86_fs = state->fs & 0xffff;
439 saved_state->v86_segs.v86_gs = state->gs & 0xffff;
440
441 /*
442 * Zero protected mode segment registers.
443 */
444 saved_state->ds = 0;
445 saved_state->es = 0;
446 saved_state->fs = 0;
447 saved_state->gs = 0;
448
449 if (thr_act->mact.pcb->ims.v86s.int_table) {
450 /*
451 * Hardware assist on.
452 */
453 thr_act->mact.pcb->ims.v86s.flags =
454 state->efl & (EFL_TF | EFL_IF);
455 }
456 }
55e303ae 457 else if (kernel_act) {
1c79356b
A
458 /*
459 * 386 mode. Set segment registers for flat
460 * 32-bit address space.
461 */
55e303ae
A
462 saved_state->cs = KERNEL_CS;
463 saved_state->ss = KERNEL_DS;
464 saved_state->ds = KERNEL_DS;
465 saved_state->es = KERNEL_DS;
466 saved_state->fs = KERNEL_DS;
467 saved_state->gs = CPU_DATA;
1c79356b
A
468 }
469 else {
470 /*
471 * User setting segment registers.
472 * Code and stack selectors have already been
473 * checked. Others will be reset by 'iret'
474 * if they are not valid.
475 */
476 saved_state->cs = state->cs;
477 saved_state->ss = state->ss;
478 saved_state->ds = state->ds;
479 saved_state->es = state->es;
480 saved_state->fs = state->fs;
481 saved_state->gs = state->gs;
482 }
483 break;
484 }
485
486 case i386_NEW_THREAD_STATE:
487 case i386_REGS_SEGS_STATE:
488 {
489 register struct i386_new_thread_state *state;
490 register struct i386_saved_state *saved_state;
491
492 if (count < i386_NEW_THREAD_STATE_COUNT) {
493 return(KERN_INVALID_ARGUMENT);
494 }
495
496 if (flavor == i386_REGS_SEGS_STATE) {
497 /*
498 * Code and stack selectors must not be null,
499 * and must have user protection levels.
500 * Only the low 16 bits are valid.
501 */
502 state->cs &= 0xffff;
503 state->ss &= 0xffff;
504 state->ds &= 0xffff;
505 state->es &= 0xffff;
506 state->fs &= 0xffff;
507 state->gs &= 0xffff;
508
509 if (!kernel_act &&
510 (state->cs == 0 || (state->cs & SEL_PL) != SEL_PL_U
511 || state->ss == 0 || (state->ss & SEL_PL) != SEL_PL_U))
512 return KERN_INVALID_ARGUMENT;
513 }
514
515 state = (struct i386_new_thread_state *) tstate;
516
517 saved_state = USER_REGS(thr_act);
518
519 /*
520 * General registers
521 */
522 saved_state->edi = state->edi;
523 saved_state->esi = state->esi;
524 saved_state->ebp = state->ebp;
525 saved_state->uesp = state->uesp;
526 saved_state->ebx = state->ebx;
527 saved_state->edx = state->edx;
528 saved_state->ecx = state->ecx;
529 saved_state->eax = state->eax;
530 saved_state->eip = state->eip;
531 if (kernel_act)
532 saved_state->efl = state->efl;
533 else
534 saved_state->efl = (state->efl & ~EFL_USER_CLEAR)
535 | EFL_USER_SET;
536
537 /*
538 * Segment registers. Set differently in V8086 mode.
539 */
540 if (state->efl & EFL_VM) {
541 /*
542 * Set V8086 mode segment registers.
543 */
544 saved_state->cs = state->cs & 0xffff;
545 saved_state->ss = state->ss & 0xffff;
546 saved_state->v86_segs.v86_ds = state->ds & 0xffff;
547 saved_state->v86_segs.v86_es = state->es & 0xffff;
548 saved_state->v86_segs.v86_fs = state->fs & 0xffff;
549 saved_state->v86_segs.v86_gs = state->gs & 0xffff;
550
551 /*
552 * Zero protected mode segment registers.
553 */
554 saved_state->ds = 0;
555 saved_state->es = 0;
556 saved_state->fs = 0;
557 saved_state->gs = 0;
558
559 if (thr_act->mact.pcb->ims.v86s.int_table) {
560 /*
561 * Hardware assist on.
562 */
563 thr_act->mact.pcb->ims.v86s.flags =
564 state->efl & (EFL_TF | EFL_IF);
565 }
566 }
55e303ae 567 else if (flavor == i386_NEW_THREAD_STATE && kernel_act) {
1c79356b
A
568 /*
569 * 386 mode. Set segment registers for flat
570 * 32-bit address space.
571 */
55e303ae
A
572 saved_state->cs = KERNEL_CS;
573 saved_state->ss = KERNEL_DS;
574 saved_state->ds = KERNEL_DS;
575 saved_state->es = KERNEL_DS;
576 saved_state->fs = KERNEL_DS;
577 saved_state->gs = CPU_DATA;
1c79356b
A
578 }
579 else {
580 /*
581 * User setting segment registers.
582 * Code and stack selectors have already been
583 * checked. Others will be reset by 'iret'
584 * if they are not valid.
585 */
586 saved_state->cs = state->cs;
587 saved_state->ss = state->ss;
588 saved_state->ds = state->ds;
589 saved_state->es = state->es;
590 saved_state->fs = state->fs;
591 saved_state->gs = state->gs;
592 }
593 break;
594 }
595
596 case i386_FLOAT_STATE: {
55e303ae
A
597 struct i386_float_state *state = (struct i386_float_state*)tstate;
598 if (count < i386_old_FLOAT_STATE_COUNT)
1c79356b 599 return(KERN_INVALID_ARGUMENT);
55e303ae
A
600 if (count < i386_FLOAT_STATE_COUNT)
601 return fpu_set_state(thr_act,(struct i386_float_state*)tstate);
602 else return fpu_set_fxstate(thr_act,(struct i386_float_state*)tstate);
1c79356b
A
603 }
604
605 /*
606 * Temporary - replace by i386_io_map
607 */
608 case i386_ISA_PORT_MAP_STATE: {
609 register struct i386_isa_port_map_state *state;
610 register iopb_tss_t tss;
611
612 if (count < i386_ISA_PORT_MAP_STATE_COUNT)
613 return(KERN_INVALID_ARGUMENT);
614
615 break;
616 }
617
618 case i386_V86_ASSIST_STATE:
619 {
620 register struct i386_v86_assist_state *state;
621 vm_offset_t int_table;
622 int int_count;
623
624 if (count < i386_V86_ASSIST_STATE_COUNT)
625 return KERN_INVALID_ARGUMENT;
626
627 state = (struct i386_v86_assist_state *) tstate;
628 int_table = state->int_table;
629 int_count = state->int_count;
630
631 if (int_table >= VM_MAX_ADDRESS ||
632 int_table +
633 int_count * sizeof(struct v86_interrupt_table)
634 > VM_MAX_ADDRESS)
635 return KERN_INVALID_ARGUMENT;
636
637 thr_act->mact.pcb->ims.v86s.int_table = int_table;
638 thr_act->mact.pcb->ims.v86s.int_count = int_count;
639
640 thr_act->mact.pcb->ims.v86s.flags =
641 USER_REGS(thr_act)->efl & (EFL_TF | EFL_IF);
642 break;
643 }
644
645 case i386_THREAD_STATE: {
646 struct i386_saved_state *saved_state;
647 i386_thread_state_t *state25;
648
649 saved_state = USER_REGS(thr_act);
650 state25 = (i386_thread_state_t *)tstate;
651
652 saved_state->eax = state25->eax;
653 saved_state->ebx = state25->ebx;
654 saved_state->ecx = state25->ecx;
655 saved_state->edx = state25->edx;
656 saved_state->edi = state25->edi;
657 saved_state->esi = state25->esi;
658 saved_state->ebp = state25->ebp;
659 saved_state->uesp = state25->esp;
660 saved_state->efl = (state25->eflags & ~EFL_USER_CLEAR)
661 | EFL_USER_SET;
662 saved_state->eip = state25->eip;
663 saved_state->cs = USER_CS; /* FIXME? */
664 saved_state->ss = USER_DS;
665 saved_state->ds = USER_DS;
666 saved_state->es = USER_DS;
55e303ae
A
667 saved_state->fs = state25->fs;
668 saved_state->gs = state25->gs;
1c79356b
A
669 }
670 break;
671
672 default:
673 return(KERN_INVALID_ARGUMENT);
674 }
675
676 return(KERN_SUCCESS);
677}
678
679/*
680 * thread_getstatus:
681 *
682 * Get the status of the specified thread.
683 */
684
685
686kern_return_t
55e303ae 687machine_thread_get_state(
1c79356b
A
688 thread_act_t thr_act,
689 thread_flavor_t flavor,
690 thread_state_t tstate,
691 mach_msg_type_number_t *count)
692{
1c79356b
A
693 switch (flavor) {
694
695 case i386_SAVED_STATE:
696 {
697 register struct i386_saved_state *state;
698 register struct i386_saved_state *saved_state;
699
700 if (*count < i386_SAVED_STATE_COUNT)
701 return(KERN_INVALID_ARGUMENT);
702
703 state = (struct i386_saved_state *) tstate;
704 saved_state = USER_REGS(thr_act);
705
706 /*
707 * First, copy everything:
708 */
709 *state = *saved_state;
710
711 if (saved_state->efl & EFL_VM) {
712 /*
713 * V8086 mode.
714 */
715 state->ds = saved_state->v86_segs.v86_ds & 0xffff;
716 state->es = saved_state->v86_segs.v86_es & 0xffff;
717 state->fs = saved_state->v86_segs.v86_fs & 0xffff;
718 state->gs = saved_state->v86_segs.v86_gs & 0xffff;
719
720 if (thr_act->mact.pcb->ims.v86s.int_table) {
721 /*
722 * Hardware assist on
723 */
724 if ((thr_act->mact.pcb->ims.v86s.flags &
725 (EFL_IF|V86_IF_PENDING)) == 0)
726 state->efl &= ~EFL_IF;
727 }
728 }
729 else {
730 /*
731 * 386 mode.
732 */
733 state->ds = saved_state->ds & 0xffff;
734 state->es = saved_state->es & 0xffff;
735 state->fs = saved_state->fs & 0xffff;
736 state->gs = saved_state->gs & 0xffff;
737 }
738 *count = i386_SAVED_STATE_COUNT;
739 break;
740 }
741
742 case i386_NEW_THREAD_STATE:
743 case i386_REGS_SEGS_STATE:
744 {
745 register struct i386_new_thread_state *state;
746 register struct i386_saved_state *saved_state;
747
748 if (*count < i386_NEW_THREAD_STATE_COUNT)
749 return(KERN_INVALID_ARGUMENT);
750
751 state = (struct i386_new_thread_state *) tstate;
752 saved_state = USER_REGS(thr_act);
753
754 /*
755 * General registers.
756 */
757 state->edi = saved_state->edi;
758 state->esi = saved_state->esi;
759 state->ebp = saved_state->ebp;
760 state->ebx = saved_state->ebx;
761 state->edx = saved_state->edx;
762 state->ecx = saved_state->ecx;
763 state->eax = saved_state->eax;
764 state->eip = saved_state->eip;
765 state->efl = saved_state->efl;
766 state->uesp = saved_state->uesp;
767
768 state->cs = saved_state->cs;
769 state->ss = saved_state->ss;
770 if (saved_state->efl & EFL_VM) {
771 /*
772 * V8086 mode.
773 */
774 state->ds = saved_state->v86_segs.v86_ds & 0xffff;
775 state->es = saved_state->v86_segs.v86_es & 0xffff;
776 state->fs = saved_state->v86_segs.v86_fs & 0xffff;
777 state->gs = saved_state->v86_segs.v86_gs & 0xffff;
778
779 if (thr_act->mact.pcb->ims.v86s.int_table) {
780 /*
781 * Hardware assist on
782 */
783 if ((thr_act->mact.pcb->ims.v86s.flags &
784 (EFL_IF|V86_IF_PENDING)) == 0)
785 state->efl &= ~EFL_IF;
786 }
787 }
788 else {
789 /*
790 * 386 mode.
791 */
792 state->ds = saved_state->ds & 0xffff;
793 state->es = saved_state->es & 0xffff;
794 state->fs = saved_state->fs & 0xffff;
795 state->gs = saved_state->gs & 0xffff;
796 }
797 *count = i386_NEW_THREAD_STATE_COUNT;
798 break;
799 }
800
801 case THREAD_SYSCALL_STATE:
802 {
803 register struct thread_syscall_state *state;
804 register struct i386_saved_state *saved_state = USER_REGS(thr_act);
805
806 state = (struct thread_syscall_state *) tstate;
807 state->eax = saved_state->eax;
808 state->edx = saved_state->edx;
809 state->efl = saved_state->efl;
810 state->eip = saved_state->eip;
811 state->esp = saved_state->uesp;
812 *count = i386_THREAD_SYSCALL_STATE_COUNT;
813 break;
814 }
815
816 case THREAD_STATE_FLAVOR_LIST:
817 if (*count < 5)
818 return (KERN_INVALID_ARGUMENT);
819 tstate[0] = i386_NEW_THREAD_STATE;
820 tstate[1] = i386_FLOAT_STATE;
821 tstate[2] = i386_ISA_PORT_MAP_STATE;
822 tstate[3] = i386_V86_ASSIST_STATE;
823 tstate[4] = THREAD_SYSCALL_STATE;
824 *count = 5;
825 break;
826
827 case i386_FLOAT_STATE: {
55e303ae 828 struct i386_float_state *state = (struct i386_float_state*)tstate;
1c79356b 829
55e303ae 830 if (*count < i386_old_FLOAT_STATE_COUNT)
1c79356b 831 return(KERN_INVALID_ARGUMENT);
55e303ae
A
832 if (*count< i386_FLOAT_STATE_COUNT) {
833 *count = i386_old_FLOAT_STATE_COUNT;
834 return fpu_get_state(thr_act,(struct i386_float_state *)tstate);
835 } else {
836 *count = i386_FLOAT_STATE_COUNT;
837 return fpu_get_fxstate(thr_act,(struct i386_float_state *)tstate);
838 }
1c79356b
A
839 }
840
841 /*
842 * Temporary - replace by i386_io_map
843 */
844 case i386_ISA_PORT_MAP_STATE: {
845 register struct i386_isa_port_map_state *state;
846 register iopb_tss_t tss;
847
848 if (*count < i386_ISA_PORT_MAP_STATE_COUNT)
849 return(KERN_INVALID_ARGUMENT);
850
851 state = (struct i386_isa_port_map_state *) tstate;
852 tss = thr_act->mact.pcb->ims.io_tss;
853
854 if (tss == 0) {
855 int i;
856
857 /*
858 * The thread has no ktss, so no IO permissions.
859 */
860
861 for (i = 0; i < sizeof state->pm; i++)
862 state->pm[i] = 0xff;
863 } else {
864 /*
865 * The thread has its own ktss.
866 */
867
868 bcopy((char *) tss->bitmap,
869 (char *) state->pm,
870 sizeof state->pm);
871 }
872
873 *count = i386_ISA_PORT_MAP_STATE_COUNT;
874 break;
875 }
876
877 case i386_V86_ASSIST_STATE:
878 {
879 register struct i386_v86_assist_state *state;
880
881 if (*count < i386_V86_ASSIST_STATE_COUNT)
882 return KERN_INVALID_ARGUMENT;
883
884 state = (struct i386_v86_assist_state *) tstate;
885 state->int_table = thr_act->mact.pcb->ims.v86s.int_table;
886 state->int_count = thr_act->mact.pcb->ims.v86s.int_count;
887
888 *count = i386_V86_ASSIST_STATE_COUNT;
889 break;
890 }
891
892 case i386_THREAD_STATE: {
893 struct i386_saved_state *saved_state;
894 i386_thread_state_t *state;
895
896 saved_state = USER_REGS(thr_act);
897 state = (i386_thread_state_t *)tstate;
898
899 state->eax = saved_state->eax;
900 state->ebx = saved_state->ebx;
901 state->ecx = saved_state->ecx;
902 state->edx = saved_state->edx;
903 state->edi = saved_state->edi;
904 state->esi = saved_state->esi;
905 state->ebp = saved_state->ebp;
906 state->esp = saved_state->uesp;
907 state->eflags = saved_state->efl;
908 state->eip = saved_state->eip;
909 state->cs = saved_state->cs;
910 state->ss = saved_state->ss;
911 state->ds = saved_state->ds;
912 state->es = saved_state->es;
913 state->fs = saved_state->fs;
914 state->gs = saved_state->gs;
915 break;
916 }
917
918 default:
919 return(KERN_INVALID_ARGUMENT);
920 }
921
922 return(KERN_SUCCESS);
923}
924
1c79356b
A
925/*
926 * Initialize the machine-dependent state for a new thread.
927 */
928kern_return_t
55e303ae
A
929machine_thread_create(
930 thread_t thread,
931 task_t task)
1c79356b 932{
55e303ae 933 pcb_t pcb = &thread->mact.xxx_pcb;
1c79356b 934
55e303ae 935 thread->mact.pcb = pcb;
1c79356b 936
55e303ae
A
937 simple_lock_init(&pcb->lock, ETAP_MISC_PCB);
938
939 /*
940 * Guarantee that the bootstrapped thread will be in user
941 * mode.
942 */
943 pcb->iss.cs = USER_CS;
944 pcb->iss.ss = USER_DS;
945 pcb->iss.ds = USER_DS;
946 pcb->iss.es = USER_DS;
947 pcb->iss.fs = USER_DS;
948 pcb->iss.gs = USER_DS;
949 pcb->iss.efl = EFL_USER_SET;
950 {
951 extern struct fake_descriptor ldt[];
952 struct real_descriptor *ldtp;
953 ldtp = (struct real_descriptor *)ldt;
954 pcb->cthread_desc = ldtp[sel_idx(USER_DS)];
955 }
1c79356b 956
0b4e3aa0
A
957 /*
958 * Allocate a kernel stack per shuttle
959 */
55e303ae 960 thread->kernel_stack = (int)stack_alloc(thread, thread_continue);
9bccf70c 961 thread->state &= ~TH_STACK_HANDOFF;
0b4e3aa0 962 assert(thread->kernel_stack != 0);
1c79356b
A
963
964 /*
0b4e3aa0 965 * Point top of kernel stack to user`s registers.
1c79356b 966 */
55e303ae 967 STACK_IEL(thread->kernel_stack)->saved_state = &pcb->iss;
0b4e3aa0 968
1c79356b
A
969 return(KERN_SUCCESS);
970}
971
972/*
973 * Machine-dependent cleanup prior to destroying a thread
974 */
975void
55e303ae
A
976machine_thread_destroy(
977 thread_t thread)
1c79356b 978{
55e303ae 979 register pcb_t pcb = thread->mact.pcb;
1c79356b 980
55e303ae
A
981 assert(pcb);
982
983 if (pcb->ims.io_tss != 0)
984 iopb_destroy(pcb->ims.io_tss);
985 if (pcb->ims.ifps != 0)
986 fp_free(pcb->ims.ifps);
987 if (pcb->ims.ldt != 0)
988 user_ldt_free(pcb->ims.ldt);
989 thread->mact.pcb = (pcb_t)0;
1c79356b
A
990}
991
992/*
993 * This is used to set the current thr_act/thread
994 * when starting up a new processor
995 */
996void
55e303ae 997machine_thread_set_current( thread_t thread )
1c79356b
A
998{
999 register int my_cpu;
1000
1001 mp_disable_preemption();
1002 my_cpu = cpu_number();
1003
55e303ae
A
1004 cpu_data[my_cpu].active_thread = thread->top_act;
1005 active_kloaded[my_cpu] = THR_ACT_NULL;
1c79356b
A
1006
1007 mp_enable_preemption();
1008}
1009
1c79356b 1010void
55e303ae 1011machine_thread_terminate_self(void)
1c79356b 1012{
1c79356b
A
1013}
1014
1015void
1016act_machine_return(int code)
1017{
1018 thread_act_t thr_act = current_act();
1019
1c79356b
A
1020 /*
1021 * This code is called with nothing locked.
1022 * It also returns with nothing locked, if it returns.
1023 *
1024 * This routine terminates the current thread activation.
1025 * If this is the only activation associated with its
1026 * thread shuttle, then the entire thread (shuttle plus
1027 * activation) is terminated.
1028 */
1029 assert( code == KERN_TERMINATED );
1030 assert( thr_act );
1031
1c79356b
A
1032 /* This is the only activation attached to the shuttle... */
1033 /* terminate the entire thread (shuttle plus activation) */
1034
1035 assert(thr_act->thread->top_act == thr_act);
1036 thread_terminate_self();
1037
1038 /*NOTREACHED*/
1039
1040 panic("act_machine_return: TALKING ZOMBIE! (1)");
1041}
1042
1043
1044/*
1045 * Perform machine-dependent per-thread initializations
1046 */
1047void
55e303ae 1048machine_thread_init(void)
1c79356b 1049{
55e303ae
A
1050 fpu_module_init();
1051 iopb_init();
1c79356b
A
1052}
1053
1054/*
1055 * Some routines for debugging activation code
1056 */
1057static void dump_handlers(thread_act_t);
1058void dump_regs(thread_act_t);
1059
1060static void
1061dump_handlers(thread_act_t thr_act)
1062{
1063 ReturnHandler *rhp = thr_act->handlers;
1064 int counter = 0;
1065
1066 printf("\t");
1067 while (rhp) {
1068 if (rhp == &thr_act->special_handler){
1069 if (rhp->next)
1070 printf("[NON-Zero next ptr(%x)]", rhp->next);
1071 printf("special_handler()->");
1072 break;
1073 }
1074 printf("hdlr_%d(%x)->",counter,rhp->handler);
1075 rhp = rhp->next;
1076 if (++counter > 32) {
1077 printf("Aborting: HUGE handler chain\n");
1078 break;
1079 }
1080 }
1081 printf("HLDR_NULL\n");
1082}
1083
1084void
1085dump_regs(thread_act_t thr_act)
1086{
1087 if (thr_act->mact.pcb) {
1088 register struct i386_saved_state *ssp = USER_REGS(thr_act);
1089 /* Print out user register state */
1090 printf("\tRegs:\tedi=%x esi=%x ebp=%x ebx=%x edx=%x\n",
1091 ssp->edi, ssp->esi, ssp->ebp, ssp->ebx, ssp->edx);
1092 printf("\t\tecx=%x eax=%x eip=%x efl=%x uesp=%x\n",
1093 ssp->ecx, ssp->eax, ssp->eip, ssp->efl, ssp->uesp);
1094 printf("\t\tcs=%x ss=%x\n", ssp->cs, ssp->ss);
1095 }
1096}
1097
1098int
1099dump_act(thread_act_t thr_act)
1100{
1101 if (!thr_act)
1102 return(0);
1103
1104 printf("thr_act(0x%x)(%d): thread=%x(%d) task=%x(%d)\n",
1105 thr_act, thr_act->ref_count,
1106 thr_act->thread, thr_act->thread ? thr_act->thread->ref_count:0,
1107 thr_act->task, thr_act->task ? thr_act->task->ref_count : 0);
1108
55e303ae 1109 printf("\tsusp=%d user_stop=%d active=%x ast=%x\n",
1c79356b
A
1110 thr_act->suspend_count, thr_act->user_stop_count,
1111 thr_act->active, thr_act->ast);
1112 printf("\thi=%x lo=%x\n", thr_act->higher, thr_act->lower);
1113 printf("\tpcb=%x\n", thr_act->mact.pcb);
1114
1115 if (thr_act->thread && thr_act->thread->kernel_stack) {
1116 vm_offset_t stack = thr_act->thread->kernel_stack;
1117
1118 printf("\tk_stk %x eip %x ebx %x esp %x iss %x\n",
1119 stack, STACK_IKS(stack)->k_eip, STACK_IKS(stack)->k_ebx,
1120 STACK_IKS(stack)->k_esp, STACK_IEL(stack)->saved_state);
1121 }
1122
1123 dump_handlers(thr_act);
1124 dump_regs(thr_act);
1125 return((int)thr_act);
1126}
1127unsigned int
1128get_useraddr()
1129{
1130
1131 thread_act_t thr_act = current_act();
1132
1133 if (thr_act->mact.pcb)
1134 return(thr_act->mact.pcb->iss.eip);
1135 else
1136 return(0);
1137
1138}
1139
1140void
1141thread_swapin_mach_alloc(thread_t thread)
1142{
1143
1144 /* 386 does not have saveareas */
1145
1146}
1147/*
1148 * detach and return a kernel stack from a thread
1149 */
1150
1151vm_offset_t
55e303ae 1152machine_stack_detach(thread_t thread)
1c79356b
A
1153{
1154 vm_offset_t stack;
1155
1156 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_DETACH),
1157 thread, thread->priority,
1158 thread->sched_pri, 0,
1159 0);
1160
1161 stack = thread->kernel_stack;
1162 thread->kernel_stack = 0;
1163 return(stack);
1164}
1165
1166/*
1167 * attach a kernel stack to a thread and initialize it
1168 */
1169
1170void
55e303ae 1171machine_stack_attach(thread_t thread,
1c79356b
A
1172 vm_offset_t stack,
1173 void (*start_pos)(thread_t))
1174{
1175 struct i386_kernel_state *statep;
1c79356b
A
1176
1177 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_ATTACH),
1178 thread, thread->priority,
1179 thread->sched_pri, continuation,
1180 0);
1181
1182 assert(stack);
1183 statep = STACK_IKS(stack);
1184 thread->kernel_stack = stack;
1185
1186 statep->k_eip = (unsigned long) Thread_continue;
1187 statep->k_ebx = (unsigned long) start_pos;
1188 statep->k_esp = (unsigned long) STACK_IEL(stack);
55e303ae
A
1189
1190 STACK_IEL(stack)->saved_state = &thread->mact.pcb->iss;
1c79356b
A
1191
1192 return;
1193}
1194
1195/*
1196 * move a stack from old to new thread
1197 */
1198
1199void
55e303ae 1200machine_stack_handoff(thread_t old,
1c79356b
A
1201 thread_t new)
1202{
1203
1204 vm_offset_t stack;
1c79356b
A
1205
1206 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_HANDOFF),
1207 thread, thread->priority,
1208 thread->sched_pri, continuation,
1209 0);
1210
1211 assert(new->top_act);
1212 assert(old->top_act);
1213
55e303ae
A
1214 stack = machine_stack_detach(old);
1215 machine_stack_attach(new, stack, 0);
1c79356b 1216
55e303ae 1217 PMAP_SWITCH_CONTEXT(old->top_act->task, new->top_act->task, cpu_number());
1c79356b 1218
9bccf70c
A
1219 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_HANDOFF) | DBG_FUNC_NONE,
1220 (int)old, (int)new, old->sched_pri, new->sched_pri, 0);
1221
55e303ae 1222 machine_thread_set_current(new);
1c79356b
A
1223
1224 active_stacks[cpu_number()] = new->kernel_stack;
1225
1226 return;
1227}
0b4e3aa0
A
1228
1229struct i386_act_context {
1230 struct i386_saved_state ss;
1231 struct i386_float_state fs;
1232};
1233
1234void *
1235act_thread_csave(void)
1236{
1237struct i386_act_context *ic;
1238kern_return_t kret;
1239int val;
1240
1241 ic = (struct i386_act_context *)kalloc(sizeof(struct i386_act_context));
1242
1243 if (ic == (struct i386_act_context *)NULL)
1244 return((void *)0);
1245
1246 val = i386_SAVED_STATE_COUNT;
55e303ae
A
1247 kret = machine_thread_get_state(current_act(),
1248 i386_SAVED_STATE,
1249 (thread_state_t) &ic->ss,
1250 &val);
0b4e3aa0
A
1251 if (kret != KERN_SUCCESS) {
1252 kfree((vm_offset_t)ic,sizeof(struct i386_act_context));
1253 return((void *)0);
1254 }
1255 val = i386_FLOAT_STATE_COUNT;
55e303ae
A
1256 kret = machine_thread_get_state(current_act(),
1257 i386_FLOAT_STATE,
1258 (thread_state_t) &ic->fs,
1259 &val);
0b4e3aa0
A
1260 if (kret != KERN_SUCCESS) {
1261 kfree((vm_offset_t)ic,sizeof(struct i386_act_context));
1262 return((void *)0);
1263 }
1264 return(ic);
1265}
1266void
1267act_thread_catt(void *ctx)
1268{
1269struct i386_act_context *ic;
1270kern_return_t kret;
1271int val;
1272
1273 ic = (struct i386_act_context *)ctx;
1274
1275 if (ic == (struct i386_act_context *)NULL)
1276 return;
1277
55e303ae
A
1278 kret = machine_thread_set_state(current_act(),
1279 i386_SAVED_STATE,
1280 (thread_state_t) &ic->ss,
1281 i386_SAVED_STATE_COUNT);
0b4e3aa0
A
1282 if (kret != KERN_SUCCESS)
1283 goto out;
1284
55e303ae
A
1285 kret = machine_thread_set_state(current_act(),
1286 i386_FLOAT_STATE,
1287 (thread_state_t) &ic->fs,
1288 i386_FLOAT_STATE_COUNT);
0b4e3aa0
A
1289 if (kret != KERN_SUCCESS)
1290 goto out;
1291out:
1292 kfree((vm_offset_t)ic,sizeof(struct i386_act_context));
1293}
1294
1295void act_thread_cfree(void *ctx)
1296{
1297 kfree((vm_offset_t)ctx,sizeof(struct i386_act_context));
1298}
1299