#include <kern/thread.h>
#include <kern/thread_act.h>
#include <kern/misc_protos.h>
#include <mach/ppc/thread_status.h>
#include <ppc/proc_reg.h>
#include <ppc/exception.h>
#include <ppc/misc_protos.h>
#include <ppc/savearea.h>
#include <ppc/thread_act.h>
#include <ppc/Firmware.h>
#include <vm/vm_map.h>
extern unsigned int killprint;
extern double FloatInit;
extern unsigned long QNaNbarbarian[4];
extern void thread_bootstrap_return(void);
extern struct Saveanchor saveanchor;
extern int real_ncpus;
#define USRSTACK 0xc0000000
kern_return_t
thread_userstack(
thread_t,
int,
thread_state_t,
unsigned int,
vm_offset_t *,
int *
);
kern_return_t
thread_entrypoint(
thread_t,
int,
thread_state_t,
unsigned int,
vm_offset_t *
);
unsigned int get_msr_exportmask(void);
unsigned int get_msr_nbits(void);
unsigned int get_msr_rbits(void);
void ppc_checkthreadstate(void *, int);
void thread_set_child(thread_act_t child, int pid);
void thread_set_parent(thread_act_t parent, int pid);
unsigned int state_count[] = {
0,
PPC_THREAD_STATE_COUNT,
PPC_FLOAT_STATE_COUNT,
PPC_EXCEPTION_STATE_COUNT,
PPC_VECTOR_STATE_COUNT,
PPC_THREAD_STATE64_COUNT,
PPC_EXCEPTION_STATE64_COUNT,
};
kern_return_t
act_machine_get_state(
thread_act_t thr_act,
thread_flavor_t flavor,
thread_state_t tstate,
mach_msg_type_number_t *count)
{
register struct savearea *sv;
register savearea_fpu *fsv;
register savearea_vec *vsv;
savearea *genuser;
int i, j;
unsigned int vrvalidwrk;
register struct ppc_thread_state *ts;
register struct ppc_thread_state64 *xts;
register struct ppc_exception_state *es;
register struct ppc_exception_state64 *xes;
register struct ppc_float_state *fs;
register struct ppc_vector_state *vs;
genuser = find_user_regs(thr_act);
switch (flavor) {
case THREAD_STATE_FLAVOR_LIST:
if (*count < 6) {
return (KERN_INVALID_ARGUMENT);
}
tstate[0] = PPC_THREAD_STATE;
tstate[1] = PPC_FLOAT_STATE;
tstate[2] = PPC_EXCEPTION_STATE;
tstate[3] = PPC_VECTOR_STATE;
tstate[4] = PPC_THREAD_STATE64;
tstate[5] = PPC_EXCEPTION_STATE64;
*count = 6;
return KERN_SUCCESS;
case PPC_THREAD_STATE:
if (*count < PPC_THREAD_STATE_COUNT) {
return KERN_INVALID_ARGUMENT;
}
ts = (struct ppc_thread_state *) tstate;
sv = genuser;
if(sv) {
ts->r0 = (unsigned int)sv->save_r0;
ts->r1 = (unsigned int)sv->save_r1;
ts->r2 = (unsigned int)sv->save_r2;
ts->r3 = (unsigned int)sv->save_r3;
ts->r4 = (unsigned int)sv->save_r4;
ts->r5 = (unsigned int)sv->save_r5;
ts->r6 = (unsigned int)sv->save_r6;
ts->r7 = (unsigned int)sv->save_r7;
ts->r8 = (unsigned int)sv->save_r8;
ts->r9 = (unsigned int)sv->save_r9;
ts->r10 = (unsigned int)sv->save_r10;
ts->r11 = (unsigned int)sv->save_r11;
ts->r12 = (unsigned int)sv->save_r12;
ts->r13 = (unsigned int)sv->save_r13;
ts->r14 = (unsigned int)sv->save_r14;
ts->r15 = (unsigned int)sv->save_r15;
ts->r16 = (unsigned int)sv->save_r16;
ts->r17 = (unsigned int)sv->save_r17;
ts->r18 = (unsigned int)sv->save_r18;
ts->r19 = (unsigned int)sv->save_r19;
ts->r20 = (unsigned int)sv->save_r20;
ts->r21 = (unsigned int)sv->save_r21;
ts->r22 = (unsigned int)sv->save_r22;
ts->r23 = (unsigned int)sv->save_r23;
ts->r24 = (unsigned int)sv->save_r24;
ts->r25 = (unsigned int)sv->save_r25;
ts->r26 = (unsigned int)sv->save_r26;
ts->r27 = (unsigned int)sv->save_r27;
ts->r28 = (unsigned int)sv->save_r28;
ts->r29 = (unsigned int)sv->save_r29;
ts->r30 = (unsigned int)sv->save_r30;
ts->r31 = (unsigned int)sv->save_r31;
ts->cr = (unsigned int)sv->save_cr;
ts->xer = (unsigned int)sv->save_xer;
ts->lr = (unsigned int)sv->save_lr;
ts->ctr = (unsigned int)sv->save_ctr;
ts->srr0 = (unsigned int)sv->save_srr0;
ts->srr1 = (unsigned int)sv->save_srr1;
ts->mq = 0;
ts->vrsave = (unsigned int)sv->save_vrsave;
}
else {
for(i=0; i < 32; i+=2) {
((unsigned int *)&ts->r0)[i] = ((unsigned int *)&FloatInit)[0];
((unsigned int *)&ts->r0)[i+1] = ((unsigned int *)&FloatInit)[1];
}
ts->cr = 0;
ts->xer = 0;
ts->lr = ((unsigned int *)&FloatInit)[0];
ts->ctr = ((unsigned int *)&FloatInit)[1];
ts->srr0 = ((unsigned int *)&FloatInit)[0];
ts->srr1 = MSR_EXPORT_MASK_SET;
ts->mq = 0;
ts->vrsave = 0;
}
*count = PPC_THREAD_STATE_COUNT;
return KERN_SUCCESS;
case PPC_THREAD_STATE64:
if (*count < PPC_THREAD_STATE64_COUNT) {
return KERN_INVALID_ARGUMENT;
}
xts = (struct ppc_thread_state64 *) tstate;
sv = genuser;
if(sv) {
xts->r0 = sv->save_r0;
xts->r1 = sv->save_r1;
xts->r2 = sv->save_r2;
xts->r3 = sv->save_r3;
xts->r4 = sv->save_r4;
xts->r5 = sv->save_r5;
xts->r6 = sv->save_r6;
xts->r7 = sv->save_r7;
xts->r8 = sv->save_r8;
xts->r9 = sv->save_r9;
xts->r10 = sv->save_r10;
xts->r11 = sv->save_r11;
xts->r12 = sv->save_r12;
xts->r13 = sv->save_r13;
xts->r14 = sv->save_r14;
xts->r15 = sv->save_r15;
xts->r16 = sv->save_r16;
xts->r17 = sv->save_r17;
xts->r18 = sv->save_r18;
xts->r19 = sv->save_r19;
xts->r20 = sv->save_r20;
xts->r21 = sv->save_r21;
xts->r22 = sv->save_r22;
xts->r23 = sv->save_r23;
xts->r24 = sv->save_r24;
xts->r25 = sv->save_r25;
xts->r26 = sv->save_r26;
xts->r27 = sv->save_r27;
xts->r28 = sv->save_r28;
xts->r29 = sv->save_r29;
xts->r30 = sv->save_r30;
xts->r31 = sv->save_r31;
xts->cr = sv->save_cr;
xts->xer = sv->save_xer;
xts->lr = sv->save_lr;
xts->ctr = sv->save_ctr;
xts->srr0 = sv->save_srr0;
xts->srr1 = sv->save_srr1;
xts->vrsave = sv->save_vrsave;
}
else {
for(i=0; i < 32; i++) {
((unsigned long long *)&xts->r0)[i] = ((unsigned long long *)&FloatInit)[0];
}
xts->cr = 0;
xts->xer = 0;
xts->lr = ((unsigned long long *)&FloatInit)[0];
xts->ctr = ((unsigned long long *)&FloatInit)[0];
xts->srr0 = ((unsigned long long *)&FloatInit)[0];
xts->srr1 = MSR_EXPORT_MASK_SET;
xts->vrsave = 0;
}
*count = PPC_THREAD_STATE64_COUNT;
return KERN_SUCCESS;
case PPC_EXCEPTION_STATE:
if (*count < PPC_EXCEPTION_STATE_COUNT) {
return KERN_INVALID_ARGUMENT;
}
es = (struct ppc_exception_state *) tstate;
sv = genuser;
if(sv) {
es->dar = (unsigned int)sv->save_dar;
es->dsisr = sv->save_dsisr;
es->exception = sv->save_exception;
}
else {
es->dar = 0;
es->dsisr = 0;
es->exception = ((unsigned int *)&FloatInit)[0];
}
*count = PPC_EXCEPTION_STATE_COUNT;
return KERN_SUCCESS;
case PPC_EXCEPTION_STATE64:
if (*count < PPC_EXCEPTION_STATE64_COUNT) {
return KERN_INVALID_ARGUMENT;
}
xes = (struct ppc_exception_state64 *) tstate;
sv = genuser;
if(sv) {
xes->dar = sv->save_dar;
xes->dsisr = sv->save_dsisr;
xes->exception = sv->save_exception;
}
else {
xes->dar = 0;
xes->dsisr = 0;
xes->exception = ((unsigned int *)&FloatInit)[0];
}
*count = PPC_EXCEPTION_STATE64_COUNT;
return KERN_SUCCESS;
case PPC_FLOAT_STATE:
if (*count < PPC_FLOAT_STATE_COUNT) {
return KERN_INVALID_ARGUMENT;
}
fpu_save(thr_act->mact.curctx);
fs = (struct ppc_float_state *) tstate;
fsv = find_user_fpu(thr_act);
if(fsv) {
bcopy((char *)&fsv->save_fp0, (char *)fs, 32*8);
fs->fpscr_pad = 0;
if(genuser) fs->fpscr = genuser->save_fpscr;
else fs->fpscr = 0;
}
else {
for(i=0; i < 32; i++) {
fs->fpregs[i] = FloatInit;
}
fs->fpscr_pad = 0;
fs->fpscr = 0;
}
*count = PPC_FLOAT_STATE_COUNT;
return KERN_SUCCESS;
case PPC_VECTOR_STATE:
if (*count < PPC_VECTOR_STATE_COUNT) {
return KERN_INVALID_ARGUMENT;
}
vec_save(thr_act->mact.curctx);
vs = (struct ppc_vector_state *) tstate;
vsv = find_user_vec(thr_act);
if(vsv) {
vrvalidwrk = vsv->save_vrvalid;
vs->save_vrvalid = vsv->save_vrvalid;
if(genuser) for(j=0; j < 4; j++) vs->save_vscr[j] = genuser->save_vscr[j];
else {
vs->save_vscr[0] = 0;
vs->save_vscr[1] = 0;
vs->save_vscr[2] = 0;
vs->save_vscr[3] = 0x00010000;
}
for(i=0; i < 32; i++) {
for(j=0; j < 4; j++) {
if(vrvalidwrk & 0x80000000) (vs->save_vr)[i][j] =
((unsigned int *)&(vsv->save_vr0))[(i * 4) + j];
else vs->save_vr[i][j] = QNaNbarbarian[j];
}
vrvalidwrk = vrvalidwrk << 1;
}
}
else {
for(i=0; i < 32; i++) {
for(j=0; j < 4; j++) vs->save_vr[i][j] = QNaNbarbarian[j];
}
if(genuser) for(j=0; j < 4; j++) vs->save_vscr[j] = genuser->save_vscr[j];
else {
vs->save_vscr[0] = 0;
vs->save_vscr[1] = 0;
vs->save_vscr[2] = 0;
vs->save_vscr[3] = 0x00010000;
}
vs->save_vrvalid = 0;
}
for (i=0; i < 4; i++) vs->save_pad5[i] = 0;
for (i=0; i < 7; i++) vs->save_pad6[i] = 0;
*count = PPC_VECTOR_STATE_COUNT;
return KERN_SUCCESS;
default:
return KERN_INVALID_ARGUMENT;
}
}
kern_return_t
act_machine_set_state(
thread_act_t thr_act,
thread_flavor_t flavor,
thread_state_t tstate,
mach_msg_type_number_t count)
{
savearea *sv, *genuser;
savearea_fpu *fsv, *fsvn, *fsvo;
savearea_vec *vsv, *vsvn, *vsvo;
unsigned int i;
int clgn;
register struct ppc_thread_state *ts;
register struct ppc_thread_state64 *xts;
register struct ppc_exception_state *es;
register struct ppc_exception_state *xes;
register struct ppc_float_state *fs;
register struct ppc_vector_state *vs;
int kernel_act = thr_act->kernel_loading || thr_act->kernel_loaded;
clgn = count;
switch (flavor) {
case PPC_THREAD_STATE:
if (clgn < PPC_THREAD_STATE_COUNT) {
return KERN_INVALID_ARGUMENT;
}
break;
case PPC_THREAD_STATE64:
if (clgn < PPC_THREAD_STATE64_COUNT) {
return KERN_INVALID_ARGUMENT;
}
break;
case PPC_EXCEPTION_STATE:
if (clgn < PPC_EXCEPTION_STATE_COUNT) {
return KERN_INVALID_ARGUMENT;
}
case PPC_EXCEPTION_STATE64:
if (clgn < PPC_EXCEPTION_STATE64_COUNT) {
return KERN_INVALID_ARGUMENT;
}
break;
case PPC_FLOAT_STATE:
if (clgn < PPC_FLOAT_STATE_COUNT) {
return KERN_INVALID_ARGUMENT;
}
break;
case PPC_VECTOR_STATE:
if (clgn < PPC_VECTOR_STATE_COUNT) {
return KERN_INVALID_ARGUMENT;
}
break;
default:
return KERN_INVALID_ARGUMENT;
}
genuser = get_user_regs(thr_act);
switch (flavor) {
case PPC_THREAD_STATE:
ts = (struct ppc_thread_state *)tstate;
genuser->save_r0 = (uint64_t)ts->r0;
genuser->save_r1 = (uint64_t)ts->r1;
genuser->save_r2 = (uint64_t)ts->r2;
genuser->save_r3 = (uint64_t)ts->r3;
genuser->save_r4 = (uint64_t)ts->r4;
genuser->save_r5 = (uint64_t)ts->r5;
genuser->save_r6 = (uint64_t)ts->r6;
genuser->save_r7 = (uint64_t)ts->r7;
genuser->save_r8 = (uint64_t)ts->r8;
genuser->save_r9 = (uint64_t)ts->r9;
genuser->save_r10 = (uint64_t)ts->r10;
genuser->save_r11 = (uint64_t)ts->r11;
genuser->save_r12 = (uint64_t)ts->r12;
genuser->save_r13 = (uint64_t)ts->r13;
genuser->save_r14 = (uint64_t)ts->r14;
genuser->save_r15 = (uint64_t)ts->r15;
genuser->save_r16 = (uint64_t)ts->r16;
genuser->save_r17 = (uint64_t)ts->r17;
genuser->save_r18 = (uint64_t)ts->r18;
genuser->save_r19 = (uint64_t)ts->r19;
genuser->save_r20 = (uint64_t)ts->r20;
genuser->save_r21 = (uint64_t)ts->r21;
genuser->save_r22 = (uint64_t)ts->r22;
genuser->save_r23 = (uint64_t)ts->r23;
genuser->save_r24 = (uint64_t)ts->r24;
genuser->save_r25 = (uint64_t)ts->r25;
genuser->save_r26 = (uint64_t)ts->r26;
genuser->save_r27 = (uint64_t)ts->r27;
genuser->save_r28 = (uint64_t)ts->r28;
genuser->save_r29 = (uint64_t)ts->r29;
genuser->save_r30 = (uint64_t)ts->r30;
genuser->save_r31 = (uint64_t)ts->r31;
genuser->save_cr = ts->cr;
genuser->save_xer = (uint64_t)ts->xer;
genuser->save_lr = (uint64_t)ts->lr;
genuser->save_ctr = (uint64_t)ts->ctr;
genuser->save_srr0 = (uint64_t)ts->srr0;
genuser->save_vrsave = ts->vrsave;
genuser->save_srr1 = MSR_PREPARE_FOR_IMPORT(genuser->save_srr1, ts->srr1);
if(!kernel_act) genuser->save_srr1 |= MSR_EXPORT_MASK_SET;
genuser->save_srr1 &= ~(MASK(MSR_FP) | MASK(MSR_VEC));
return KERN_SUCCESS;
case PPC_THREAD_STATE64:
xts = (struct ppc_thread_state64 *)tstate;
genuser->save_r0 = xts->r0;
genuser->save_r1 = xts->r1;
genuser->save_r2 = xts->r2;
genuser->save_r3 = xts->r3;
genuser->save_r4 = xts->r4;
genuser->save_r5 = xts->r5;
genuser->save_r6 = xts->r6;
genuser->save_r7 = xts->r7;
genuser->save_r8 = xts->r8;
genuser->save_r9 = xts->r9;
genuser->save_r10 = xts->r10;
genuser->save_r11 = xts->r11;
genuser->save_r12 = xts->r12;
genuser->save_r13 = xts->r13;
genuser->save_r14 = xts->r14;
genuser->save_r15 = xts->r15;
genuser->save_r16 = xts->r16;
genuser->save_r17 = xts->r17;
genuser->save_r18 = xts->r18;
genuser->save_r19 = xts->r19;
genuser->save_r20 = xts->r20;
genuser->save_r21 = xts->r21;
genuser->save_r22 = xts->r22;
genuser->save_r23 = xts->r23;
genuser->save_r24 = xts->r24;
genuser->save_r25 = xts->r25;
genuser->save_r26 = xts->r26;
genuser->save_r27 = xts->r27;
genuser->save_r28 = xts->r28;
genuser->save_r29 = xts->r29;
genuser->save_r30 = xts->r30;
genuser->save_r31 = xts->r31;
genuser->save_cr = xts->cr;
genuser->save_xer = xts->xer;
genuser->save_lr = xts->lr;
genuser->save_ctr = xts->ctr;
genuser->save_srr0 = xts->srr0;
genuser->save_vrsave = xts->vrsave;
genuser->save_srr1 = MSR_PREPARE_FOR_IMPORT(genuser->save_srr1, xts->srr1);
if(!kernel_act) genuser->save_srr1 |= MSR_EXPORT_MASK_SET;
genuser->save_srr1 &= ~(MASK(MSR_FP) | MASK(MSR_VEC));
return KERN_SUCCESS;
case PPC_EXCEPTION_STATE:
es = (struct ppc_exception_state *) tstate;
genuser->save_dar = (uint64_t)es->dar;
genuser->save_dsisr = es->dsisr;
genuser->save_exception = es->exception;
return KERN_SUCCESS;
case PPC_EXCEPTION_STATE64:
xes = (struct ppc_exception_state *) tstate;
genuser->save_dar = xes->dar;
genuser->save_dsisr = xes->dsisr;
genuser->save_exception = xes->exception;
return KERN_SUCCESS;
case PPC_FLOAT_STATE:
toss_live_fpu(thr_act->mact.curctx);
fsv = find_user_fpu(thr_act);
if(!fsv) {
fsv = (savearea_fpu *)save_alloc();
fsv->save_hdr.save_flags = (fsv->save_hdr.save_flags & ~SAVtype) | (SAVfloat << SAVtypeshft);
fsv->save_hdr.save_act = thr_act;
fsv->save_hdr.save_prev = 0;
fsv->save_hdr.save_level = 0;
if(!thr_act->mact.curctx->FPUsave) thr_act->mact.curctx->FPUsave = fsv;
else {
fsvn = fsvo = thr_act->mact.curctx->FPUsave;
while (fsvn) {
fsvo = fsvn;
fsvn = (savearea_fpu *)fsvo->save_hdr.save_prev;
}
fsvo->save_hdr.save_prev = (addr64_t)fsv;
}
}
fs = (struct ppc_float_state *) tstate;
bcopy((char *)fs, (char *)&fsv->save_fp0, 32*8);
genuser->save_fpscr = fs->fpscr;
return KERN_SUCCESS;
case PPC_VECTOR_STATE:
toss_live_vec(thr_act->mact.curctx);
vsv = find_user_vec(thr_act);
if(!vsv) {
vsv = (savearea_vec *)save_alloc();
vsv->save_hdr.save_flags = (vsv->save_hdr.save_flags & ~SAVtype) | (SAVvector << SAVtypeshft);
vsv->save_hdr.save_act = thr_act;
vsv->save_hdr.save_prev = 0;
vsv->save_hdr.save_level = 0;
if(!thr_act->mact.curctx->VMXsave) thr_act->mact.curctx->VMXsave = vsv;
else {
vsvn = vsvo = thr_act->mact.curctx->VMXsave;
while (vsvn) {
vsvo = vsvn;
vsvn = (savearea_vec *)vsvo->save_hdr.save_prev;
}
vsvo->save_hdr.save_prev = (addr64_t)vsv;
}
}
vs = (struct ppc_vector_state *) tstate;
bcopy((char *)vs, (char *)&vsv->save_vr0, 32*16);
vsv->save_vrvalid = vs->save_vrvalid;
for(i = 0; i < 4; i++) genuser->save_vscr[i] = vs->save_vscr[i];
return KERN_SUCCESS;
default:
return KERN_INVALID_ARGUMENT;
}
}
void act_thread_dup(thread_act_t old, thread_act_t new) {
savearea *sv, *osv;
savearea_fpu *fsv, *fsvn;
savearea_vec *vsv, *vsvn;
unsigned int spc, i, *srs;
fpu_save(old->mact.curctx);
vec_save(old->mact.curctx);
sv = get_user_regs(new);
osv = find_user_regs(old);
if(!osv) {
panic("act_thread_dup: old activation (%08X) has no general user context\n", old);
}
bcopy((char *)((unsigned int)osv + sizeof(savearea_comm)),
(char *)((unsigned int)sv + sizeof(savearea_comm)),
sizeof(struct savearea) - sizeof(savearea_comm));
sv->save_srr1 &= ~(MASK(MSR_FP) | MASK(MSR_VEC));
fsv = find_user_fpu(old);
new->mact.curctx->FPUsave = 0;
if(fsv) {
fsvn = (savearea_fpu *)save_alloc();
fsvn->save_hdr.save_flags = (fsvn->save_hdr.save_flags & ~SAVtype) | (SAVfloat << SAVtypeshft);
fsvn->save_hdr.save_act = new;
fsvn->save_hdr.save_prev = 0;
fsvn->save_hdr.save_level = 0;
new->mact.curctx->FPUsave = fsvn;
bcopy((char *)((unsigned int)fsv + sizeof(savearea_comm)),
(char *)((unsigned int)fsvn + sizeof(savearea_comm)),
sizeof(struct savearea) - sizeof(savearea_comm));
}
vsv = find_user_vec(old);
new->mact.curctx->VMXsave = 0;
if(vsv) {
vsvn = (savearea_vec *)save_alloc();
vsvn->save_hdr.save_flags = (vsvn->save_hdr.save_flags & ~SAVtype) | (SAVvector << SAVtypeshft);
vsvn->save_hdr.save_act = new;
vsvn->save_hdr.save_prev = 0;
vsvn->save_hdr.save_level = 0;
new->mact.curctx->VMXsave = vsvn;
bcopy((char *)((unsigned int)vsv + sizeof(savearea_comm)),
(char *)((unsigned int)vsvn + sizeof(savearea_comm)),
sizeof(struct savearea) - sizeof(savearea_comm));
}
return;
}
savearea *get_user_regs(thread_act_t act) {
savearea *sv, *osv;
unsigned int spc, i, *srs;
sv = act->mact.pcb;
osv = 0;
while(sv) {
if(sv->save_srr1 & MASK(MSR_PR)) return sv;
osv = sv;
sv = (savearea *)sv->save_hdr.save_prev;
}
sv = save_alloc();
sv->save_hdr.save_flags = (sv->save_hdr.save_flags & ~SAVtype) | (SAVgeneral << SAVtypeshft);
sv->save_hdr.save_act = act;
sv->save_hdr.save_prev = 0;
sv->save_hdr.save_level = 0;
if(osv) {
osv->save_hdr.save_prev = (addr64_t)sv;
}
else {
act->mact.pcb = sv;
}
for(i=0; i < 32; i+=2) {
((unsigned int *)&sv->save_r0)[i] = ((unsigned int *)&FloatInit)[0];
((unsigned int *)&sv->save_r0)[i+1] = ((unsigned int *)&FloatInit)[1];
}
sv->save_cr = 0;
sv->save_xer = 0;
sv->save_lr = (uint64_t)FloatInit;
sv->save_ctr = (uint64_t)FloatInit;
sv->save_srr0 = (uint64_t)FloatInit;
sv->save_srr1 = (uint64_t)MSR_EXPORT_MASK_SET;
sv->save_fpscr = 0;
sv->save_vrsave = 0;
sv->save_vscr[0] = 0x00000000;
sv->save_vscr[1] = 0x00000000;
sv->save_vscr[2] = 0x00000000;
sv->save_vscr[3] = 0x00010000;
return sv;
}
savearea *find_user_regs(thread_act_t act) {
savearea *sv;
sv = act->mact.pcb;
while(sv) {
if(sv->save_srr1 & MASK(MSR_PR)) {
break;
}
sv = (savearea *)sv->save_hdr.save_prev;
}
return sv;
}
savearea_fpu *find_user_fpu(thread_act_t act) {
savearea_fpu *fsv;
fsv = act->mact.curctx->FPUsave;
while(fsv) {
if(!(fsv->save_hdr.save_level)) break;
fsv = (savearea_fpu *)fsv->save_hdr.save_prev;
}
return fsv;
}
savearea_vec *find_user_vec(thread_act_t act) {
savearea_vec *vsv;
vsv = act->mact.curctx->VMXsave;
while(vsv) {
if(!(vsv->save_hdr.save_level)) break;
vsv = (savearea_vec *)vsv->save_hdr.save_prev;
}
return vsv;
}
kern_return_t
thread_userstack(
thread_t thread,
int flavor,
thread_state_t tstate,
unsigned int count,
vm_offset_t *user_stack,
int *customstack
)
{
struct ppc_thread_state *state;
if (*user_stack == 0)
*user_stack = USRSTACK;
if (customstack)
*customstack = 0;
switch (flavor) {
case PPC_THREAD_STATE:
if (count < PPC_THREAD_STATE_COUNT)
return (KERN_INVALID_ARGUMENT);
state = (struct ppc_thread_state *) tstate;
*user_stack = state->r1 ? state->r1: USRSTACK;
if (customstack && state->r1)
*customstack = 1;
break;
default :
return (KERN_INVALID_ARGUMENT);
}
return (KERN_SUCCESS);
}
void thread_setuserstack(struct thread_activation *act, unsigned int user_stack)
{
savearea *sv;
sv = get_user_regs(act);
sv->save_r1 = (uint64_t)user_stack;
return;
}
unsigned int thread_adjuserstack(struct thread_activation *act, int adjust)
{
savearea *sv;
sv = get_user_regs(act);
sv->save_r1 += adjust;
return (unsigned int)sv->save_r1;
}
void thread_setentrypoint(struct thread_activation *act, unsigned int entry)
{
savearea *sv;
sv = get_user_regs(act);
sv->save_srr0 = (uint64_t)entry;
return;
}
kern_return_t
thread_entrypoint(
thread_t thread,
int flavor,
thread_state_t tstate,
unsigned int count,
vm_offset_t *entry_point
)
{
struct ppc_thread_state *state;
if (*entry_point == 0)
*entry_point = VM_MIN_ADDRESS;
switch (flavor) {
case PPC_THREAD_STATE:
if (count < PPC_THREAD_STATE_COUNT)
return (KERN_INVALID_ARGUMENT);
state = (struct ppc_thread_state *) tstate;
*entry_point = state->srr0 ? state->srr0: VM_MIN_ADDRESS;
break;
default:
return (KERN_INVALID_ARGUMENT);
}
return (KERN_SUCCESS);
}
unsigned int get_msr_exportmask(void)
{
return (MSR_EXPORT_MASK_SET);
}
unsigned int get_msr_nbits(void)
{
return (MASK(MSR_POW)|MASK(MSR_ILE)|MASK(MSR_IP)|MASK(MSR_LE));
}
unsigned int get_msr_rbits(void)
{
return (MASK(MSR_PR)|MASK(MSR_ME)|MASK(MSR_IR)|MASK(MSR_DR)|MASK(MSR_EE));
}
void ppc_checkthreadstate(void * tsptr, int flavor)
{
if (flavor == PPC_THREAD_STATE64) {
struct ppc_thread_state64 *ts64 =(struct ppc_thread_state64 *)tsptr;
ts64->srr1 &= ~(MASK(MSR_POW)|MASK(MSR_ILE)|MASK(MSR_IP)|MASK(MSR_LE));
ts64->srr1 |= (MASK(MSR_PR)|MASK(MSR_ME)|MASK(MSR_IR)|MASK(MSR_DR)|MASK(MSR_EE));
} else {
struct ppc_thread_state *ts =(struct ppc_thread_state *)tsptr;
ts->srr1 &= ~(MASK(MSR_POW)|MASK(MSR_ILE)|MASK(MSR_IP)|MASK(MSR_LE));
ts->srr1 |= (MASK(MSR_PR)|MASK(MSR_ME)|MASK(MSR_IR)|MASK(MSR_DR)|MASK(MSR_EE));
}
return;
}
void thread_set_child(thread_act_t child, int pid)
{
struct savearea *child_state;
child_state = get_user_regs(child);
child_state->save_r3 = (uint_t)pid;
child_state->save_r4 = 1ULL;
}
void thread_set_parent(thread_act_t parent, int pid)
{
struct savearea *parent_state;
parent_state = get_user_regs(parent);
parent_state->save_r3 = (uint64_t)pid;
parent_state->save_r4 = 0;
}
void *act_thread_csave(void) {
savearea *sv, *osv;
savearea_fpu *fsv, *ofsv;
savearea_vec *vsv, *ovsv;
unsigned int spc, i, *srs;
thread_act_t act;
act = current_act();
fpu_save(act->mact.curctx);
vec_save(act->mact.curctx);
osv = find_user_regs(act);
if(!osv) {
panic("act_thread_csave: attempting to preserve the context of an activation with none (%08X)\n", act);
}
sv = save_alloc();
sv->save_hdr.save_flags = (sv->save_hdr.save_flags & ~SAVtype) | (SAVgeneral << SAVtypeshft);
sv->save_hdr.save_act = act;
sv->save_hdr.save_prev = 0;
sv->save_hdr.save_level = 0;
bcopy((char *)((unsigned int)osv + sizeof(savearea_comm)),
(char *)((unsigned int)sv + sizeof(savearea_comm)),
sizeof(struct savearea) - sizeof(savearea_comm));
sv->save_srr1 &= ~(MASK(MSR_FP) | MASK(MSR_VEC));
sv->save_hdr.save_misc2 = 0xDEBB1ED0;
sv->save_hdr.save_misc3 = 0xE5DA11A5;
ofsv = find_user_fpu(act);
sv->save_hdr.save_misc0 = 0;
if(ofsv) {
fsv = (savearea_fpu *)save_alloc();
fsv->save_hdr.save_flags = (fsv->save_hdr.save_flags & ~SAVtype) | (SAVfloat << SAVtypeshft);
fsv->save_hdr.save_act = act;
fsv->save_hdr.save_prev = 0;
fsv->save_hdr.save_level = 0;
fsv->save_hdr.save_misc2 = 0xDEBB1ED0;
fsv->save_hdr.save_misc3 = 0xE5DA11A5;
sv->save_hdr.save_misc0 = (uint64_t)fsv;
bcopy((char *)((unsigned int)ofsv + sizeof(savearea_comm)),
(char *)((unsigned int)fsv + sizeof(savearea_comm)),
sizeof(struct savearea) - sizeof(savearea_comm));
}
ovsv = find_user_vec(act);
sv->save_hdr.save_misc1 = 0;
if(ovsv) {
vsv = (savearea_vec *)save_alloc();
vsv->save_hdr.save_flags = (vsv->save_hdr.save_flags & ~SAVtype) | (SAVvector << SAVtypeshft);
vsv->save_hdr.save_act = act;
vsv->save_hdr.save_prev = 0;
vsv->save_hdr.save_level = 0;
vsv->save_hdr.save_misc2 = 0xDEBB1ED0;
vsv->save_hdr.save_misc3 = 0xE5DA11A5;
sv->save_hdr.save_misc1 = (uint64_t)vsv;
bcopy((char *)((unsigned int)ovsv + sizeof(savearea_comm)),
(char *)((unsigned int)vsv + sizeof(savearea_comm)),
sizeof(struct savearea) - sizeof(savearea_comm));
}
return (void *)sv;
}
void act_thread_catt(void *ctx) {
savearea *sv, *osv, *psv;
savearea_fpu *fsv, *ofsv, *pfsv;
savearea_vec *vsv, *ovsv, *pvsv;
unsigned int spc, i, *srs;
thread_act_t act;
sv = (savearea *)ctx;
fsv = (savearea_fpu *)sv->save_hdr.save_misc0;
vsv = (savearea_vec *)sv->save_hdr.save_misc1;
if((sv->save_hdr.save_misc2 != 0xDEBB1ED0) || (sv->save_hdr.save_misc3 != 0xE5DA11A5)) {
panic("act_thread_catt: attempt to attach invalid general context savearea - %08X\n", sv);
}
if(fsv && ((fsv->save_hdr.save_misc2 != 0xDEBB1ED0) || (fsv->save_hdr.save_misc3 != 0xE5DA11A5))) {
panic("act_thread_catt: attempt to attach invalid float context savearea - %08X\n", fsv);
}
if(vsv && ((vsv->save_hdr.save_misc2 != 0xDEBB1ED0) || (vsv->save_hdr.save_misc3 != 0xE5DA11A5))) {
panic("act_thread_catt: attempt to attach invalid vector context savearea - %08X\n", vsv);
}
act = current_act();
toss_live_fpu(act->mact.curctx);
toss_live_vec(act->mact.curctx);
sv->save_hdr.save_misc2 = 0;
sv->save_hdr.save_misc3 = 0;
sv->save_hdr.save_act = act;
spc = (unsigned int)act->map->pmap->space;
osv = act->mact.pcb;
psv = 0;
while(osv) {
if(osv->save_srr1 & MASK(MSR_PR)) break;
psv = osv;
osv = (savearea *)osv->save_hdr.save_prev;
}
if(osv) {
if(psv) psv->save_hdr.save_prev = 0;
else act->mact.pcb = 0;
save_release(osv);
}
if(psv) psv->save_hdr.save_prev = (addr64_t)sv;
else act->mact.pcb = (pcb_t)sv;
ovsv = act->mact.curctx->VMXsave;
pvsv = 0;
while(ovsv) {
if(!(ovsv->save_hdr.save_level)) break;
pvsv = ovsv;
ovsv = (savearea_vec *)ovsv->save_hdr.save_prev;
}
if(ovsv) {
if(pvsv) pvsv->save_hdr.save_prev = 0;
else act->mact.curctx->VMXsave = 0;
save_release((savearea *)ovsv);
}
if(vsv) {
if(pvsv) pvsv->save_hdr.save_prev = (addr64_t)vsv;
else act->mact.curctx->VMXsave = vsv;
vsv->save_hdr.save_misc2 = 0;
vsv->save_hdr.save_misc3 = 0;
vsv->save_hdr.save_act = act;
}
ofsv = act->mact.curctx->FPUsave;
pfsv = 0;
while(ofsv) {
if(!(ofsv->save_hdr.save_level)) break;
pfsv = ofsv;
ofsv = (savearea_fpu *)ofsv->save_hdr.save_prev;
}
if(ofsv) {
if(pfsv) pfsv->save_hdr.save_prev = 0;
else act->mact.curctx->FPUsave = 0;
save_release((savearea *)ofsv);
}
if(fsv) {
if(pfsv) pfsv->save_hdr.save_prev = (addr64_t)fsv;
else act->mact.curctx->FPUsave = fsv;
fsv->save_hdr.save_misc2 = 0;
fsv->save_hdr.save_misc3 = 0;
fsv->save_hdr.save_act = act;
}
}
void act_thread_cfree(void *ctx) {
savearea *sv, *osv;
savearea_fpu *fsv, *ofsv;
savearea_vec *vsv, *ovsv, *pvsv;
sv = (savearea *)ctx;
fsv = (savearea_fpu *)sv->save_hdr.save_misc0;
vsv = (savearea_vec *)sv->save_hdr.save_misc1;
if((sv->save_hdr.save_misc2 != 0xDEBB1ED0) || (sv->save_hdr.save_misc3 != 0xE5DA11A5)) {
panic("act_thread_cfree: attempt to detatch invalid general context savearea - %08X\n", sv);
}
save_release(sv);
if(fsv) {
if((fsv->save_hdr.save_misc2 != 0xDEBB1ED0) || (fsv->save_hdr.save_misc3 != 0xE5DA11A5)) {
panic("act_thread_cfree: attempt to detatch invalid float context savearea - %08X\n", fsv);
}
save_release((savearea *)fsv);
}
if(vsv) {
if((vsv->save_hdr.save_misc2 != 0xDEBB1ED0) || (vsv->save_hdr.save_misc3 != 0xE5DA11A5)) {
panic("act_thread_cfree: attempt to detatch invalid vector context savearea - %08X\n", vsv);
}
save_release((savearea *)vsv);
}
return;
}
int thread_enable_fpe(thread_act_t act, int onoff)
{
savearea *sv;
unsigned int oldmsr;
sv = find_user_regs(act);
if(!sv) sv = get_user_regs(act);
oldmsr = sv->save_srr1;
if(onoff) sv->save_srr1 = oldmsr | MASK(MSR_FE0) | MASK(MSR_FE1);
else sv->save_srr1 = oldmsr & ~(MASK(MSR_FE0) | MASK(MSR_FE1));
return ((oldmsr & (MASK(MSR_FE0) | MASK(MSR_FE1))) != 0);
}