2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
27 #include <kern/thread.h>
28 #include <kern/thread_act.h>
29 #include <kern/misc_protos.h>
30 #include <mach/ppc/thread_status.h>
31 #include <ppc/proc_reg.h>
32 #include <ppc/exception.h>
33 #include <ppc/fpu_protos.h>
34 #include <ppc/misc_protos.h>
35 #include <ppc/savearea.h>
36 #include <ppc/thread_act.h>
37 #include <ppc/Firmware.h>
39 #include <vm/vm_map.h>
41 extern unsigned int killprint
;
42 extern double FloatInit
;
43 extern unsigned long QNaNbarbarian
[4];
44 extern void thread_bootstrap_return(void);
45 extern struct Saveanchor saveanchor
;
46 extern int real_ncpus
; /* Number of actual CPUs */
49 struct ppc_saved_state
* get_user_regs(thread_act_t
);
51 #define USRSTACK 0xc0000000
72 unsigned int get_msr_exportmask(void);
73 unsigned int get_msr_nbits(void);
74 unsigned int get_msr_rbits(void);
75 void thread_set_child(thread_act_t child
, int pid
);
76 void thread_set_parent(thread_act_t parent
, int pid
);
79 * Maps state flavor to number of words in the state:
81 unsigned int state_count
[] = {
83 PPC_THREAD_STATE_COUNT
,
84 PPC_FLOAT_STATE_COUNT
,
85 PPC_EXCEPTION_STATE_COUNT
,
91 * Get the status of the specified thread.
95 act_machine_get_state(
97 thread_flavor_t flavor
,
98 thread_state_t tstate
,
99 mach_msg_type_number_t
*count
)
102 register struct savearea
*sv
; /* Pointer to the context savearea */
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
;
112 if (watchacts
& WA_STATE
)
113 printf("act_%x act_machine_get_state(thr_act=%x,flav=%x,st=%x,cnt@%x=%x)\n",
114 current_act(), thr_act
, flavor
, tstate
,
115 count
, (count
? *count
: 0));
116 #endif /* MACH_ASSERT */
121 case THREAD_STATE_FLAVOR_LIST
:
124 return (KERN_INVALID_ARGUMENT
);
127 tstate
[0] = PPC_THREAD_STATE
;
128 tstate
[1] = PPC_FLOAT_STATE
;
129 tstate
[2] = PPC_EXCEPTION_STATE
;
134 case PPC_THREAD_STATE
:
136 if (*count
< PPC_THREAD_STATE_COUNT
) { /* Is the count ok? */
137 return KERN_INVALID_ARGUMENT
;
140 ts
= (struct ppc_thread_state
*) tstate
;
142 sv
= (savearea
*)(thr_act
->mact
.pcb
); /* Start with the normal savearea */
143 while(sv
) { /* Find the user context */
144 if(sv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
145 break; /* Outta here */
147 sv
= sv
->save_prev
; /* Back chain */
150 if(sv
) { /* Is there a save area yet? */
151 ts
->r0
= sv
->save_r0
;
152 ts
->r1
= sv
->save_r1
;
153 ts
->r2
= sv
->save_r2
;
154 ts
->r3
= sv
->save_r3
;
155 ts
->r4
= sv
->save_r4
;
156 ts
->r5
= sv
->save_r5
;
157 ts
->r6
= sv
->save_r6
;
158 ts
->r7
= sv
->save_r7
;
159 ts
->r8
= sv
->save_r8
;
160 ts
->r9
= sv
->save_r9
;
161 ts
->r10
= sv
->save_r10
;
162 ts
->r11
= sv
->save_r11
;
163 ts
->r12
= sv
->save_r12
;
164 ts
->r13
= sv
->save_r13
;
165 ts
->r14
= sv
->save_r14
;
166 ts
->r15
= sv
->save_r15
;
167 ts
->r16
= sv
->save_r16
;
168 ts
->r17
= sv
->save_r17
;
169 ts
->r18
= sv
->save_r18
;
170 ts
->r19
= sv
->save_r19
;
171 ts
->r20
= sv
->save_r20
;
172 ts
->r21
= sv
->save_r21
;
173 ts
->r22
= sv
->save_r22
;
174 ts
->r23
= sv
->save_r23
;
175 ts
->r24
= sv
->save_r24
;
176 ts
->r25
= sv
->save_r25
;
177 ts
->r26
= sv
->save_r26
;
178 ts
->r27
= sv
->save_r27
;
179 ts
->r28
= sv
->save_r28
;
180 ts
->r29
= sv
->save_r29
;
181 ts
->r30
= sv
->save_r30
;
182 ts
->r31
= sv
->save_r31
;
183 ts
->cr
= sv
->save_cr
;
184 ts
->xer
= sv
->save_xer
;
185 ts
->lr
= sv
->save_lr
;
186 ts
->ctr
= sv
->save_ctr
;
187 ts
->srr0
= sv
->save_srr0
;
188 ts
->srr1
= sv
->save_srr1
;
189 ts
->mq
= sv
->save_mq
; /* MQ register (601 only) */
190 ts
->vrsave
= sv
->save_vrsave
; /* VRSAVE register (Altivec only) */
192 else { /* No user state yet. Save seemingly random values. */
194 for(i
=0; i
< 32; i
+=2) { /* Fill up with defaults */
195 ((unsigned int *)&ts
->r0
)[i
] = ((unsigned int *)&FloatInit
)[0];
196 ((unsigned int *)&ts
->r0
)[i
+1] = ((unsigned int *)&FloatInit
)[1];
200 ts
->lr
= ((unsigned int *)&FloatInit
)[0];
201 ts
->ctr
= ((unsigned int *)&FloatInit
)[1];
202 ts
->srr0
= ((unsigned int *)&FloatInit
)[0];
203 ts
->srr1
= MSR_EXPORT_MASK_SET
;
205 ts
->vrsave
= 0; /* VRSAVE register (Altivec only) */
208 *count
= PPC_THREAD_STATE_COUNT
; /* Pass back the amount we actually copied */
211 case PPC_EXCEPTION_STATE
:
213 if (*count
< PPC_EXCEPTION_STATE_COUNT
) {
214 return KERN_INVALID_ARGUMENT
;
217 es
= (struct ppc_exception_state
*) tstate
;
219 sv
= (savearea
*)(thr_act
->mact
.pcb
); /* Start with the normal savearea */
220 while(sv
) { /* Find the user context */
221 if(sv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
222 break; /* Outta here */
224 sv
= sv
->save_prev
; /* Back chain */
227 if(sv
) { /* See if valid state yet */
228 es
->dar
= sv
->save_dar
;
229 es
->dsisr
= sv
->save_dsisr
;
230 es
->exception
= sv
->save_exception
;
232 else { /* Nope, not yet */
235 es
->exception
= ((unsigned int *)&FloatInit
)[0];
238 *count
= PPC_EXCEPTION_STATE_COUNT
;
241 case PPC_FLOAT_STATE
:
243 if (*count
< PPC_FLOAT_STATE_COUNT
) {
244 return KERN_INVALID_ARGUMENT
;
247 fpu_save(thr_act
); /* Just in case it's live, save it */
249 fs
= (struct ppc_float_state
*) tstate
; /* Point to destination */
251 sv
= (savearea
*)(thr_act
->mact
.FPU_pcb
); /* Start with the top FPU savearea */
252 while(sv
) { /* Find the user context */
253 if(!sv
->save_level_fp
) { /* Are we looking at the user context? */
254 break; /* Outta here */
256 sv
= sv
->save_prev_float
; /* Back chain */
259 if(sv
) { /* See if we have any */
260 bcopy((char *)&sv
->save_fp0
, (char *)fs
, 33*8); /* 32 registers plus status and pad */
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
); /* Just in case it's live, save it */
283 vs
= (struct ppc_vector_state
*) tstate
; /* Point to destination */
285 sv
= (savearea
*)(thr_act
->mact
.VMX_pcb
); /* Start with the top FPU savearea */
286 while(sv
) { /* Find the user context */
287 if(!sv
->save_level_vec
) { /* Are we looking at the user context? */
288 break; /* Outta here */
290 sv
= sv
->save_prev_vector
; /* Back chain */
293 if(sv
) { /* See if we have any */
295 vrvalidwrk
= sv
->save_vrvalid
; /* Get the valid flags */
296 vs
->save_vrvalid
= sv
->save_vrvalid
; /* Set the valid flags */
297 for(j
=0; j
< 4; j
++) vs
->save_vscr
[j
] = sv
->save_vscr
[j
]; /* Set value for vscr */
299 for(i
=0; i
< 32; i
++) { /* Copy the saved registers and invalidate the others */
300 for(j
=0; j
< 4; j
++) {
301 if(vrvalidwrk
& 0x80000000) (vs
->save_vr
)[i
][j
] =
302 ((unsigned int *)&(sv
->save_vr0
))[(i
* 4) + j
]; /* We have this register saved */
303 else vs
->save_vr
[i
][j
] = QNaNbarbarian
[j
]; /* Set invalid value */
305 vrvalidwrk
= vrvalidwrk
<< 1; /* Shift over to the next */
308 else { /* No vector yet */
310 for(i
=0; i
< 32; i
++) { /* Initialize vector registers */
311 for(j
=0; j
< 4; j
++) vs
->save_vr
[i
][j
] = QNaNbarbarian
[j
]; /* Initial value */
313 for(j
=0; j
< 4; j
++) vs
->save_vscr
[j
] = 0; /* Initial value */
314 vs
->save_vrvalid
= 0; /* Clear the valid flags */
317 for (i
=0; i
< 4; i
++) vs
->save_pad5
[i
] = 0; /* Clear cruft */
318 for (i
=0; i
< 7; i
++) vs
->save_pad6
[i
] = 0; /* Clear cruft */
320 *count
= PPC_VECTOR_STATE_COUNT
;
324 return KERN_INVALID_ARGUMENT
;
332 * Set the status of the specified thread.
335 act_machine_set_state(
336 thread_act_t thr_act
,
337 thread_flavor_t flavor
,
338 thread_state_t tstate
,
339 mach_msg_type_number_t count
)
342 savearea
*sv
, *osv
, *usv
, *ssv
;
343 unsigned int spc
, i
, *srs
, isnew
, clgn
;
344 register struct ppc_thread_state
*ts
;
345 register struct ppc_exception_state
*es
;
346 register struct ppc_float_state
*fs
;
347 register struct ppc_vector_state
*vs
;
350 int kernel_act
= thr_act
->kernel_loading
|| thr_act
->kernel_loaded
;
353 if (watchacts
& WA_STATE
)
354 printf("act_%x act_machine_set_state(thr_act=%x,flav=%x,st=%x,cnt=%x)\n",
355 current_act(), thr_act
, flavor
, tstate
, count
);
356 #endif /* MACH_ASSERT */
358 // dbgTrace((unsigned int)thr_act, (unsigned int)sv, flavor); /* (TEST/DEBUG) */
360 clgn
= count
; /* Get the count */
362 switch (flavor
) { /* Validate the count before we do anything else */
363 case PPC_THREAD_STATE
:
365 if (clgn
< PPC_THREAD_STATE_COUNT
) { /* Is it too short? */
366 return KERN_INVALID_ARGUMENT
; /* Yeah, just leave... */
369 if(clgn
> PPC_THREAD_STATE_COUNT
) clgn
= PPC_THREAD_STATE_COUNT
; /* If too long, pin it at max */
372 case PPC_EXCEPTION_STATE
:
374 if (clgn
< PPC_EXCEPTION_STATE_COUNT
) { /* Is it too short? */
375 return KERN_INVALID_ARGUMENT
; /* Yeah, just leave... */
378 if(clgn
> PPC_EXCEPTION_STATE_COUNT
) clgn
= PPC_EXCEPTION_STATE_COUNT
; /* If too long, pin it at max */
381 case PPC_FLOAT_STATE
:
383 if (clgn
< PPC_FLOAT_STATE_COUNT
) { /* Is it too short? */
384 return KERN_INVALID_ARGUMENT
; /* Yeah, just leave... */
387 if(clgn
> PPC_FLOAT_STATE_COUNT
) clgn
= PPC_FLOAT_STATE_COUNT
; /* If too long, pin it at max */
391 case PPC_VECTOR_STATE
:
393 if (clgn
< PPC_VECTOR_STATE_COUNT
) { /* Is it too short? */
394 return KERN_INVALID_ARGUMENT
; /* Yeah, just leave... */
397 if(clgn
> PPC_VECTOR_STATE_COUNT
) clgn
= PPC_VECTOR_STATE_COUNT
; /* If too long, pin it at max */
401 return KERN_INVALID_ARGUMENT
;
404 isnew
= 0; /* Remember when we make a new one */
408 case PPC_THREAD_STATE
:
409 case PPC_EXCEPTION_STATE
:
411 ts
= (struct ppc_thread_state
*)tstate
;
413 sv
= (savearea
*)thr_act
->mact
.pcb
; /* Get the top savearea on the stack */
414 osv
= 0; /* Set no user savearea yet */
416 while(sv
) { /* Find the user context */
417 if(sv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
418 break; /* Outta here */
420 osv
= sv
; /* Save the last one */
421 sv
= sv
->save_prev
; /* Get the previous context */
424 if(!sv
) { /* We didn't find a user context so allocate and initialize one */
425 isnew
= 1; /* Remember we made a new one */
426 sv
= save_alloc(); /* Get one */
427 sv
->save_act
= thr_act
; /* Point to the activation */
428 sv
->save_flags
|= SAVattach
; /* Say that it is in use */
429 sv
->save_srr1
= MSR_EXPORT_MASK_SET
& ~MASK(MSR_PR
); /* Assume kernel state */
430 sv
->save_xfpscrpad
= 0; /* Start with a clear fpscr */
431 sv
->save_xfpscr
= 0; /* Start with a clear fpscr */
433 spc
= (unsigned int)thr_act
->map
->pmap
->space
; /* Get the space we're in */
435 srs
= (unsigned int *)&sv
->save_sr0
; /* Point to the SRs */
436 for(i
=0; i
< 16; i
++) { /* Fill in the SRs for the new context */
437 srs
[i
] = SEG_REG_PROT
| (i
<<20) | spc
; /* Set the SR */
440 sv
->save_sr_copyin
= SEG_REG_PROT
| (SR_COPYIN_NUM
<<20) | spc
; /* Make sure the copyin is set */
442 if(osv
) { /* Did we already have one? */
443 osv
->save_prev
= sv
; /* Chain us on the end */
445 else { /* We are the first */
446 thr_act
->mact
.pcb
= (pcb_t
)sv
; /* Put it there */
448 sv
->save_prev
= 0; /* Properly terminate the chain */
452 if(flavor
== PPC_THREAD_STATE
) { /* Are we updating plain state? */
454 sv
->save_r0
= ts
->r0
;
455 sv
->save_r1
= ts
->r1
;
456 sv
->save_r2
= ts
->r2
;
457 sv
->save_r3
= ts
->r3
;
458 sv
->save_r4
= ts
->r4
;
459 sv
->save_r5
= ts
->r5
;
460 sv
->save_r6
= ts
->r6
;
461 sv
->save_r7
= ts
->r7
;
462 sv
->save_r8
= ts
->r8
;
463 sv
->save_r9
= ts
->r9
;
464 sv
->save_r10
= ts
->r10
;
465 sv
->save_r11
= ts
->r11
;
466 sv
->save_r12
= ts
->r12
;
467 sv
->save_r13
= ts
->r13
;
468 sv
->save_r14
= ts
->r14
;
469 sv
->save_r15
= ts
->r15
;
470 sv
->save_r16
= ts
->r16
;
471 sv
->save_r17
= ts
->r17
;
472 sv
->save_r18
= ts
->r18
;
473 sv
->save_r19
= ts
->r19
;
474 sv
->save_r20
= ts
->r20
;
475 sv
->save_r21
= ts
->r21
;
476 sv
->save_r22
= ts
->r22
;
477 sv
->save_r23
= ts
->r23
;
478 sv
->save_r24
= ts
->r24
;
479 sv
->save_r25
= ts
->r25
;
480 sv
->save_r26
= ts
->r26
;
481 sv
->save_r27
= ts
->r27
;
482 sv
->save_r28
= ts
->r28
;
483 sv
->save_r29
= ts
->r29
;
484 sv
->save_r30
= ts
->r30
;
485 sv
->save_r31
= ts
->r31
;
487 sv
->save_cr
= ts
->cr
;
488 sv
->save_xer
= ts
->xer
;
489 sv
->save_lr
= ts
->lr
;
490 sv
->save_ctr
= ts
->ctr
;
491 sv
->save_srr0
= ts
->srr0
;
492 sv
->save_mq
= ts
->mq
;
493 sv
->save_vrsave
= ts
->vrsave
; /* VRSAVE register (Altivec only) */
495 sv
->save_srr1
= MSR_PREPARE_FOR_IMPORT(sv
->save_srr1
, ts
->srr1
); /* Set the bits we can change */
497 if(!kernel_act
) sv
->save_srr1
|= MSR_EXPORT_MASK_SET
; /* If not a kernel guy, force the magic bits on */
499 sv
->save_srr1
&= ~(MASK(MSR_FP
) | MASK(MSR_VEC
)); /* Make sure we don't enable the floating point unit */
501 if(isnew
) { /* Is it a new one? */
502 sv
->save_dar
= 0; /* Yes, these need initialization also */
504 sv
->save_exception
= 0;
509 else { /* This must be exception state */
510 if(isnew
) /* If new, we need to initialize the normal registers */
511 for(i
=0; i
< 32; i
+=2) { /* Fill up with defaults */
512 ((unsigned int *)&sv
->save_r0
)[i
] = ((unsigned int *)&FloatInit
)[0];
513 ((unsigned int *)&sv
->save_r0
)[i
+1] = ((unsigned int *)&FloatInit
)[1];
517 sv
->save_lr
= ((unsigned int *)&FloatInit
)[0];
518 sv
->save_ctr
= ((unsigned int *)&FloatInit
)[1];
519 sv
->save_srr0
= ((unsigned int *)&FloatInit
)[0];
520 sv
->save_srr1
= MSR_EXPORT_MASK_SET
;
522 sv
->save_vrsave
= 0; /* VRSAVE register (Altivec only) */
525 es
= (struct ppc_exception_state
*) tstate
;
527 sv
->save_dar
= es
->dar
;
528 sv
->save_dsisr
= es
->dsisr
;
529 sv
->save_exception
= es
->exception
;
533 case PPC_FLOAT_STATE
:
535 spl
= splhigh(); /* Don't bother me while I'm zapping the owner stuff */
537 if (per_proc_info
[cpu_number()].FPU_thread
== (unsigned int)thr_act
) /* If we own the FPU, and */
538 if(!thr_act
->mact
.FPU_lvl
) per_proc_info
[cpu_number()].FPU_thread
= 0; /* it's user level, say we don't own it any more */
540 splx(spl
); /* Restore the interrupt level */
542 sv
= (savearea
*)thr_act
->mact
.FPU_pcb
; /* Get the top savearea on the stack */
543 osv
= 0; /* Set no user savearea yet */
545 if(sv
&& (sv
->save_level_fp
== 1)) { /* Is the first savearea invalid? */
546 thr_act
->mact
.FPU_pcb
= (pcb_t
)sv
->save_prev_float
; /* Yes, clean it out */
547 sv
->save_flags
&= ~SAVfpuvalid
; /* Clear the floating point flag */
548 if(!(sv
->save_flags
& SAVinuse
)) { /* Anyone left with this one? */
549 save_release(sv
); /* Nope, release it */
551 sv
= (savearea
*)thr_act
->mact
.FPU_pcb
; /* Get the new top savearea on the stack */
554 while(sv
) { /* Find the user context */
555 if(!(sv
->save_level_fp
)) { /* Are we looking at the user context? */
556 break; /* Outta here */
558 osv
= sv
; /* Save the last one */
559 sv
= sv
->save_prev_float
; /* Get the previous context */
562 if(!sv
) { /* We didn't find a user context so allocate and initialize one */
564 sv
= (savearea
*)thr_act
->mact
.pcb
; /* Point to the top savearea on the normal stack */
566 while(sv
) { /* Have we hit the end? */
567 if(!(sv
->save_flags
& SAVfpuvalid
)) break; /* Is floating point in use here? */
568 sv
= sv
->save_prev
; /* Back chain */
571 if(!sv
) { /* If there wasn't one on the normal chain, check vector */
572 sv
= (savearea
*)thr_act
->mact
.VMX_pcb
; /* Point to the top savearea on the vector stack */
573 while(sv
) { /* Have we hit the end? */
574 if(!(sv
->save_flags
& SAVfpuvalid
)) break; /* Is floating point in use here? */
575 sv
= sv
->save_prev_vector
; /* Back chain */
579 if(!sv
) { /* Do we have one yet? */
580 sv
= save_alloc(); /* If we still don't have one, get a new one */
581 sv
->save_act
= thr_act
; /* Point to the activation */
583 spc
=(unsigned int)thr_act
->map
->pmap
->space
; /* Get the space we're in */
585 srs
=(unsigned int *)&sv
->save_sr0
; /* Point to the SRs */
586 for(i
=0; i
< 16; i
++) { /* Fill in the SRs for the new context */
587 srs
[i
] = SEG_REG_PROT
| (i
<<20) | spc
; /* Set the SR */
590 sv
->save_sr_copyin
= SEG_REG_PROT
| (SR_COPYIN_NUM
<<20) | spc
; /* Make sure the copyin is set */
593 if(osv
) { /* Did we already have one? */
594 osv
->save_prev_float
= sv
; /* Chain us on the end */
596 else { /* We are the first */
597 thr_act
->mact
.FPU_pcb
= (pcb_t
)sv
; /* Put it there */
599 sv
->save_prev_float
= 0; /* Properly terminate the chain */
600 sv
->save_level_fp
= 0; /* Make sure we are for the user level */
601 sv
->save_flags
|= SAVfpuvalid
; /* Say that it is in use by floating point */
604 fs
= (struct ppc_float_state
*) tstate
; /* Point to source */
607 bcopy((char *)fs
, (char *)&sv
->save_fp0
, clgn
*4); /* 32 registers plus status and pad */
609 usv
= find_user_regs(thr_act
); /* Find the user registers */
610 if(!usv
) usv
= get_user_regs(thr_act
); /* Didn't find any, allocate and initialize one */
612 usv
->save_xfpscrpad
= sv
->save_fpscr_pad
; /* Copy the pad value to normal */
613 usv
->save_xfpscr
= sv
->save_fpscr
; /* Copy the fpscr value to normal */
618 case PPC_VECTOR_STATE
:
620 spl
= splhigh(); /* Don't bother me while I'm zapping the owner stuff */
622 if (per_proc_info
[cpu_number()].VMX_thread
== (unsigned int)thr_act
) /* If we own the vector, and */
623 if(!thr_act
->mact
.VMX_lvl
) per_proc_info
[cpu_number()].VMX_thread
= 0; /* it's user level, say we don't own it any more */
625 splx(spl
); /* Restore the interrupt level */
627 sv
= (savearea
*)thr_act
->mact
.VMX_pcb
; /* Get the top savearea on the stack */
628 osv
= 0; /* Set no user savearea yet */
630 if(sv
&& (sv
->save_level_vec
== 1)) { /* Is the first savearea invalid? */
631 thr_act
->mact
.VMX_pcb
= (pcb_t
)sv
->save_prev_vector
; /* Yes, clean it out */
632 sv
->save_flags
&= ~SAVvmxvalid
; /* Clear the floating point flag */
633 if(!(sv
->save_flags
& SAVinuse
)) { /* Anyone left with this one? */
634 save_release(sv
); /* Nope, release it */
636 sv
= (savearea
*)thr_act
->mact
.VMX_pcb
; /* Get the new top savearea on the stack */
639 while(sv
) { /* Find the user context */
640 if(!(sv
->save_level_vec
)) { /* Are we looking at the user context? */
641 break; /* Outta here */
643 osv
= sv
; /* Save the last one */
644 sv
= sv
->save_prev_vector
; /* Get the previous context */
647 if(!sv
) { /* We didn't find a user context so allocate and initialize one */
649 sv
= (savearea
*)thr_act
->mact
.pcb
; /* Point to the top savearea on the normal stack */
651 while(sv
) { /* Have we hit the end? */
652 if(!(sv
->save_flags
& SAVvmxvalid
)) break; /* Is vector in use here? */
653 sv
= sv
->save_prev
; /* Back chain */
656 if(!sv
) { /* If there wasn't one on the normal chain, check vector */
657 sv
= (savearea
*)thr_act
->mact
.FPU_pcb
; /* Point to the top savearea on the FPU stack */
658 while(sv
) { /* Have we hit the end? */
659 if(!(sv
->save_flags
& SAVvmxvalid
)) break; /* Is vector in use here? */
660 sv
= sv
->save_prev_float
; /* Get the previous context */
664 if(!sv
) { /* Do we have one yet? */
665 sv
= save_alloc(); /* If we still don't have one, get a new one */
666 sv
->save_act
= thr_act
; /* Point to the activation */
668 spc
=(unsigned int)thr_act
->map
->pmap
->space
; /* Get the space we're in */
670 srs
=(unsigned int *)&sv
->save_sr0
; /* Point to the SRs */
671 for(i
=0; i
< 16; i
++) { /* Fill in the SRs for the new context */
672 srs
[i
] = SEG_REG_PROT
| (i
<<20) | spc
; /* Set the SR */
675 sv
->save_sr_copyin
= SEG_REG_PROT
| (SR_COPYIN_NUM
<<20) | spc
; /* Make sure the copyin is set */
678 if(osv
) { /* Did we already have one? */
679 osv
->save_prev_vector
= sv
; /* Chain us on the end */
681 else { /* We are the first */
682 thr_act
->mact
.VMX_pcb
= (pcb_t
)sv
; /* Put it there */
684 sv
->save_prev_vector
= 0; /* Properly terminate the chain */
685 sv
->save_level_vec
= 0; /* Make sure we are for the user level */
686 sv
->save_flags
|= SAVvmxvalid
; /* Say that it is in use by vector */
690 vs
= (struct ppc_vector_state
*) tstate
; /* Point to source */
692 bcopy((char *)vs
, (char *)&sv
->save_vr0
, clgn
*4); /* 32 registers plus status and validity and pad */
698 return KERN_INVALID_ARGUMENT
;
703 * Duplicates the context of one thread into a new one.
704 * The new thread is assumed to be new and have no user state contexts.
705 * We also assume that the old thread can't be running anywhere.
707 * We're only going to be duplicating user context here. That means that we will have to
708 * eliminate any floating point or vector kernel contexts and carry across the user state ones.
709 * We will optimize and cram all states into one savearea. Actually that will be the easiest thing
713 void act_thread_dup(thread_act_t old
, thread_act_t
new) {
715 savearea
*sv
, *osv
, *fsv
;
716 unsigned int spc
, i
, *srs
;
718 fpu_save(old
); /* Make certain floating point state is all saved */
719 vec_save(old
); /* Make certain the vector state is all saved */
721 osv
= (savearea
*)new->mact
.pcb
; /* Get the top savearea on the stack */
722 sv
= 0; /* Set no new user savearea yet */
724 while(osv
) { /* Find the user context */
725 if(osv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
726 sv
=osv
; /* Say which to use */
727 break; /* Outta here */
729 osv
=osv
->save_prev
; /* Get the previous context */
732 if(!sv
) { /* We didn't find a user context so allocate and initialize one */
733 osv
= (savearea
*)new->mact
.pcb
; /* Point to the top savearea on the stack */
734 sv
= save_alloc(); /* Get one */
735 sv
->save_flags
|= SAVattach
; /* Say that it is in use */
736 sv
->save_act
= new; /* Point to the activation */
738 spc
=(unsigned int)new->map
->pmap
->space
; /* Get the space we're in */
740 srs
=(unsigned int *)&sv
->save_sr0
; /* Point to the SRs */
741 for(i
=0; i
< 16; i
++) { /* Fill in the SRs for the new context */
742 srs
[i
] = SEG_REG_PROT
| (i
<<20) | spc
; /* Set the SR */
745 sv
->save_sr_copyin
= SEG_REG_PROT
| (SR_COPYIN_NUM
<<20) | spc
; /* Make sure the copyin is set */
747 if(osv
) { /* Did we already have one? */
748 sv
->save_prev
= osv
->save_prev
; /* Move the back chain of the top savearea */
749 osv
->save_prev
= sv
; /* Chain us just after it */
751 else { /* We are the first */
752 new->mact
.pcb
= (pcb_t
)sv
; /* Make it the active one */
757 osv
= (savearea
*)(old
->mact
.pcb
); /* Start with the normal savearea */
758 while(osv
) { /* Find the user context */
759 if(osv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
760 break; /* Outta here */
762 osv
= osv
->save_prev
; /* Back chain */
765 bcopy((char *)&osv
->save_srr0
, (char *)&sv
->save_srr0
, sizeof(struct ppc_thread_state
)); /* Copy in normal state stuff */
767 sv
->save_xfpscrpad
= osv
->save_xfpscrpad
; /* Copy the pad value to old */
768 sv
->save_xfpscr
= osv
->save_xfpscr
; /* Copy the fpscr value to old */
770 new->mact
.FPU_pcb
= (pcb_t
)0 ; /* Initialize floating point savearea */
771 new->mact
.FPU_lvl
= (pcb_t
)0 ; /* Initialize floating point level */
772 new->mact
.FPU_cpu
= 0 ; /* Initialize last used cpu (FP not live, so this doesn't really matter) */
773 new->mact
.VMX_pcb
= (pcb_t
)0 ; /* Initialize vector savearea */
774 new->mact
.VMX_lvl
= (pcb_t
)0 ; /* Initialize vector level */
775 new->mact
.VMX_cpu
= 0 ; /* Initialize last used cpu (vector not live, so this doesn't reall matter) */
777 sv
->save_prev_float
= (savearea
*)0; /* Clear the back chain */
778 sv
->save_prev_vector
= (savearea
*)0; /* Clear the back chain */
779 sv
->save_level_fp
= 0; /* Set the level for FP */
780 sv
->save_level_vec
= 0; /* Set the level for vector */
782 sv
->save_srr1
&= ~(MASK(MSR_FP
) | MASK(MSR_VEC
)); /* Make certain that floating point and vector are turned off */
784 fsv
= (savearea
*)old
->mact
.FPU_pcb
; /* Get the start of the floating point chain */
785 while(fsv
) { /* Look until the end or we find it */
786 if(!(fsv
->save_level_fp
)) { /* Is the the user state stuff? (the level is 0 if so) */
787 sv
->save_flags
|= SAVfpuvalid
; /* Show we have it */
788 bcopy((char *)&osv
->save_fp0
, (char *)&sv
->save_fp0
, sizeof(struct ppc_float_state
)); /* Copy in floating point state stuff */
789 new->mact
.FPU_pcb
= (pcb_t
)sv
; /* Make it the active one */
790 break; /* Done, everything else is all set up... */
792 fsv
= fsv
->save_prev_float
; /* Try the previous one */
795 fsv
= (savearea
*)old
->mact
.VMX_pcb
; /* Get the start of the vector chain */
796 while(fsv
) { /* Look until the end or we find it */
797 if(!(fsv
->save_level_vec
)) { /* Is the the user state stuff? (the level is 0 if so) */
798 sv
->save_flags
|= SAVvmxvalid
; /* Show we have it */
799 bcopy((char *)&osv
->save_vr0
, (char *)&sv
->save_vr0
, sizeof(struct ppc_vector_state
)); /* Copy in Altivec state stuff */
800 new->mact
.VMX_pcb
= (pcb_t
)sv
; /* Make it the active one */
801 break; /* Done, everything else is all set up... */
803 fsv
= fsv
->save_prev_vector
; /* Try the previous one */
806 return; /* Bye bye... */
810 * Initializes a fresh set of user state values. If there is no user state context,
811 * one is created. Floats and VMX are not created. We set initial values for everything.
814 struct ppc_saved_state
* get_user_regs(thread_act_t act
) {
817 unsigned int spc
, i
, *srs
;
819 sv
= (savearea
*)act
->mact
.pcb
; /* Get the top savearea on the stack */
820 osv
= 0; /* Set no user savearea yet */
822 while(sv
) { /* Find the user context */
823 if(sv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
824 break; /* Outta here */
826 osv
= sv
; /* Save the last one */
827 sv
= sv
->save_prev
; /* Get the previous context */
830 if(!sv
) { /* We didn't find a user context so allocate and initialize one */
831 sv
= save_alloc(); /* Get one */
832 sv
->save_flags
|= SAVattach
; /* Say that it is in use */
833 sv
->save_act
= act
; /* Point to the activation */
835 if(osv
) { /* Did we already have one? */
836 osv
->save_prev
= sv
; /* Chain us on the end */
838 else { /* We are the first */
839 act
->mact
.pcb
= (pcb_t
)sv
; /* Put it there */
841 sv
->save_prev
= 0; /* Properly terminate the chain */
844 for(i
=0; i
< 32; i
+=2) { /* Fill up with defaults */
845 ((unsigned int *)&sv
->save_r0
)[i
] = ((unsigned int *)&FloatInit
)[0];
846 ((unsigned int *)&sv
->save_r0
)[i
+1] = ((unsigned int *)&FloatInit
)[1];
850 sv
->save_lr
= ((unsigned int *)&FloatInit
)[0];
851 sv
->save_ctr
= ((unsigned int *)&FloatInit
)[1];
852 sv
->save_srr0
= ((unsigned int *)&FloatInit
)[0];
853 sv
->save_srr1
= MSR_EXPORT_MASK_SET
;
855 sv
->save_vrsave
= 0; /* VRSAVE register (Altivec only) */
856 sv
->save_xfpscrpad
= 0; /* Start with a clear fpscr */
857 sv
->save_xfpscr
= 0; /* Start with a clear fpscr */
859 spc
=(unsigned int)act
->map
->pmap
->space
; /* Get the space we're in */
861 srs
=(unsigned int *)&sv
->save_sr0
; /* Point to the SRs */
862 for(i
=0; i
< 16; i
++) { /* Fill in the SRs for the new context */
863 srs
[i
] = SEG_REG_PROT
| (i
<<20) | spc
; /* Set the SR */
866 sv
->save_sr_copyin
= SEG_REG_PROT
| (SR_COPYIN_NUM
<<20) | spc
; /* Make sure the copyin is set */
868 return (struct ppc_saved_state
*)sv
; /* Bye bye... */
872 * Find the user state context. If there is no user state context,
873 * we just return a 0.
876 struct ppc_saved_state
* find_user_regs(thread_act_t act
) {
880 sv
= (savearea
*)act
->mact
.pcb
; /* Get the top savearea on the stack */
882 while(sv
) { /* Find the user context */
883 if(sv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
884 break; /* Outta here */
886 sv
= sv
->save_prev
; /* Get the previous context */
889 return (struct ppc_saved_state
*)sv
; /* Bye bye... */
893 * Find the user state floating pointcontext. If there is no user state context,
894 * we just return a 0.
897 struct ppc_float_state
* find_user_fpu(thread_act_t act
) {
901 fsv
= (savearea
*)act
->mact
.FPU_pcb
; /* Get the start of the floating point chain */
902 while(fsv
) { /* Look until the end or we find it */
903 if(!(fsv
->save_level_fp
)) break; /* Is the the user state stuff? (the level is 0 if so) */
904 fsv
= fsv
->save_prev_float
; /* Try the previous one */
907 return (struct ppc_float_state
*)&(fsv
->save_fp0
); /* Bye bye... */
913 * Return the user stack pointer from the machine
914 * dependent thread state info.
920 thread_state_t tstate
,
922 vm_offset_t
*user_stack
,
926 struct ppc_thread_state
*state
;
931 if (*user_stack
== 0)
932 *user_stack
= USRSTACK
;
937 case PPC_THREAD_STATE
:
938 if (count
< PPC_THREAD_STATE_COUNT
)
939 return (KERN_INVALID_ARGUMENT
);
941 state
= (struct ppc_thread_state
*) tstate
;
944 * If a valid user stack is specified, use it.
946 *user_stack
= state
->r1
? state
->r1
: USRSTACK
;
948 if (customstack
&& state
->r1
)
953 return (KERN_INVALID_ARGUMENT
);
956 return (KERN_SUCCESS
);
963 thread_state_t tstate
,
965 vm_offset_t
*entry_point
968 struct ppc_thread_state
*state
;
973 if (*entry_point
== 0)
974 *entry_point
= VM_MIN_ADDRESS
;
978 case PPC_THREAD_STATE
:
979 if (count
< PPC_THREAD_STATE_COUNT
)
980 return (KERN_INVALID_ARGUMENT
);
982 state
= (struct ppc_thread_state
*) tstate
;
985 * If a valid entry point is specified, use it.
987 *entry_point
= state
->srr0
? state
->srr0
: VM_MIN_ADDRESS
;
990 return (KERN_INVALID_ARGUMENT
);
993 return (KERN_SUCCESS
);
996 unsigned int get_msr_exportmask(void)
998 return (MSR_EXPORT_MASK_SET
);
1001 unsigned int get_msr_nbits(void)
1003 return (MASK(MSR_POW
)|MASK(MSR_ILE
)|MASK(MSR_IP
)|MASK(MSR_LE
));
1005 unsigned int get_msr_rbits(void)
1007 return (MASK(MSR_PR
)|MASK(MSR_ME
)|MASK(MSR_IR
)|MASK(MSR_DR
)|MASK(MSR_EE
));
1010 void thread_set_child(thread_act_t child
, int pid
)
1012 struct ppc_saved_state
*child_state
;
1014 child_state
= find_user_regs(child
);
1016 child_state
->r3
= pid
;
1017 child_state
->r4
= 1;
1019 void thread_set_parent(thread_act_t parent
, int pid
)
1021 struct ppc_saved_state
*parent_state
;
1023 parent_state
= find_user_regs(parent
);
1025 parent_state
->r3
= pid
;
1026 parent_state
->r4
= 0;
1030 * Saves the complete context (general, floating point, and vector) of the current activation.
1031 * We will collect everything into one savearea and pass that back.
1033 * The savearea is made to look like it belongs to the source activation. This needs to
1034 * be adjusted when these contexts are attached to a new activation.
1038 void *act_thread_csave(void) {
1040 savearea
*sv
, *osv
, *fsv
;
1041 unsigned int spc
, i
, *srs
;
1045 fpu_save(current_act()); /* Make certain floating point state is all saved */
1046 vec_save(current_act()); /* Make certain the vector state is all saved */
1048 sv
= save_alloc(); /* Get a fresh save area */
1049 hw_atomic_add(&saveanchor
.saveneed
, 1); /* Account for the extra saveareas "need" */
1051 act
= current_act(); /* Find ourselves */
1053 sv
->save_flags
|= SAVattach
; /* Say that it is in use */
1054 sv
->save_act
= act
; /* Point to the activation */
1056 spc
=(unsigned int)act
->map
->pmap
->space
; /* Get the space we're in */
1058 srs
=(unsigned int *)&sv
->save_sr0
; /* Point to the SRs */
1059 for(i
=0; i
< 16; i
++) { /* Fill in the SRs for the new context */
1060 srs
[i
] = SEG_REG_PROT
| (i
<<20) | spc
; /* Set the SR */
1063 sv
->save_sr_copyin
= SEG_REG_PROT
| (SR_COPYIN_NUM
<<20) | spc
; /* Make sure the copyin is set */
1065 osv
= (savearea
*)(act
->mact
.pcb
); /* Start with the normal savearea */
1066 fsv
= 0; /* Assume none */
1067 while(osv
) { /* Find the user context */
1068 if(osv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
1069 fsv
= osv
; /* Remember what we found */
1070 break; /* Outta here */
1072 osv
= osv
->save_prev
; /* Back chain */
1075 if(!fsv
) { /* Did we find one? */
1076 for(i
=0; i
< 32; i
+=2) { /* Fill up with defaults */
1077 ((unsigned int *)&sv
->save_r0
)[i
] = ((unsigned int *)&FloatInit
)[0];
1078 ((unsigned int *)&sv
->save_r0
)[i
+1] = ((unsigned int *)&FloatInit
)[1];
1082 sv
->save_lr
= ((unsigned int *)&FloatInit
)[0];
1083 sv
->save_ctr
= ((unsigned int *)&FloatInit
)[1];
1084 sv
->save_srr0
= ((unsigned int *)&FloatInit
)[0];
1085 sv
->save_srr1
= MSR_EXPORT_MASK_SET
;
1087 sv
->save_vrsave
= 0; /* VRSAVE register (Altivec only) */
1088 sv
->save_xfpscrpad
= 0; /* Start with a clear fpscr */
1089 sv
->save_xfpscr
= 0; /* Start with a clear fpscr */
1091 else { /* We did find one, copy it */
1092 bcopy((char *)&fsv
->save_srr0
, (char *)&sv
->save_srr0
, sizeof(struct ppc_thread_state
)); /* Copy in normal state stuff */
1093 sv
->save_xfpscrpad
= osv
->save_xfpscrpad
; /* Copy the pad value to old */
1094 sv
->save_xfpscr
= osv
->save_xfpscr
; /* Copy the fpscr value to old */
1098 sv
->save_prev
= (savearea
*)0xDEBB1ED0; /* Eye catcher for debug */
1099 sv
->save_prev_float
= (savearea
*)0xE5DA11A5; /* Eye catcher for debug */
1100 sv
->save_prev_vector
= (savearea
*)0; /* Clear */
1101 sv
->save_level_fp
= 0; /* Set the level for FP */
1102 sv
->save_level_vec
= 0; /* Set the level for vector */
1104 sv
->save_srr1
&= ~(MASK(MSR_FP
) | MASK(MSR_VEC
)); /* Make certain that floating point and vector are turned off */
1106 fsv
= (savearea
*)act
->mact
.FPU_pcb
; /* Get the start of the floating point chain */
1107 while(fsv
) { /* Look until the end or we find it */
1108 if(!(fsv
->save_level_fp
)) { /* Is the the user state stuff? (the level is 0 if so) */
1109 sv
->save_flags
|= SAVfpuvalid
; /* Show we have it */
1110 bcopy((char *)&fsv
->save_fp0
, (char *)&sv
->save_fp0
, sizeof(struct ppc_float_state
)); /* Copy in floating point state stuff */
1111 break; /* Done, everything else is all set up... */
1113 fsv
= fsv
->save_prev_float
; /* Try the previous one */
1116 fsv
= (savearea
*)act
->mact
.VMX_pcb
; /* Get the start of the vector chain */
1117 while(fsv
) { /* Look until the end or we find it */
1118 if(!(fsv
->save_level_vec
)) { /* Is the the user state stuff? (the level is 0 if so) */
1119 sv
->save_flags
|= SAVvmxvalid
; /* Show we have it */
1120 bcopy((char *)&fsv
->save_vr0
, (char *)&sv
->save_vr0
, sizeof(struct ppc_vector_state
)); /* Copy in Altivec state stuff */
1121 break; /* Done, everything else is all set up... */
1123 fsv
= fsv
->save_prev_vector
; /* Try the previous one */
1126 return (void *)sv
; /* Bye bye... */
1132 * Attaches saved user state context to an activation. We will replace any
1133 * user state context with what is passed in. The saved context consists of a
1134 * savearea that was setup by
1135 * We will collect everything into one savearea and pass that back.
1137 * The savearea is made to look like it belongs to the source activation. This needs to
1138 * be adjusted when these contexts are attached to a new activation.
1142 void act_thread_catt(void *ctx
) {
1144 savearea
*sv
, *osv
, *fsv
, *psv
;
1145 unsigned int spc
, i
, *srs
;
1148 sv
= (savearea
*)ctx
; /* Make this easier for C */
1150 if((sv
->save_prev
!= (savearea
*)0xDEBB1ED0) || (sv
->save_prev_float
!= (savearea
*)0xE5DA11A5)) { /* See if valid savearea */
1151 panic("act_thread_catt: attempt to attach invalid context savearea - %08X\n", sv
); /* Die */
1154 act
= current_act(); /* Find ourselves */
1157 * This next bit insures that any live facility context for this thread is discarded on every processor
1160 * Note that this will not be good if the activation has any kernel fp or vec contexts that are live.
1161 * We won't worry about it because it would be silly to call this if we are a kernel task using altivec
1162 * or floating point......
1165 for(i
=0; i
< real_ncpus
; i
++) { /* Cycle through processors */
1166 (void)hw_compare_and_store((unsigned int)act
, 0, &per_proc_info
[i
].FPU_thread
); /* Clear if ours */
1167 (void)hw_compare_and_store((unsigned int)act
, 0, &per_proc_info
[i
].VMX_thread
); /* Clear if ours */
1172 * Now we make the savearea look like we own it
1175 sv
->save_prev
= (savearea
*)0; /* Clear */
1176 sv
->save_prev_float
= (savearea
*)0; /* Clear */
1177 sv
->save_prev_vector
= (savearea
*)0; /* Clear */
1178 sv
->save_act
= act
; /* Point to the activation */
1180 spc
=(unsigned int)act
->map
->pmap
->space
; /* Get the space we're in */
1182 srs
=(unsigned int *)&sv
->save_sr0
; /* Point to the SRs */
1183 for(i
=0; i
< 16; i
++) { /* Fill in the SRs for the new context */
1184 srs
[i
] = SEG_REG_PROT
| (i
<<20) | spc
; /* Set the SRs */
1187 sv
->save_sr_copyin
= SEG_REG_PROT
| (SR_COPYIN_NUM
<<20) | spc
; /* Make sure the copyin is set */
1189 osv
= (savearea
*)act
->mact
.VMX_pcb
; /* Get the top vector savearea */
1191 if(osv
&& (osv
->save_level_vec
== 1)) { /* Is the first one a special dummy one? */
1192 psv
= osv
; /* Yes, remember it */
1193 osv
= osv
->save_prev_vector
; /* Step to the next */
1194 (savearea
*)act
->mact
.VMX_pcb
= osv
; /* Dequeue it */
1195 psv
->save_flags
&= ~SAVvmxvalid
; /* Clear the VMX flag */
1196 if(!(psv
->save_flags
& SAVinuse
)) { /* Anyone left with this one? */
1197 save_release(psv
); /* Nope, release it */
1202 while(osv
) { /* Any VMX saved state? */
1203 if(!(osv
->save_level_vec
)) break; /* Leave if this is user state */
1204 psv
= osv
; /* Save previous savearea address */
1205 osv
= osv
->save_prev_vector
; /* Get one underneath our's */
1208 if(osv
) { /* Did we find one? */
1209 if(psv
) psv
->save_prev_vector
= 0; /* Yes, clear pointer to it (it should always be last) or */
1210 else act
->mact
.VMX_pcb
= 0; /* to the start if the only one */
1212 osv
->save_flags
&= ~SAVvmxvalid
; /* Clear the VMX flag */
1213 if(!(osv
->save_flags
& SAVinuse
)) { /* Anyone left with this one? */
1214 save_release(osv
); /* Nope, release it */
1218 if(sv
->save_flags
& SAVvmxvalid
) { /* Are we adding Altivec context? */
1219 if(psv
) psv
->save_prev_vector
= sv
; /* Yes, chain us to the end or */
1220 else act
->mact
.VMX_pcb
= (pcb_t
)sv
; /* to the start if the only one */
1223 osv
= (savearea
*)act
->mact
.FPU_pcb
; /* Get the top floating point savearea */
1225 if(osv
&& (osv
->save_level_fp
== 1)) { /* Is the first one a special dummy one? */
1226 psv
= osv
; /* Yes, remember it */
1227 osv
= osv
->save_prev_float
; /* Step to the next */
1228 (savearea
*)act
->mact
.FPU_pcb
= osv
; /* Dequeue it */
1229 psv
->save_flags
&= ~SAVfpuvalid
; /* Clear the float flag */
1230 if(!(psv
->save_flags
& SAVinuse
)) { /* Anyone left with this one? */
1231 save_release(psv
); /* Nope, release it */
1236 while(osv
) { /* Any floating point saved state? */
1237 if(!(osv
->save_level_fp
)) break; /* Leave if this is user state */
1238 psv
= osv
; /* Save previous savearea address */
1239 osv
= osv
->save_prev_float
; /* Get one underneath our's */
1242 if(osv
) { /* Did we find one? */
1243 if(psv
) psv
->save_prev_float
= 0; /* Yes, clear pointer to it (it should always be last) or */
1244 else act
->mact
.FPU_pcb
= 0; /* to the start if the only one */
1246 osv
->save_flags
&= ~SAVfpuvalid
; /* Clear the floating point flag */
1247 if(!(osv
->save_flags
& SAVinuse
)) { /* Anyone left with this one? */
1248 save_release(osv
); /* Nope, release it */
1252 if(sv
->save_flags
& SAVfpuvalid
) { /* Are we adding floating point context? */
1253 if(psv
) psv
->save_prev_float
= sv
; /* Yes, chain us to the end or */
1254 else act
->mact
.FPU_pcb
= (pcb_t
)sv
; /* to the start if the only one */
1257 osv
= (savearea
*)act
->mact
.pcb
; /* Get the top general savearea */
1259 while(osv
) { /* Any floating point saved state? */
1260 if(osv
->save_srr1
& MASK(MSR_PR
)) break; /* Leave if this is user state */
1261 psv
= osv
; /* Save previous savearea address */
1262 osv
= osv
->save_prev
; /* Get one underneath our's */
1265 if(osv
) { /* Did we find one? */
1266 if(psv
) psv
->save_prev
= 0; /* Yes, clear pointer to it (it should always be last) or */
1267 else act
->mact
.pcb
= 0; /* to the start if the only one */
1269 osv
->save_flags
&= ~SAVattach
; /* Clear the attached flag */
1270 if(!(osv
->save_flags
& SAVinuse
)) { /* Anyone left with this one? */
1271 save_release(osv
); /* Nope, release it */
1275 if(psv
) psv
->save_prev
= sv
; /* Chain us to the end or */
1276 else act
->mact
.pcb
= (pcb_t
)sv
; /* to the start if the only one */
1278 hw_atomic_sub(&saveanchor
.saveneed
, 1); /* Unaccount for the savearea we think we "need" */
1284 * Releases saved context. We need this because the saved context is opague.
1285 * be adjusted when these contexts are attached to a new activation.
1289 void act_thread_cfree(void *ctx
) {
1291 if((((savearea
*)ctx
)->save_prev
!= (savearea
*)0xDEBB1ED0) ||
1292 (((savearea
*)ctx
)->save_prev_float
!= (savearea
*)0xE5DA11A5)) { /* See if valid savearea */
1293 panic("act_thread_cfree: attempt to free invalid context savearea - %08X\n", ctx
); /* Die */
1296 ((savearea
*)ctx
)->save_flags
= 0; /* Clear all flags since we release this in any case */
1297 save_release((savearea
*)ctx
); /* Release this one */
1298 hw_atomic_sub(&saveanchor
.saveneed
, 1); /* Unaccount for the savearea we think we "need" */