static __always_inline int __unsafe_restore_general_regs(struct pt_regs *regs, struct mcontext __user *sr)
{ /* copy up to but not including MSR */
unsafe_copy_from_user(regs, &sr->mc_gregs, PT_MSR * sizeof(elf_greg_t), failed);
/* copy from orig_r3 (the word after the MSR) up to the end */
unsafe_copy_from_user(®s->orig_gpr3, &sr->mc_gregs[PT_ORIG_R3],
GP_REGS_SIZE - PT_ORIG_R3 * sizeof(elf_greg_t), failed);
return0;
failed: return1;
} #endif
#define unsafe_save_general_regs(regs, frame, label) do { \ if (__unsafe_save_general_regs(regs, frame)) \ goto label; \
} while (0)
#define unsafe_restore_general_regs(regs, frame, label) do { \ if (__unsafe_restore_general_regs(regs, frame)) \ goto label; \
} while (0)
/* save general registers */
unsafe_save_general_regs(regs, frame, failed);
#ifdef CONFIG_ALTIVEC /* save altivec registers */ if (current->thread.used_vr) {
unsafe_copy_to_user(&frame->mc_vregs, ¤t->thread.vr_state,
ELF_NVRREG * sizeof(vector128), failed); /* set MSR_VEC in the saved MSR value to indicate that
frame->mc_vregs contains valid data */
msr |= MSR_VEC;
} /* else assert((regs->msr & MSR_VEC) == 0) */
/* We always copy to/from vrsave, it's 0 if we don't have or don't *usealtivec.SinceVSCRonlycontains32bitssavedintheleast *significantbitsofavector,we"cheat"andstuffVRSAVEinthe *mostsignificantbitsofthatsamevector.--BenH *NotethatthecurrentVRSAVEvalueisintheSPRatthispoint.
*/
unsafe_put_user(current->thread.vrsave, (u32 __user *)&frame->mc_vregs[32],
failed); #endif/* CONFIG_ALTIVEC */
unsafe_copy_fpr_to_user(&frame->mc_fregs, current, failed);
/* *CleartheMSRVSXbittoindicatethereisnovalidstateattached *tothiscontext,exceptinthespecificcasebelowwherewesetit.
*/
msr &= ~MSR_VSX; #ifdef CONFIG_VSX /* *CopyVSR0-31upperhalffromthread_structtolocal *buffer,thenwritethattouserspace.AlsosetMSR_VSXin *thesavedMSRvaluetoindicatethatframe->mc_vregs *containsvaliddata
*/ if (current->thread.used_vsr && ctx_has_vsx_region) {
unsafe_copy_vsx_to_user(&frame->mc_vsregs, current, failed);
msr |= MSR_VSX;
} #endif/* CONFIG_VSX */ #ifdef CONFIG_SPE /* save spe registers */ if (current->thread.used_spe) {
unsafe_copy_to_user(&frame->mc_vregs, current->thread.evr,
ELF_NEVRREG * sizeof(u32), failed); /* set MSR_SPE in the saved MSR value to indicate that
frame->mc_vregs contains valid data */
msr |= MSR_SPE;
} /* else assert((regs->msr & MSR_SPE) == 0) */
/* We need to write 0 the MSR top 32 bits in the tm frame so that we *cancheckitontherestoretoseeifTMisactive
*/ if (tm_frame)
unsafe_put_user(0, &tm_frame->mc_gregs[PT_MSR], failed);
return0;
failed: return1;
}
#define unsafe_save_user_regs(regs, frame, tm_frame, has_vsx, label) do { \ if (__unsafe_save_user_regs(regs, frame, tm_frame, has_vsx)) \ goto label; \
} while (0)
if (cpu_has_feature(CPU_FTR_ALTIVEC))
current->thread.ckvrsave = mfspr(SPRN_VRSAVE);
}
static __always_inline int
save_tm_user_regs_unsafe(struct pt_regs *regs, struct mcontext __user *frame, struct mcontext __user *tm_frame, unsignedlong msr)
{ /* Save both sets of general registers */
unsafe_save_general_regs(¤t->thread.ckpt_regs, frame, failed);
unsafe_save_general_regs(regs, tm_frame, failed);
/* Stash the top half of the 64bit MSR into the 32bit MSR word *ofthetransactionalmcontext.Thiswaywehaveabackward-compatible *MSRinthe'normal'(checkpointed)mcontextandadditionallyonecan *alsolookatwhattypeoftransaction(TorS)wasactiveatthe *timeofthesignal.
*/
unsafe_put_user((msr >> 32), &tm_frame->mc_gregs[PT_MSR], failed);
/* Always get VRSAVE back */
unsafe_get_user(current->thread.ckvrsave,
(u32 __user *)&sr->mc_vregs[32], failed); if (cpu_has_feature(CPU_FTR_ALTIVEC))
mtspr(SPRN_VRSAVE, current->thread.ckvrsave);
/* *CAUTION: *Afterregs->MSR[TS]beingupdated,makesurethatget_user(), *put_user()orsimilarfunctionsare*not*called.These *functionscangeneratepagefaultswhichwillcausetheprocess *tobede-scheduledwithMSR[TS]setbutwithoutcalling *tm_recheckpoint().Thiscancauseabug. * *PullintheMSRTMbitsfromtheusercontext
*/
regs_set_return_msr(regs, (regs->msr & ~MSR_TS_MASK) | (msr_hi & MSR_TS_MASK)); /* Now, recheckpoint. This loads up all of the checkpointed (older) *registers,includingFPandV[S]Rs.Afterrecheckpointing,the *transactionalversionsshouldbeloaded.
*/
tm_enable(); /* Make sure the transaction is marked as failed */
current->thread.tm_texasr |= TEXASR_FS; /* This loads the checkpointed FP/VEC state, if used */
tm_recheckpoint(¤t->thread);
/* This loads the speculative FP/VEC state, if used */
msr_check_and_set(msr & (MSR_FP | MSR_VEC)); if (msr & MSR_FP) {
load_fp_state(¤t->thread.fp_state);
regs_set_return_msr(regs, regs->msr | (MSR_FP | current->thread.fpexc_mode));
} if (msr & MSR_VEC) {
load_vr_state(¤t->thread.vr_state);
regs_set_return_msr(regs, regs->msr | MSR_VEC);
}
/* Set up Signal Frame */
frame = get_sigframe(ksig, tsk, sizeof(*frame), 1);
mctx = &frame->uc.uc_mcontext; #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
tm_mctx = &frame->uc_transact.uc_mcontext; #endif if (MSR_TM_ACTIVE(msr))
prepare_save_tm_user_regs(); else
prepare_save_user_regs(1);
if (!user_access_begin(frame, sizeof(*frame))) goto badframe;
/* Put the siginfo & fill in most of the ucontext */
unsafe_put_user(0, &frame->uc.uc_flags, failed); #ifdef CONFIG_PPC64
unsafe_compat_save_altstack(&frame->uc.uc_stack, regs->gpr[1], failed); #else
unsafe_save_altstack(&frame->uc.uc_stack, regs->gpr[1], failed); #endif
unsafe_put_user(to_user_ptr(&frame->uc.uc_mcontext), &frame->uc.uc_regs, failed);
/* Save user registers on the stack */ if (tsk->mm->context.vdso) {
tramp = VDSO32_SYMBOL(tsk->mm->context.vdso, sigtramp_rt32);
} else {
tramp = (unsignedlong)mctx->mc_pad;
unsafe_put_user(PPC_RAW_LI(_R0, __NR_rt_sigreturn), &mctx->mc_pad[0], failed);
unsafe_put_user(PPC_RAW_SC(), &mctx->mc_pad[1], failed); asm("dcbst %y0; sync; icbi %y0; sync" :: "Z" (mctx->mc_pad[0]));
}
unsafe_put_sigset_t(&frame->uc.uc_sigmask, oldset, failed);
user_access_end();
if (copy_siginfo_to_user(&frame->info, &ksig->info)) goto badframe;
regs->link = tramp;
#ifdef CONFIG_PPC_FPU_REGS
tsk->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */ #endif
/* create a stack frame for the caller of the handler */
newsp = ((unsignedlong)frame) - (__SIGNAL_FRAMESIZE + 16); if (put_user(regs->gpr[1], (u32 __user *)newsp)) goto badframe;
/* Fill registers for signal handler */
regs->gpr[1] = newsp;
regs->gpr[3] = ksig->sig;
regs->gpr[4] = (unsignedlong)&frame->info;
regs->gpr[5] = (unsignedlong)&frame->uc;
regs->gpr[6] = (unsignedlong)frame;
regs_set_return_ip(regs, (unsignedlong) ksig->ka.sa.sa_handler); /* enter the signal handler in native-endian mode */
regs_set_return_msr(regs, (regs->msr & ~MSR_LE) | (MSR_KERNEL & MSR_LE));
#ifdef CONFIG_PPC_FPU_REGS
tsk->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */ #endif
/* create a stack frame for the caller of the handler */
newsp = ((unsignedlong)frame) - __SIGNAL_FRAMESIZE; if (put_user(regs->gpr[1], (u32 __user *)newsp)) goto badframe;
regs->gpr[1] = newsp;
regs->gpr[3] = ksig->sig;
regs->gpr[4] = (unsignedlong) sc;
regs_set_return_ip(regs, (unsignedlong) ksig->ka.sa.sa_handler); /* enter the signal handler in native-endian mode */
regs_set_return_msr(regs, (regs->msr & ~MSR_LE) | (MSR_KERNEL & MSR_LE));
if (__get_user(tmp, &rt_sf->uc.uc_link)) goto bad;
uc_transact = (struct ucontext __user *)(uintptr_t)tmp; if (uc_transact) {
u32 cmcp; struct mcontext __user *mcp;
if (__get_user(cmcp, &uc_transact->uc_regs)) return -EFAULT;
mcp = (struct mcontext __user *)(u64)cmcp; /* The top 32 bits of the MSR are stashed in the transactional
* ucontext. */ if (__get_user(msr_hi, &mcp->mc_gregs[PT_MSR])) goto bad;
if (MSR_TM_ACTIVE(msr_hi<<32)) { /* Trying to start TM on non TM system */ if (!cpu_has_feature(CPU_FTR_TM)) goto bad; /* We only recheckpoint on return if we're *transaction.
*/
tm_restore = 1; if (do_setcontext_tm(&rt_sf->uc, uc_transact, regs)) goto bad;
}
} if (!tm_restore) { /* *Unsetregs->msrbecauseucontextMSRTSisnot *set,andrecheckpointwasnotcalled.Thisavoid *hittingaTMBadthingatRFID
*/
regs_set_return_msr(regs, regs->msr & ~MSR_TS_MASK);
} /* Fall through, for non-TM restore */ #endif if (!tm_restore) if (do_setcontext(&rt_sf->uc, regs, 1)) goto bad;
for (i=0; i<ndbg; i++) { if (copy_from_user(&op, dbg + i, sizeof(op))) return -EFAULT; switch (op.dbg_type) { case SIG_DBG_SINGLE_STEPPING: #ifdef CONFIG_PPC_ADV_DEBUG_REGS if (op.dbg_value) {
new_msr |= MSR_DE;
new_dbcr0 |= (DBCR0_IDM | DBCR0_IC);
} else {
new_dbcr0 &= ~DBCR0_IC; if (!DBCR_ACTIVE_EVENTS(new_dbcr0,
current->thread.debug.dbcr1)) {
new_msr &= ~MSR_DE;
new_dbcr0 &= ~DBCR0_IDM;
}
} #else if (op.dbg_value)
new_msr |= MSR_SE; else
new_msr &= ~MSR_SE; #endif break; case SIG_DBG_BRANCH_TRACING: #ifdef CONFIG_PPC_ADV_DEBUG_REGS return -EINVAL; #else if (op.dbg_value)
new_msr |= MSR_BE; else
new_msr &= ~MSR_BE; #endif break;
default: return -EINVAL;
}
}
/* We wait until here to actually install the values in the registerssoifwefailintheaboveloop,itwillnot affectthecontentsoftheseregisters.Afterthispoint, failureisaproblem,anyway,andit'sveryunlikelyunless
the user is really doing something wrong. */
regs_set_return_msr(regs, new_msr); #ifdef CONFIG_PPC_ADV_DEBUG_REGS
current->thread.debug.dbcr0 = new_dbcr0; #endif
if (!access_ok(ctx, sizeof(*ctx)) ||
fault_in_readable((char __user *)ctx, sizeof(*ctx))) return -EFAULT;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.