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