FreeBSD/Linux Kernel Cross Reference
sys/i386/pcb.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: pcb.c,v $
29 * Revision 2.14 93/01/14 17:29:21 danner
30 * Added include of mach/std_types.h
31 * [92/12/10 17:41:42 af]
32 *
33 * Revision 2.13 92/01/03 20:08:34 dbg
34 * Disable thread_set_state of ISA_PORT_MAP, but have it still
35 * return KERN_SUCCESS (for DOS emulator compatibility).
36 * [91/12/06 dbg]
37 *
38 * Add user ldt management. Move floating-point state
39 * manipulation to i386/fpu.{c,h}.
40 *
41 * Add user_stack_low and set_user_regs for passing control to
42 * bootstrap in user space.
43 * [91/10/30 dbg]
44 *
45 * Revision 2.12 91/10/09 16:07:08 af
46 * Set value of kernel_stack field in stack_handoff().
47 * [91/08/29 tak]
48 *
49 * Revision 2.11 91/07/31 17:39:56 dbg
50 * Add thread_set_syscall_return.
51 *
52 * Save user regs directly in PCB on trap, and switch to separate
53 * kernel stack.
54 *
55 * Add v8086 mode interrupt support.
56 * [91/07/30 16:56:09 dbg]
57 *
58 * Revision 2.10 91/05/14 16:13:06 mrt
59 * Correcting copyright
60 *
61 * Revision 2.9 91/05/08 12:40:34 dbg
62 * Use iopb_tss_t for IO permission bitmap.
63 * [91/03/21 dbg]
64 *
65 * Revision 2.8 91/03/16 14:44:51 rpd
66 * Pulled i386_fpsave_state out of i386_machine_state.
67 * Added pcb_module_init.
68 * [91/02/18 rpd]
69 *
70 * Replaced stack_switch with stack_handoff and
71 * switch_task_context with switch_context.
72 * [91/02/18 rpd]
73 * Added active_stacks.
74 * [91/01/29 rpd]
75 *
76 * Revision 2.7 91/02/05 17:13:19 mrt
77 * Changed to new Mach copyright
78 * [91/02/01 17:36:24 mrt]
79 *
80 * Revision 2.6 91/01/09 22:41:41 rpd
81 * Revised the pcb yet again.
82 * Picked up i386_ISA_PORT_MAP_STATE flavors.
83 * Added load_context, switch_task_context cover functions.
84 * [91/01/09 rpd]
85 *
86 * Revision 2.5 91/01/08 15:10:58 rpd
87 * Removed pcb_synch. Added pcb_collect.
88 * [91/01/03 rpd]
89 *
90 * Split i386_machine_state off of i386_kernel_state.
91 * Set k_stack_top correctly for V8086 threads.
92 * [90/12/31 rpd]
93 * Added stack_switch. Moved stack_alloc_try, stack_alloc,
94 * stack_free, stack_statistics to kern/thread.c.
95 * [90/12/14 rpd]
96 *
97 * Reorganized the pcb.
98 * Added stack_attach, stack_alloc, stack_alloc_try,
99 * stack_free, stack_statistics.
100 * [90/12/11 rpd]
101 *
102 * Revision 2.4 90/08/27 21:57:34 dbg
103 * Return correct count from thread_getstatus.
104 * [90/08/22 dbg]
105 *
106 * Revision 2.3 90/08/07 14:24:47 rpd
107 * Include seg.h for segment names.
108 * [90/07/17 dbg]
109 *
110 * Revision 2.2 90/05/03 15:35:51 dbg
111 * Created.
112 * [90/02/08 dbg]
113 *
114 */
115
116 #include <cpus.h>
117 #include <mach_debug.h>
118
119 #include <mach/std_types.h>
120 #include <mach/kern_return.h>
121 #include <mach/thread_status.h>
122 #include <mach/vm_param.h>
123
124 #include <kern/counters.h>
125 #include <kern/mach_param.h>
126 #include <kern/thread.h>
127 #include <kern/sched_prim.h>
128 #include <vm/vm_kern.h>
129 #include <vm/pmap.h>
130
131 #include <i386/thread.h>
132 #include <i386/eflags.h>
133 #include <i386/proc_reg.h>
134 #include <i386/seg.h>
135 #include <i386/tss.h>
136 #include <i386/user_ldt.h>
137 #include <i386/fpu.h>
138
139 #if NCPUS > 1
140 #include <i386/mp_desc.h>
141 #endif
142
143 extern thread_t Switch_context();
144 extern void Thread_continue();
145
146 extern struct i386_tss ktss;
147 extern struct fake_descriptor gdt[];
148
149 extern iopb_tss_t iopb_create();
150 extern void iopb_destroy();
151 extern void user_ldt_free();
152
153 zone_t pcb_zone;
154
155 vm_offset_t kernel_stack[NCPUS]; /* top of active_stack */
156
157 /*
158 * stack_attach:
159 *
160 * Attach a kernel stack to a thread.
161 */
162
163 void stack_attach(thread, stack, continuation)
164 register thread_t thread;
165 register vm_offset_t stack;
166 void (*continuation)();
167 {
168 counter(if (++c_stacks_current > c_stacks_max)
169 c_stacks_max = c_stacks_current);
170
171 thread->kernel_stack = stack;
172
173 /*
174 * We want to run continuation, giving it as an argument
175 * the return value from Load_context/Switch_context.
176 * Thread_continue takes care of the mismatch between
177 * the argument-passing/return-value conventions.
178 * This function will not return normally,
179 * so we don`t have to worry about a return address.
180 */
181 STACK_IKS(stack)->k_eip = (int) Thread_continue;
182 STACK_IKS(stack)->k_ebx = (int) continuation;
183 STACK_IKS(stack)->k_esp = (int) STACK_IEL(stack);
184
185 /*
186 * Point top of kernel stack to user`s registers.
187 */
188 STACK_IEL(stack)->saved_state = &thread->pcb->iss;
189 }
190
191 /*
192 * stack_detach:
193 *
194 * Detaches a kernel stack from a thread, returning the old stack.
195 */
196
197 vm_offset_t stack_detach(thread)
198 register thread_t thread;
199 {
200 register vm_offset_t stack;
201
202 counter(if (--c_stacks_current < c_stacks_min)
203 c_stacks_min = c_stacks_current);
204
205 stack = thread->kernel_stack;
206 thread->kernel_stack = 0;
207
208 return stack;
209 }
210
211 #if NCPUS > 1
212 #define curr_gdt(mycpu) (mp_gdt[mycpu])
213 #define curr_ktss(mycpu) (mp_ktss[mycpu])
214 #else
215 #define curr_gdt(mycpu) (gdt)
216 #define curr_ktss(mycpu) (&ktss)
217 #endif
218
219 #define gdt_desc_p(mycpu,sel) \
220 ((struct real_descriptor *)&curr_gdt(mycpu)[sel_idx(sel)])
221
222 void switch_ktss(pcb)
223 register pcb_t pcb;
224 {
225 int mycpu = cpu_number();
226 {
227 register iopb_tss_t tss = pcb->ims.io_tss;
228 vm_offset_t pcb_stack_top;
229
230 /*
231 * Save a pointer to the top of the "kernel" stack -
232 * actually the place in the PCB where a trap into
233 * kernel mode will push the registers.
234 * The location depends on V8086 mode. If we are
235 * not in V8086 mode, then a trap into the kernel
236 * won`t save the v86 segments, so we leave room.
237 */
238
239 pcb_stack_top = (pcb->iss.efl & EFL_VM)
240 ? (int) (&pcb->iss + 1)
241 : (int) (&pcb->iss.v86_segs);
242
243 if (tss == 0) {
244 /*
245 * No per-thread IO permissions.
246 * Use standard kernel TSS.
247 */
248 if (!(gdt_desc_p(mycpu,KERNEL_TSS)->access & ACC_TSS_BUSY))
249 set_tr(KERNEL_TSS);
250 curr_ktss(mycpu)->esp0 = pcb_stack_top;
251 }
252 else {
253 /*
254 * Set the IO permissions. Use this thread`s TSS.
255 */
256 *gdt_desc_p(mycpu,USER_TSS)
257 = *(struct real_descriptor *)tss->iopb_desc;
258 tss->tss.esp0 = pcb_stack_top;
259 set_tr(USER_TSS);
260 gdt_desc_p(mycpu,KERNEL_TSS)->access &= ~ ACC_TSS_BUSY;
261 }
262 }
263
264 {
265 register user_ldt_t ldt = pcb->ims.ldt;
266 /*
267 * Set the thread`s LDT.
268 */
269 if (ldt == 0) {
270 /*
271 * Use system LDT.
272 */
273 set_ldt(KERNEL_LDT);
274 }
275 else {
276 /*
277 * Thread has its own LDT.
278 */
279 *gdt_desc_p(mycpu,USER_LDT) = ldt->desc;
280 set_ldt(USER_LDT);
281 }
282 }
283 /*
284 * Load the floating-point context, if necessary.
285 */
286 fpu_load_context(pcb);
287
288 }
289
290 /*
291 * stack_handoff:
292 *
293 * Move the current thread's kernel stack to the new thread.
294 */
295
296 void stack_handoff(old, new)
297 register thread_t old;
298 register thread_t new;
299 {
300 register int mycpu = cpu_number();
301 register vm_offset_t stack;
302
303 /*
304 * Save FP registers if in use.
305 */
306 fpu_save_context(old);
307
308 /*
309 * Switch address maps if switching tasks.
310 */
311 {
312 task_t old_task, new_task;
313
314 if ((old_task = old->task) != (new_task = new->task)) {
315 PMAP_DEACTIVATE_USER(vm_map_pmap(old_task->map),
316 old, mycpu);
317 PMAP_ACTIVATE_USER(vm_map_pmap(new_task->map),
318 new, mycpu);
319 }
320 }
321
322 /*
323 * Load the rest of the user state for the new thread
324 */
325 switch_ktss(new->pcb);
326
327 /*
328 * Switch to new thread
329 */
330 stack = current_stack();
331 old->kernel_stack = 0;
332 new->kernel_stack = stack;
333 active_threads[mycpu] = new;
334
335 /*
336 * Switch exception link to point to new
337 * user registers.
338 */
339
340 STACK_IEL(stack)->saved_state = &new->pcb->iss;
341
342 }
343
344 /*
345 * Switch to the first thread on a CPU.
346 */
347 void load_context(new)
348 register thread_t new;
349 {
350 switch_ktss(new->pcb);
351 Load_context(new);
352 }
353
354 /*
355 * Switch to a new thread.
356 * Save the old thread`s kernel state or continuation,
357 * and return it.
358 */
359 thread_t switch_context(old, continuation, new)
360 register thread_t old;
361 void (*continuation)();
362 register thread_t new;
363 {
364 /*
365 * Save FP registers if in use.
366 */
367 fpu_save_context(old);
368
369 /*
370 * Switch address maps if switching tasks.
371 */
372 {
373 task_t old_task, new_task;
374 int mycpu = cpu_number();
375
376 if ((old_task = old->task) != (new_task = new->task)) {
377 PMAP_DEACTIVATE_USER(vm_map_pmap(old_task->map),
378 old, mycpu);
379 PMAP_ACTIVATE_USER(vm_map_pmap(new_task->map),
380 new, mycpu);
381 }
382 }
383
384 /*
385 * Load the rest of the user state for the new thread
386 */
387 switch_ktss(new->pcb);
388
389 return Switch_context(old, continuation, new);
390 }
391
392 void pcb_module_init()
393 {
394 pcb_zone = zinit(sizeof(struct pcb),
395 THREAD_MAX * sizeof(struct pcb),
396 THREAD_CHUNK * sizeof(struct pcb),
397 FALSE, "i386 pcb state");
398
399 fpu_module_init();
400 iopb_init();
401 }
402
403 void pcb_init(thread)
404 register thread_t thread;
405 {
406 register pcb_t pcb;
407
408 pcb = (pcb_t) zalloc(pcb_zone);
409 if (pcb == 0)
410 panic("pcb_init");
411
412 counter(if (++c_threads_current > c_threads_max)
413 c_threads_max = c_threads_current);
414
415 /*
416 * We can't let random values leak out to the user.
417 */
418 bzero((char *) pcb, sizeof *pcb);
419 simple_lock_init(&pcb->lock);
420
421 /*
422 * Guarantee that the bootstrapped thread will be in user
423 * mode.
424 */
425 pcb->iss.cs = USER_CS;
426 pcb->iss.ss = USER_DS;
427 pcb->iss.ds = USER_DS;
428 pcb->iss.es = USER_DS;
429 pcb->iss.fs = USER_DS;
430 pcb->iss.gs = USER_DS;
431 pcb->iss.efl = EFL_USER_SET;
432
433 thread->pcb = pcb;
434 }
435
436 void pcb_terminate(thread)
437 register thread_t thread;
438 {
439 register pcb_t pcb = thread->pcb;
440
441 counter(if (--c_threads_current < c_threads_min)
442 c_threads_min = c_threads_current);
443
444 if (pcb->ims.io_tss != 0)
445 iopb_destroy(pcb->ims.io_tss);
446 if (pcb->ims.ifps != 0)
447 fp_free(pcb->ims.ifps);
448 if (pcb->ims.ldt != 0)
449 user_ldt_free(pcb->ims.ldt);
450 zfree(pcb_zone, (vm_offset_t) pcb);
451 thread->pcb = 0;
452 }
453
454 /*
455 * pcb_collect:
456 *
457 * Attempt to free excess pcb memory.
458 */
459
460 void pcb_collect(thread)
461 thread_t thread;
462 {
463 }
464
465
466 /*
467 * thread_setstatus:
468 *
469 * Set the status of the specified thread.
470 */
471
472 kern_return_t thread_setstatus(thread, flavor, tstate, count)
473 thread_t thread;
474 int flavor;
475 thread_state_t tstate;
476 unsigned int count;
477 {
478 switch (flavor) {
479 case i386_THREAD_STATE:
480 case i386_REGS_SEGS_STATE:
481 {
482 register struct i386_thread_state *state;
483 register struct i386_saved_state *saved_state;
484
485 if (count < i386_THREAD_STATE_COUNT) {
486 return(KERN_INVALID_ARGUMENT);
487 }
488
489 if (flavor == i386_REGS_SEGS_STATE) {
490 /*
491 * Code and stack selectors must not be null,
492 * and must have user protection levels.
493 * Only the low 16 bits are valid.
494 */
495 state->cs &= 0xffff;
496 state->ss &= 0xffff;
497 state->ds &= 0xffff;
498 state->es &= 0xffff;
499 state->fs &= 0xffff;
500 state->gs &= 0xffff;
501
502 if (state->cs == 0 || (state->cs & SEL_PL) != SEL_PL_U
503 || state->ss == 0 || (state->ss & SEL_PL) != SEL_PL_U)
504 return KERN_INVALID_ARGUMENT;
505 }
506
507 state = (struct i386_thread_state *) tstate;
508
509 saved_state = USER_REGS(thread);
510
511 /*
512 * General registers
513 */
514 saved_state->edi = state->edi;
515 saved_state->esi = state->esi;
516 saved_state->ebp = state->ebp;
517 saved_state->uesp = state->uesp;
518 saved_state->ebx = state->ebx;
519 saved_state->edx = state->edx;
520 saved_state->ecx = state->ecx;
521 saved_state->eax = state->eax;
522 saved_state->eip = state->eip;
523 saved_state->efl = (state->efl & ~EFL_USER_CLEAR)
524 | EFL_USER_SET;
525
526 /*
527 * Segment registers. Set differently in V8086 mode.
528 */
529 if (state->efl & EFL_VM) {
530 /*
531 * Set V8086 mode segment registers.
532 */
533 saved_state->cs = state->cs & 0xffff;
534 saved_state->ss = state->ss & 0xffff;
535 saved_state->v86_segs.v86_ds = state->ds & 0xffff;
536 saved_state->v86_segs.v86_es = state->es & 0xffff;
537 saved_state->v86_segs.v86_fs = state->fs & 0xffff;
538 saved_state->v86_segs.v86_gs = state->gs & 0xffff;
539
540 /*
541 * Zero protected mode segment registers.
542 */
543 saved_state->ds = 0;
544 saved_state->es = 0;
545 saved_state->fs = 0;
546 saved_state->gs = 0;
547
548 if (thread->pcb->ims.v86s.int_table) {
549 /*
550 * Hardware assist on.
551 */
552 thread->pcb->ims.v86s.flags =
553 state->efl & (EFL_TF | EFL_IF);
554 }
555 }
556 else if (flavor == i386_THREAD_STATE) {
557 /*
558 * 386 mode. Set segment registers for flat
559 * 32-bit address space.
560 */
561 saved_state->cs = USER_CS;
562 saved_state->ss = USER_DS;
563 saved_state->ds = USER_DS;
564 saved_state->es = USER_DS;
565 saved_state->fs = USER_DS;
566 saved_state->gs = USER_DS;
567 }
568 else {
569 /*
570 * User setting segment registers.
571 * Code and stack selectors have already been
572 * checked. Others will be reset by 'iret'
573 * if they are not valid.
574 */
575 saved_state->cs = state->cs;
576 saved_state->ss = state->ss;
577 saved_state->ds = state->ds;
578 saved_state->es = state->es;
579 saved_state->fs = state->fs;
580 saved_state->gs = state->gs;
581 }
582 break;
583 }
584
585 case i386_FLOAT_STATE: {
586
587 if (count < i386_FLOAT_STATE_COUNT)
588 return(KERN_INVALID_ARGUMENT);
589
590 return fpu_set_state(thread,
591 (struct i386_float_state *) tstate);
592 }
593
594 /*
595 * Temporary - replace by i386_io_map
596 */
597 case i386_ISA_PORT_MAP_STATE: {
598 register struct i386_isa_port_map_state *state;
599 register iopb_tss_t tss;
600
601 if (count < i386_ISA_PORT_MAP_STATE_COUNT)
602 return(KERN_INVALID_ARGUMENT);
603
604 #if 0
605 /*
606 * If the thread has no ktss yet,
607 * we must allocate one.
608 */
609
610 state = (struct i386_isa_port_map_state *) tstate;
611 tss = thread->pcb->ims.io_tss;
612 if (tss == 0) {
613 tss = iopb_create();
614 thread->pcb->ims.io_tss = tss;
615 }
616
617 bcopy((char *) state->pm,
618 (char *) tss->bitmap,
619 sizeof state->pm);
620 #endif
621 break;
622 }
623
624 case i386_V86_ASSIST_STATE:
625 {
626 register struct i386_v86_assist_state *state;
627 vm_offset_t int_table;
628 int int_count;
629
630 if (count < i386_V86_ASSIST_STATE_COUNT)
631 return KERN_INVALID_ARGUMENT;
632
633 state = (struct i386_v86_assist_state *) tstate;
634 int_table = state->int_table;
635 int_count = state->int_count;
636
637 if (int_table >= VM_MAX_ADDRESS ||
638 int_table +
639 int_count * sizeof(struct v86_interrupt_table)
640 > VM_MAX_ADDRESS)
641 return KERN_INVALID_ARGUMENT;
642
643 thread->pcb->ims.v86s.int_table = int_table;
644 thread->pcb->ims.v86s.int_count = int_count;
645
646 thread->pcb->ims.v86s.flags =
647 USER_REGS(thread)->efl & (EFL_TF | EFL_IF);
648 break;
649 }
650
651 default:
652 return(KERN_INVALID_ARGUMENT);
653 }
654
655 return(KERN_SUCCESS);
656 }
657
658 /*
659 * thread_getstatus:
660 *
661 * Get the status of the specified thread.
662 */
663
664 kern_return_t thread_getstatus(thread, flavor, tstate, count)
665 register thread_t thread;
666 int flavor;
667 thread_state_t tstate; /* pointer to OUT array */
668 unsigned int *count; /* IN/OUT */
669 {
670 switch (flavor) {
671 case THREAD_STATE_FLAVOR_LIST:
672 if (*count < 4)
673 return (KERN_INVALID_ARGUMENT);
674 tstate[0] = i386_THREAD_STATE;
675 tstate[1] = i386_FLOAT_STATE;
676 tstate[2] = i386_ISA_PORT_MAP_STATE;
677 tstate[3] = i386_V86_ASSIST_STATE;
678 *count = 4;
679 break;
680
681 case i386_THREAD_STATE:
682 case i386_REGS_SEGS_STATE:
683 {
684 register struct i386_thread_state *state;
685 register struct i386_saved_state *saved_state;
686
687 if (*count < i386_THREAD_STATE_COUNT)
688 return(KERN_INVALID_ARGUMENT);
689
690 state = (struct i386_thread_state *) tstate;
691 saved_state = USER_REGS(thread);
692
693 /*
694 * General registers.
695 */
696 state->edi = saved_state->edi;
697 state->esi = saved_state->esi;
698 state->ebp = saved_state->ebp;
699 state->ebx = saved_state->ebx;
700 state->edx = saved_state->edx;
701 state->ecx = saved_state->ecx;
702 state->eax = saved_state->eax;
703 state->eip = saved_state->eip;
704 state->efl = saved_state->efl;
705 state->uesp = saved_state->uesp;
706
707 state->cs = saved_state->cs;
708 state->ss = saved_state->ss;
709 if (saved_state->efl & EFL_VM) {
710 /*
711 * V8086 mode.
712 */
713 state->ds = saved_state->v86_segs.v86_ds & 0xffff;
714 state->es = saved_state->v86_segs.v86_es & 0xffff;
715 state->fs = saved_state->v86_segs.v86_fs & 0xffff;
716 state->gs = saved_state->v86_segs.v86_gs & 0xffff;
717
718 if (thread->pcb->ims.v86s.int_table) {
719 /*
720 * Hardware assist on
721 */
722 if ((thread->pcb->ims.v86s.flags &
723 (EFL_IF|V86_IF_PENDING))
724 == 0)
725 state->efl &= ~EFL_IF;
726 }
727 }
728 else {
729 /*
730 * 386 mode.
731 */
732 state->ds = saved_state->ds & 0xffff;
733 state->es = saved_state->es & 0xffff;
734 state->fs = saved_state->fs & 0xffff;
735 state->gs = saved_state->gs & 0xffff;
736 }
737 *count = i386_THREAD_STATE_COUNT;
738 break;
739 }
740
741 case i386_FLOAT_STATE: {
742
743 if (*count < i386_FLOAT_STATE_COUNT)
744 return(KERN_INVALID_ARGUMENT);
745
746 *count = i386_FLOAT_STATE_COUNT;
747 return fpu_get_state(thread,
748 (struct i386_float_state *)tstate);
749 }
750
751 /*
752 * Temporary - replace by i386_io_map
753 */
754 case i386_ISA_PORT_MAP_STATE: {
755 register struct i386_isa_port_map_state *state;
756 register iopb_tss_t tss;
757
758 if (*count < i386_ISA_PORT_MAP_STATE_COUNT)
759 return(KERN_INVALID_ARGUMENT);
760
761 state = (struct i386_isa_port_map_state *) tstate;
762 tss = thread->pcb->ims.io_tss;
763
764 if (tss == 0) {
765 int i;
766
767 /*
768 * The thread has no ktss, so no IO permissions.
769 */
770
771 for (i = 0; i < sizeof state->pm; i++)
772 state->pm[i] = 0xff;
773 } else {
774 /*
775 * The thread has its own ktss.
776 */
777
778 bcopy((char *) tss->bitmap,
779 (char *) state->pm,
780 sizeof state->pm);
781 }
782
783 *count = i386_ISA_PORT_MAP_STATE_COUNT;
784 break;
785 }
786
787 case i386_V86_ASSIST_STATE:
788 {
789 register struct i386_v86_assist_state *state;
790
791 if (*count < i386_V86_ASSIST_STATE_COUNT)
792 return KERN_INVALID_ARGUMENT;
793
794 state = (struct i386_v86_assist_state *) tstate;
795 state->int_table = thread->pcb->ims.v86s.int_table;
796 state->int_count = thread->pcb->ims.v86s.int_count;
797
798 *count = i386_V86_ASSIST_STATE_COUNT;
799 break;
800 }
801
802 default:
803 return(KERN_INVALID_ARGUMENT);
804 }
805
806 return(KERN_SUCCESS);
807 }
808
809 /*
810 * Alter the thread`s state so that a following thread_exception_return
811 * will make the thread return 'retval' from a syscall.
812 */
813 void
814 thread_set_syscall_return(thread, retval)
815 thread_t thread;
816 kern_return_t retval;
817 {
818 thread->pcb->iss.eax = retval;
819 }
820
821
822 /*
823 * Return prefered address of user stack.
824 * Always returns low address. If stack grows up,
825 * the stack grows away from this address;
826 * if stack grows down, the stack grows towards this
827 * address.
828 */
829 vm_offset_t
830 user_stack_low(stack_size)
831 vm_size_t stack_size;
832 {
833 return (VM_MAX_ADDRESS - stack_size);
834 }
835
836 /*
837 * Allocate argument area and set registers for first user thread.
838 */
839 vm_offset_t
840 set_user_regs(stack_base, stack_size, entry, arg_size)
841 vm_offset_t stack_base; /* low address */
842 vm_offset_t stack_size;
843 int *entry;
844 vm_size_t arg_size;
845 {
846 vm_offset_t arg_addr;
847 register struct i386_saved_state *saved_state;
848
849 arg_size = (arg_size + sizeof(int) - 1) & ~(sizeof(int)-1);
850 arg_addr = stack_base + stack_size - arg_size;
851
852 saved_state = USER_REGS(current_thread());
853 saved_state->uesp = (int)arg_addr;
854 saved_state->eip = entry[0];
855
856 return (arg_addr);
857 }
Cache object: bbb88f92cffc65d9c61a4f9196d40c84
|