|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright (c) 1992 NeXT Computer, Inc.
27: *
28: * Intel386 Family: Machine dependent thread module.
29: *
30: * HISTORY
31: *
32: * 6 April 1992 ? at NeXT
33: * Created.
34: */
35:
36: #import <mach/mach_types.h>
37:
38: #import <kern/mach_param.h>
39:
40: #import <architecture/i386/table.h>
41:
42: #import <machdep/i386/fp_exported.h>
43: #import <machdep/i386/configure.h>
44:
45: #import <machdep/i386/ldt.h>
46: #import <machdep/i386/table_inline.h>
47: #import <machdep/i386/desc_inline.h>
48: #import <machdep/i386/sel_inline.h>
49: #import <machdep/i386/cpu_inline.h>
50:
51: /* U**X crap!! */
52: #import <sys/param.h>
53: #import <sys/proc.h>
54:
55: #import <fp_emul.h>
56: #import <pc_support.h>
57:
58: zone_t pcb_zone;
59:
60: vm_offset_t stack_pointers[NCPUS];
61: boolean_t empty_stacks[NCPUS];
62:
63: /*
64: * The base of the kernel stack
65: * is different when a thread is
66: * in v86 mode.
67: */
68: #define KERNEL_STACK_BASE(state) \
69: ((unsigned int) &(state)->frame.v_es)
70:
71: #define KERNEL_V86_STACK_BASE(state) \
72: ((unsigned int) &(&(state)->frame)[1])
73:
74: void
75: stack_attach(
76: thread_t thread,
77: vm_offset_t stack,
78: void (*continuation)(void)
79: )
80: {
81: tss_t *tss;
82: extern void _stack_attach(void);
83:
84: thread->kernel_stack = stack;
85:
86: tss = thread->pcb->tss;
87: tss->esp = tss->ebp = stack + KERNEL_STACK_SIZE;
88: tss->eip = (unsigned int)_stack_attach;
89: tss->ebx = (unsigned int)continuation;
90: }
91:
92:
93: vm_offset_t
94: stack_detach(
95: thread_t thread
96: )
97: {
98: vm_offset_t stack;
99:
100: stack = thread->kernel_stack;
101: thread->kernel_stack = 0;
102:
103: return (stack);
104: }
105:
106: void
107: stack_handoff(
108: thread_t old,
109: thread_t new
110: )
111: {
112: struct pcb *new_pcb = new->pcb,
113: *old_pcb = old->pcb;
114: vm_offset_t stack = stack_detach(old);
115:
116: stack_attach(new, stack, 0);
117:
118: /*
119: * Change software state.
120: */
121: if (new->task != old->task) {
122: int mycpu = cpu_number();
123:
124: PMAP_DEACTIVATE(vm_map_pmap(old->task->map), old, mycpu);
125: PMAP_ACTIVATE(vm_map_pmap(new->task->map), new, mycpu);
126: }
127:
128: current_thread() = new;
129:
130: /*
131: * Change hardware state.
132: */
133: if (new_pcb->tss->cr3 != old_pcb->tss->cr3)
134: set_cr3(new_pcb->tss->cr3);
135:
136: if (new_pcb->ldt != old_pcb->ldt
137: || new_pcb->ldt_size != old_pcb->ldt_size) {
138: map_ldt(sel_to_gdt_entry(LDT_SEL),
139: (vm_offset_t) new_pcb->ldt,
140: (vm_size_t) new_pcb->ldt_size);
141: lldt();
142: }
143:
144: map_tss(sel_to_gdt_entry(TSS_SEL),
145: (vm_offset_t) new_pcb->tss
146: + KERNEL_LINEAR_BASE,
147: (vm_size_t) new_pcb->tss_size);
148: ltr(); setts();
149: }
150:
151: extern
152: thread_t
153: _switch_tss(
154: tss_t *old_tss,
155: tss_t *new_tss,
156: thread_t old
157: );
158:
159: thread_t
160: switch_context(
161: thread_t old,
162: void (*continuation)(void),
163: thread_t new
164: )
165: {
166: struct pcb *new_pcb = new->pcb,
167: *old_pcb = old->pcb;
168:
169: /*
170: * Change software state.
171: */
172: if (new->task != old->task) {
173: int mycpu = cpu_number();
174:
175: PMAP_DEACTIVATE(vm_map_pmap(old->task->map), old, mycpu);
176: PMAP_ACTIVATE(vm_map_pmap(new->task->map), new, mycpu);
177: }
178:
179: current_thread() = new;
180: current_stack() = new->kernel_stack;
181: current_stack_pointer() = new->kernel_stack + KERNEL_STACK_SIZE;
182:
183: /*
184: * Change hardware state.
185: */
186: if (new_pcb->tss->cr3 != old_pcb->tss->cr3)
187: set_cr3(new_pcb->tss->cr3);
188:
189: if (new_pcb->ldt != old_pcb->ldt
190: || new_pcb->ldt_size != old_pcb->ldt_size) {
191: map_ldt(sel_to_gdt_entry(LDT_SEL),
192: (vm_offset_t) new_pcb->ldt,
193: (vm_size_t) new_pcb->ldt_size);
194: lldt();
195: }
196:
197: map_tss(sel_to_gdt_entry(TSS_SEL),
198: (vm_offset_t) new_pcb->tss
199: + KERNEL_LINEAR_BASE,
200: (vm_size_t) new_pcb->tss_size);
201: ltr(); setts();
202:
203: if (old->swap_func = continuation)
204: return _switch_tss(0, new_pcb->tss, old);
205: else
206: return _switch_tss(old_pcb->tss, new_pcb->tss, old);
207: }
208:
209: void
210: call_continuation(
211: void (*continuation)(void)
212: )
213: {
214: _call_with_stack(continuation, current_stack_pointer());
215: /* NOTREACHED */
216: }
217:
218: void
219: pcb_module_init(void)
220: {
221: pcb_zone = zinit(
222: sizeof (struct pcb),
223: THREAD_MAX * sizeof (struct pcb),
224: THREAD_CHUNK * sizeof (struct pcb),
225: FALSE, "pcb");
226: }
227:
228: /*
229: * Initialize a pcb for a
230: * new thread.
231: */
232: void pcb_init(
233: thread_t thread
234: )
235: {
236: struct pcb *pcb;
237: tss_t *tss;
238:
239: /*
240: * Allocate a new pcb.
241: */
242: thread->pcb = pcb = (void *)zalloc(pcb_zone);
243: *pcb = (struct pcb) { 0 };
244:
245: /*
246: * Setup with internal TSS.
247: */
248: pcb->tss = tss = &pcb->tss_store.internal;
249: pcb->tss_size = TSS_SIZE(0);
250:
251: /*
252: * Context from pmap.
253: */
254: tss->cr3 = vm_map_pmap(thread->task->map)->cr3;
255:
256: /*
257: * Setup with default LDT.
258: */
259: pcb->ldt = (vm_offset_t)ldt + KERNEL_LINEAR_BASE;
260: pcb->ldt_size = LDTSZ * sizeof (ldt_entry_t);
261:
262: tss->ldt = LDT_SEL;
263:
264: /*
265: * Kernel state.
266: */
267: tss->ss0 = KDS_SEL;
268: tss->eflags = EFL_IF;
269: tss->ss = KDS_SEL;
270: tss->cs = KCS_SEL;
271: tss->ds = KDS_SEL;
272: tss->es = KDS_SEL;
273: tss->fs = LDATA_SEL;
274: tss->gs = NULL_SEL;
275: tss->io_bmap = TSS_SIZE(0);
276: }
277:
278: void
279: pcb_common_init(
280: task_t task
281: )
282: {
283: pcb_common_t *common = (void *)kalloc(sizeof (*common));
284:
285: lock_init(&common->lock, TRUE);
286: common->ldt = (vm_offset_t)ldt + KERNEL_LINEAR_BASE;
287: common->ldt_size = LDTSZ * sizeof (ldt_entry_t);
288: common->io_bmap.length = common->io_bmap.base = 0;
289: task->pcb_common = common;
290: }
291:
292: /*
293: * Set the thread's io space to the region
294: * defined by base and length. The TSS is
295: * expanded if necessary. Thread must either
296: * be the current thread, or suspended.
297: * N.B. On exit, the thread is guaranteed to
298: * have an external TSS.
299: */
300: static void
301: thread_set_io_bmap(
302: thread_t thread,
303: vm_offset_t base,
304: vm_size_t length
305: )
306: {
307: struct pcb *pcb = thread->pcb;
308:
309: if (pcb->tss_size < TSS_SIZE(length + 1)) {
310: struct tss_alloc new_tss_alloc, old_tss_alloc;
311: tss_t *new_tss, *old_tss;
312:
313: /*
314: * TSS needs to be enlarged.
315: */
316: new_tss_alloc.length = TSS_SIZE(length + 1);
317: new_tss_alloc.base = (vm_offset_t)kalloc(new_tss_alloc.length);
318:
319: new_tss = (tss_t *)new_tss_alloc.base;
320: old_tss = pcb->tss;
321:
322: /*
323: * Copy old TSS to new one.
324: */
325: *new_tss = *old_tss;
326:
327: if (pcb->extern_tss) {
328: /*
329: * Deal with old external tss.
330: */
331: old_tss_alloc = pcb->tss_store.external;
332:
333: /*
334: * Switch to new TSS.
335: */
336: pcb->tss_store.external = new_tss_alloc;
337: pcb->tss = new_tss;
338: pcb->tss_size = new_tss_alloc.length;
339: pcb->extern_tss = TRUE;
340:
341: /*
342: * Free old TSS.
343: */
344: kfree((void *)old_tss_alloc.base, old_tss_alloc.length);
345: }
346: else {
347: /*
348: * Switch to new TSS.
349: */
350: pcb->tss_store.external = new_tss_alloc;
351: pcb->tss = new_tss;
352: pcb->tss_size = new_tss_alloc.length;
353: pcb->extern_tss = TRUE;
354: }
355:
356: /*
357: * If changing the current
358: * thread, remap its tss now.
359: */
360: if (thread == current_thread()) {
361: map_tss(sel_to_gdt_entry(TSS_SEL),
362: (vm_offset_t) thread->pcb->tss
363: + KERNEL_LINEAR_BASE,
364: (vm_size_t) thread->pcb->tss_size);
365: ltr();
366: }
367: }
368:
369: memcpy(
370: (void *)pcb->tss + pcb->tss->io_bmap,
371: (void *)base, length);
372: }
373:
374: static void
375: task_update_io_bmap(
376: task_t task
377: )
378: {
379: queue_head_t *list;
380: thread_t thread, prev_thread;
381: pcb_common_t *common = task->pcb_common;
382:
383: list = &task->thread_list;
384: prev_thread = THREAD_NULL;
385: task_lock(task);
386: thread = (thread_t)queue_first(list);
387: while (!queue_end(list, (queue_entry_t)thread)) {
388: thread_reference(thread);
389: task_unlock(task);
390: if (prev_thread != THREAD_NULL)
391: thread_deallocate(prev_thread);
392: thread_set_io_bmap(thread,
393: common->io_bmap.base,
394: common->io_bmap.length);
395: prev_thread = thread;
396: task_lock(task);
397: thread = (thread_t)queue_next(&thread->thread_list);
398: }
399: task_unlock(task);
400: if (prev_thread != THREAD_NULL)
401: thread_deallocate(prev_thread);
402: }
403:
404: kern_return_t
405: task_map_io_ports(
406: task_t task,
407: unsigned int port,
408: unsigned int length,
409: boolean_t unmap
410: )
411: {
412: pcb_common_t *common = task->pcb_common;
413: vm_offset_t new_io_bmap_base;
414: vm_size_t new_io_bmap_length;
415: int i;
416:
417: /*
418: * Bad port range.
419: */
420: if ((port + length) > 65536)
421: return (KERN_INVALID_ADDRESS);
422:
423: if (task->kernel_vm_space)
424: return (KERN_SUCCESS);
425:
426: /*
427: * If task is being terminated,
428: * don't bother.
429: */
430: if (task_hold(task) != KERN_SUCCESS)
431: return (KERN_INVALID_ARGUMENT);
432:
433: new_io_bmap_length = roundup(port + length, NBBY) / NBBY;
434:
435: lock_write(&common->lock);
436:
437: if (common->io_bmap.length < new_io_bmap_length) {
438: new_io_bmap_base = (vm_offset_t)kalloc(new_io_bmap_length);
439:
440: /*
441: * Invalidate all of new IO bitmap.
442: */
443: memset(
444: (void *)new_io_bmap_base,
445: 0xff, new_io_bmap_length);
446:
447: /*
448: * Copy old IO bitmap.
449: */
450: memcpy(
451: (void *)new_io_bmap_base,
452: (void *)common->io_bmap.base, common->io_bmap.length);
453:
454: kfree((void *)common->io_bmap.base, common->io_bmap.length);
455:
456: common->io_bmap.base = new_io_bmap_base;
457: common->io_bmap.length = new_io_bmap_length;
458: }
459:
460: for (i = port; i < (port + length); i++)
461: if (unmap)
462: setbit(common->io_bmap.base, i);
463: else
464: clrbit(common->io_bmap.base, i);
465:
466: (void) task_dowait(task, TRUE);
467:
468: task_update_io_bmap(task);
469:
470: (void) task_release(task);
471:
472: lock_done(&common->lock);
473:
474: return (KERN_SUCCESS);
475: }
476:
477: static void
478: thread_set_ldt(
479: thread_t thread,
480: vm_offset_t address,
481: vm_size_t size
482: )
483: {
484: thread->pcb->ldt = address;
485: thread->pcb->ldt_size = size;
486:
487: /*
488: * If changing the current
489: * thread, remap its LDT now.
490: */
491: if (thread == current_thread()) {
492: map_ldt(sel_to_gdt_entry(LDT_SEL),
493: (vm_offset_t) thread->pcb->ldt,
494: (vm_size_t) thread->pcb->ldt_size);
495: lldt();
496: }
497: }
498:
499: static void
500: task_update_ldt(
501: task_t task
502: )
503: {
504: queue_head_t *list;
505: thread_t thread, prev_thread;
506: pcb_common_t *common = task->pcb_common;
507:
508: list = &task->thread_list;
509: prev_thread = THREAD_NULL;
510: task_lock(task);
511: thread = (thread_t)queue_first(list);
512: while (!queue_end(list, (queue_entry_t)thread)) {
513: thread_reference(thread);
514: task_unlock(task);
515: if (prev_thread != THREAD_NULL)
516: thread_deallocate(prev_thread);
517: thread_set_ldt(thread, common->ldt, common->ldt_size);
518: prev_thread = thread;
519: task_lock(task);
520: thread = (thread_t)queue_next(&thread->thread_list);
521: }
522: task_unlock(task);
523: if (prev_thread != THREAD_NULL)
524: thread_deallocate(prev_thread);
525: }
526:
527: kern_return_t
528: task_locate_ldt(
529: task_t task,
530: vm_offset_t address,
531: vm_size_t size
532: )
533: {
534: pcb_common_t *common = task->pcb_common;
535:
536: if (vm_map_min(task->map) > address ||
537: vm_map_max(task->map) <= (address + size))
538: return (KERN_INVALID_ADDRESS);
539:
540: /*
541: * If task is being terminated,
542: * don't bother.
543: */
544: if (task_hold(task) != KERN_SUCCESS)
545: return (KERN_INVALID_ARGUMENT);
546:
547: lock_write(&common->lock);
548:
549: common->ldt = address;
550: common->ldt_size = size;
551:
552: (void) task_dowait(task, TRUE);
553:
554: task_update_ldt(task);
555:
556: (void) task_release(task);
557:
558: lock_done(&common->lock);
559:
560: return (KERN_SUCCESS);
561: }
562:
563: kern_return_t
564: task_default_ldt(
565: task_t task
566: )
567: {
568: pcb_common_t *common = task->pcb_common;
569:
570: /*
571: * If task is being terminated,
572: * don't bother.
573: */
574: if (task_hold(task) != KERN_SUCCESS)
575: return (KERN_INVALID_ARGUMENT);
576:
577: lock_write(&common->lock);
578:
579: common->ldt = (vm_offset_t)ldt + KERNEL_LINEAR_BASE;
580: common->ldt_size = LDTSZ * sizeof (ldt_entry_t);
581:
582: (void) task_dowait(task, TRUE);
583:
584: task_update_ldt(task);
585:
586: (void) task_release(task);
587:
588: lock_done(&common->lock);
589:
590: return (KERN_SUCCESS);
591: }
592:
593: thread_saved_state_t *
594: thread_user_state(
595: thread_t thread
596: )
597: {
598: thread_save_area_t *save_area = thread->pcb->save_area;
599:
600: if (save_area == 0) {
601: thread_saved_state_t *saved_state;
602:
603: thread->pcb->save_area =
604: save_area = (void *)kalloc(sizeof (*save_area));
605:
606: saved_state = &save_area->sa_u;
607: *saved_state = (thread_saved_state_t) { 0 };
608: saved_state->frame.eflags = EFL_IF;
609: saved_state->frame.cs = UCODE_SEL;
610: saved_state->frame.ss = UDATA_SEL;
611: saved_state->regs.ds = UDATA_SEL;
612: saved_state->regs.es = UDATA_SEL;
613: saved_state->regs.fs = NULL_SEL;
614: saved_state->regs.gs = NULL_SEL;
615:
616: return (saved_state);
617: }
618: else
619: return (&save_area->sa_u);
620: }
621:
622: /*
623: * Entry point for new user
624: * threads.
625: */
626: void
627: thread_bootstrap_return(void)
628: {
629: thread_t thread = current_thread();
630: pcb_common_t *common = thread->task->pcb_common;
631: struct pcb *pcb = thread->pcb;
632:
633: lock_read(&common->lock);
634:
635: if (common->io_bmap.length > 0)
636: thread_set_io_bmap(thread,
637: common->io_bmap.base,
638: common->io_bmap.length);
639:
640: if (common->ldt != pcb->ldt)
641: thread_set_ldt(thread, common->ldt, common->ldt_size);
642:
643: lock_done(&common->lock);
644:
645: thread_exception_return();
646: /* NOTREACHED */
647: }
648:
649: void
650: thread_exception_return(void)
651: {
652: thread_t thread = current_thread();
653: thread_saved_state_t *saved_state = USER_REGS(thread);
654:
655: check_for_ast(saved_state); // *may* not return
656:
657: thread->pcb->tss->esp0 =
658: ((saved_state->frame.eflags & EFL_VM) ?
659: KERNEL_V86_STACK_BASE(saved_state) :
660: KERNEL_STACK_BASE(saved_state));
661:
662: _return_with_state(saved_state);
663: /* NOTREACHED */
664: }
665:
666: void __volatile__
667: thread_syscall_return(
668: kern_return_t result
669: )
670: {
671: thread_t thread = current_thread();
672: thread_saved_state_t *saved_state = USER_REGS(thread);
673:
674: saved_state->regs.eax = result;
675:
676: check_for_ast(saved_state); // *may* not return
677:
678: thread->pcb->tss->esp0 =
679: ((saved_state->frame.eflags & EFL_VM) ?
680: KERNEL_V86_STACK_BASE(saved_state) :
681: KERNEL_STACK_BASE(saved_state));
682:
683: _return_with_state(saved_state);
684: /* NOTREACHED */
685: }
686:
687: void
688: thread_set_syscall_return(
689: thread_t thread,
690: kern_return_t result
691: )
692: {
693: thread_saved_state_t *saved_state = USER_REGS(thread);
694:
695: saved_state->regs.eax = result;
696: }
697:
698: /*
699: * Called from locore to
700: * startup the first thread. (never returns)
701: */
702: void
703: start_initial_context(
704: thread_t thread
705: )
706: {
707: struct pcb *pcb = thread->pcb;
708:
709: /*
710: * Initialize the common,
711: * static LDT.
712: */
713: ldt_init();
714:
715: /*
716: * Change software state.
717: */
718: PMAP_ACTIVATE(vm_map_pmap(thread->task->map), thread, 0);
719:
720: current_thread() = thread;
721: current_stack() = thread->kernel_stack;
722: current_stack_pointer() = thread->kernel_stack + KERNEL_STACK_SIZE;
723:
724: /*
725: * Change hardware state.
726: */
727: set_cr3(pcb->tss->cr3);
728:
729: map_ldt(sel_to_gdt_entry(LDT_SEL),
730: (vm_offset_t) pcb->ldt,
731: (vm_size_t) pcb->ldt_size);
732: lldt();
733:
734: map_tss(sel_to_gdt_entry(TSS_SEL),
735: (vm_offset_t) pcb->tss
736: + KERNEL_LINEAR_BASE,
737: (vm_size_t) pcb->tss_size);
738: ltr(); setts();
739:
740: _switch_tss(0, pcb->tss, 0);
741: }
742:
743: /*
744: * Set externally visible thread
745: * state.
746: */
747: kern_return_t
748: thread_setstatus(
749: thread_t thread,
750: int flavor,
751: thread_state_t tstate,
752: unsigned int count
753: )
754: {
755: switch (flavor) {
756:
757: case i386_THREAD_STATE:
758: return (set_thread_state(thread, tstate, count));
759:
760: case i386_THREAD_FPSTATE:
761: return (set_thread_fpstate(thread, tstate, count));
762:
763: default:
764: return (KERN_INVALID_ARGUMENT);
765: }
766: }
767:
768: static void set_thread_v86_state(
769: thread_t thread,
770: i386_thread_state_t *state);
771:
772: kern_return_t
773: set_thread_state(
774: thread_t thread,
775: thread_state_t tstate,
776: unsigned int count
777: )
778: {
779: thread_saved_state_t *saved_state;
780: i386_thread_state_t *state;
781:
782: if (count < i386_THREAD_STATE_COUNT)
783: return (KERN_INVALID_ARGUMENT);
784:
785: state = (i386_thread_state_t *)tstate;
786:
787: if ((state->eflags & EFL_VM) != 0)
788: set_thread_v86_state(thread, state);
789: else {
790: if (!thread->task->kernel_privilege) {
791: /*
792: * Validate segment selector values.
793: */
794: if (
795: !valid_user_code_selector(state->cs) ||
796: !valid_user_data_selector(state->ds) ||
797: !valid_user_data_selector(state->es) ||
798: !valid_user_data_selector(state->fs) ||
799: !valid_user_data_selector(state->gs) ||
800: !valid_user_stack_selector(state->ss)
801: )
802: return (KERN_INVALID_ARGUMENT);
803: }
804: else {
805: tss_t *tss = thread->pcb->tss;
806: /*
807: * State for kernel threads
808: * can only be set before thread
809: * is first started.
810: *
811: * XXX This hack is due to the
812: * fact that the &^%$#@! kernel loader
813: * uses the thread_set_state() call to
814: * start a thread in kernel mode.
815: */
816: if (thread->swap_func != thread_bootstrap_return)
817: return (KERN_INVALID_ARGUMENT);
818:
819: tss->eax = state->eax;
820: tss->ebx = state->ebx;
821: tss->ecx = state->ecx;
822: tss->edx = state->edx;
823: tss->edi = state->edi;
824: tss->esi = state->esi;
825:
826: thread_start(thread, state->eip);
827:
828: return (KERN_SUCCESS);
829: }
830:
831: saved_state = USER_REGS(thread);
832:
833: saved_state->regs.eax = state->eax;
834: saved_state->regs.ebx = state->ebx;
835: saved_state->regs.ecx = state->ecx;
836: saved_state->regs.edx = state->edx;
837: saved_state->regs.edi = state->edi;
838: saved_state->regs.esi = state->esi;
839: saved_state->regs.ebp = state->ebp;
840: saved_state->frame.esp = state->esp;
841: saved_state->frame.ss = selector_to_sel(state->ss);
842: saved_state->frame.eflags = state->eflags;
843: saved_state->frame.eflags &= ~( EFL_VM | EFL_NT | EFL_IOPL | EFL_CLR );
844: saved_state->frame.eflags |= ( EFL_IF | EFL_SET );
845: saved_state->frame.eip = state->eip;
846: saved_state->frame.cs = selector_to_sel(state->cs);
847: saved_state->regs.ds = selector_to_sel(state->ds);
848: saved_state->regs.es = selector_to_sel(state->es);
849: saved_state->regs.fs = selector_to_sel(state->fs);
850: saved_state->regs.gs = selector_to_sel(state->gs);
851: }
852:
853: return (KERN_SUCCESS);
854: }
855:
856: static
857: void
858: set_thread_v86_state(
859: thread_t thread,
860: i386_thread_state_t *state
861: )
862: {
863: thread_saved_state_t *saved_state = USER_REGS(thread);
864:
865: saved_state->regs.eax = state->eax;
866: saved_state->regs.ebx = state->ebx;
867: saved_state->regs.ecx = state->ecx;
868: saved_state->regs.edx = state->edx;
869: saved_state->regs.edi = state->edi;
870: saved_state->regs.esi = state->esi;
871: saved_state->regs.ebp = state->ebp;
872: saved_state->frame.esp = state->esp;
873: saved_state->frame.ss = selector_to_sel(state->ss);
874: saved_state->frame.eflags = state->eflags;
875: saved_state->frame.eflags &= ~( EFL_NT | EFL_IOPL | EFL_CLR );
876: saved_state->frame.eflags |= ( EFL_VM | EFL_IF | EFL_SET );
877: saved_state->frame.eip = state->eip;
878: saved_state->frame.cs = selector_to_sel(state->cs);
879: saved_state->regs.ds = NULL_SEL;
880: saved_state->regs.es = NULL_SEL;
881: saved_state->regs.fs = NULL_SEL;
882: saved_state->regs.gs = NULL_SEL;
883: saved_state->frame.v_ds = state->ds;
884: saved_state->frame.v_es = state->es;
885: saved_state->frame.v_fs = state->fs;
886: saved_state->frame.v_gs = state->gs;
887: }
888:
889: kern_return_t
890: set_thread_fpstate(
891: thread_t thread,
892: thread_state_t tstate,
893: unsigned int count
894: )
895: {
896: fp_state_t *saved_state;
897: i386_thread_fpstate_t *state;
898:
899: if (count < i386_THREAD_FPSTATE_COUNT)
900: return (KERN_INVALID_ARGUMENT);
901:
902: state = (i386_thread_fpstate_t *)tstate;
903: saved_state = &thread->pcb->fpstate;
904:
905: fp_terminate(thread);
906:
907: saved_state->environ = state->environ;
908: saved_state->stack = state->stack;
909:
910: thread->pcb->fpvalid = TRUE;
911:
912: return (KERN_SUCCESS);
913: }
914:
915: kern_return_t
916: thread_set_cthread_self(
917: int self
918: )
919: {
920: current_thread()->pcb->cthread_self = (unsigned int)self;
921:
922: return (KERN_SUCCESS);
923: }
924:
925: /*
926: * Return externally visible
927: * thread status.
928: */
929: kern_return_t
930: thread_getstatus(
931: thread_t thread,
932: int flavor,
933: thread_state_t tstate,
934: unsigned int *count
935: )
936: {
937: switch (flavor) {
938:
939: case i386_THREAD_STATE:
940: return (get_thread_state(thread, tstate, count));
941:
942: case i386_THREAD_FPSTATE:
943: return (get_thread_fpstate(thread, tstate, count));
944:
945: case i386_THREAD_EXCEPTSTATE:
946: return (get_thread_exceptstate(thread, tstate, count));
947:
948: case i386_THREAD_CTHREADSTATE:
949: return (get_thread_cthreadstate(thread, tstate, count));
950:
951: case THREAD_STATE_FLAVOR_LIST:
952: return (get_thread_state_flavor_list(tstate, count));
953:
954: default:
955: return (KERN_INVALID_ARGUMENT);
956: }
957: }
958:
959: kern_return_t
960: get_thread_state(
961: thread_t thread,
962: thread_state_t tstate,
963: unsigned int *count
964: )
965: {
966: thread_saved_state_t *saved_state;
967: i386_thread_state_t *state;
968:
969: if (*count < i386_THREAD_STATE_COUNT)
970: return (KERN_INVALID_ARGUMENT);
971:
972: state = (i386_thread_state_t *)tstate;
973: saved_state = USER_REGS(thread);
974:
975: state->eax = saved_state->regs.eax;
976: state->ebx = saved_state->regs.ebx;
977: state->ecx = saved_state->regs.ecx;
978: state->edx = saved_state->regs.edx;
979: state->edi = saved_state->regs.edi;
980: state->esi = saved_state->regs.esi;
981: state->ebp = saved_state->regs.ebp;
982: state->esp = saved_state->frame.esp;
983: state->ss = sel_to_selector(saved_state->frame.ss);
984: state->eflags = saved_state->frame.eflags;
985: state->eip = saved_state->frame.eip;
986: state->cs = sel_to_selector(saved_state->frame.cs);
987: if ((saved_state->frame.eflags & EFL_VM) == 0) {
988: state->ds = sel_to_selector(saved_state->regs.ds);
989: state->es = sel_to_selector(saved_state->regs.es);
990: state->fs = sel_to_selector(saved_state->regs.fs);
991: state->gs = sel_to_selector(saved_state->regs.gs);
992: }
993: else {
994: state->ds = saved_state->frame.v_ds;
995: state->es = saved_state->frame.v_es;
996: state->fs = saved_state->frame.v_fs;
997: state->gs = saved_state->frame.v_gs;
998: }
999:
1000: *count = i386_THREAD_STATE_COUNT;
1001:
1002: return (KERN_SUCCESS);
1003: }
1004:
1005: kern_return_t
1006: get_thread_fpstate(
1007: thread_t thread,
1008: thread_state_t tstate,
1009: unsigned int *count
1010: )
1011: {
1012: fp_state_t *saved_state;
1013: i386_thread_fpstate_t *state;
1014:
1015: if (*count < i386_THREAD_FPSTATE_COUNT)
1016: return (KERN_INVALID_ARGUMENT);
1017:
1018: state = (i386_thread_fpstate_t *)tstate;
1019: saved_state = &thread->pcb->fpstate;
1020:
1021: fp_synch(thread);
1022:
1023: state->environ = saved_state->environ;
1024: state->stack = saved_state->stack;
1025:
1026: *count = i386_THREAD_FPSTATE_COUNT;
1027:
1028: return (KERN_SUCCESS);
1029: }
1030:
1031: kern_return_t
1032: get_thread_exceptstate(
1033: thread_t thread,
1034: thread_state_t tstate,
1035: unsigned int *count
1036: )
1037: {
1038: thread_saved_state_t *saved_state;
1039: i386_thread_exceptstate_t *state;
1040:
1041: if (*count < i386_THREAD_EXCEPTSTATE_COUNT)
1042: return (KERN_INVALID_ARGUMENT);
1043:
1044: state = (i386_thread_exceptstate_t *)tstate;
1045: saved_state = USER_REGS(thread);
1046:
1047: state->trapno = saved_state->trapno;
1048: state->err = saved_state->frame.err;
1049:
1050: *count = i386_THREAD_EXCEPTSTATE_COUNT;
1051:
1052: return (KERN_SUCCESS);
1053: }
1054:
1055: kern_return_t
1056: get_thread_cthreadstate(
1057: thread_t thread,
1058: thread_state_t tstate,
1059: unsigned int *count
1060: )
1061: {
1062: i386_thread_cthreadstate_t *state;
1063:
1064: if (*count < i386_THREAD_CTHREADSTATE_COUNT)
1065: return (KERN_INVALID_ARGUMENT);
1066:
1067: state = (i386_thread_cthreadstate_t *)tstate;
1068: state->self = thread->pcb->cthread_self;
1069:
1070: *count = i386_THREAD_CTHREADSTATE_COUNT;
1071:
1072: return (KERN_SUCCESS);
1073: }
1074:
1075: kern_return_t
1076: thread_get_cthread_self(
1077: void
1078: )
1079: {
1080: return ((kern_return_t)current_thread()->pcb->cthread_self);
1081: }
1082:
1083: kern_return_t
1084: get_thread_state_flavor_list(
1085: thread_state_t tstate,
1086: unsigned int *count
1087: )
1088: {
1089: struct thread_state_flavor *state;
1090: #define i386_THREAD_STATE_FLAVOR_COUNT 4
1091:
1092: #define i386_THREAD_STATE_FLAVOR_LIST_COUNT \
1093: ( i386_THREAD_STATE_FLAVOR_COUNT * \
1094: ( sizeof (struct thread_state_flavor) / sizeof (int) ) )
1095:
1096: if (*count < i386_THREAD_STATE_FLAVOR_COUNT)
1097: return (KERN_INVALID_ARGUMENT);
1098:
1099: state = (struct thread_state_flavor *)tstate;
1100:
1101: state->flavor = i386_THREAD_STATE;
1102: state->count = i386_THREAD_STATE_COUNT;
1103:
1104: (++state)->flavor = i386_THREAD_FPSTATE;
1105: state->count = i386_THREAD_FPSTATE_COUNT;
1106:
1107: (++state)->flavor = i386_THREAD_EXCEPTSTATE;
1108: state->count = i386_THREAD_EXCEPTSTATE_COUNT;
1109:
1110: (++state)->flavor = i386_THREAD_CTHREADSTATE;
1111: state->count = i386_THREAD_CTHREADSTATE_COUNT;
1112:
1113: *count = i386_THREAD_STATE_FLAVOR_LIST_COUNT;
1114:
1115: return (KERN_SUCCESS);
1116: }
1117:
1118: /*
1119: * thread_userstack:
1120: *
1121: * Return the user stack pointer from the machine dependent thread state info.
1122: */
1123: kern_return_t
1124: thread_userstack(
1125: thread_t thread,
1126: int flavor,
1127: thread_state_t tstate,
1128: unsigned int count,
1129: vm_offset_t *user_stack
1130: )
1131: {
1132: i386_thread_state_t *state;
1133:
1134: /*
1135: * Set a default.
1136: */
1137: if (*user_stack == 0)
1138: *user_stack = VM_MAX_ADDRESS;
1139:
1140: switch (flavor) {
1141:
1142: case i386_THREAD_STATE:
1143: if (count < i386_THREAD_STATE_COUNT)
1144: return (KERN_INVALID_ARGUMENT);
1145:
1146: state = (i386_thread_state_t *) tstate;
1147:
1148: /*
1149: * If a valid user stack is specified, use it.
1150: */
1151: *user_stack = state->esp ? state->esp: VM_MAX_ADDRESS;
1152: break;
1153: }
1154:
1155: return (KERN_SUCCESS);
1156: }
1157: kern_return_t
1158: thread_entrypoint(
1159: thread_t thread,
1160: int flavor,
1161: thread_state_t tstate,
1162: unsigned int count,
1163: vm_offset_t *entry_point
1164: )
1165: {
1166: i386_thread_state_t *state;
1167:
1168: /*
1169: * Set a default.
1170: */
1171: if (*entry_point == 0)
1172: *entry_point = VM_MIN_ADDRESS;
1173:
1174: switch (flavor) {
1175:
1176: case i386_THREAD_STATE:
1177: if (count < i386_THREAD_STATE_COUNT)
1178: return (KERN_INVALID_ARGUMENT);
1179:
1180: state = (i386_thread_state_t *) tstate;
1181:
1182: /*
1183: * If a valid entry point is specified, use it.
1184: */
1185: *entry_point = state->eip ? state->eip: VM_MIN_ADDRESS;
1186: break;
1187: }
1188:
1189: return (KERN_SUCCESS);
1190: }
1191:
1192: /*
1193: * Duplicate parent state in child
1194: * for U**X fork.
1195: */
1196: thread_dup(
1197: thread_t parent,
1198: thread_t child
1199: )
1200: {
1201: struct thread_saved_state *parent_state, *child_state;
1202:
1203: parent_state = USER_REGS(parent);
1204: child_state = thread_user_state(child);
1205:
1206: *child_state = *parent_state;
1207:
1208: child_state->regs.eax = child->task->proc->p_pid;
1209:
1210: child_state->regs.edx = 1;
1211: child_state->frame.eflags &= ~EFL_CF;
1212: }
1213:
1214: /*
1215: * Release resources on
1216: * thread termination.
1217: */
1218: pcb_terminate(
1219: thread_t thread
1220: )
1221: {
1222: struct pcb *pcb = thread->pcb;
1223:
1224: /*
1225: * Give up the fpu if
1226: * necessary.
1227: */
1228: fp_terminate(thread);
1229:
1230: #if PC_SUPPORT
1231: if (pcb->PCpriv)
1232: PCdestroy(thread);
1233: #endif
1234:
1235: /*
1236: * Free save area.
1237: */
1238: if (pcb->save_area)
1239: kfree((void *)pcb->save_area,
1240: sizeof (*pcb->save_area));
1241:
1242: /*
1243: * Free external tss.
1244: */
1245: if (pcb->extern_tss)
1246: kfree(
1247: (void *)pcb->tss_store.external.base,
1248: pcb->tss_store.external.length);
1249:
1250: thread->pcb = 0;
1251: zfree(pcb_zone, pcb);
1252: }
1253:
1254: /*
1255: * Synchronize pcb with
1256: * hardware state.
1257: */
1258: pcb_synch(
1259: thread_t thread
1260: )
1261: {
1262: /*
1263: * Write out our fp state
1264: * if necessary.
1265: */
1266: fp_synch(thread);
1267: }
1268:
1269: void
1270: pcb_common_terminate(
1271: task_t task
1272: )
1273: {
1274: pcb_common_t *common = task->pcb_common;
1275:
1276: kfree((void *)common, sizeof (*common));
1277: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.