2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
30 #include <kern/thread.h>
31 #include <kern/thread_act.h>
32 #include <kern/misc_protos.h>
33 #include <mach/ppc/thread_status.h>
34 #include <ppc/proc_reg.h>
35 #include <ppc/exception.h>
36 #include <ppc/misc_protos.h>
37 #include <ppc/savearea.h>
38 #include <ppc/thread_act.h>
39 #include <ppc/Firmware.h>
41 #include <vm/vm_map.h>
43 extern unsigned int killprint
;
44 extern double FloatInit
;
45 extern unsigned long QNaNbarbarian
[4];
46 extern void thread_bootstrap_return(void);
47 extern struct Saveanchor saveanchor
;
48 extern int real_ncpus
; /* Number of actual CPUs */
69 unsigned int get_msr_exportmask(void);
70 unsigned int get_msr_nbits(void);
71 unsigned int get_msr_rbits(void);
72 void thread_set_child(thread_act_t child
, int pid
);
73 void thread_set_parent(thread_act_t parent
, int pid
);
76 * Maps state flavor to number of words in the state:
78 unsigned int state_count
[] = {
80 PPC_THREAD_STATE_COUNT
,
81 PPC_FLOAT_STATE_COUNT
,
82 PPC_EXCEPTION_STATE_COUNT
,
88 * Get the status of the specified thread.
92 act_machine_get_state(
94 thread_flavor_t flavor
,
95 thread_state_t tstate
,
96 mach_msg_type_number_t
*count
)
99 register struct savearea
*sv
; /* Pointer to the context savearea */
100 register savearea_fpu
*fsv
;
101 register savearea_vec
*vsv
;
104 unsigned int vrvalidwrk
;
106 register struct ppc_thread_state
*ts
;
107 register struct ppc_exception_state
*es
;
108 register struct ppc_float_state
*fs
;
109 register struct ppc_vector_state
*vs
;
113 if (watchacts
& WA_STATE
)
114 printf("act_%x act_machine_get_state(thr_act=%x,flav=%x,st=%x,cnt@%x=%x)\n",
115 current_act(), thr_act
, flavor
, tstate
,
116 count
, (count
? *count
: 0));
117 #endif /* MACH_ASSERT */
119 genuser
= find_user_regs(thr_act
); /* Find the current user general context for this activation */
123 case THREAD_STATE_FLAVOR_LIST
:
126 return (KERN_INVALID_ARGUMENT
);
129 tstate
[0] = PPC_THREAD_STATE
;
130 tstate
[1] = PPC_FLOAT_STATE
;
131 tstate
[2] = PPC_EXCEPTION_STATE
;
136 case PPC_THREAD_STATE
:
138 if (*count
< PPC_THREAD_STATE_COUNT
) { /* Is the count ok? */
139 return KERN_INVALID_ARGUMENT
;
142 ts
= (struct ppc_thread_state
*) tstate
;
144 sv
= genuser
; /* Copy this over */
146 if(sv
) { /* Is there a save area yet? */
147 ts
->r0
= sv
->save_r0
;
148 ts
->r1
= sv
->save_r1
;
149 ts
->r2
= sv
->save_r2
;
150 ts
->r3
= sv
->save_r3
;
151 ts
->r4
= sv
->save_r4
;
152 ts
->r5
= sv
->save_r5
;
153 ts
->r6
= sv
->save_r6
;
154 ts
->r7
= sv
->save_r7
;
155 ts
->r8
= sv
->save_r8
;
156 ts
->r9
= sv
->save_r9
;
157 ts
->r10
= sv
->save_r10
;
158 ts
->r11
= sv
->save_r11
;
159 ts
->r12
= sv
->save_r12
;
160 ts
->r13
= sv
->save_r13
;
161 ts
->r14
= sv
->save_r14
;
162 ts
->r15
= sv
->save_r15
;
163 ts
->r16
= sv
->save_r16
;
164 ts
->r17
= sv
->save_r17
;
165 ts
->r18
= sv
->save_r18
;
166 ts
->r19
= sv
->save_r19
;
167 ts
->r20
= sv
->save_r20
;
168 ts
->r21
= sv
->save_r21
;
169 ts
->r22
= sv
->save_r22
;
170 ts
->r23
= sv
->save_r23
;
171 ts
->r24
= sv
->save_r24
;
172 ts
->r25
= sv
->save_r25
;
173 ts
->r26
= sv
->save_r26
;
174 ts
->r27
= sv
->save_r27
;
175 ts
->r28
= sv
->save_r28
;
176 ts
->r29
= sv
->save_r29
;
177 ts
->r30
= sv
->save_r30
;
178 ts
->r31
= sv
->save_r31
;
179 ts
->cr
= sv
->save_cr
;
180 ts
->xer
= sv
->save_xer
;
181 ts
->lr
= sv
->save_lr
;
182 ts
->ctr
= sv
->save_ctr
;
183 ts
->srr0
= sv
->save_srr0
;
184 ts
->srr1
= sv
->save_srr1
;
185 ts
->mq
= 0; /* MQ register (601 only) */
186 ts
->vrsave
= sv
->save_vrsave
; /* VRSAVE register (Altivec only) */
188 else { /* No user state yet. Save seemingly random values. */
190 for(i
=0; i
< 32; i
+=2) { /* Fill up with defaults */
191 ((unsigned int *)&ts
->r0
)[i
] = ((unsigned int *)&FloatInit
)[0];
192 ((unsigned int *)&ts
->r0
)[i
+1] = ((unsigned int *)&FloatInit
)[1];
196 ts
->lr
= ((unsigned int *)&FloatInit
)[0];
197 ts
->ctr
= ((unsigned int *)&FloatInit
)[1];
198 ts
->srr0
= ((unsigned int *)&FloatInit
)[0];
199 ts
->srr1
= MSR_EXPORT_MASK_SET
;
201 ts
->vrsave
= 0; /* VRSAVE register (Altivec only) */
204 *count
= PPC_THREAD_STATE_COUNT
; /* Pass back the amount we actually copied */
207 case PPC_EXCEPTION_STATE
:
209 if (*count
< PPC_EXCEPTION_STATE_COUNT
) {
210 return KERN_INVALID_ARGUMENT
;
213 es
= (struct ppc_exception_state
*) tstate
;
215 sv
= thr_act
->mact
.pcb
; /* Start with the normal savearea */
216 while(sv
) { /* Find the user context */
217 if(sv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
218 break; /* Outta here */
220 sv
= sv
->save_hdr
.save_prev
; /* Back chain */
223 if(sv
) { /* See if valid state yet */
224 es
->dar
= sv
->save_dar
;
225 es
->dsisr
= sv
->save_dsisr
;
226 es
->exception
= sv
->save_exception
;
228 else { /* Nope, not yet */
231 es
->exception
= ((unsigned int *)&FloatInit
)[0];
234 *count
= PPC_EXCEPTION_STATE_COUNT
;
237 case PPC_FLOAT_STATE
:
239 if (*count
< PPC_FLOAT_STATE_COUNT
) {
240 return KERN_INVALID_ARGUMENT
;
243 fpu_save(thr_act
->mact
.curctx
); /* Just in case it's live, save it */
245 fs
= (struct ppc_float_state
*) tstate
; /* Point to destination */
247 fsv
= (savearea_fpu
*)thr_act
->mact
.curctx
->FPUsave
; /* Start with the top FPU savearea */
249 while(fsv
) { /* Find the user context */
250 if(!fsv
->save_hdr
.save_level
) { /* Are we looking at the user context? */
251 break; /* Outta here */
253 fsv
= (savearea_fpu
*)fsv
->save_hdr
.save_prev
; /* Back chain */
256 if(fsv
) { /* See if we have any */
257 bcopy((char *)&fsv
->save_fp0
, (char *)fs
, 32*8); /* 32 registers */
258 fs
->fpscr_pad
= 0; /* Be clean and tidy */
259 if(genuser
) fs
->fpscr
= genuser
->save_fpscr
; /* Set the fpscr value to general */
260 else fs
->fpscr
= 0; /* If no user, initialize this */
262 else { /* No floating point yet */
264 for(i
=0; i
< 32; i
++) { /* Initialize floating points */
265 fs
->fpregs
[i
] = FloatInit
; /* Initial value */
267 fs
->fpscr_pad
= 0; /* Initial value */
268 fs
->fpscr
= 0; /* Initial value */
271 *count
= PPC_FLOAT_STATE_COUNT
;
275 case PPC_VECTOR_STATE
:
277 if (*count
< PPC_VECTOR_STATE_COUNT
) {
278 return KERN_INVALID_ARGUMENT
;
281 vec_save(thr_act
->mact
.curctx
); /* Just in case it's live, save it */
283 vs
= (struct ppc_vector_state
*) tstate
; /* Point to destination */
285 vsv
= (savearea_vec
*)thr_act
->mact
.curctx
->VMXsave
; /* Start with the top vector savearea */
287 while(vsv
) { /* Find the user context */
288 if(!vsv
->save_hdr
.save_level
) { /* Are we looking at the user context? */
289 break; /* Outta here */
291 vsv
= (savearea_vec
*)vsv
->save_hdr
.save_prev
; /* Back chain */
294 if(vsv
) { /* See if we have any */
296 vrvalidwrk
= vsv
->save_vrvalid
; /* Get the valid flags */
297 vs
->save_vrvalid
= vsv
->save_vrvalid
; /* Set the valid flags */
298 if(genuser
) for(j
=0; j
< 4; j
++) vs
->save_vscr
[j
] = genuser
->save_vscr
[j
]; /* Set value for vscr */
300 vs
->save_vscr
[0] = 0; /* Set an initial value if no general user yet */
301 vs
->save_vscr
[1] = 0;
302 vs
->save_vscr
[2] = 0;
303 vs
->save_vscr
[3] = 0x00010000;
305 for(i
=0; i
< 32; i
++) { /* Copy the saved registers and invalidate the others */
306 for(j
=0; j
< 4; j
++) {
307 if(vrvalidwrk
& 0x80000000) (vs
->save_vr
)[i
][j
] =
308 ((unsigned int *)&(vsv
->save_vr0
))[(i
* 4) + j
]; /* We have this register saved */
309 else vs
->save_vr
[i
][j
] = QNaNbarbarian
[j
]; /* Set invalid value */
311 vrvalidwrk
= vrvalidwrk
<< 1; /* Shift over to the next */
314 else { /* No vector yet */
316 for(i
=0; i
< 32; i
++) { /* Initialize vector registers */
317 for(j
=0; j
< 4; j
++) vs
->save_vr
[i
][j
] = QNaNbarbarian
[j
]; /* Initial value */
320 if(genuser
) for(j
=0; j
< 4; j
++) vs
->save_vscr
[j
] = genuser
->save_vscr
[j
]; /* Set value for vscr */
322 vs
->save_vscr
[0] = 0; /* Set an initial value if no general user yet */
323 vs
->save_vscr
[1] = 0;
324 vs
->save_vscr
[2] = 0;
325 vs
->save_vscr
[3] = 0x00010000;
327 vs
->save_vrvalid
= 0; /* Clear the valid flags */
330 for (i
=0; i
< 4; i
++) vs
->save_pad5
[i
] = 0; /* Clear cruft */
331 for (i
=0; i
< 7; i
++) vs
->save_pad6
[i
] = 0; /* Clear cruft */
333 *count
= PPC_VECTOR_STATE_COUNT
;
337 return KERN_INVALID_ARGUMENT
;
345 * Set the status of the specified thread.
348 act_machine_set_state(
349 thread_act_t thr_act
,
350 thread_flavor_t flavor
,
351 thread_state_t tstate
,
352 mach_msg_type_number_t count
)
355 savearea
*sv
, *genuser
;
356 savearea_fpu
*fsv
, *fsvn
, *fsvo
;
357 savearea_vec
*vsv
, *vsvn
, *vsvo
;
360 register struct ppc_thread_state
*ts
;
361 register struct ppc_exception_state
*es
;
362 register struct ppc_float_state
*fs
;
363 register struct ppc_vector_state
*vs
;
365 int kernel_act
= thr_act
->kernel_loading
|| thr_act
->kernel_loaded
;
368 if (watchacts
& WA_STATE
)
369 printf("act_%x act_machine_set_state(thr_act=%x,flav=%x,st=%x,cnt=%x)\n",
370 current_act(), thr_act
, flavor
, tstate
, count
);
371 #endif /* MACH_ASSERT */
373 // dbgTrace((unsigned int)thr_act, (unsigned int)sv, flavor); /* (TEST/DEBUG) */
375 clgn
= count
; /* Get the count */
377 switch (flavor
) { /* Validate the count before we do anything else */
378 case PPC_THREAD_STATE
:
380 if (clgn
< PPC_THREAD_STATE_COUNT
) { /* Is it too short? */
381 return KERN_INVALID_ARGUMENT
; /* Yeah, just leave... */
385 case PPC_EXCEPTION_STATE
:
387 if (clgn
< PPC_EXCEPTION_STATE_COUNT
) { /* Is it too short? */
388 return KERN_INVALID_ARGUMENT
; /* Yeah, just leave... */
393 case PPC_FLOAT_STATE
:
395 if (clgn
< PPC_FLOAT_STATE_COUNT
) { /* Is it too short? */
396 return KERN_INVALID_ARGUMENT
; /* Yeah, just leave... */
402 case PPC_VECTOR_STATE
:
404 if (clgn
< PPC_VECTOR_STATE_COUNT
) { /* Is it too short? */
405 return KERN_INVALID_ARGUMENT
; /* Yeah, just leave... */
411 return KERN_INVALID_ARGUMENT
;
414 genuser
= get_user_regs(thr_act
); /* Find or allocate and initialize one */
418 case PPC_THREAD_STATE
:
419 case PPC_EXCEPTION_STATE
:
421 ts
= (struct ppc_thread_state
*)tstate
;
423 if(flavor
== PPC_THREAD_STATE
) { /* Are we updating plain state? */
425 genuser
->save_r0
= ts
->r0
;
426 genuser
->save_r1
= ts
->r1
;
427 genuser
->save_r2
= ts
->r2
;
428 genuser
->save_r3
= ts
->r3
;
429 genuser
->save_r4
= ts
->r4
;
430 genuser
->save_r5
= ts
->r5
;
431 genuser
->save_r6
= ts
->r6
;
432 genuser
->save_r7
= ts
->r7
;
433 genuser
->save_r8
= ts
->r8
;
434 genuser
->save_r9
= ts
->r9
;
435 genuser
->save_r10
= ts
->r10
;
436 genuser
->save_r11
= ts
->r11
;
437 genuser
->save_r12
= ts
->r12
;
438 genuser
->save_r13
= ts
->r13
;
439 genuser
->save_r14
= ts
->r14
;
440 genuser
->save_r15
= ts
->r15
;
441 genuser
->save_r16
= ts
->r16
;
442 genuser
->save_r17
= ts
->r17
;
443 genuser
->save_r18
= ts
->r18
;
444 genuser
->save_r19
= ts
->r19
;
445 genuser
->save_r20
= ts
->r20
;
446 genuser
->save_r21
= ts
->r21
;
447 genuser
->save_r22
= ts
->r22
;
448 genuser
->save_r23
= ts
->r23
;
449 genuser
->save_r24
= ts
->r24
;
450 genuser
->save_r25
= ts
->r25
;
451 genuser
->save_r26
= ts
->r26
;
452 genuser
->save_r27
= ts
->r27
;
453 genuser
->save_r28
= ts
->r28
;
454 genuser
->save_r29
= ts
->r29
;
455 genuser
->save_r30
= ts
->r30
;
456 genuser
->save_r31
= ts
->r31
;
458 genuser
->save_cr
= ts
->cr
;
459 genuser
->save_xer
= ts
->xer
;
460 genuser
->save_lr
= ts
->lr
;
461 genuser
->save_ctr
= ts
->ctr
;
462 genuser
->save_srr0
= ts
->srr0
;
463 genuser
->save_vrsave
= ts
->vrsave
; /* VRSAVE register (Altivec only) */
465 genuser
->save_srr1
= MSR_PREPARE_FOR_IMPORT(genuser
->save_srr1
, ts
->srr1
); /* Set the bits we can change */
467 if(!kernel_act
) genuser
->save_srr1
|= MSR_EXPORT_MASK_SET
; /* If not a kernel guy, force the magic bits on */
469 genuser
->save_srr1
&= ~(MASK(MSR_FP
) | MASK(MSR_VEC
)); /* Make sure we don't enable the floating point unit */
475 es
= (struct ppc_exception_state
*) tstate
;
477 genuser
->save_dar
= es
->dar
;
478 genuser
->save_dsisr
= es
->dsisr
;
479 genuser
->save_exception
= es
->exception
;
483 case PPC_FLOAT_STATE
:
485 toss_live_fpu(thr_act
->mact
.curctx
); /* Toss my floating point if live anywhere */
487 fsv
= find_user_fpu(thr_act
); /* Get the user's floating point context */
489 if(!fsv
) { /* Do we have one yet? */
490 fsv
= (savearea_fpu
*)save_alloc(); /* If we still don't have one, get a new one */
491 fsv
->save_hdr
.save_flags
= (fsv
->save_hdr
.save_flags
& ~SAVtype
) | (SAVfloat
<< SAVtypeshft
); /* Mark as in use as float */
492 fsv
->save_hdr
.save_act
= thr_act
; /* Point to the activation */
493 fsv
->save_hdr
.save_prev
= 0; /* Mark no more */
494 fsv
->save_hdr
.save_level
= 0; /* Mark user state */
496 if(!thr_act
->mact
.curctx
->FPUsave
) thr_act
->mact
.curctx
->FPUsave
= fsv
; /* If no floating point, chain us first */
499 fsvn
= fsvo
= thr_act
->mact
.curctx
->FPUsave
; /* Remember first one */
501 while (fsvn
) { /* Go until we hit the end */
502 fsvo
= fsvn
; /* Remember the previous one */
503 fsvn
= (savearea_fpu
*)fsvo
->save_hdr
.save_prev
; /* Skip on to the next */
506 fsvo
->save_hdr
.save_prev
= (savearea
*)fsv
; /* Queue us on in */
511 fs
= (struct ppc_float_state
*) tstate
; /* Point to source */
514 bcopy((char *)fs
, (char *)&fsv
->save_fp0
, 32*8); /* Move in the 32 registers */
516 genuser
->save_fpscr
= fs
->fpscr
; /* Copy the fpscr value to normal */
521 case PPC_VECTOR_STATE
:
523 toss_live_vec(thr_act
->mact
.curctx
); /* Toss my vector if live anywhere */
525 vsv
= find_user_vec(thr_act
); /* Get the user's vector context */
527 if(!vsv
) { /* Do we have one yet? */
528 vsv
= (savearea_vec
*)save_alloc(); /* If we still don't have one, get a new one */
529 vsv
->save_hdr
.save_flags
= (vsv
->save_hdr
.save_flags
& ~SAVtype
) | (SAVvector
<< SAVtypeshft
); /* Mark as in use as vector */
530 vsv
->save_hdr
.save_act
= thr_act
; /* Point to the activation */
531 vsv
->save_hdr
.save_prev
= 0; /* Mark no more */
532 vsv
->save_hdr
.save_level
= 0; /* Mark user state */
534 if(!thr_act
->mact
.curctx
->VMXsave
) thr_act
->mact
.curctx
->VMXsave
= vsv
; /* If no vector, chain us first */
537 vsvn
= vsvo
= thr_act
->mact
.curctx
->VMXsave
; /* Remember first one */
539 while (vsvn
) { /* Go until we hit the end */
540 vsvo
= vsvn
; /* Remember the previous one */
541 vsvn
= (savearea_vec
*)vsvo
->save_hdr
.save_prev
; /* Skip on to the next */
544 vsvo
->save_hdr
.save_prev
= (savearea
*)vsv
; /* Queue us on in */
549 vs
= (struct ppc_vector_state
*) tstate
; /* Point to source */
551 bcopy((char *)vs
, (char *)&vsv
->save_vr0
, 32*16); /* 32 registers plus status and validity and pad */
552 vsv
->save_vrvalid
= vs
->save_vrvalid
; /* Set validity bits */
555 for(i
= 0; i
< 4; i
++) genuser
->save_vscr
[i
] = vs
->save_vscr
[i
]; /* Set value for vscr */
561 return KERN_INVALID_ARGUMENT
;
566 * Duplicates the context of one thread into a new one.
567 * The new thread is assumed to be new and have no user state contexts except maybe a general one.
568 * We also assume that the old thread can't be running anywhere.
570 * We're only going to be duplicating user context here. That means that we will have to
571 * eliminate any floating point or vector kernel contexts and carry across the user state ones.
574 void act_thread_dup(thread_act_t old
, thread_act_t
new) {
577 savearea_fpu
*fsv
, *fsvn
;
578 savearea_vec
*vsv
, *vsvn
;
579 unsigned int spc
, i
, *srs
;
581 fpu_save(old
->mact
.curctx
); /* Make certain floating point state is all saved */
582 vec_save(old
->mact
.curctx
); /* Make certain the vector state is all saved */
584 sv
= get_user_regs(new); /* Allocate and initialze context in the new activation */
586 osv
= find_user_regs(old
); /* Find the original context */
588 panic("act_thread_dup: old activation (%08X) has no general user context\n", old
);
591 bcopy((char *)((unsigned int)osv
+ sizeof(savearea_comm
)), /* Copy everything but the headers */
592 (char *)((unsigned int)sv
+ sizeof(savearea_comm
)),
593 sizeof(struct savearea
) - sizeof(savearea_comm
));
595 sv
->save_srr1
&= ~(MASK(MSR_FP
) | MASK(MSR_VEC
)); /* Make certain that floating point and vector are turned off */
597 fsv
= find_user_fpu(old
); /* Get any user floating point */
599 new->mact
.curctx
->FPUsave
= 0; /* Assume no floating point */
601 if(fsv
) { /* Did we find one? */
602 fsvn
= (savearea_fpu
*)save_alloc(); /* If we still don't have one, get a new one */
603 fsvn
->save_hdr
.save_flags
= (fsvn
->save_hdr
.save_flags
& ~SAVtype
) | (SAVfloat
<< SAVtypeshft
); /* Mark as in use as float */
604 fsvn
->save_hdr
.save_act
= new; /* Point to the activation */
605 fsvn
->save_hdr
.save_prev
= 0; /* Mark no more */
606 fsvn
->save_hdr
.save_level
= 0; /* Mark user state */
608 new->mact
.curctx
->FPUsave
= fsvn
; /* Chain in the floating point */
610 bcopy((char *)((unsigned int)fsv
+ sizeof(savearea_comm
)), /* Copy everything but the headers */
611 (char *)((unsigned int)fsvn
+ sizeof(savearea_comm
)),
612 sizeof(struct savearea
) - sizeof(savearea_comm
));
615 vsv
= find_user_vec(old
); /* Get any user vector */
617 new->mact
.curctx
->VMXsave
= 0; /* Assume no vector */
619 if(vsv
) { /* Did we find one? */
620 vsvn
= (savearea_vec
*)save_alloc(); /* If we still don't have one, get a new one */
621 vsvn
->save_hdr
.save_flags
= (vsvn
->save_hdr
.save_flags
& ~SAVtype
) | (SAVvector
<< SAVtypeshft
); /* Mark as in use as float */
622 vsvn
->save_hdr
.save_act
= new; /* Point to the activation */
623 vsvn
->save_hdr
.save_prev
= 0; /* Mark no more */
624 vsvn
->save_hdr
.save_level
= 0; /* Mark user state */
626 new->mact
.curctx
->VMXsave
= vsvn
; /* Chain in the floating point */
628 bcopy((char *)((unsigned int)vsv
+ sizeof(savearea_comm
)), /* Copy everything but the headers */
629 (char *)((unsigned int)vsvn
+ sizeof(savearea_comm
)),
630 sizeof(struct savearea
) - sizeof(savearea_comm
));
633 return; /* Bye bye... */
637 * Initializes a fresh set of user state values. If there is no user state context,
638 * one is created. Floats and VMX are not created.
640 * We only set initial values if there was no context found.
643 savearea
*get_user_regs(thread_act_t act
) {
646 unsigned int spc
, i
, *srs
;
648 sv
= act
->mact
.pcb
; /* Get the top savearea on the stack */
649 osv
= 0; /* Set no user savearea yet */
651 while(sv
) { /* Find the user context */
652 if(sv
->save_srr1
& MASK(MSR_PR
)) return sv
; /* We found a user state context... */
654 osv
= sv
; /* Save the last one */
655 sv
= sv
->save_hdr
.save_prev
; /* Get the previous context */
658 sv
= save_alloc(); /* Get one */
659 sv
->save_hdr
.save_flags
= (sv
->save_hdr
.save_flags
& ~SAVtype
) | (SAVgeneral
<< SAVtypeshft
); /* Mark as in use as general */
660 sv
->save_hdr
.save_act
= act
; /* Point to the activation */
661 sv
->save_hdr
.save_prev
= 0; /* Mark no more */
662 sv
->save_hdr
.save_level
= 0; /* Mark user state */
664 if(osv
) { /* Did we already have one? */
665 osv
->save_hdr
.save_prev
= sv
; /* Chain us on the end */
667 else { /* We are the first */
668 act
->mact
.pcb
= sv
; /* Put it there */
671 for(i
=0; i
< 32; i
+=2) { /* Fill up with defaults */
672 ((unsigned int *)&sv
->save_r0
)[i
] = ((unsigned int *)&FloatInit
)[0];
673 ((unsigned int *)&sv
->save_r0
)[i
+1] = ((unsigned int *)&FloatInit
)[1];
677 sv
->save_lr
= ((unsigned int *)&FloatInit
)[0];
678 sv
->save_ctr
= ((unsigned int *)&FloatInit
)[1];
679 sv
->save_srr0
= ((unsigned int *)&FloatInit
)[0];
680 sv
->save_srr1
= MSR_EXPORT_MASK_SET
;
682 sv
->save_fpscr
= 0; /* Clear all floating point exceptions */
684 sv
->save_vrsave
= 0; /* Set the vector save state */
685 sv
->save_vscr
[0] = 0x00000000;
686 sv
->save_vscr
[1] = 0x00000000;
687 sv
->save_vscr
[2] = 0x00000000;
688 sv
->save_vscr
[3] = 0x00010000; /* Supress java mode and clear saturated */
690 spc
= (unsigned int)act
->map
->pmap
->space
; /* Get the space we're in */
692 srs
= (unsigned int *)&sv
->save_sr0
; /* Point to the SRs */
693 for(i
= 0; i
< 16; i
++) { /* Fill in the SRs for the new context */
694 srs
[i
] = SEG_REG_PROT
| (i
<<20) | spc
; /* Set the SR */
697 return sv
; /* Bye bye... */
701 * Find the user state context. If there is no user state context,
702 * we just return a 0.
705 savearea
*find_user_regs(thread_act_t act
) {
709 sv
= act
->mact
.pcb
; /* Get the top savearea on the stack */
711 while(sv
) { /* Find the user context */
712 if(sv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
713 break; /* Outta here */
715 sv
= sv
->save_hdr
.save_prev
; /* Get the previous context */
718 return sv
; /* Bye bye... */
722 * Find the user state floating point context. If there is no user state context,
723 * we just return a 0.
726 savearea_fpu
*find_user_fpu(thread_act_t act
) {
730 fsv
= act
->mact
.curctx
->FPUsave
; /* Get the start of the floating point chain */
732 while(fsv
) { /* Look until the end or we find it */
733 if(!(fsv
->save_hdr
.save_level
)) break; /* Is the the user state stuff? (the level is 0 if so) */
734 fsv
= (savearea_fpu
*)fsv
->save_hdr
.save_prev
; /* Try the previous one */
737 return fsv
; /* Bye bye... */
741 * Find the user state vector context. If there is no user state context,
742 * we just return a 0.
745 savearea_vec
*find_user_vec(thread_act_t act
) {
749 vsv
= act
->mact
.curctx
->VMXsave
; /* Get the start of the vector chain */
751 while(vsv
) { /* Look until the end or we find it */
752 if(!(vsv
->save_hdr
.save_level
)) break; /* Is the the user state stuff? (the level is 0 if so) */
753 vsv
= (savearea_vec
*)vsv
->save_hdr
.save_prev
; /* Try the previous one */
756 return vsv
; /* Bye bye... */
762 * Return the user stack pointer from the machine
763 * dependent thread state info.
769 thread_state_t tstate
,
771 vm_offset_t
*user_stack
,
775 struct ppc_thread_state
*state
;
781 case PPC_THREAD_STATE
:
782 if (count
< PPC_THREAD_STATE_COUNT
)
783 return (KERN_INVALID_ARGUMENT
);
785 state
= (struct ppc_thread_state
*) tstate
;
787 /* If a valid user stack is specified, use it. */
789 *user_stack
= state
->r1
;
791 if (customstack
&& state
->r1
)
796 return (KERN_INVALID_ARGUMENT
);
799 return (KERN_SUCCESS
);
804 * thread_setuserstack:
806 * Sets the user stack pointer into the machine
807 * dependent thread state info.
809 void thread_setuserstack(struct thread_activation
*act
, unsigned int user_stack
)
813 sv
= get_user_regs(act
); /* Get the user state registers */
815 sv
->save_r1
= user_stack
;
821 * thread_adjuserstack:
823 * Returns the adjusted user stack pointer from the machine
824 * dependent thread state info.
826 unsigned int thread_adjuserstack(struct thread_activation
*act
, int adjust
)
830 sv
= get_user_regs(act
); /* Get the user state registers */
832 sv
->save_r1
+= adjust
; /* Adjust the stack */
834 return sv
->save_r1
; /* Return the adjusted stack */
839 * thread_setentrypoint:
841 * Sets the user PC into the machine
842 * dependent thread state info.
845 void thread_setentrypoint(struct thread_activation
*act
, unsigned int entry
)
849 sv
= get_user_regs(act
); /* Get the user state registers */
851 sv
->save_srr0
= entry
;
860 thread_state_t tstate
,
862 vm_offset_t
*entry_point
865 struct ppc_thread_state
*state
;
870 if (*entry_point
== 0)
871 *entry_point
= VM_MIN_ADDRESS
;
875 case PPC_THREAD_STATE
:
876 if (count
< PPC_THREAD_STATE_COUNT
)
877 return (KERN_INVALID_ARGUMENT
);
879 state
= (struct ppc_thread_state
*) tstate
;
882 * If a valid entry point is specified, use it.
884 *entry_point
= state
->srr0
? state
->srr0
: VM_MIN_ADDRESS
;
887 return (KERN_INVALID_ARGUMENT
);
890 return (KERN_SUCCESS
);
893 unsigned int get_msr_exportmask(void)
895 return (MSR_EXPORT_MASK_SET
);
898 unsigned int get_msr_nbits(void)
900 return (MASK(MSR_POW
)|MASK(MSR_ILE
)|MASK(MSR_IP
)|MASK(MSR_LE
));
902 unsigned int get_msr_rbits(void)
904 return (MASK(MSR_PR
)|MASK(MSR_ME
)|MASK(MSR_IR
)|MASK(MSR_DR
)|MASK(MSR_EE
));
907 void thread_set_child(thread_act_t child
, int pid
)
909 struct savearea
*child_state
;
911 child_state
= get_user_regs(child
);
913 child_state
->save_r3
= pid
;
914 child_state
->save_r4
= 1;
916 void thread_set_parent(thread_act_t parent
, int pid
)
918 struct savearea
*parent_state
;
920 parent_state
= get_user_regs(parent
);
922 parent_state
->save_r3
= pid
;
923 parent_state
->save_r4
= 0;
927 * Saves the complete context (general, floating point, and vector) of the current activation.
928 * We will collect everything into an opaque block of 1 to 3 saveareas and pass back a
931 * The savearea is made to look like it belongs to the source activation. This needs to
932 * be adjusted when these contexts are attached to a new activation.
936 void *act_thread_csave(void) {
939 savearea_fpu
*fsv
, *ofsv
;
940 savearea_vec
*vsv
, *ovsv
;
941 unsigned int spc
, i
, *srs
;
945 act
= current_act(); /* Find ourselves */
947 fpu_save(act
->mact
.curctx
); /* Make certain floating point state is all saved */
948 vec_save(act
->mact
.curctx
); /* Make certain the vector state is all saved */
950 osv
= find_user_regs(act
); /* Get our savearea */
953 panic("act_thread_csave: attempting to preserve the context of an activation with none (%08X)\n", act
);
956 sv
= save_alloc(); /* Get a fresh save area to save into */
957 sv
->save_hdr
.save_flags
= (sv
->save_hdr
.save_flags
& ~SAVtype
) | (SAVgeneral
<< SAVtypeshft
); /* Mark as in use as general */
958 sv
->save_hdr
.save_act
= act
; /* Point to the activation */
959 sv
->save_hdr
.save_prev
= 0; /* Mark no more */
960 sv
->save_hdr
.save_level
= 0; /* Mark user state */
963 bcopy((char *)((unsigned int)osv
+ sizeof(savearea_comm
)), /* Copy everything but the headers */
964 (char *)((unsigned int)sv
+ sizeof(savearea_comm
)),
965 sizeof(struct savearea
) - sizeof(savearea_comm
));
967 sv
->save_srr1
&= ~(MASK(MSR_FP
) | MASK(MSR_VEC
)); /* Make certain that floating point and vector are turned off */
969 sv
->save_hdr
.save_misc2
= 0xDEBB1ED0; /* Eye catcher for debug */
970 sv
->save_hdr
.save_misc3
= 0xE5DA11A5; /* Eye catcher for debug */
973 ofsv
= find_user_fpu(act
); /* Get any user floating point */
975 sv
->save_hdr
.save_misc0
= 0; /* Assume no floating point */
977 if(ofsv
) { /* Did we find one? */
978 fsv
= (savearea_fpu
*)save_alloc(); /* If we still don't have one, get a new one */
979 fsv
->save_hdr
.save_flags
= (fsv
->save_hdr
.save_flags
& ~SAVtype
) | (SAVfloat
<< SAVtypeshft
); /* Mark as in use as float */
980 fsv
->save_hdr
.save_act
= act
; /* Point to the activation */
981 fsv
->save_hdr
.save_prev
= 0; /* Mark no more */
982 fsv
->save_hdr
.save_level
= 0; /* Mark user state */
983 fsv
->save_hdr
.save_misc2
= 0xDEBB1ED0; /* Eye catcher for debug */
984 fsv
->save_hdr
.save_misc3
= 0xE5DA11A5; /* Eye catcher for debug */
986 sv
->save_hdr
.save_misc0
= (unsigned int)fsv
; /* Remember this one */
988 bcopy((char *)((unsigned int)ofsv
+ sizeof(savearea_comm
)), /* Copy everything but the headers */
989 (char *)((unsigned int)fsv
+ sizeof(savearea_comm
)),
990 sizeof(struct savearea
) - sizeof(savearea_comm
));
993 ovsv
= find_user_vec(act
); /* Get any user vector */
995 sv
->save_hdr
.save_misc1
= 0; /* Assume no vector */
997 if(ovsv
) { /* Did we find one? */
998 vsv
= (savearea_vec
*)save_alloc(); /* If we still don't have one, get a new one */
999 vsv
->save_hdr
.save_flags
= (vsv
->save_hdr
.save_flags
& ~SAVtype
) | (SAVvector
<< SAVtypeshft
); /* Mark as in use as float */
1000 vsv
->save_hdr
.save_act
= act
; /* Point to the activation */
1001 vsv
->save_hdr
.save_prev
= 0; /* Mark no more */
1002 vsv
->save_hdr
.save_level
= 0; /* Mark user state */
1003 vsv
->save_hdr
.save_misc2
= 0xDEBB1ED0; /* Eye catcher for debug */
1004 vsv
->save_hdr
.save_misc3
= 0xE5DA11A5; /* Eye catcher for debug */
1006 sv
->save_hdr
.save_misc1
= (unsigned int)vsv
; /* Chain in the floating point */
1008 bcopy((char *)((unsigned int)ovsv
+ sizeof(savearea_comm
)), /* Copy everything but the headers */
1009 (char *)((unsigned int)vsv
+ sizeof(savearea_comm
)),
1010 sizeof(struct savearea
) - sizeof(savearea_comm
));
1013 return (void *)sv
; /* Bye bye... */
1019 * Attaches saved user state context to an activation. We will replace any
1020 * user state context with what is passed in. The saved context consists of a
1021 * savearea that was setup by
1022 * We will collect everything into one savearea and pass that back.
1024 * The savearea is made to look like it belongs to the source activation. This needs to
1025 * be adjusted when these contexts are attached to a new activation.
1029 void act_thread_catt(void *ctx
) {
1031 savearea
*sv
, *osv
, *psv
;
1032 savearea_fpu
*fsv
, *ofsv
, *pfsv
;
1033 savearea_vec
*vsv
, *ovsv
, *pvsv
;
1034 unsigned int spc
, i
, *srs
;
1037 sv
= (savearea
*)ctx
; /* Make this easier for C */
1039 fsv
= (savearea_fpu
*)sv
->save_hdr
.save_misc0
; /* Get a possible floating point savearea */
1040 vsv
= (savearea_vec
*)sv
->save_hdr
.save_misc1
; /* Get a possible vector savearea */
1042 if((sv
->save_hdr
.save_misc2
!= 0xDEBB1ED0) || (sv
->save_hdr
.save_misc3
!= 0xE5DA11A5)) { /* See if valid savearea */
1043 panic("act_thread_catt: attempt to attach invalid general context savearea - %08X\n", sv
); /* Die */
1046 if(fsv
&& ((fsv
->save_hdr
.save_misc2
!= 0xDEBB1ED0) || (fsv
->save_hdr
.save_misc3
!= 0xE5DA11A5))) { /* See if valid savearea */
1047 panic("act_thread_catt: attempt to attach invalid float context savearea - %08X\n", fsv
); /* Die */
1050 if(vsv
&& ((vsv
->save_hdr
.save_misc2
!= 0xDEBB1ED0) || (vsv
->save_hdr
.save_misc3
!= 0xE5DA11A5))) { /* See if valid savearea */
1051 panic("act_thread_catt: attempt to attach invalid vector context savearea - %08X\n", vsv
); /* Die */
1054 act
= current_act(); /* Find ourselves */
1056 toss_live_fpu(act
->mact
.curctx
); /* Toss my floating point if live anywhere */
1057 toss_live_vec(act
->mact
.curctx
); /* Toss my vector if live anywhere */
1059 sv
->save_hdr
.save_misc2
= 0; /* Eye catcher for debug */
1060 sv
->save_hdr
.save_misc3
= 0; /* Eye catcher for debug */
1061 sv
->save_hdr
.save_act
= act
; /* Set us as owner */
1063 spc
= (unsigned int)act
->map
->pmap
->space
; /* Get the space we're in */
1065 srs
= (unsigned int *)&sv
->save_sr0
; /* Point to the SRs */
1066 for(i
= 0; i
< 16; i
++) { /* Fill in the SRs for the new context */
1067 srs
[i
] = SEG_REG_PROT
| (i
<<20) | spc
; /* Set the SRs */
1070 osv
= act
->mact
.pcb
; /* Get the top general savearea */
1072 while(osv
) { /* Any saved state? */
1073 if(osv
->save_srr1
& MASK(MSR_PR
)) break; /* Leave if this is user state */
1074 psv
= osv
; /* Save previous savearea address */
1075 osv
= osv
->save_hdr
.save_prev
; /* Get one underneath our's */
1078 if(osv
) { /* Did we find one? */
1079 if(psv
) psv
->save_hdr
.save_prev
= 0; /* Yes, clear pointer to it (it should always be last) or */
1080 else act
->mact
.pcb
= 0; /* to the start if the only one */
1082 save_release(osv
); /* Nope, release it */
1086 if(psv
) psv
->save_hdr
.save_prev
= sv
; /* Chain us to the end or */
1087 else act
->mact
.pcb
= (pcb_t
)sv
; /* to the start if the only one */
1089 ovsv
= act
->mact
.curctx
->VMXsave
; /* Get the top vector savearea */
1092 while(ovsv
) { /* Any VMX saved state? */
1093 if(!(ovsv
->save_hdr
.save_level
)) break; /* Leave if this is user state */
1094 pvsv
= ovsv
; /* Save previous savearea address */
1095 ovsv
= (savearea_vec
*)ovsv
->save_hdr
.save_prev
; /* Get one underneath our's */
1098 if(ovsv
) { /* Did we find one? */
1099 if(pvsv
) pvsv
->save_hdr
.save_prev
= 0; /* Yes, clear pointer to it (it should always be last) or */
1100 else act
->mact
.curctx
->VMXsave
= 0; /* to the start if the only one */
1102 save_release((savearea
*)ovsv
); /* Nope, release it */
1105 if(vsv
) { /* Are we sticking any vector on this one? */
1106 if(pvsv
) pvsv
->save_hdr
.save_prev
= (savearea
*)vsv
; /* Yes, chain us to the end or */
1107 else act
->mact
.curctx
->VMXsave
= vsv
; /* to the start if the only one */
1109 vsv
->save_hdr
.save_misc2
= 0; /* Eye catcher for debug */
1110 vsv
->save_hdr
.save_misc3
= 0; /* Eye catcher for debug */
1111 vsv
->save_hdr
.save_act
= act
; /* Set us as owner */
1114 ofsv
= act
->mact
.curctx
->FPUsave
; /* Get the top float savearea */
1117 while(ofsv
) { /* Any float saved state? */
1118 if(!(ofsv
->save_hdr
.save_level
)) break; /* Leave if this is user state */
1119 pfsv
= ofsv
; /* Save previous savearea address */
1120 ofsv
= (savearea_fpu
*)ofsv
->save_hdr
.save_prev
; /* Get one underneath our's */
1123 if(ofsv
) { /* Did we find one? */
1124 if(pfsv
) pfsv
->save_hdr
.save_prev
= 0; /* Yes, clear pointer to it (it should always be last) or */
1125 else act
->mact
.curctx
->FPUsave
= 0; /* to the start if the only one */
1127 save_release((savearea
*)ofsv
); /* Nope, release it */
1130 if(fsv
) { /* Are we sticking any vector on this one? */
1131 if(pfsv
) pfsv
->save_hdr
.save_prev
= (savearea
*)fsv
; /* Yes, chain us to the end or */
1132 else act
->mact
.curctx
->FPUsave
= fsv
; /* to the start if the only one */
1134 fsv
->save_hdr
.save_misc2
= 0; /* Eye catcher for debug */
1135 fsv
->save_hdr
.save_misc3
= 0; /* Eye catcher for debug */
1136 fsv
->save_hdr
.save_act
= act
; /* Set us as owner */
1144 * Releases saved context. We need this because the saved context is opague.
1145 * be adjusted when these contexts are attached to a new activation.
1149 void act_thread_cfree(void *ctx
) {
1152 savearea_fpu
*fsv
, *ofsv
;
1153 savearea_vec
*vsv
, *ovsv
, *pvsv
;
1155 sv
= (savearea
*)ctx
; /* Make this easier for C */
1157 fsv
= (savearea_fpu
*)sv
->save_hdr
.save_misc0
; /* Get a possible floating point savearea */
1158 vsv
= (savearea_vec
*)sv
->save_hdr
.save_misc1
; /* Get a possible vector savearea */
1160 if((sv
->save_hdr
.save_misc2
!= 0xDEBB1ED0) || (sv
->save_hdr
.save_misc3
!= 0xE5DA11A5)) { /* See if valid savearea */
1161 panic("act_thread_cfree: attempt to detatch invalid general context savearea - %08X\n", sv
); /* Die */
1164 save_release(sv
); /* Toss the general savearea */
1166 if(fsv
) { /* See if there is any saved floating point */
1167 if((fsv
->save_hdr
.save_misc2
!= 0xDEBB1ED0) || (fsv
->save_hdr
.save_misc3
!= 0xE5DA11A5)) { /* See if valid savearea */
1168 panic("act_thread_cfree: attempt to detatch invalid float context savearea - %08X\n", fsv
); /* Die */
1171 save_release((savearea
*)fsv
); /* Toss saved context */
1174 if(vsv
) { /* See if there is any saved floating point */
1175 if((vsv
->save_hdr
.save_misc2
!= 0xDEBB1ED0) || (vsv
->save_hdr
.save_misc3
!= 0xE5DA11A5)) { /* See if valid savearea */
1176 panic("act_thread_cfree: attempt to detatch invalid vector context savearea - %08X\n", vsv
); /* Die */
1179 save_release((savearea
*)vsv
); /* Toss saved context */
1186 * thread_enable_fpe:
1188 * enables or disables floating point exceptions for the thread.
1191 int thread_enable_fpe(thread_act_t act
, int onoff
)
1194 unsigned int oldmsr
;
1196 sv
= find_user_regs(act
); /* Find the user registers */
1197 if(!sv
) sv
= get_user_regs(act
); /* Didn't find any, allocate and initialize o
1200 oldmsr
= sv
->save_srr1
; /* Get the old msr */
1202 if(onoff
) sv
->save_srr1
= oldmsr
| MASK(MSR_FE0
) | MASK(MSR_FE1
); /* Flip on precise FP exceptions */
1203 else sv
->save_srr1
= oldmsr
& ~(MASK(MSR_FE0
) | MASK(MSR_FE1
)); /* Flip on precise FP exceptions */
1205 return ((oldmsr
& (MASK(MSR_FE0
) | MASK(MSR_FE1
))) != 0); /* Return if it was enabled or not */