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