diff options
Diffstat (limited to 'arch/arm64/kernel/signal.c')
| -rw-r--r-- | arch/arm64/kernel/signal.c | 52 | 
1 files changed, 35 insertions, 17 deletions
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index 890a591f75d..6357b9c6c90 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -17,6 +17,7 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */ +#include <linux/compat.h>  #include <linux/errno.h>  #include <linux/signal.h>  #include <linux/personality.h> @@ -25,7 +26,6 @@  #include <linux/tracehook.h>  #include <linux/ratelimit.h> -#include <asm/compat.h>  #include <asm/debug-monitors.h>  #include <asm/elf.h>  #include <asm/cacheflush.h> @@ -51,7 +51,7 @@ static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)  	int err;  	/* dump the hardware registers to the fpsimd_state structure */ -	fpsimd_save_state(fpsimd); +	fpsimd_preserve_current_state();  	/* copy the FP and status/control registers */  	err = __copy_to_user(ctx->vregs, fpsimd->vregs, sizeof(fpsimd->vregs)); @@ -86,11 +86,8 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)  	__get_user_error(fpsimd.fpcr, &ctx->fpcr, err);  	/* load the hardware registers from the fpsimd_state structure */ -	if (!err) { -		preempt_disable(); -		fpsimd_load_state(&fpsimd); -		preempt_enable(); -	} +	if (!err) +		fpsimd_update_current_state(&fpsimd);  	return err ? -EFAULT : 0;  } @@ -100,8 +97,7 @@ static int restore_sigframe(struct pt_regs *regs,  {  	sigset_t set;  	int i, err; -	struct aux_context __user *aux = -		(struct aux_context __user *)sf->uc.uc_mcontext.__reserved; +	void *aux = sf->uc.uc_mcontext.__reserved;  	err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));  	if (err == 0) @@ -121,8 +117,11 @@ static int restore_sigframe(struct pt_regs *regs,  	err |= !valid_user_regs(®s->user_regs); -	if (err == 0) -		err |= restore_fpsimd_context(&aux->fpsimd); +	if (err == 0) { +		struct fpsimd_context *fpsimd_ctx = +			container_of(aux, struct fpsimd_context, head); +		err |= restore_fpsimd_context(fpsimd_ctx); +	}  	return err;  } @@ -167,8 +166,8 @@ static int setup_sigframe(struct rt_sigframe __user *sf,  			  struct pt_regs *regs, sigset_t *set)  {  	int i, err = 0; -	struct aux_context __user *aux = -		(struct aux_context __user *)sf->uc.uc_mcontext.__reserved; +	void *aux = sf->uc.uc_mcontext.__reserved; +	struct _aarch64_ctx *end;  	/* set up the stack frame for unwinding */  	__put_user_error(regs->regs[29], &sf->fp, err); @@ -185,12 +184,27 @@ static int setup_sigframe(struct rt_sigframe __user *sf,  	err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); -	if (err == 0) -		err |= preserve_fpsimd_context(&aux->fpsimd); +	if (err == 0) { +		struct fpsimd_context *fpsimd_ctx = +			container_of(aux, struct fpsimd_context, head); +		err |= preserve_fpsimd_context(fpsimd_ctx); +		aux += sizeof(*fpsimd_ctx); +	} + +	/* fault information, if valid */ +	if (current->thread.fault_code) { +		struct esr_context *esr_ctx = +			container_of(aux, struct esr_context, head); +		__put_user_error(ESR_MAGIC, &esr_ctx->head.magic, err); +		__put_user_error(sizeof(*esr_ctx), &esr_ctx->head.size, err); +		__put_user_error(current->thread.fault_code, &esr_ctx->esr, err); +		aux += sizeof(*esr_ctx); +	}  	/* set the "end" magic */ -	__put_user_error(0, &aux->end.magic, err); -	__put_user_error(0, &aux->end.size, err); +	end = aux; +	__put_user_error(0, &end->magic, err); +	__put_user_error(0, &end->size, err);  	return err;  } @@ -416,4 +430,8 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,  		clear_thread_flag(TIF_NOTIFY_RESUME);  		tracehook_notify_resume(regs);  	} + +	if (thread_flags & _TIF_FOREIGN_FPSTATE) +		fpsimd_restore_current_state(); +  }  | 
