]>
Commit | Line | Data |
---|---|---|
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 | 105 | unsigned 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 |
119 | void act_machine_throughcall(thread_t thr_act); |
120 | user_addr_t get_useraddr(void); | |
121 | void act_machine_return(int); | |
122 | void act_machine_sv_free(thread_t, int); | |
123 | ||
1c79356b | 124 | extern thread_t Switch_context( |
91447636 A |
125 | thread_t old, |
126 | thread_continue_t cont, | |
127 | thread_t new); | |
1c79356b A |
128 | extern void Thread_continue(void); |
129 | extern 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 | */ | |
137 | void | |
91447636 | 138 | consider_machine_collect(void) |
1c79356b A |
139 | { |
140 | } | |
141 | ||
1c79356b | 142 | void |
91447636 | 143 | consider_machine_adjust(void) |
1c79356b | 144 | { |
1c79356b A |
145 | } |
146 | ||
147 | ||
21362eb3 A |
148 | // DEBUG |
149 | int DEBUG_kldt = 0; | |
150 | int DEBUG_uldt = 0; | |
1c79356b | 151 | |
91447636 A |
152 | static void |
153 | act_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 | */ | |
239 | void | |
55e303ae | 240 | machine_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 | */ | |
252 | thread_t | |
55e303ae | 253 | machine_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 | */ | |
292 | void | |
91447636 | 293 | act_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 | */ | |
302 | kern_return_t | |
303 | machine_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 | ||
318 | kern_return_t | |
55e303ae | 319 | machine_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 |
645 | kern_return_t |
646 | machine_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 | */ | |
885 | kern_return_t | |
55e303ae A |
886 | machine_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 | */ | |
926 | void | |
55e303ae A |
927 | machine_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 | */ | |
947 | void | |
91447636 | 948 | machine_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 | 958 | void |
55e303ae | 959 | machine_thread_terminate_self(void) |
1c79356b | 960 | { |
1c79356b A |
961 | } |
962 | ||
963 | void | |
964 | act_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 | */ | |
988 | void | |
55e303ae | 989 | machine_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 |
998 | static void dump_handlers(thread_t); |
999 | void dump_regs(thread_t); | |
1000 | int dump_act(thread_t thr_act); | |
1c79356b A |
1001 | |
1002 | static void | |
91447636 | 1003 | dump_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 | ||
1026 | void | |
91447636 | 1027 | dump_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 | ||
1040 | int | |
91447636 | 1041 | dump_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 | |
1068 | user_addr_t | |
1069 | get_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 | ||
1085 | vm_offset_t | |
55e303ae | 1086 | machine_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 | ||
1104 | void | |
91447636 A |
1105 | machine_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 | ||
1132 | void | |
55e303ae | 1133 | machine_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 |
1160 | struct i386_act_context { |
1161 | struct i386_saved_state ss; | |
1162 | struct i386_float_state fs; | |
0b4e3aa0 A |
1163 | }; |
1164 | ||
1165 | void * | |
1166 | act_thread_csave(void) | |
1167 | { | |
21362eb3 A |
1168 | struct i386_act_context *ic; |
1169 | kern_return_t kret; | |
1170 | int 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 | } |
1197 | void | |
1198 | act_thread_catt(void *ctx) | |
1199 | { | |
21362eb3 A |
1200 | struct i386_act_context *ic; |
1201 | kern_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; | |
1221 | out: | |
1222 | kfree(ic,sizeof(struct i386_act_context)); | |
0b4e3aa0 A |
1223 | } |
1224 | ||
21362eb3 | 1225 | void act_thread_cfree(void *ctx) |
0b4e3aa0 | 1226 | { |
21362eb3 | 1227 | kfree(ctx,sizeof(struct i386_act_context)); |
0b4e3aa0 | 1228 | } |
21362eb3 | 1229 |