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);
47 struct ppc_saved_state
* get_user_regs(thread_act_t
);
49 #define USRSTACK 0xc0000000
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
);
75 * Maps state flavor to number of words in the state:
77 unsigned int state_count
[] = {
79 PPC_THREAD_STATE_COUNT
,
80 PPC_FLOAT_STATE_COUNT
,
81 PPC_EXCEPTION_STATE_COUNT
,
87 * Get the status of the specified thread.
91 act_machine_get_state(
93 thread_flavor_t flavor
,
94 thread_state_t tstate
,
95 mach_msg_type_number_t
*count
)
98 register struct savearea
*sv
; /* Pointer to the context savearea */
100 unsigned int vrvalidwrk
;
102 register struct ppc_thread_state
*ts
;
103 register struct ppc_exception_state
*es
;
104 register struct ppc_float_state
*fs
;
105 register struct ppc_vector_state
*vs
;
108 if (watchacts
& WA_STATE
)
109 printf("act_%x act_machine_get_state(thr_act=%x,flav=%x,st=%x,cnt@%x=%x)\n",
110 current_act(), thr_act
, flavor
, tstate
,
111 count
, (count
? *count
: 0));
112 #endif /* MACH_ASSERT */
117 case THREAD_STATE_FLAVOR_LIST
:
120 return (KERN_INVALID_ARGUMENT
);
123 tstate
[0] = PPC_THREAD_STATE
;
124 tstate
[1] = PPC_FLOAT_STATE
;
125 tstate
[2] = PPC_EXCEPTION_STATE
;
130 case PPC_THREAD_STATE
:
132 if (*count
< PPC_THREAD_STATE_COUNT
) { /* Is the count ok? */
133 return KERN_INVALID_ARGUMENT
;
136 ts
= (struct ppc_thread_state
*) tstate
;
138 sv
= (savearea
*)(thr_act
->mact
.pcb
); /* Start with the normal savearea */
139 while(sv
) { /* Find the user context */
140 if(sv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
141 break; /* Outta here */
143 sv
= sv
->save_prev
; /* Back chain */
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
= sv
->save_mq
; /* 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
= (savearea
*)(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_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(); /* Just in case it's live, save it */
245 fs
= (struct ppc_float_state
*) tstate
; /* Point to destination */
247 sv
= (savearea
*)(thr_act
->mact
.FPU_pcb
); /* Start with the top FPU savearea */
248 while(sv
) { /* Find the user context */
249 if(!sv
->save_level_fp
) { /* Are we looking at the user context? */
250 break; /* Outta here */
252 sv
= sv
->save_prev_float
; /* Back chain */
255 if(sv
) { /* See if we have any */
256 bcopy((char *)&sv
->save_fp0
, (char *)fs
, 33*8); /* 32 registers plus status and pad */
258 else { /* No floating point yet */
260 for(i
=0; i
< 32; i
++) { /* Initialize floating points */
261 fs
->fpregs
[i
] = FloatInit
; /* Initial value */
263 fs
->fpscr_pad
= 0; /* Initial value */
264 fs
->fpscr
= 0; /* Initial value */
267 *count
= PPC_FLOAT_STATE_COUNT
;
271 case PPC_VECTOR_STATE
:
273 if (*count
< PPC_VECTOR_STATE_COUNT
) {
274 return KERN_INVALID_ARGUMENT
;
277 vec_save(); /* Just in case it's live, save it */
279 vs
= (struct ppc_vector_state
*) tstate
; /* Point to destination */
281 sv
= (savearea
*)(thr_act
->mact
.VMX_pcb
); /* Start with the top FPU savearea */
282 while(sv
) { /* Find the user context */
283 if(!sv
->save_level_vec
) { /* Are we looking at the user context? */
284 break; /* Outta here */
286 sv
= sv
->save_prev_vector
; /* Back chain */
289 if(sv
) { /* See if we have any */
291 vrvalidwrk
= sv
->save_vrvalid
; /* Get the valid flags */
292 vs
->save_vrvalid
= sv
->save_vrvalid
; /* Set the valid flags */
293 for(j
=0; j
< 4; j
++) vs
->save_vscr
[j
] = sv
->save_vscr
[j
]; /* Set value for vscr */
295 for(i
=0; i
< 32; i
++) { /* Copy the saved registers and invalidate the others */
296 for(j
=0; j
< 4; j
++) {
297 if(vrvalidwrk
& 0x80000000) (vs
->save_vr
)[i
][j
] =
298 ((unsigned int *)&(sv
->save_vr0
))[(i
* 4) + j
]; /* We have this register saved */
299 else vs
->save_vr
[i
][j
] = QNaNbarbarian
[j
]; /* Set invalid value */
301 vrvalidwrk
= vrvalidwrk
<< 1; /* Shift over to the next */
304 else { /* No vector yet */
306 for(i
=0; i
< 32; i
++) { /* Initialize vector registers */
307 for(j
=0; j
< 4; j
++) vs
->save_vr
[i
][j
] = QNaNbarbarian
[j
]; /* Initial value */
309 for(j
=0; j
< 4; j
++) vs
->save_vscr
[j
] = 0; /* Initial value */
310 vs
->save_vrvalid
= 0; /* Clear the valid flags */
313 for (i
=0; i
< 4; i
++) vs
->save_pad5
[i
] = 0; /* Clear cruft */
314 for (i
=0; i
< 7; i
++) vs
->save_pad6
[i
] = 0; /* Clear cruft */
316 *count
= PPC_VECTOR_STATE_COUNT
;
320 return KERN_INVALID_ARGUMENT
;
328 * Set the status of the specified thread.
331 act_machine_set_state(
332 thread_act_t thr_act
,
333 thread_flavor_t flavor
,
334 thread_state_t tstate
,
335 mach_msg_type_number_t count
)
338 savearea
*sv
, *osv
, *usv
, *ssv
;
339 unsigned int spc
, i
, *srs
, isnew
, clgn
;
340 register struct ppc_thread_state
*ts
;
341 register struct ppc_exception_state
*es
;
342 register struct ppc_float_state
*fs
;
343 register struct ppc_vector_state
*vs
;
346 int kernel_act
= thr_act
->kernel_loading
|| thr_act
->kernel_loaded
;
349 if (watchacts
& WA_STATE
)
350 printf("act_%x act_machine_set_state(thr_act=%x,flav=%x,st=%x,cnt=%x)\n",
351 current_act(), thr_act
, flavor
, tstate
, count
);
352 #endif /* MACH_ASSERT */
354 // dbgTrace((unsigned int)thr_act, (unsigned int)sv, flavor); /* (TEST/DEBUG) */
356 clgn
= count
; /* Get the count */
358 switch (flavor
) { /* Validate the count before we do anything else */
359 case PPC_THREAD_STATE
:
361 if (clgn
< PPC_THREAD_STATE_COUNT
) { /* Is it too short? */
362 return KERN_INVALID_ARGUMENT
; /* Yeah, just leave... */
365 if(clgn
> PPC_THREAD_STATE_COUNT
) clgn
= PPC_THREAD_STATE_COUNT
; /* If too long, pin it at max */
368 case PPC_EXCEPTION_STATE
:
370 if (clgn
< PPC_EXCEPTION_STATE_COUNT
) { /* Is it too short? */
371 return KERN_INVALID_ARGUMENT
; /* Yeah, just leave... */
374 if(clgn
> PPC_EXCEPTION_STATE_COUNT
) clgn
= PPC_EXCEPTION_STATE_COUNT
; /* If too long, pin it at max */
377 case PPC_FLOAT_STATE
:
379 if (clgn
< PPC_FLOAT_STATE_COUNT
) { /* Is it too short? */
380 return KERN_INVALID_ARGUMENT
; /* Yeah, just leave... */
383 if(clgn
> PPC_FLOAT_STATE_COUNT
) clgn
= PPC_FLOAT_STATE_COUNT
; /* If too long, pin it at max */
387 case PPC_VECTOR_STATE
:
389 if (clgn
< PPC_VECTOR_STATE_COUNT
) { /* Is it too short? */
390 return KERN_INVALID_ARGUMENT
; /* Yeah, just leave... */
393 if(clgn
> PPC_VECTOR_STATE_COUNT
) clgn
= PPC_VECTOR_STATE_COUNT
; /* If too long, pin it at max */
397 return KERN_INVALID_ARGUMENT
;
400 isnew
= 0; /* Remember when we make a new one */
404 case PPC_THREAD_STATE
:
405 case PPC_EXCEPTION_STATE
:
407 ts
= (struct ppc_thread_state
*)tstate
;
409 sv
= (savearea
*)thr_act
->mact
.pcb
; /* Get the top savearea on the stack */
410 osv
= 0; /* Set no user savearea yet */
412 while(sv
) { /* Find the user context */
413 if(sv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
414 break; /* Outta here */
416 osv
= sv
; /* Save the last one */
417 sv
= sv
->save_prev
; /* Get the previous context */
420 if(!sv
) { /* We didn't find a user context so allocate and initialize one */
421 isnew
= 1; /* Remember we made a new one */
422 sv
= save_alloc(); /* Get one */
423 sv
->save_act
= thr_act
; /* Point to the activation */
424 sv
->save_flags
|= SAVattach
; /* Say that it is in use */
425 sv
->save_srr1
= MSR_EXPORT_MASK_SET
& ~MASK(MSR_PR
); /* Assume kernel state */
426 sv
->save_xfpscrpad
= 0; /* Start with a clear fpscr */
427 sv
->save_xfpscr
= 0; /* Start with a clear fpscr */
429 spc
= (unsigned int)thr_act
->map
->pmap
->space
; /* Get the space we're in */
431 srs
= (unsigned int *)&sv
->save_sr0
; /* Point to the SRs */
432 for(i
=0; i
< 16; i
++) { /* Fill in the SRs for the new context */
433 srs
[i
] = SEG_REG_PROT
| (i
<<20) | spc
; /* Set the SR */
436 sv
->save_sr_copyin
= SEG_REG_PROT
| (SR_COPYIN_NUM
<<20) | spc
; /* Make sure the copyin is set */
438 if(osv
) { /* Did we already have one? */
439 osv
->save_prev
= sv
; /* Chain us on the end */
441 else { /* We are the first */
442 thr_act
->mact
.pcb
= (pcb_t
)sv
; /* Put it there */
444 sv
->save_prev
= 0; /* Properly terminate the chain */
448 if(flavor
== PPC_THREAD_STATE
) { /* Are we updating plain state? */
450 sv
->save_r0
= ts
->r0
;
451 sv
->save_r1
= ts
->r1
;
452 sv
->save_r2
= ts
->r2
;
453 sv
->save_r3
= ts
->r3
;
454 sv
->save_r4
= ts
->r4
;
455 sv
->save_r5
= ts
->r5
;
456 sv
->save_r6
= ts
->r6
;
457 sv
->save_r7
= ts
->r7
;
458 sv
->save_r8
= ts
->r8
;
459 sv
->save_r9
= ts
->r9
;
460 sv
->save_r10
= ts
->r10
;
461 sv
->save_r11
= ts
->r11
;
462 sv
->save_r12
= ts
->r12
;
463 sv
->save_r13
= ts
->r13
;
464 sv
->save_r14
= ts
->r14
;
465 sv
->save_r15
= ts
->r15
;
466 sv
->save_r16
= ts
->r16
;
467 sv
->save_r17
= ts
->r17
;
468 sv
->save_r18
= ts
->r18
;
469 sv
->save_r19
= ts
->r19
;
470 sv
->save_r20
= ts
->r20
;
471 sv
->save_r21
= ts
->r21
;
472 sv
->save_r22
= ts
->r22
;
473 sv
->save_r23
= ts
->r23
;
474 sv
->save_r24
= ts
->r24
;
475 sv
->save_r25
= ts
->r25
;
476 sv
->save_r26
= ts
->r26
;
477 sv
->save_r27
= ts
->r27
;
478 sv
->save_r28
= ts
->r28
;
479 sv
->save_r29
= ts
->r29
;
480 sv
->save_r30
= ts
->r30
;
481 sv
->save_r31
= ts
->r31
;
483 sv
->save_cr
= ts
->cr
;
484 sv
->save_xer
= ts
->xer
;
485 sv
->save_lr
= ts
->lr
;
486 sv
->save_ctr
= ts
->ctr
;
487 sv
->save_srr0
= ts
->srr0
;
488 sv
->save_mq
= ts
->mq
;
489 sv
->save_vrsave
= ts
->vrsave
; /* VRSAVE register (Altivec only) */
491 sv
->save_srr1
= MSR_PREPARE_FOR_IMPORT(sv
->save_srr1
, ts
->srr1
); /* Set the bits we can change */
493 if(!kernel_act
) sv
->save_srr1
|= MSR_EXPORT_MASK_SET
; /* If not a kernel guy, force the magic bits on */
495 sv
->save_srr1
&= ~(MASK(MSR_FP
) | MASK(MSR_FP
)); /* Make sure we don't enable the floating point unit */
497 if(isnew
) { /* Is it a new one? */
498 sv
->save_dar
= 0; /* Yes, these need initialization also */
500 sv
->save_exception
= 0;
505 else { /* This must be exception state */
506 if(isnew
) /* If new, we need to initialize the normal registers */
507 for(i
=0; i
< 32; i
+=2) { /* Fill up with defaults */
508 ((unsigned int *)&sv
->save_r0
)[i
] = ((unsigned int *)&FloatInit
)[0];
509 ((unsigned int *)&sv
->save_r0
)[i
+1] = ((unsigned int *)&FloatInit
)[1];
513 sv
->save_lr
= ((unsigned int *)&FloatInit
)[0];
514 sv
->save_ctr
= ((unsigned int *)&FloatInit
)[1];
515 sv
->save_srr0
= ((unsigned int *)&FloatInit
)[0];
516 sv
->save_srr1
= MSR_EXPORT_MASK_SET
;
518 sv
->save_vrsave
= 0; /* VRSAVE register (Altivec only) */
521 es
= (struct ppc_exception_state
*) tstate
;
523 sv
->save_dar
= es
->dar
;
524 sv
->save_dsisr
= es
->dsisr
;
525 sv
->save_exception
= es
->exception
;
529 case PPC_FLOAT_STATE
:
531 spl
= splhigh(); /* Don't bother me while I'm zapping the owner stuff */
533 if (per_proc_info
[cpu_number()].FPU_thread
== (unsigned int)thr_act
) /* If we own the FPU, and */
534 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 */
536 splx(spl
); /* Restore the interrupt level */
538 sv
= (savearea
*)thr_act
->mact
.FPU_pcb
; /* Get the top savearea on the stack */
539 osv
= 0; /* Set no user savearea yet */
541 while(sv
) { /* Find the user context */
542 if(!(sv
->save_level_fp
)) { /* Are we looking at the user context? */
543 break; /* Outta here */
545 osv
= sv
; /* Save the last one */
546 sv
= sv
->save_prev_float
; /* Get the previous context */
549 if(!sv
) { /* We didn't find a user context so allocate and initialize one */
551 sv
= (savearea
*)thr_act
->mact
.pcb
; /* Point to the top savearea on the normal stack */
553 while(sv
) { /* Have we hit the end? */
554 if(!(sv
->save_flags
& SAVfpuvalid
)) break; /* Is floating point in use here? */
555 sv
= sv
->save_prev
; /* Back chain */
558 if(!sv
) { /* If there wasn't one on the normal chain, check vector */
559 sv
= (savearea
*)thr_act
->mact
.VMX_pcb
; /* Point to the top savearea on the vector stack */
560 while(sv
) { /* Have we hit the end? */
561 if(!(sv
->save_flags
& SAVfpuvalid
)) break; /* Is floating point in use here? */
562 sv
= sv
->save_prev_vector
; /* Back chain */
566 if(!sv
) { /* Do we have one yet? */
567 sv
= save_alloc(); /* If we still don't have one, get a new one */
568 sv
->save_act
= thr_act
; /* Point to the activation */
570 spc
=(unsigned int)thr_act
->map
->pmap
->space
; /* Get the space we're in */
572 srs
=(unsigned int *)&sv
->save_sr0
; /* Point to the SRs */
573 for(i
=0; i
< 16; i
++) { /* Fill in the SRs for the new context */
574 srs
[i
] = SEG_REG_PROT
| (i
<<20) | spc
; /* Set the SR */
577 sv
->save_sr_copyin
= SEG_REG_PROT
| (SR_COPYIN_NUM
<<20) | spc
; /* Make sure the copyin is set */
580 if(osv
) { /* Did we already have one? */
581 osv
->save_prev_float
= sv
; /* Chain us on the end */
583 else { /* We are the first */
584 thr_act
->mact
.FPU_pcb
= (pcb_t
)sv
; /* Put it there */
586 sv
->save_prev_float
= 0; /* Properly terminate the chain */
587 sv
->save_level_fp
= 0; /* Make sure we are for the user level */
588 sv
->save_flags
|= SAVfpuvalid
; /* Say that it is in use by floating point */
591 fs
= (struct ppc_float_state
*) tstate
; /* Point to source */
594 bcopy((char *)fs
, (char *)&sv
->save_fp0
, clgn
*4); /* 32 registers plus status and pad */
596 usv
= find_user_regs(thr_act
); /* Find the user registers */
597 if(!usv
) usv
= get_user_regs(thr_act
); /* Didn't find any, allocate and initialize one */
599 usv
->save_xfpscrpad
= sv
->save_fpscr_pad
; /* Copy the pad value to normal */
600 usv
->save_xfpscr
= sv
->save_fpscr
; /* Copy the fpscr value to normal */
606 case PPC_VECTOR_STATE
:
608 spl
= splhigh(); /* Don't bother me while I'm zapping the owner stuff */
610 if (per_proc_info
[cpu_number()].VMX_thread
== (unsigned int)thr_act
) /* If we own the vector, and */
611 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 */
613 splx(spl
); /* Restore the interrupt level */
615 sv
= (savearea
*)thr_act
->mact
.VMX_pcb
; /* Get the top savearea on the stack */
616 osv
= 0; /* Set no user savearea yet */
618 while(sv
) { /* Find the user context */
619 if(!(sv
->save_level_vec
)) { /* Are we looking at the user context? */
620 break; /* Outta here */
622 osv
= sv
; /* Save the last one */
623 sv
= sv
->save_prev_vector
; /* Get the previous context */
626 if(!sv
) { /* We didn't find a user context so allocate and initialize one */
628 sv
= (savearea
*)thr_act
->mact
.pcb
; /* Point to the top savearea on the normal stack */
630 while(sv
) { /* Have we hit the end? */
631 if(!(sv
->save_flags
& SAVvmxvalid
)) break; /* Is vector in use here? */
632 sv
= sv
->save_prev
; /* Back chain */
635 if(!sv
) { /* If there wasn't one on the normal chain, check vector */
636 sv
= (savearea
*)thr_act
->mact
.FPU_pcb
; /* Point to the top savearea on the FPU stack */
637 while(sv
) { /* Have we hit the end? */
638 if(!(sv
->save_flags
& SAVvmxvalid
)) break; /* Is vector in use here? */
639 sv
= sv
->save_prev_float
; /* Get the previous context */
643 if(!sv
) { /* Do we have one yet? */
644 sv
= save_alloc(); /* If we still don't have one, get a new one */
645 sv
->save_act
= thr_act
; /* Point to the activation */
647 spc
=(unsigned int)thr_act
->map
->pmap
->space
; /* Get the space we're in */
649 srs
=(unsigned int *)&sv
->save_sr0
; /* Point to the SRs */
650 for(i
=0; i
< 16; i
++) { /* Fill in the SRs for the new context */
651 srs
[i
] = SEG_REG_PROT
| (i
<<20) | spc
; /* Set the SR */
654 sv
->save_sr_copyin
= SEG_REG_PROT
| (SR_COPYIN_NUM
<<20) | spc
; /* Make sure the copyin is set */
657 if(osv
) { /* Did we already have one? */
658 osv
->save_prev_vector
= sv
; /* Chain us on the end */
660 else { /* We are the first */
661 thr_act
->mact
.VMX_pcb
= (pcb_t
)sv
; /* Put it there */
663 sv
->save_prev_vector
= 0; /* Properly terminate the chain */
664 sv
->save_level_vec
= 0; /* Make sure we are for the user level */
665 sv
->save_flags
|= SAVvmxvalid
; /* Say that it is in use by vector */
669 vs
= (struct ppc_vector_state
*) tstate
; /* Point to source */
671 bcopy((char *)vs
, (char *)&sv
->save_vr0
, clgn
*4); /* 32 registers plus status and validity and pad */
677 return KERN_INVALID_ARGUMENT
;
682 * Duplicates the context of one thread into a new one.
683 * The new thread is assumed to be new and have no user state contexts.
684 * We also assume that the old thread can't be running anywhere.
686 * We're only going to be duplicating user context here. That means that we will have to
687 * eliminate any floating point or vector kernel contexts and carry across the user state ones.
688 * We will optimize and cram all states into one savearea. Actually that will be the easiest thing
692 void act_thread_dup(thread_act_t old
, thread_act_t
new) {
694 savearea
*sv
, *osv
, *fsv
;
695 unsigned int spc
, i
, *srs
;
697 fpu_save(); /* Make certain floating point state is all saved */
698 vec_save(); /* Make certain the vector state is all saved */
700 osv
= (savearea
*)new->mact
.pcb
; /* Get the top savearea on the stack */
701 sv
= 0; /* Set no new user savearea yet */
703 while(osv
) { /* Find the user context */
704 if(osv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
705 sv
=osv
; /* Say which to use */
706 break; /* Outta here */
708 osv
=osv
->save_prev
; /* Get the previous context */
711 if(!sv
) { /* We didn't find a user context so allocate and initialize one */
712 osv
= (savearea
*)new->mact
.pcb
; /* Point to the top savearea on the stack */
713 sv
= save_alloc(); /* Get one */
714 sv
->save_flags
|= SAVattach
; /* Say that it is in use */
715 sv
->save_act
= new; /* Point to the activation */
717 spc
=(unsigned int)new->map
->pmap
->space
; /* Get the space we're in */
719 srs
=(unsigned int *)&sv
->save_sr0
; /* Point to the SRs */
720 for(i
=0; i
< 16; i
++) { /* Fill in the SRs for the new context */
721 srs
[i
] = SEG_REG_PROT
| (i
<<20) | spc
; /* Set the SR */
724 sv
->save_sr_copyin
= SEG_REG_PROT
| (SR_COPYIN_NUM
<<20) | spc
; /* Make sure the copyin is set */
726 if(osv
) { /* Did we already have one? */
727 sv
->save_prev
= osv
->save_prev
; /* Move the back chain of the top savearea */
728 osv
->save_prev
= sv
; /* Chain us just after it */
730 else { /* We are the first */
731 new->mact
.pcb
= (pcb_t
)sv
; /* Make it the active one */
736 osv
= (savearea
*)(old
->mact
.pcb
); /* Start with the normal savearea */
737 while(osv
) { /* Find the user context */
738 if(osv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
739 break; /* Outta here */
741 osv
= osv
->save_prev
; /* Back chain */
744 bcopy((char *)&osv
->save_srr0
, (char *)&sv
->save_srr0
, sizeof(struct ppc_thread_state
)); /* Copy in normal state stuff */
746 sv
->save_xfpscrpad
= osv
->save_xfpscrpad
; /* Copy the pad value to old */
747 sv
->save_xfpscr
= osv
->save_xfpscr
; /* Copy the fpscr value to old */
749 new->mact
.FPU_pcb
= (pcb_t
)0 ; /* Initialize floating point savearea */
750 new->mact
.FPU_lvl
= (pcb_t
)0 ; /* Initialize floating point level */
751 new->mact
.FPU_cpu
= 0 ; /* Initialize last used cpu (FP not live, so this doesn't really matter) */
752 new->mact
.VMX_pcb
= (pcb_t
)0 ; /* Initialize vector savearea */
753 new->mact
.VMX_lvl
= (pcb_t
)0 ; /* Initialize vector level */
754 new->mact
.VMX_cpu
= 0 ; /* Initialize last used cpu (vector not live, so this doesn't reall matter) */
756 sv
->save_prev_float
= (savearea
*)0; /* Clear the back chain */
757 sv
->save_prev_vector
= (savearea
*)0; /* Clear the back chain */
759 sv
->save_srr1
&= ~(MASK(MSR_FP
) | MASK(MSR_VEC
)); /* Make certain that floating point and vector are turned off */
761 fsv
= (savearea
*)old
->mact
.FPU_pcb
; /* Get the start of the floating point chain */
762 while(fsv
) { /* Look until the end or we find it */
763 if(!(fsv
->save_level_fp
)) { /* Is the the user state stuff? (the level is 0 if so) */
764 sv
->save_flags
|= SAVfpuvalid
; /* Show we have it */
765 bcopy((char *)&osv
->save_fp0
, (char *)&sv
->save_fp0
, sizeof(struct ppc_float_state
)); /* Copy in floating point state stuff */
766 new->mact
.FPU_pcb
= (pcb_t
)sv
; /* Make it the active one */
767 break; /* Done, everything else is all set up... */
769 fsv
= fsv
->save_prev_float
; /* Try the previous one */
772 fsv
= (savearea
*)old
->mact
.VMX_pcb
; /* Get the start of the vector chain */
773 while(fsv
) { /* Look until the end or we find it */
774 if(!(fsv
->save_level_vec
)) { /* Is the the user state stuff? (the level is 0 if so) */
775 sv
->save_flags
|= SAVvmxvalid
; /* Show we have it */
776 bcopy((char *)&osv
->save_vr0
, (char *)&sv
->save_vr0
, sizeof(struct ppc_vector_state
)); /* Copy in Altivec state stuff */
777 new->mact
.VMX_pcb
= (pcb_t
)sv
; /* Make it the active one */
778 break; /* Done, everything else is all set up... */
780 fsv
= fsv
->save_prev_vector
; /* Try the previous one */
783 return; /* Bye bye... */
787 * Initializes a fresh set of user state values. If there is no user state context,
788 * one is created. Floats and VMX are not created. We set initial values for everything.
791 struct ppc_saved_state
* get_user_regs(thread_act_t act
) {
794 unsigned int spc
, i
, *srs
;
796 sv
= (savearea
*)act
->mact
.pcb
; /* Get the top savearea on the stack */
797 osv
= 0; /* Set no user savearea yet */
799 while(sv
) { /* Find the user context */
800 if(sv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
801 break; /* Outta here */
803 osv
= sv
; /* Save the last one */
804 sv
= sv
->save_prev
; /* Get the previous context */
807 if(!sv
) { /* We didn't find a user context so allocate and initialize one */
808 sv
= save_alloc(); /* Get one */
809 sv
->save_flags
|= SAVattach
; /* Say that it is in use */
810 sv
->save_act
= act
; /* Point to the activation */
812 if(osv
) { /* Did we already have one? */
813 osv
->save_prev
= sv
; /* Chain us on the end */
815 else { /* We are the first */
816 act
->mact
.pcb
= (pcb_t
)sv
; /* Put it there */
818 sv
->save_prev
= 0; /* Properly terminate the chain */
821 for(i
=0; i
< 32; i
+=2) { /* Fill up with defaults */
822 ((unsigned int *)&sv
->save_r0
)[i
] = ((unsigned int *)&FloatInit
)[0];
823 ((unsigned int *)&sv
->save_r0
)[i
+1] = ((unsigned int *)&FloatInit
)[1];
827 sv
->save_lr
= ((unsigned int *)&FloatInit
)[0];
828 sv
->save_ctr
= ((unsigned int *)&FloatInit
)[1];
829 sv
->save_srr0
= ((unsigned int *)&FloatInit
)[0];
830 sv
->save_srr1
= MSR_EXPORT_MASK_SET
;
832 sv
->save_vrsave
= 0; /* VRSAVE register (Altivec only) */
833 sv
->save_xfpscrpad
= 0; /* Start with a clear fpscr */
834 sv
->save_xfpscr
= 0; /* Start with a clear fpscr */
836 spc
=(unsigned int)act
->map
->pmap
->space
; /* Get the space we're in */
838 srs
=(unsigned int *)&sv
->save_sr0
; /* Point to the SRs */
839 for(i
=0; i
< 16; i
++) { /* Fill in the SRs for the new context */
840 srs
[i
] = SEG_REG_PROT
| (i
<<20) | spc
; /* Set the SR */
843 sv
->save_sr_copyin
= SEG_REG_PROT
| (SR_COPYIN_NUM
<<20) | spc
; /* Make sure the copyin is set */
845 return (struct ppc_saved_state
*)sv
; /* Bye bye... */
849 * Find the user state context. If there is no user state context,
850 * we just return a 0.
853 struct ppc_saved_state
* find_user_regs(thread_act_t act
) {
857 sv
= (savearea
*)act
->mact
.pcb
; /* Get the top savearea on the stack */
859 while(sv
) { /* Find the user context */
860 if(sv
->save_srr1
& MASK(MSR_PR
)) { /* Are we looking at the user context? */
861 break; /* Outta here */
863 sv
= sv
->save_prev
; /* Get the previous context */
866 return (struct ppc_saved_state
*)sv
; /* Bye bye... */
870 * Find the user state floating pointcontext. If there is no user state context,
871 * we just return a 0.
874 struct ppc_float_state
* find_user_fpu(thread_act_t act
) {
878 fsv
= (savearea
*)act
->mact
.FPU_pcb
; /* Get the start of the floating point chain */
879 while(fsv
) { /* Look until the end or we find it */
880 if(!(fsv
->save_level_fp
)) break; /* Is the the user state stuff? (the level is 0 if so) */
881 fsv
= fsv
->save_prev_float
; /* Try the previous one */
884 return (struct ppc_float_state
*)&(fsv
->save_fp0
); /* Bye bye... */
890 * Return the user stack pointer from the machine
891 * dependent thread state info.
897 thread_state_t tstate
,
899 vm_offset_t
*user_stack
902 struct ppc_thread_state
*state
;
907 if (*user_stack
== 0)
908 *user_stack
= USRSTACK
;
911 case PPC_THREAD_STATE
:
912 if (count
< PPC_THREAD_STATE_COUNT
)
913 return (KERN_INVALID_ARGUMENT
);
915 state
= (struct ppc_thread_state
*) tstate
;
918 * If a valid user stack is specified, use it.
920 *user_stack
= state
->r1
? state
->r1
: USRSTACK
;
923 return (KERN_INVALID_ARGUMENT
);
926 return (KERN_SUCCESS
);
933 thread_state_t tstate
,
935 vm_offset_t
*entry_point
938 struct ppc_thread_state
*state
;
943 if (*entry_point
== 0)
944 *entry_point
= VM_MIN_ADDRESS
;
948 case PPC_THREAD_STATE
:
949 if (count
< PPC_THREAD_STATE_COUNT
)
950 return (KERN_INVALID_ARGUMENT
);
952 state
= (struct ppc_thread_state
*) tstate
;
955 * If a valid entry point is specified, use it.
957 *entry_point
= state
->srr0
? state
->srr0
: VM_MIN_ADDRESS
;
960 return (KERN_INVALID_ARGUMENT
);
963 return (KERN_SUCCESS
);
966 unsigned int get_msr_exportmask(void)
968 return (MSR_EXPORT_MASK_SET
);
971 unsigned int get_msr_nbits(void)
973 return (MASK(MSR_POW
)|MASK(MSR_ILE
)|MASK(MSR_IP
)|MASK(MSR_LE
));
975 unsigned int get_msr_rbits(void)
977 return (MASK(MSR_PR
)|MASK(MSR_ME
)|MASK(MSR_IR
)|MASK(MSR_DR
)|MASK(MSR_EE
));
980 void thread_set_child(thread_act_t child
, int pid
)
982 struct ppc_saved_state
*child_state
;
984 child_state
= find_user_regs(child
);
986 child_state
->r3
= pid
;