Commit ef75e731 authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman

powerpc/signal32: Transform save_user_regs() and save_tm_user_regs() in 'unsafe' version

Change those two functions to be used within a user access block.

For that, change save_general_regs() to and unsafe_save_general_regs(),
then replace all user accesses by unsafe_ versions.

This series leads to a reduction from 2.55s to 1.73s of
the system CPU time with the following microbench app
on an mpc832x with KUAP (approx 32%)

Without KUAP, the difference is in the noise.

	void sigusr1(int sig) { }

	int main(int argc, char **argv)
	{
		int i = 100000;

		signal(SIGUSR1, sigusr1);
		for (;i--;)
		    raise(SIGUSR1);
		exit(0);
	}

An additional 0.10s reduction is achieved by removing
CONFIG_PPC_FPU, as the mpc832x has no FPU.

A bit less spectacular on an 8xx as KUAP is less heavy, prior to
the series (with KUAP) it ran in 8.10 ms. Once applies the removal
of FPU regs handling, we get 7.05s. With the full series, we get 6.9s.
If artificially re-activating FPU regs handling with the full series,
we get 7.6s.

So for the 8xx, the removal of the FPU regs copy is what makes the
difference, but the rework of handle_signal also have a benefit.

Same as above, without KUAP the difference is in the noise.
Signed-off-by: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
[mpe: Fixup typo in SPE handling]
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/c7b37b385ccf9666066452e58f018a86573f83e8.1597770847.git.christophe.leroy@csgroup.eu
parent 968c4fcc
...@@ -93,8 +93,8 @@ static inline int get_sigset_t(sigset_t *set, ...@@ -93,8 +93,8 @@ static inline int get_sigset_t(sigset_t *set,
#define to_user_ptr(p) ptr_to_compat(p) #define to_user_ptr(p) ptr_to_compat(p)
#define from_user_ptr(p) compat_ptr(p) #define from_user_ptr(p) compat_ptr(p)
static inline int save_general_regs(struct pt_regs *regs, static __always_inline int
struct mcontext __user *frame) save_general_regs_unsafe(struct pt_regs *regs, struct mcontext __user *frame)
{ {
elf_greg_t64 *gregs = (elf_greg_t64 *)regs; elf_greg_t64 *gregs = (elf_greg_t64 *)regs;
int val, i; int val, i;
...@@ -108,10 +108,12 @@ static inline int save_general_regs(struct pt_regs *regs, ...@@ -108,10 +108,12 @@ static inline int save_general_regs(struct pt_regs *regs,
else else
val = gregs[i]; val = gregs[i];
if (__put_user(val, &frame->mc_gregs[i])) unsafe_put_user(val, &frame->mc_gregs[i], failed);
return -EFAULT;
} }
return 0; return 0;
failed:
return 1;
} }
static inline int restore_general_regs(struct pt_regs *regs, static inline int restore_general_regs(struct pt_regs *regs,
...@@ -148,11 +150,15 @@ static inline int get_sigset_t(sigset_t *set, const sigset_t __user *uset) ...@@ -148,11 +150,15 @@ static inline int get_sigset_t(sigset_t *set, const sigset_t __user *uset)
#define to_user_ptr(p) ((unsigned long)(p)) #define to_user_ptr(p) ((unsigned long)(p))
#define from_user_ptr(p) ((void __user *)(p)) #define from_user_ptr(p) ((void __user *)(p))
static inline int save_general_regs(struct pt_regs *regs, static __always_inline int
struct mcontext __user *frame) save_general_regs_unsafe(struct pt_regs *regs, struct mcontext __user *frame)
{ {
WARN_ON(!FULL_REGS(regs)); WARN_ON(!FULL_REGS(regs));
return __copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE); unsafe_copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE, failed);
return 0;
failed:
return 1;
} }
static inline int restore_general_regs(struct pt_regs *regs, static inline int restore_general_regs(struct pt_regs *regs,
...@@ -170,6 +176,11 @@ static inline int restore_general_regs(struct pt_regs *regs, ...@@ -170,6 +176,11 @@ static inline int restore_general_regs(struct pt_regs *regs,
} }
#endif #endif
#define unsafe_save_general_regs(regs, frame, label) do { \
if (save_general_regs_unsafe(regs, frame)) \
goto label; \
} while (0)
/* /*
* When we have signals to deliver, we set up on the * When we have signals to deliver, we set up on the
* user stack, going down from the original stack pointer: * user stack, going down from the original stack pointer:
...@@ -249,21 +260,19 @@ static void prepare_save_user_regs(int ctx_has_vsx_region) ...@@ -249,21 +260,19 @@ static void prepare_save_user_regs(int ctx_has_vsx_region)
#endif #endif
} }
static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, static int save_user_regs_unsafe(struct pt_regs *regs, struct mcontext __user *frame,
struct mcontext __user *tm_frame, int ctx_has_vsx_region) struct mcontext __user *tm_frame, int ctx_has_vsx_region)
{ {
unsigned long msr = regs->msr; unsigned long msr = regs->msr;
/* save general registers */ /* save general registers */
if (save_general_regs(regs, frame)) unsafe_save_general_regs(regs, frame, failed);
return 1;
#ifdef CONFIG_ALTIVEC #ifdef CONFIG_ALTIVEC
/* save altivec registers */ /* save altivec registers */
if (current->thread.used_vr) { if (current->thread.used_vr) {
if (__copy_to_user(&frame->mc_vregs, &current->thread.vr_state, unsafe_copy_to_user(&frame->mc_vregs, &current->thread.vr_state,
ELF_NVRREG * sizeof(vector128))) ELF_NVRREG * sizeof(vector128), failed);
return 1;
/* set MSR_VEC in the saved MSR value to indicate that /* set MSR_VEC in the saved MSR value to indicate that
frame->mc_vregs contains valid data */ frame->mc_vregs contains valid data */
msr |= MSR_VEC; msr |= MSR_VEC;
...@@ -276,11 +285,10 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, ...@@ -276,11 +285,10 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
* most significant bits of that same vector. --BenH * most significant bits of that same vector. --BenH
* Note that the current VRSAVE value is in the SPR at this point. * Note that the current VRSAVE value is in the SPR at this point.
*/ */
if (__put_user(current->thread.vrsave, (u32 __user *)&frame->mc_vregs[32])) unsafe_put_user(current->thread.vrsave, (u32 __user *)&frame->mc_vregs[32],
return 1; failed);
#endif /* CONFIG_ALTIVEC */ #endif /* CONFIG_ALTIVEC */
if (copy_fpr_to_user(&frame->mc_fregs, current)) unsafe_copy_fpr_to_user(&frame->mc_fregs, current, failed);
return 1;
/* /*
* Clear the MSR VSX bit to indicate there is no valid state attached * Clear the MSR VSX bit to indicate there is no valid state attached
...@@ -295,17 +303,15 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, ...@@ -295,17 +303,15 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
* contains valid data * contains valid data
*/ */
if (current->thread.used_vsr && ctx_has_vsx_region) { if (current->thread.used_vsr && ctx_has_vsx_region) {
if (copy_vsx_to_user(&frame->mc_vsregs, current)) unsafe_copy_vsx_to_user(&frame->mc_vsregs, current, failed);
return 1;
msr |= MSR_VSX; msr |= MSR_VSX;
} }
#endif /* CONFIG_VSX */ #endif /* CONFIG_VSX */
#ifdef CONFIG_SPE #ifdef CONFIG_SPE
/* save spe registers */ /* save spe registers */
if (current->thread.used_spe) { if (current->thread.used_spe) {
if (__copy_to_user(&frame->mc_vregs, current->thread.evr, unsafe_copy_to_user(&frame->mc_vregs, current->thread.evr,
ELF_NEVRREG * sizeof(u32))) ELF_NEVRREG * sizeof(u32), failed);
return 1;
/* set MSR_SPE in the saved MSR value to indicate that /* set MSR_SPE in the saved MSR value to indicate that
frame->mc_vregs contains valid data */ frame->mc_vregs contains valid data */
msr |= MSR_SPE; msr |= MSR_SPE;
...@@ -313,21 +319,29 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, ...@@ -313,21 +319,29 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
/* else assert((regs->msr & MSR_SPE) == 0) */ /* else assert((regs->msr & MSR_SPE) == 0) */
/* We always copy to/from spefscr */ /* We always copy to/from spefscr */
if (__put_user(current->thread.spefscr, (u32 __user *)&frame->mc_vregs + ELF_NEVRREG)) unsafe_put_user(current->thread.spefscr,
return 1; (u32 __user *)&frame->mc_vregs + ELF_NEVRREG, failed);
#endif /* CONFIG_SPE */ #endif /* CONFIG_SPE */
if (__put_user(msr, &frame->mc_gregs[PT_MSR])) unsafe_put_user(msr, &frame->mc_gregs[PT_MSR], failed);
return 1;
/* We need to write 0 the MSR top 32 bits in the tm frame so that we /* We need to write 0 the MSR top 32 bits in the tm frame so that we
* can check it on the restore to see if TM is active * can check it on the restore to see if TM is active
*/ */
if (tm_frame && __put_user(0, &tm_frame->mc_gregs[PT_MSR])) if (tm_frame)
return 1; unsafe_put_user(0, &tm_frame->mc_gregs[PT_MSR], failed);
return 0; return 0;
failed:
return 1;
} }
#define unsafe_save_user_regs(regs, frame, tm_frame, has_vsx, label) do { \
if (save_user_regs_unsafe(regs, frame, tm_frame, has_vsx)) \
goto label; \
} while (0)
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
/* /*
* Save the current user registers on the user stack. * Save the current user registers on the user stack.
...@@ -336,7 +350,7 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, ...@@ -336,7 +350,7 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
* We also save the transactional registers to a second ucontext in the * We also save the transactional registers to a second ucontext in the
* frame. * frame.
* *
* See save_user_regs() and signal_64.c:setup_tm_sigcontexts(). * See save_user_regs_unsafe() and signal_64.c:setup_tm_sigcontexts().
*/ */
static void prepare_save_tm_user_regs(void) static void prepare_save_tm_user_regs(void)
{ {
...@@ -352,13 +366,12 @@ static void prepare_save_tm_user_regs(void) ...@@ -352,13 +366,12 @@ static void prepare_save_tm_user_regs(void)
#endif #endif
} }
static int save_tm_user_regs(struct pt_regs *regs, struct mcontext __user *frame, static int save_tm_user_regs_unsafe(struct pt_regs *regs, struct mcontext __user *frame,
struct mcontext __user *tm_frame, unsigned long msr) struct mcontext __user *tm_frame, unsigned long msr)
{ {
/* Save both sets of general registers */ /* Save both sets of general registers */
if (save_general_regs(&current->thread.ckpt_regs, frame) unsafe_save_general_regs(&current->thread.ckpt_regs, frame, failed);
|| save_general_regs(regs, tm_frame)) unsafe_save_general_regs(regs, tm_frame, failed);
return 1;
/* Stash the top half of the 64bit MSR into the 32bit MSR word /* Stash the top half of the 64bit MSR into the 32bit MSR word
* of the transactional mcontext. This way we have a backward-compatible * of the transactional mcontext. This way we have a backward-compatible
...@@ -366,26 +379,21 @@ static int save_tm_user_regs(struct pt_regs *regs, struct mcontext __user *frame ...@@ -366,26 +379,21 @@ static int save_tm_user_regs(struct pt_regs *regs, struct mcontext __user *frame
* also look at what type of transaction (T or S) was active at the * also look at what type of transaction (T or S) was active at the
* time of the signal. * time of the signal.
*/ */
if (__put_user((msr >> 32), &tm_frame->mc_gregs[PT_MSR])) unsafe_put_user((msr >> 32), &tm_frame->mc_gregs[PT_MSR], failed);
return 1;
#ifdef CONFIG_ALTIVEC #ifdef CONFIG_ALTIVEC
/* save altivec registers */ /* save altivec registers */
if (current->thread.used_vr) { if (current->thread.used_vr) {
if (__copy_to_user(&frame->mc_vregs, &current->thread.ckvr_state, unsafe_copy_to_user(&frame->mc_vregs, &current->thread.ckvr_state,
ELF_NVRREG * sizeof(vector128))) ELF_NVRREG * sizeof(vector128), failed);
return 1; if (msr & MSR_VEC)
if (msr & MSR_VEC) { unsafe_copy_to_user(&tm_frame->mc_vregs,
if (__copy_to_user(&tm_frame->mc_vregs, &current->thread.vr_state,
&current->thread.vr_state, ELF_NVRREG * sizeof(vector128), failed);
ELF_NVRREG * sizeof(vector128))) else
return 1; unsafe_copy_to_user(&tm_frame->mc_vregs,
} else { &current->thread.ckvr_state,
if (__copy_to_user(&tm_frame->mc_vregs, ELF_NVRREG * sizeof(vector128), failed);
&current->thread.ckvr_state,
ELF_NVRREG * sizeof(vector128)))
return 1;
}
/* set MSR_VEC in the saved MSR value to indicate that /* set MSR_VEC in the saved MSR value to indicate that
* frame->mc_vregs contains valid data * frame->mc_vregs contains valid data
...@@ -398,29 +406,21 @@ static int save_tm_user_regs(struct pt_regs *regs, struct mcontext __user *frame ...@@ -398,29 +406,21 @@ static int save_tm_user_regs(struct pt_regs *regs, struct mcontext __user *frame
* significant bits of a vector, we "cheat" and stuff VRSAVE in the * significant bits of a vector, we "cheat" and stuff VRSAVE in the
* most significant bits of that same vector. --BenH * most significant bits of that same vector. --BenH
*/ */
if (__put_user(current->thread.ckvrsave, unsafe_put_user(current->thread.ckvrsave,
(u32 __user *)&frame->mc_vregs[32])) (u32 __user *)&frame->mc_vregs[32], failed);
return 1; if (msr & MSR_VEC)
if (msr & MSR_VEC) { unsafe_put_user(current->thread.vrsave,
if (__put_user(current->thread.vrsave, (u32 __user *)&tm_frame->mc_vregs[32], failed);
(u32 __user *)&tm_frame->mc_vregs[32])) else
return 1; unsafe_put_user(current->thread.ckvrsave,
} else { (u32 __user *)&tm_frame->mc_vregs[32], failed);
if (__put_user(current->thread.ckvrsave,
(u32 __user *)&tm_frame->mc_vregs[32]))
return 1;
}
#endif /* CONFIG_ALTIVEC */ #endif /* CONFIG_ALTIVEC */
if (copy_ckfpr_to_user(&frame->mc_fregs, current)) unsafe_copy_ckfpr_to_user(&frame->mc_fregs, current, failed);
return 1; if (msr & MSR_FP)
if (msr & MSR_FP) { unsafe_copy_fpr_to_user(&tm_frame->mc_fregs, current, failed);
if (copy_fpr_to_user(&tm_frame->mc_fregs, current)) else
return 1; unsafe_copy_ckfpr_to_user(&tm_frame->mc_fregs, current, failed);
} else {
if (copy_ckfpr_to_user(&tm_frame->mc_fregs, current))
return 1;
}
#ifdef CONFIG_VSX #ifdef CONFIG_VSX
/* /*
...@@ -430,53 +430,54 @@ static int save_tm_user_regs(struct pt_regs *regs, struct mcontext __user *frame ...@@ -430,53 +430,54 @@ static int save_tm_user_regs(struct pt_regs *regs, struct mcontext __user *frame
* contains valid data * contains valid data
*/ */
if (current->thread.used_vsr) { if (current->thread.used_vsr) {
if (copy_ckvsx_to_user(&frame->mc_vsregs, current)) unsafe_copy_ckvsx_to_user(&frame->mc_vsregs, current, failed);
return 1; if (msr & MSR_VSX)
if (msr & MSR_VSX) { unsafe_copy_vsx_to_user(&tm_frame->mc_vsregs, current, failed);
if (copy_vsx_to_user(&tm_frame->mc_vsregs, else
current)) unsafe_copy_ckvsx_to_user(&tm_frame->mc_vsregs, current, failed);
return 1;
} else {
if (copy_ckvsx_to_user(&tm_frame->mc_vsregs, current))
return 1;
}
msr |= MSR_VSX; msr |= MSR_VSX;
} }
#endif /* CONFIG_VSX */ #endif /* CONFIG_VSX */
#ifdef CONFIG_SPE #ifdef CONFIG_SPE
/* SPE regs are not checkpointed with TM, so this section is /* SPE regs are not checkpointed with TM, so this section is
* simply the same as in save_user_regs(). * simply the same as in save_user_regs_unsafe().
*/ */
if (current->thread.used_spe) { if (current->thread.used_spe) {
if (__copy_to_user(&frame->mc_vregs, current->thread.evr, unsafe_copy_to_user(&frame->mc_vregs, current->thread.evr,
ELF_NEVRREG * sizeof(u32))) ELF_NEVRREG * sizeof(u32), failed);
return 1;
/* set MSR_SPE in the saved MSR value to indicate that /* set MSR_SPE in the saved MSR value to indicate that
* frame->mc_vregs contains valid data */ * frame->mc_vregs contains valid data */
msr |= MSR_SPE; msr |= MSR_SPE;
} }
/* We always copy to/from spefscr */ /* We always copy to/from spefscr */
if (__put_user(current->thread.spefscr, (u32 __user *)&frame->mc_vregs + ELF_NEVRREG)) unsafe_put_user(current->thread.spefscr,
return 1; (u32 __user *)&frame->mc_vregs + ELF_NEVRREG, failed);
#endif /* CONFIG_SPE */ #endif /* CONFIG_SPE */
if (__put_user(msr, &frame->mc_gregs[PT_MSR])) unsafe_put_user(msr, &frame->mc_gregs[PT_MSR], failed);
return 1;
return 0; return 0;
failed:
return 1;
} }
#else #else
static void prepare_save_tm_user_regs(void) { } static void prepare_save_tm_user_regs(void) { }
static int save_tm_user_regs(struct pt_regs *regs, struct mcontext __user *frame, static int save_tm_user_regs_unsafe(struct pt_regs *regs, struct mcontext __user *frame,
struct mcontext __user *tm_frame, unsigned long msr) struct mcontext __user *tm_frame, unsigned long msr)
{ {
return 0; return 0;
} }
#endif #endif
#define unsafe_save_tm_user_regs(regs, frame, tm_frame, msr, label) do { \
if (save_tm_user_regs_unsafe(regs, frame, tm_frame, msr)) \
goto label; \
} while (0)
/* /*
* Restore the current user register values from the user stack, * Restore the current user register values from the user stack,
* (except for MSR). * (except for MSR).
...@@ -769,6 +770,11 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, ...@@ -769,6 +770,11 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
tm_mctx = &frame->uc_transact.uc_mcontext; tm_mctx = &frame->uc_transact.uc_mcontext;
#endif #endif
if (MSR_TM_ACTIVE(msr))
prepare_save_tm_user_regs();
else
prepare_save_user_regs(1);
if (!user_write_access_begin(frame, sizeof(*frame))) if (!user_write_access_begin(frame, sizeof(*frame)))
goto badframe; goto badframe;
...@@ -788,8 +794,10 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, ...@@ -788,8 +794,10 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,
unsafe_put_user((unsigned long)tm_mctx, unsafe_put_user((unsigned long)tm_mctx,
&frame->uc_transact.uc_regs, failed); &frame->uc_transact.uc_regs, failed);
#endif #endif
unsafe_save_tm_user_regs(regs, mctx, tm_mctx, msr, failed);
} else { } else {
unsafe_put_user(0, &frame->uc.uc_link, failed); unsafe_put_user(0, &frame->uc.uc_link, failed);
unsafe_save_user_regs(regs, mctx, tm_mctx, 1, failed);
} }
/* Save user registers on the stack */ /* Save user registers on the stack */
...@@ -812,15 +820,6 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, ...@@ -812,15 +820,6 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,
if (tramp == (unsigned long)mctx->mc_pad) if (tramp == (unsigned long)mctx->mc_pad)
flush_icache_range(tramp, tramp + 2 * sizeof(unsigned long)); flush_icache_range(tramp, tramp + 2 * sizeof(unsigned long));
if (MSR_TM_ACTIVE(msr)) {
prepare_save_tm_user_regs();
if (save_tm_user_regs(regs, mctx, tm_mctx, msr))
goto badframe;
} else {
prepare_save_user_regs(1);
if (save_user_regs(regs, mctx, tm_mctx, 1))
goto badframe;
}
regs->link = tramp; regs->link = tramp;
#ifdef CONFIG_PPC_FPU_REGS #ifdef CONFIG_PPC_FPU_REGS
...@@ -875,6 +874,11 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset, ...@@ -875,6 +874,11 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset,
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
tm_mctx = &frame->mctx_transact; tm_mctx = &frame->mctx_transact;
#endif #endif
if (MSR_TM_ACTIVE(msr))
prepare_save_tm_user_regs();
else
prepare_save_user_regs(1);
if (!user_write_access_begin(frame, sizeof(*frame))) if (!user_write_access_begin(frame, sizeof(*frame)))
goto badframe; goto badframe;
sc = (struct sigcontext __user *) &frame->sctx; sc = (struct sigcontext __user *) &frame->sctx;
...@@ -892,6 +896,11 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset, ...@@ -892,6 +896,11 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset,
unsafe_put_user(to_user_ptr(mctx), &sc->regs, failed); unsafe_put_user(to_user_ptr(mctx), &sc->regs, failed);
unsafe_put_user(ksig->sig, &sc->signal, failed); unsafe_put_user(ksig->sig, &sc->signal, failed);
if (MSR_TM_ACTIVE(msr))
unsafe_save_tm_user_regs(regs, mctx, tm_mctx, msr, failed);
else
unsafe_save_user_regs(regs, mctx, tm_mctx, 1, failed);
if (vdso32_sigtramp && tsk->mm->context.vdso_base) { if (vdso32_sigtramp && tsk->mm->context.vdso_base) {
tramp = tsk->mm->context.vdso_base + vdso32_sigtramp; tramp = tsk->mm->context.vdso_base + vdso32_sigtramp;
} else { } else {
...@@ -905,16 +914,6 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset, ...@@ -905,16 +914,6 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset,
if (tramp == (unsigned long)mctx->mc_pad) if (tramp == (unsigned long)mctx->mc_pad)
flush_icache_range(tramp, tramp + 2 * sizeof(unsigned long)); flush_icache_range(tramp, tramp + 2 * sizeof(unsigned long));
if (MSR_TM_ACTIVE(msr)) {
prepare_save_tm_user_regs();
if (save_tm_user_regs(regs, mctx, tm_mctx, msr))
goto badframe;
} else {
prepare_save_user_regs(1);
if (save_user_regs(regs, mctx, tm_mctx, 1))
goto badframe;
}
regs->link = tramp; regs->link = tramp;
#ifdef CONFIG_PPC_FPU_REGS #ifdef CONFIG_PPC_FPU_REGS
...@@ -1066,10 +1065,9 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx, ...@@ -1066,10 +1065,9 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx,
mctx = (struct mcontext __user *) mctx = (struct mcontext __user *)
((unsigned long) &old_ctx->uc_mcontext & ~0xfUL); ((unsigned long) &old_ctx->uc_mcontext & ~0xfUL);
prepare_save_user_regs(ctx_has_vsx_region); prepare_save_user_regs(ctx_has_vsx_region);
if (save_user_regs(regs, mctx, NULL, ctx_has_vsx_region))
return -EFAULT;
if (!user_write_access_begin(old_ctx, ctx_size)) if (!user_write_access_begin(old_ctx, ctx_size))
return -EFAULT; return -EFAULT;
unsafe_save_user_regs(regs, mctx, NULL, ctx_has_vsx_region, failed);
unsafe_put_sigset_t(&old_ctx->uc_sigmask, &current->blocked, failed); unsafe_put_sigset_t(&old_ctx->uc_sigmask, &current->blocked, failed);
unsafe_put_user(to_user_ptr(mctx), &old_ctx->uc_regs, failed); unsafe_put_user(to_user_ptr(mctx), &old_ctx->uc_regs, failed);
user_write_access_end(); user_write_access_end();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment