]> git.saurik.com Git - apple/xnu.git/blame_incremental - osfmk/ppc/pcb.c
xnu-1228.15.4.tar.gz
[apple/xnu.git] / osfmk / ppc / pcb.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31/*
32 * Copyright (c) 1990,1991,1992 The University of Utah and
33 * the Center for Software Science (CSS). All rights reserved.
34 *
35 * Permission to use, copy, modify and distribute this software is hereby
36 * granted provided that (1) source code retains these copyright, permission,
37 * and disclaimer notices, and (2) redistributions including binaries
38 * reproduce the notices in supporting documentation, and (3) all advertising
39 * materials mentioning features or use of this software display the following
40 * acknowledgement: ``This product includes software developed by the Center
41 * for Software Science at the University of Utah.''
42 *
43 * THE UNIVERSITY OF UTAH AND CSS ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
44 * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSS DISCLAIM ANY LIABILITY OF
45 * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 *
47 * CSS requests users of this software to return to css-dist@cs.utah.edu any
48 * improvements that they make and grant CSS redistribution rights.
49 *
50 * Utah $Hdr: pcb.c 1.23 92/06/27$
51 */
52
53#include <debug.h>
54
55#include <types.h>
56
57#include <mach/mach_types.h>
58#include <mach/thread_status.h>
59
60#include <kern/kern_types.h>
61#include <kern/task.h>
62#include <kern/thread.h>
63#include <kern/misc_protos.h>
64#include <kern/mach_param.h>
65#include <kern/spl.h>
66#include <kern/machine.h>
67
68#include <vm/vm_map.h>
69#include <vm/vm_kern.h>
70#include <vm/vm_protos.h>
71
72#include <ppc/misc_protos.h>
73#include <ppc/cpu_internal.h>
74#include <ppc/exception.h>
75#include <ppc/proc_reg.h>
76#include <ppc/pmap.h>
77#include <ppc/trap.h>
78#include <ppc/mappings.h>
79#include <ppc/savearea.h>
80#include <ppc/Firmware.h>
81#include <ppc/asm.h>
82#include <ppc/thread.h>
83#include <ppc/vmachmon.h>
84#include <ppc/low_trace.h>
85#include <ppc/lowglobals.h>
86#include <ppc/fpu_protos.h>
87
88#include <sys/kdebug.h>
89
90void machine_act_terminate(thread_t);
91
92/*
93 * These constants are dumb. They should not be in asm.h!
94 */
95
96#define KF_SIZE (FM_SIZE+ARG_SIZE+FM_REDZONE)
97
98#if DEBUG
99int fpu_trap_count = 0;
100int fpu_switch_count = 0;
101int vec_trap_count = 0;
102int vec_switch_count = 0;
103#endif
104
105/*
106 * consider_machine_collect: try to collect machine-dependent pages
107 */
108void
109consider_machine_collect(void)
110{
111 /*
112 * XXX none currently available
113 */
114}
115
116void
117consider_machine_adjust(void)
118{
119 consider_mapping_adjust();
120}
121
122/*
123 * switch_context: Switch from one thread to another, needed for
124 * switching of space
125 *
126 */
127thread_t
128machine_switch_context(
129 thread_t old,
130 thread_continue_t continuation,
131 thread_t new)
132{
133 register thread_t retval;
134 pmap_t new_pmap;
135 facility_context *fowner;
136 struct per_proc_info *ppinfo;
137
138 if (old == new)
139 panic("machine_switch_context");
140
141 ppinfo = getPerProc(); /* Get our processor block */
142
143 ppinfo->old_thread = (unsigned int)old;
144
145 /* Our context might wake up on another processor, so we must
146 * not keep hot state in our FPU, it must go back to the pcb
147 * so that it can be found by the other if needed
148 */
149 if(real_ncpus > 1) { /* This is potentially slow, so only do when actually SMP */
150 fowner = ppinfo->FPU_owner; /* Cache this because it may change */
151 if(fowner) { /* Is there any live context? */
152 if(fowner->facAct == old) { /* Is it for us? */
153 fpu_save(fowner); /* Yes, save it */
154 }
155 }
156 fowner = ppinfo->VMX_owner; /* Cache this because it may change */
157 if(fowner) { /* Is there any live context? */
158 if(fowner->facAct == old) { /* Is it for us? */
159 vec_save(fowner); /* Yes, save it */
160 }
161 }
162 }
163
164 /*
165 * If old thread is running VM, save per proc userProtKey and FamVMmode spcFlags bits in the thread spcFlags
166 * This bits can be modified in the per proc without updating the thread spcFlags
167 */
168 if(old->machine.specFlags & runningVM) {
169 old->machine.specFlags &= ~(userProtKey|FamVMmode);
170 old->machine.specFlags |= (ppinfo->spcFlags) & (userProtKey|FamVMmode);
171 }
172 old->machine.specFlags &= ~OnProc;
173 new->machine.specFlags |= OnProc;
174
175 /*
176 * We do not have to worry about the PMAP module, so switch.
177 *
178 * We must not use thread->map since this may not be the actual
179 * task map, but the map being used for a klcopyin/out.
180 */
181
182 if(new->machine.specFlags & runningVM) { /* Is the new guy running a VM? */
183 pmap_switch(new->machine.vmmCEntry->vmmPmap); /* Switch to the VM's pmap */
184 ppinfo->VMMareaPhys = new->machine.vmmCEntry->vmmContextPhys;
185 ppinfo->VMMXAFlgs = new->machine.vmmCEntry->vmmXAFlgs;
186 ppinfo->FAMintercept = new->machine.vmmCEntry->vmmFAMintercept;
187 }
188 else { /* otherwise, we use the task's pmap */
189 new_pmap = new->task->map->pmap;
190 if ((old->task->map->pmap != new_pmap) || (old->machine.specFlags & runningVM)) {
191 pmap_switch(new_pmap); /* Switch if there is a change */
192 }
193 }
194
195 if(old->machine.umwSpace != invalSpace) { /* Does our old guy have an active window? */
196 old->machine.umwSpace |= umwSwitchAway; /* Show we switched away from this guy */
197 hw_blow_seg(lowGlo.lgUMWvaddr); /* Blow off the first segment */
198 hw_blow_seg(lowGlo.lgUMWvaddr + 0x10000000ULL); /* Blow off the second segment */
199 }
200
201 retval = Switch_context(old, continuation, new);
202 assert(retval != NULL);
203
204 /* We've returned from having switched context, so we should be
205 * back in the original context.
206 */
207
208 return retval;
209}
210
211/*
212 * Initialize the machine-dependent state for a new thread.
213 */
214kern_return_t
215machine_thread_create(
216 thread_t thread,
217 task_t task)
218{
219 struct savearea *sv; /* Pointer to newly allocated savearea */
220
221 (void)hw_atomic_add(&saveanchor.savetarget, 4); /* Account for the number of saveareas we think we "need"
222 for this activation */
223 assert(thread->machine.pcb == (struct savearea *)0); /* Make sure there was no previous savearea */
224
225 sv = save_alloc(); /* Go get us a savearea */
226
227 bzero((char *)((unsigned int)sv + sizeof(savearea_comm)), (sizeof(struct savearea) - sizeof(savearea_comm))); /* Clear it */
228
229 sv->save_hdr.save_prev = 0; /* Clear the back pointer */
230 sv->save_hdr.save_flags = (sv->save_hdr.save_flags & ~SAVtype) | (SAVgeneral << SAVtypeshft); /* Mark as in use */
231 sv->save_hdr.save_act = thread; /* Set who owns it */
232 thread->machine.pcb = sv; /* Point to the save area */
233 thread->machine.curctx = &thread->machine.facctx; /* Initialize facility context */
234 thread->machine.facctx.facAct = thread; /* Initialize facility context pointer to activation */
235 thread->machine.umwSpace = invalSpace; /* Initialize user memory window space to invalid */
236 thread->machine.preemption_count = 0; /* Initialize preemption counter */
237
238 /*
239 * User threads will pull their context from the pcb when first
240 * returning to user mode, so fill in all the necessary values.
241 * Kernel threads are initialized from the save state structure
242 * at the base of the kernel stack (see stack_attach()).
243 */
244
245 thread->machine.upcb = sv; /* Set user pcb */
246 sv->save_srr1 = (uint64_t)MSR_EXPORT_MASK_SET; /* Set the default user MSR */
247 if(task_has_64BitAddr(task)) sv->save_srr1 |= (uint64_t)MASK32(MSR_SF) << 32; /* If 64-bit task, force 64-bit mode */
248 sv->save_fpscr = 0; /* Clear all floating point exceptions */
249 sv->save_vrsave = 0; /* Set the vector save state */
250 sv->save_vscr[0] = 0x00000000;
251 sv->save_vscr[1] = 0x00000000;
252 sv->save_vscr[2] = 0x00000000;
253 sv->save_vscr[3] = 0x00010000; /* Disable java mode and clear saturated */
254
255 return(KERN_SUCCESS);
256}
257
258/*
259 * Machine-dependent cleanup prior to destroying a thread
260 */
261void
262machine_thread_destroy(
263 thread_t thread)
264{
265 struct savearea *local_pcb, *ppsv;
266 savearea_vec *vsv, *vpsv;
267 savearea_fpu *fsv, *fpsv;
268 boolean_t intr;
269
270/*
271 * This function will release all context.
272 */
273
274 machine_act_terminate(thread); /* Make sure all virtual machines are dead first */
275
276/*
277 *
278 * Walk through and release all floating point and vector contexts. Also kill live context.
279 *
280 */
281
282 intr = ml_set_interrupts_enabled(FALSE); /* Disable for interruptions */
283
284 toss_live_vec(thread->machine.curctx); /* Dump live vectors */
285
286 vsv = thread->machine.curctx->VMXsave; /* Get the top vector savearea */
287
288 while(vsv) { /* Any VMX saved state? */
289 vpsv = vsv; /* Remember so we can toss this */
290 /* XXX save_prev should be a void * 4425537 */
291 vsv = CAST_DOWN(savearea_vec *, vsv->save_hdr.save_prev); /* Get one underneath our's */
292 save_release((struct savearea *)vpsv); /* Release it */
293 }
294
295 thread->machine.curctx->VMXsave = NULL; /* Kill chain */
296
297 toss_live_fpu(thread->machine.curctx); /* Dump live float */
298
299 fsv = thread->machine.curctx->FPUsave; /* Get the top float savearea */
300
301 while(fsv) { /* Any float saved state? */
302 fpsv = fsv; /* Remember so we can toss this */
303 /* XXX save_prev should be a void * 4425537 */
304 fsv = CAST_DOWN(savearea_fpu *, fsv->save_hdr.save_prev); /* Get one underneath our's */
305 save_release((struct savearea *)fpsv); /* Release it */
306 }
307
308 thread->machine.curctx->FPUsave = NULL; /* Kill chain */
309
310/*
311 * free all regular saveareas.
312 */
313
314 local_pcb = thread->machine.pcb; /* Get the general savearea */
315
316 while(local_pcb) { /* Any float saved state? */
317 ppsv = local_pcb; /* Remember so we can toss this */
318 /* XXX save_prev should be a void * 4425537 */
319 local_pcb = CAST_DOWN(struct savearea *, local_pcb->save_hdr.save_prev); /* Get one underneath our's */
320 save_release(ppsv); /* Release it */
321 }
322
323 (void)hw_atomic_sub(&saveanchor.savetarget, 4); /* Unaccount for the number of saveareas we think we "need" */
324
325 (void) ml_set_interrupts_enabled(intr); /* Restore interrupts if enabled */
326
327}
328
329/*
330 * act_machine_sv_free
331 * release saveareas associated with a thread. if flag is true, release
332 * user level savearea(s) too, else don't
333 *
334 * This code must run with interruptions disabled because an interrupt handler
335 * could use floating point and/or vectors. If this happens and the thread we
336 * are blowing off owns the facility, we can deadlock.
337 */
338void
339act_machine_sv_free(thread_t act, __unused int flag)
340{
341 struct savearea *local_pcb, *userpcb;
342 register savearea_vec *vsv, *vpst, *vsvt;
343 register savearea_fpu *fsv, *fpst, *fsvt;
344 struct savearea *svp;
345 boolean_t intr;
346
347/*
348 * This function will release all non-user state context.
349 */
350
351/*
352 *
353 * Walk through and release all floating point and vector contexts that are not
354 * user state. We will also blow away live context if it belongs to non-user state.
355 * Note that the level can not change while we are in this code. Nor can another
356 * context be pushed on the stack.
357 *
358 * We do nothing here if the current level is user. Otherwise,
359 * the live context is cleared. Then we find the user saved context.
360 * Next, we take the sync lock (to keep us from munging things in *_switch).
361 * The level is set to 0 and all stacked context other than user is dequeued.
362 * Then we unlock. Next, all of the old kernel contexts are released.
363 *
364 */
365
366 intr = ml_set_interrupts_enabled(FALSE); /* Disable for interruptions */
367
368 if(act->machine.curctx->VMXlevel) { /* Is the current level user state? */
369
370 toss_live_vec(act->machine.curctx); /* Dump live vectors if is not user */
371
372 if(!hw_lock_to((hw_lock_t)&act->machine.curctx->VMXsync, LockTimeOut)) { /* Get the sync lock */
373 panic("act_machine_sv_free - timeout getting VMX sync lock\n"); /* Tell all and die */
374 }
375
376 vsv = act->machine.curctx->VMXsave; /* Get the top vector savearea */
377 while(vsv && vsv->save_hdr.save_level) /* Find user context if any */
378 /* XXX save_prev should be a void * 4425537 */
379 vsv = CAST_DOWN(savearea_vec *,
380 vsv->save_hdr.save_prev);
381
382 vsvt = act->machine.curctx->VMXsave; /* Get the top of the chain */
383 act->machine.curctx->VMXsave = vsv; /* Point to the user context */
384 act->machine.curctx->VMXlevel = NULL; /* Set the level to user */
385 hw_lock_unlock((hw_lock_t)&act->machine.curctx->VMXsync); /* Unlock */
386
387 while(vsvt) { /* Clear any VMX saved state */
388 if (vsvt == vsv) break; /* Done when hit user if any */
389 vpst = vsvt; /* Remember so we can toss this */
390 /* XXX save_prev should be a void * 4425537 */
391 vsvt = CAST_DOWN(savearea_vec *, vsvt->save_hdr.save_prev); /* Get one underneath our's */
392 save_ret((struct savearea *)vpst); /* Release it */
393 }
394
395 }
396
397 if(act->machine.curctx->FPUlevel) { /* Is the current level user state? */
398
399 toss_live_fpu(act->machine.curctx); /* Dump live floats if is not user */
400
401 if(!hw_lock_to((hw_lock_t)&act->machine.curctx->FPUsync, LockTimeOut)) { /* Get the sync lock */
402 panic("act_machine_sv_free - timeout getting FPU sync lock\n"); /* Tell all and die */
403 }
404
405 fsv = act->machine.curctx->FPUsave; /* Get the top floats savearea */
406 while(fsv && fsv->save_hdr.save_level) /* Find user context if any */
407 /* XXX save_prev should be a void * */
408 fsv = CAST_DOWN(savearea_fpu *, fsv->save_hdr.save_prev);
409
410 fsvt = act->machine.curctx->FPUsave; /* Get the top of the chain */
411 act->machine.curctx->FPUsave = fsv; /* Point to the user context */
412 act->machine.curctx->FPUlevel = NULL; /* Set the level to user */
413 hw_lock_unlock((hw_lock_t)&act->machine.curctx->FPUsync); /* Unlock */
414
415 while(fsvt) { /* Clear any VMX saved state */
416 if (fsvt == fsv) break; /* Done when hit user if any */
417 fpst = fsvt; /* Remember so we can toss this */
418 /* XXX save_prev should be a void * 4425537 */
419 fsvt = CAST_DOWN(savearea_fpu *, fsvt->save_hdr.save_prev); /* Get one underneath our's */
420 save_ret((struct savearea *)fpst); /* Release it */
421 }
422
423 }
424
425/*
426 * free all regular saveareas except a user savearea, if any
427 */
428
429 local_pcb = act->machine.pcb; /* Get the general savearea */
430 userpcb = NULL; /* Assume no user context for now */
431
432 while(local_pcb) { /* Any float saved state? */
433 if (local_pcb->save_srr1 & MASK(MSR_PR)) { /* Is this a user savearea? */
434 userpcb = local_pcb; /* Remember so we can toss this */
435 break;
436 }
437 svp = local_pcb; /* Remember this */
438 /* XXX save_prev should be a void * 4425537 */
439 local_pcb = CAST_DOWN(struct savearea *, local_pcb->save_hdr.save_prev); /* Get one underneath our's */
440 save_ret(svp); /* Release it */
441 }
442
443 act->machine.pcb = userpcb; /* Chain in the user if there is one, or 0 if not */
444 (void) ml_set_interrupts_enabled(intr); /* Restore interrupts if enabled */
445
446}
447
448void
449machine_act_terminate(
450 thread_t act)
451{
452 if(act->machine.bbDescAddr) { /* Check if the Blue box assist is active */
453 disable_bluebox_internal(act); /* Kill off bluebox */
454 }
455
456 if(act->machine.vmmControl) { /* Check if VMM is active */
457 vmm_tear_down_all(act); /* Kill off all VMM contexts */
458 }
459}
460
461void
462machine_thread_terminate_self(void)
463{
464 machine_act_terminate(current_thread());
465}
466
467void
468machine_thread_init(void)
469{
470#ifdef MACHINE_STACK
471#if KERNEL_STACK_SIZE > PPC_PGBYTES
472 panic("KERNEL_STACK_SIZE can't be greater than PPC_PGBYTES\n");
473#endif
474#endif
475}
476
477#if MACH_ASSERT
478void
479dump_thread(thread_t th)
480{
481 printf(" thread @ %p:\n", th);
482}
483#endif /* MACH_ASSERT */
484
485user_addr_t
486get_useraddr(void)
487{
488 return(current_thread()->machine.upcb->save_srr0);
489}
490
491/*
492 * detach and return a kernel stack from a thread
493 */
494
495vm_offset_t
496machine_stack_detach(
497 thread_t thread)
498{
499 vm_offset_t stack;
500
501 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_DETACH),
502 thread, thread->priority,
503 thread->sched_pri, 0, 0);
504
505 act_machine_sv_free(thread, 0); /* XXX flag == 0 OK? */
506
507 stack = thread->kernel_stack;
508 thread->kernel_stack = 0;
509 return(stack);
510}
511
512/*
513 * attach a kernel stack to a thread and initialize it
514 *
515 * attaches a stack to a thread. if there is no save
516 * area we allocate one. the top save area is then
517 * loaded with the pc (continuation address), the initial
518 * stack pointer, and a std kernel MSR. if the top
519 * save area is the user save area bad things will
520 * happen
521 *
522 */
523
524void
525machine_stack_attach(
526 thread_t thread,
527 vm_offset_t stack)
528{
529 unsigned int *kss;
530 struct savearea *sv;
531
532 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_ATTACH),
533 thread, thread->priority,
534 thread->sched_pri, 0, 0);
535
536 assert(stack);
537 kss = (unsigned int *)STACK_IKS(stack);
538 thread->kernel_stack = stack;
539
540 /* during initialization we sometimes do not have an
541 activation. in that case do not do anything */
542 sv = save_get(); /* cannot block */
543 sv->save_hdr.save_flags = (sv->save_hdr.save_flags & ~SAVtype) | (SAVgeneral << SAVtypeshft); /* Mark as in use */
544 sv->save_hdr.save_act = thread;
545 sv->save_hdr.save_prev = (addr64_t)((uintptr_t)thread->machine.pcb);
546 thread->machine.pcb = sv;
547
548 sv->save_srr0 = (unsigned int)thread_continue;
549 /* sv->save_r3 = ARG ? */
550 sv->save_r1 = (vm_offset_t)((int)kss - KF_SIZE);
551 sv->save_srr1 = MSR_SUPERVISOR_INT_OFF;
552 sv->save_fpscr = 0; /* Clear all floating point exceptions */
553 sv->save_vrsave = 0; /* Set the vector save state */
554 sv->save_vscr[3] = 0x00010000; /* Supress java mode */
555 *(CAST_DOWN(int *, sv->save_r1)) = 0;
556
557 thread->machine.ksp = 0;
558}
559
560/*
561 * move a stack from old to new thread
562 */
563
564void
565machine_stack_handoff(
566 thread_t old,
567 thread_t new)
568{
569
570 vm_offset_t stack;
571 pmap_t new_pmap;
572 facility_context *fowner;
573 mapping_t *mp;
574 struct per_proc_info *ppinfo;
575
576 assert(new);
577 assert(old);
578
579 if (old == new)
580 panic("machine_stack_handoff");
581
582 stack = machine_stack_detach(old);
583 new->kernel_stack = stack;
584 if (stack == old->reserved_stack) {
585 assert(new->reserved_stack);
586 old->reserved_stack = new->reserved_stack;
587 new->reserved_stack = stack;
588 }
589
590 ppinfo = getPerProc(); /* Get our processor block */
591
592 if(real_ncpus > 1) { /* This is potentially slow, so only do when actually SMP */
593 fowner = ppinfo->FPU_owner; /* Cache this because it may change */
594 if(fowner) { /* Is there any live context? */
595 if(fowner->facAct == old) { /* Is it for us? */
596 fpu_save(fowner); /* Yes, save it */
597 }
598 }
599 fowner = ppinfo->VMX_owner; /* Cache this because it may change */
600 if(fowner) { /* Is there any live context? */
601 if(fowner->facAct == old) { /* Is it for us? */
602 vec_save(fowner); /* Yes, save it */
603 }
604 }
605 }
606
607 /*
608 * If old thread is running VM, save per proc userProtKey and FamVMmode spcFlags bits in the thread spcFlags
609 * This bits can be modified in the per proc without updating the thread spcFlags
610 */
611 if(old->machine.specFlags & runningVM) { /* Is the current thread running a VM? */
612 old->machine.specFlags &= ~(userProtKey|FamVMmode);
613 old->machine.specFlags |= (ppinfo->spcFlags) & (userProtKey|FamVMmode);
614 }
615 old->machine.specFlags &= ~OnProc;
616 new->machine.specFlags |= OnProc;
617
618 if(new->machine.specFlags & runningVM) { /* Is the new guy running a VM? */
619 pmap_switch(new->machine.vmmCEntry->vmmPmap); /* Switch to the VM's pmap */
620 ppinfo->VMMareaPhys = new->machine.vmmCEntry->vmmContextPhys;
621 ppinfo->VMMXAFlgs = new->machine.vmmCEntry->vmmXAFlgs;
622 ppinfo->FAMintercept = new->machine.vmmCEntry->vmmFAMintercept;
623 }
624 else { /* otherwise, we use the task's pmap */
625 new_pmap = new->task->map->pmap;
626 if ((old->task->map->pmap != new_pmap) || (old->machine.specFlags & runningVM)) {
627 pmap_switch(new_pmap);
628 }
629 }
630
631 machine_set_current_thread(new);
632 ppinfo->Uassist = new->machine.cthread_self;
633
634 ppinfo->ppbbTaskEnv = new->machine.bbTaskEnv;
635 ppinfo->spcFlags = new->machine.specFlags;
636
637 old->machine.umwSpace |= umwSwitchAway; /* Show we switched away from this guy */
638 mp = (mapping_t *)&ppinfo->ppUMWmp;
639 mp->mpSpace = invalSpace; /* Since we can't handoff in the middle of copy in/out, just invalidate */
640
641 if(trcWork.traceMask) dbgTrace(0x9903, (unsigned int)old, (unsigned int)new, 0, 0); /* Cut trace entry if tracing */
642
643 return;
644}
645
646void Call_continuation(thread_continue_t, void *, wait_result_t, vm_offset_t);
647
648/*
649 * clean and initialize the current kernel stack and go to
650 * the given continuation routine
651 */
652
653void
654call_continuation(
655 thread_continue_t continuation,
656 void *parameter,
657 wait_result_t wresult)
658{
659 thread_t self = current_thread();
660 unsigned int *kss;
661 vm_offset_t tsp;
662
663 assert(self->kernel_stack);
664 kss = (unsigned int *)STACK_IKS(self->kernel_stack);
665 assert(continuation);
666
667 tsp = (vm_offset_t)((int)kss - KF_SIZE);
668 assert(tsp);
669 *((int *)tsp) = 0;
670
671 Call_continuation(continuation, parameter, wresult, tsp);
672}