xref: /linux/arch/loongarch/kernel/signal.c (revision c968b99f)
1b74baf4aSHuacai Chen // SPDX-License-Identifier: GPL-2.0+
2b74baf4aSHuacai Chen /*
3b74baf4aSHuacai Chen  * Author: Hanlu Li <lihanlu@loongson.cn>
4b74baf4aSHuacai Chen  *         Huacai Chen <chenhuacai@loongson.cn>
5b74baf4aSHuacai Chen  * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
6b74baf4aSHuacai Chen  *
7b74baf4aSHuacai Chen  * Derived from MIPS:
8b74baf4aSHuacai Chen  * Copyright (C) 1991, 1992  Linus Torvalds
9b74baf4aSHuacai Chen  * Copyright (C) 1994 - 2000  Ralf Baechle
10b74baf4aSHuacai Chen  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
11b74baf4aSHuacai Chen  * Copyright (C) 2014, Imagination Technologies Ltd.
12b74baf4aSHuacai Chen  */
13b74baf4aSHuacai Chen #include <linux/audit.h>
14b74baf4aSHuacai Chen #include <linux/cache.h>
15b74baf4aSHuacai Chen #include <linux/context_tracking.h>
16c718a0baSBibo Mao #include <linux/entry-common.h>
17b74baf4aSHuacai Chen #include <linux/irqflags.h>
18*c968b99fSRandy Dunlap #include <linux/rseq.h>
19b74baf4aSHuacai Chen #include <linux/sched.h>
20b74baf4aSHuacai Chen #include <linux/mm.h>
21b74baf4aSHuacai Chen #include <linux/personality.h>
22b74baf4aSHuacai Chen #include <linux/smp.h>
23b74baf4aSHuacai Chen #include <linux/kernel.h>
24b74baf4aSHuacai Chen #include <linux/signal.h>
25b74baf4aSHuacai Chen #include <linux/errno.h>
26b74baf4aSHuacai Chen #include <linux/wait.h>
27b74baf4aSHuacai Chen #include <linux/ptrace.h>
28b74baf4aSHuacai Chen #include <linux/unistd.h>
29b74baf4aSHuacai Chen #include <linux/compiler.h>
30b74baf4aSHuacai Chen #include <linux/syscalls.h>
31b74baf4aSHuacai Chen #include <linux/uaccess.h>
32b74baf4aSHuacai Chen 
33b74baf4aSHuacai Chen #include <asm/asm.h>
34b74baf4aSHuacai Chen #include <asm/cacheflush.h>
35b74baf4aSHuacai Chen #include <asm/cpu-features.h>
36b74baf4aSHuacai Chen #include <asm/fpu.h>
37bd3c5798SQi Hu #include <asm/lbt.h>
38b74baf4aSHuacai Chen #include <asm/ucontext.h>
39b74baf4aSHuacai Chen #include <asm/vdso.h>
40b74baf4aSHuacai Chen 
41b74baf4aSHuacai Chen #ifdef DEBUG_SIG
42b74baf4aSHuacai Chen #  define DEBUGP(fmt, args...) printk("%s: " fmt, __func__, ##args)
43b74baf4aSHuacai Chen #else
44b74baf4aSHuacai Chen #  define DEBUGP(fmt, args...)
45b74baf4aSHuacai Chen #endif
46b74baf4aSHuacai Chen 
47b74baf4aSHuacai Chen /* Make sure we will not lose FPU ownership */
48b74baf4aSHuacai Chen #define lock_fpu_owner()	({ preempt_disable(); pagefault_disable(); })
49b74baf4aSHuacai Chen #define unlock_fpu_owner()	({ pagefault_enable(); preempt_enable(); })
50bd3c5798SQi Hu /* Make sure we will not lose LBT ownership */
51bd3c5798SQi Hu #define lock_lbt_owner()	({ preempt_disable(); pagefault_disable(); })
52bd3c5798SQi Hu #define unlock_lbt_owner()	({ pagefault_enable(); preempt_enable(); })
53b74baf4aSHuacai Chen 
54b74baf4aSHuacai Chen /* Assembly functions to move context to/from the FPU */
55b74baf4aSHuacai Chen extern asmlinkage int
56b74baf4aSHuacai Chen _save_fp_context(void __user *fpregs, void __user *fcc, void __user *csr);
57b74baf4aSHuacai Chen extern asmlinkage int
58b74baf4aSHuacai Chen _restore_fp_context(void __user *fpregs, void __user *fcc, void __user *csr);
5961650023SHuacai Chen extern asmlinkage int
6061650023SHuacai Chen _save_lsx_context(void __user *fpregs, void __user *fcc, void __user *fcsr);
6161650023SHuacai Chen extern asmlinkage int
6261650023SHuacai Chen _restore_lsx_context(void __user *fpregs, void __user *fcc, void __user *fcsr);
6361650023SHuacai Chen extern asmlinkage int
6461650023SHuacai Chen _save_lasx_context(void __user *fpregs, void __user *fcc, void __user *fcsr);
6561650023SHuacai Chen extern asmlinkage int
6661650023SHuacai Chen _restore_lasx_context(void __user *fpregs, void __user *fcc, void __user *fcsr);
67b74baf4aSHuacai Chen 
68bd3c5798SQi Hu #ifdef CONFIG_CPU_HAS_LBT
69bd3c5798SQi Hu extern asmlinkage int _save_lbt_context(void __user *regs, void __user *eflags);
70bd3c5798SQi Hu extern asmlinkage int _restore_lbt_context(void __user *regs, void __user *eflags);
71bd3c5798SQi Hu extern asmlinkage int _save_ftop_context(void __user *ftop);
72bd3c5798SQi Hu extern asmlinkage int _restore_ftop_context(void __user *ftop);
73bd3c5798SQi Hu #endif
74bd3c5798SQi Hu 
75b74baf4aSHuacai Chen struct rt_sigframe {
76b74baf4aSHuacai Chen 	struct siginfo rs_info;
77b74baf4aSHuacai Chen 	struct ucontext rs_uctx;
78b74baf4aSHuacai Chen };
79b74baf4aSHuacai Chen 
80b74baf4aSHuacai Chen struct _ctx_layout {
81b74baf4aSHuacai Chen 	struct sctx_info *addr;
82b74baf4aSHuacai Chen 	unsigned int size;
83b74baf4aSHuacai Chen };
84b74baf4aSHuacai Chen 
85b74baf4aSHuacai Chen struct extctx_layout {
86b74baf4aSHuacai Chen 	unsigned long size;
87b74baf4aSHuacai Chen 	unsigned int flags;
88b74baf4aSHuacai Chen 	struct _ctx_layout fpu;
8961650023SHuacai Chen 	struct _ctx_layout lsx;
9061650023SHuacai Chen 	struct _ctx_layout lasx;
91bd3c5798SQi Hu 	struct _ctx_layout lbt;
92b74baf4aSHuacai Chen 	struct _ctx_layout end;
93b74baf4aSHuacai Chen };
94b74baf4aSHuacai Chen 
get_ctx_through_ctxinfo(struct sctx_info * info)95b74baf4aSHuacai Chen static void __user *get_ctx_through_ctxinfo(struct sctx_info *info)
96b74baf4aSHuacai Chen {
97b74baf4aSHuacai Chen 	return (void __user *)((char *)info + sizeof(struct sctx_info));
98b74baf4aSHuacai Chen }
99b74baf4aSHuacai Chen 
100b74baf4aSHuacai Chen /*
101b74baf4aSHuacai Chen  * Thread saved context copy to/from a signal context presumed to be on the
102b74baf4aSHuacai Chen  * user stack, and therefore accessed with appropriate macros from uaccess.h.
103b74baf4aSHuacai Chen  */
copy_fpu_to_sigcontext(struct fpu_context __user * ctx)104b74baf4aSHuacai Chen static int copy_fpu_to_sigcontext(struct fpu_context __user *ctx)
105b74baf4aSHuacai Chen {
106b74baf4aSHuacai Chen 	int i;
107b74baf4aSHuacai Chen 	int err = 0;
108b74baf4aSHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
109b74baf4aSHuacai Chen 	uint64_t __user *fcc	= &ctx->fcc;
110b74baf4aSHuacai Chen 	uint32_t __user *fcsr	= &ctx->fcsr;
111b74baf4aSHuacai Chen 
112b74baf4aSHuacai Chen 	for (i = 0; i < NUM_FPU_REGS; i++) {
113b74baf4aSHuacai Chen 		err |=
114b74baf4aSHuacai Chen 		    __put_user(get_fpr64(&current->thread.fpu.fpr[i], 0),
115b74baf4aSHuacai Chen 			       &regs[i]);
116b74baf4aSHuacai Chen 	}
117b74baf4aSHuacai Chen 	err |= __put_user(current->thread.fpu.fcc, fcc);
118b74baf4aSHuacai Chen 	err |= __put_user(current->thread.fpu.fcsr, fcsr);
119b74baf4aSHuacai Chen 
120b74baf4aSHuacai Chen 	return err;
121b74baf4aSHuacai Chen }
122b74baf4aSHuacai Chen 
copy_fpu_from_sigcontext(struct fpu_context __user * ctx)123b74baf4aSHuacai Chen static int copy_fpu_from_sigcontext(struct fpu_context __user *ctx)
124b74baf4aSHuacai Chen {
125b74baf4aSHuacai Chen 	int i;
126b74baf4aSHuacai Chen 	int err = 0;
127b74baf4aSHuacai Chen 	u64 fpr_val;
128b74baf4aSHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
129b74baf4aSHuacai Chen 	uint64_t __user *fcc	= &ctx->fcc;
130b74baf4aSHuacai Chen 	uint32_t __user *fcsr	= &ctx->fcsr;
131b74baf4aSHuacai Chen 
132b74baf4aSHuacai Chen 	for (i = 0; i < NUM_FPU_REGS; i++) {
133b74baf4aSHuacai Chen 		err |= __get_user(fpr_val, &regs[i]);
134b74baf4aSHuacai Chen 		set_fpr64(&current->thread.fpu.fpr[i], 0, fpr_val);
135b74baf4aSHuacai Chen 	}
136b74baf4aSHuacai Chen 	err |= __get_user(current->thread.fpu.fcc, fcc);
137b74baf4aSHuacai Chen 	err |= __get_user(current->thread.fpu.fcsr, fcsr);
138b74baf4aSHuacai Chen 
139b74baf4aSHuacai Chen 	return err;
140b74baf4aSHuacai Chen }
141b74baf4aSHuacai Chen 
copy_lsx_to_sigcontext(struct lsx_context __user * ctx)14261650023SHuacai Chen static int copy_lsx_to_sigcontext(struct lsx_context __user *ctx)
14361650023SHuacai Chen {
14461650023SHuacai Chen 	int i;
14561650023SHuacai Chen 	int err = 0;
14661650023SHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
14761650023SHuacai Chen 	uint64_t __user *fcc	= &ctx->fcc;
14861650023SHuacai Chen 	uint32_t __user *fcsr	= &ctx->fcsr;
14961650023SHuacai Chen 
15061650023SHuacai Chen 	for (i = 0; i < NUM_FPU_REGS; i++) {
15161650023SHuacai Chen 		err |= __put_user(get_fpr64(&current->thread.fpu.fpr[i], 0),
15261650023SHuacai Chen 				  &regs[2*i]);
15361650023SHuacai Chen 		err |= __put_user(get_fpr64(&current->thread.fpu.fpr[i], 1),
15461650023SHuacai Chen 				  &regs[2*i+1]);
15561650023SHuacai Chen 	}
15661650023SHuacai Chen 	err |= __put_user(current->thread.fpu.fcc, fcc);
15761650023SHuacai Chen 	err |= __put_user(current->thread.fpu.fcsr, fcsr);
15861650023SHuacai Chen 
15961650023SHuacai Chen 	return err;
16061650023SHuacai Chen }
16161650023SHuacai Chen 
copy_lsx_from_sigcontext(struct lsx_context __user * ctx)16261650023SHuacai Chen static int copy_lsx_from_sigcontext(struct lsx_context __user *ctx)
16361650023SHuacai Chen {
16461650023SHuacai Chen 	int i;
16561650023SHuacai Chen 	int err = 0;
16661650023SHuacai Chen 	u64 fpr_val;
16761650023SHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
16861650023SHuacai Chen 	uint64_t __user *fcc	= &ctx->fcc;
16961650023SHuacai Chen 	uint32_t __user *fcsr	= &ctx->fcsr;
17061650023SHuacai Chen 
17161650023SHuacai Chen 	for (i = 0; i < NUM_FPU_REGS; i++) {
17261650023SHuacai Chen 		err |= __get_user(fpr_val, &regs[2*i]);
17361650023SHuacai Chen 		set_fpr64(&current->thread.fpu.fpr[i], 0, fpr_val);
17461650023SHuacai Chen 		err |= __get_user(fpr_val, &regs[2*i+1]);
17561650023SHuacai Chen 		set_fpr64(&current->thread.fpu.fpr[i], 1, fpr_val);
17661650023SHuacai Chen 	}
17761650023SHuacai Chen 	err |= __get_user(current->thread.fpu.fcc, fcc);
17861650023SHuacai Chen 	err |= __get_user(current->thread.fpu.fcsr, fcsr);
17961650023SHuacai Chen 
18061650023SHuacai Chen 	return err;
18161650023SHuacai Chen }
18261650023SHuacai Chen 
copy_lasx_to_sigcontext(struct lasx_context __user * ctx)18361650023SHuacai Chen static int copy_lasx_to_sigcontext(struct lasx_context __user *ctx)
18461650023SHuacai Chen {
18561650023SHuacai Chen 	int i;
18661650023SHuacai Chen 	int err = 0;
18761650023SHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
18861650023SHuacai Chen 	uint64_t __user *fcc	= &ctx->fcc;
18961650023SHuacai Chen 	uint32_t __user *fcsr	= &ctx->fcsr;
19061650023SHuacai Chen 
19161650023SHuacai Chen 	for (i = 0; i < NUM_FPU_REGS; i++) {
19261650023SHuacai Chen 		err |= __put_user(get_fpr64(&current->thread.fpu.fpr[i], 0),
19361650023SHuacai Chen 				  &regs[4*i]);
19461650023SHuacai Chen 		err |= __put_user(get_fpr64(&current->thread.fpu.fpr[i], 1),
19561650023SHuacai Chen 				  &regs[4*i+1]);
19661650023SHuacai Chen 		err |= __put_user(get_fpr64(&current->thread.fpu.fpr[i], 2),
19761650023SHuacai Chen 				  &regs[4*i+2]);
19861650023SHuacai Chen 		err |= __put_user(get_fpr64(&current->thread.fpu.fpr[i], 3),
19961650023SHuacai Chen 				  &regs[4*i+3]);
20061650023SHuacai Chen 	}
20161650023SHuacai Chen 	err |= __put_user(current->thread.fpu.fcc, fcc);
20261650023SHuacai Chen 	err |= __put_user(current->thread.fpu.fcsr, fcsr);
20361650023SHuacai Chen 
20461650023SHuacai Chen 	return err;
20561650023SHuacai Chen }
20661650023SHuacai Chen 
copy_lasx_from_sigcontext(struct lasx_context __user * ctx)20761650023SHuacai Chen static int copy_lasx_from_sigcontext(struct lasx_context __user *ctx)
20861650023SHuacai Chen {
20961650023SHuacai Chen 	int i;
21061650023SHuacai Chen 	int err = 0;
21161650023SHuacai Chen 	u64 fpr_val;
21261650023SHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
21361650023SHuacai Chen 	uint64_t __user *fcc	= &ctx->fcc;
21461650023SHuacai Chen 	uint32_t __user *fcsr	= &ctx->fcsr;
21561650023SHuacai Chen 
21661650023SHuacai Chen 	for (i = 0; i < NUM_FPU_REGS; i++) {
21761650023SHuacai Chen 		err |= __get_user(fpr_val, &regs[4*i]);
21861650023SHuacai Chen 		set_fpr64(&current->thread.fpu.fpr[i], 0, fpr_val);
21961650023SHuacai Chen 		err |= __get_user(fpr_val, &regs[4*i+1]);
22061650023SHuacai Chen 		set_fpr64(&current->thread.fpu.fpr[i], 1, fpr_val);
22161650023SHuacai Chen 		err |= __get_user(fpr_val, &regs[4*i+2]);
22261650023SHuacai Chen 		set_fpr64(&current->thread.fpu.fpr[i], 2, fpr_val);
22361650023SHuacai Chen 		err |= __get_user(fpr_val, &regs[4*i+3]);
22461650023SHuacai Chen 		set_fpr64(&current->thread.fpu.fpr[i], 3, fpr_val);
22561650023SHuacai Chen 	}
22661650023SHuacai Chen 	err |= __get_user(current->thread.fpu.fcc, fcc);
22761650023SHuacai Chen 	err |= __get_user(current->thread.fpu.fcsr, fcsr);
22861650023SHuacai Chen 
22961650023SHuacai Chen 	return err;
23061650023SHuacai Chen }
23161650023SHuacai Chen 
232bd3c5798SQi Hu #ifdef CONFIG_CPU_HAS_LBT
copy_lbt_to_sigcontext(struct lbt_context __user * ctx)233bd3c5798SQi Hu static int copy_lbt_to_sigcontext(struct lbt_context __user *ctx)
234bd3c5798SQi Hu {
235bd3c5798SQi Hu 	int err = 0;
236bd3c5798SQi Hu 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
237bd3c5798SQi Hu 	uint32_t __user *eflags	= (uint32_t *)&ctx->eflags;
238bd3c5798SQi Hu 
239bd3c5798SQi Hu 	err |= __put_user(current->thread.lbt.scr0, &regs[0]);
240bd3c5798SQi Hu 	err |= __put_user(current->thread.lbt.scr1, &regs[1]);
241bd3c5798SQi Hu 	err |= __put_user(current->thread.lbt.scr2, &regs[2]);
242bd3c5798SQi Hu 	err |= __put_user(current->thread.lbt.scr3, &regs[3]);
243bd3c5798SQi Hu 	err |= __put_user(current->thread.lbt.eflags, eflags);
244bd3c5798SQi Hu 
245bd3c5798SQi Hu 	return err;
246bd3c5798SQi Hu }
247bd3c5798SQi Hu 
copy_lbt_from_sigcontext(struct lbt_context __user * ctx)248bd3c5798SQi Hu static int copy_lbt_from_sigcontext(struct lbt_context __user *ctx)
249bd3c5798SQi Hu {
250bd3c5798SQi Hu 	int err = 0;
251bd3c5798SQi Hu 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
252bd3c5798SQi Hu 	uint32_t __user *eflags	= (uint32_t *)&ctx->eflags;
253bd3c5798SQi Hu 
254bd3c5798SQi Hu 	err |= __get_user(current->thread.lbt.scr0, &regs[0]);
255bd3c5798SQi Hu 	err |= __get_user(current->thread.lbt.scr1, &regs[1]);
256bd3c5798SQi Hu 	err |= __get_user(current->thread.lbt.scr2, &regs[2]);
257bd3c5798SQi Hu 	err |= __get_user(current->thread.lbt.scr3, &regs[3]);
258bd3c5798SQi Hu 	err |= __get_user(current->thread.lbt.eflags, eflags);
259bd3c5798SQi Hu 
260bd3c5798SQi Hu 	return err;
261bd3c5798SQi Hu }
262bd3c5798SQi Hu 
copy_ftop_to_sigcontext(struct lbt_context __user * ctx)263bd3c5798SQi Hu static int copy_ftop_to_sigcontext(struct lbt_context __user *ctx)
264bd3c5798SQi Hu {
265bd3c5798SQi Hu 	uint32_t  __user *ftop	= &ctx->ftop;
266bd3c5798SQi Hu 
267bd3c5798SQi Hu 	return __put_user(current->thread.fpu.ftop, ftop);
268bd3c5798SQi Hu }
269bd3c5798SQi Hu 
copy_ftop_from_sigcontext(struct lbt_context __user * ctx)270bd3c5798SQi Hu static int copy_ftop_from_sigcontext(struct lbt_context __user *ctx)
271bd3c5798SQi Hu {
272bd3c5798SQi Hu 	uint32_t  __user *ftop	= &ctx->ftop;
273bd3c5798SQi Hu 
274bd3c5798SQi Hu 	return __get_user(current->thread.fpu.ftop, ftop);
275bd3c5798SQi Hu }
276bd3c5798SQi Hu #endif
277bd3c5798SQi Hu 
278b74baf4aSHuacai Chen /*
279b74baf4aSHuacai Chen  * Wrappers for the assembly _{save,restore}_fp_context functions.
280b74baf4aSHuacai Chen  */
save_hw_fpu_context(struct fpu_context __user * ctx)281b74baf4aSHuacai Chen static int save_hw_fpu_context(struct fpu_context __user *ctx)
282b74baf4aSHuacai Chen {
283b74baf4aSHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
284b74baf4aSHuacai Chen 	uint64_t __user *fcc	= &ctx->fcc;
285b74baf4aSHuacai Chen 	uint32_t __user *fcsr	= &ctx->fcsr;
286b74baf4aSHuacai Chen 
287b74baf4aSHuacai Chen 	return _save_fp_context(regs, fcc, fcsr);
288b74baf4aSHuacai Chen }
289b74baf4aSHuacai Chen 
restore_hw_fpu_context(struct fpu_context __user * ctx)290b74baf4aSHuacai Chen static int restore_hw_fpu_context(struct fpu_context __user *ctx)
291b74baf4aSHuacai Chen {
292b74baf4aSHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
293b74baf4aSHuacai Chen 	uint64_t __user *fcc	= &ctx->fcc;
294b74baf4aSHuacai Chen 	uint32_t __user *fcsr	= &ctx->fcsr;
295b74baf4aSHuacai Chen 
296b74baf4aSHuacai Chen 	return _restore_fp_context(regs, fcc, fcsr);
297b74baf4aSHuacai Chen }
298b74baf4aSHuacai Chen 
save_hw_lsx_context(struct lsx_context __user * ctx)29961650023SHuacai Chen static int save_hw_lsx_context(struct lsx_context __user *ctx)
30061650023SHuacai Chen {
30161650023SHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
30261650023SHuacai Chen 	uint64_t __user *fcc	= &ctx->fcc;
30361650023SHuacai Chen 	uint32_t __user *fcsr	= &ctx->fcsr;
30461650023SHuacai Chen 
30561650023SHuacai Chen 	return _save_lsx_context(regs, fcc, fcsr);
30661650023SHuacai Chen }
30761650023SHuacai Chen 
restore_hw_lsx_context(struct lsx_context __user * ctx)30861650023SHuacai Chen static int restore_hw_lsx_context(struct lsx_context __user *ctx)
30961650023SHuacai Chen {
31061650023SHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
31161650023SHuacai Chen 	uint64_t __user *fcc	= &ctx->fcc;
31261650023SHuacai Chen 	uint32_t __user *fcsr	= &ctx->fcsr;
31361650023SHuacai Chen 
31461650023SHuacai Chen 	return _restore_lsx_context(regs, fcc, fcsr);
31561650023SHuacai Chen }
31661650023SHuacai Chen 
save_hw_lasx_context(struct lasx_context __user * ctx)31761650023SHuacai Chen static int save_hw_lasx_context(struct lasx_context __user *ctx)
31861650023SHuacai Chen {
31961650023SHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
32061650023SHuacai Chen 	uint64_t __user *fcc	= &ctx->fcc;
32161650023SHuacai Chen 	uint32_t __user *fcsr	= &ctx->fcsr;
32261650023SHuacai Chen 
32361650023SHuacai Chen 	return _save_lasx_context(regs, fcc, fcsr);
32461650023SHuacai Chen }
32561650023SHuacai Chen 
restore_hw_lasx_context(struct lasx_context __user * ctx)32661650023SHuacai Chen static int restore_hw_lasx_context(struct lasx_context __user *ctx)
32761650023SHuacai Chen {
32861650023SHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
32961650023SHuacai Chen 	uint64_t __user *fcc	= &ctx->fcc;
33061650023SHuacai Chen 	uint32_t __user *fcsr	= &ctx->fcsr;
33161650023SHuacai Chen 
33261650023SHuacai Chen 	return _restore_lasx_context(regs, fcc, fcsr);
33361650023SHuacai Chen }
33461650023SHuacai Chen 
335bd3c5798SQi Hu /*
336bd3c5798SQi Hu  * Wrappers for the assembly _{save,restore}_lbt_context functions.
337bd3c5798SQi Hu  */
338bd3c5798SQi Hu #ifdef CONFIG_CPU_HAS_LBT
save_hw_lbt_context(struct lbt_context __user * ctx)339bd3c5798SQi Hu static int save_hw_lbt_context(struct lbt_context __user *ctx)
340bd3c5798SQi Hu {
341bd3c5798SQi Hu 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
342bd3c5798SQi Hu 	uint32_t __user *eflags	= (uint32_t *)&ctx->eflags;
343bd3c5798SQi Hu 
344bd3c5798SQi Hu 	return _save_lbt_context(regs, eflags);
345bd3c5798SQi Hu }
346bd3c5798SQi Hu 
restore_hw_lbt_context(struct lbt_context __user * ctx)347bd3c5798SQi Hu static int restore_hw_lbt_context(struct lbt_context __user *ctx)
348bd3c5798SQi Hu {
349bd3c5798SQi Hu 	uint64_t __user *regs	= (uint64_t *)&ctx->regs;
350bd3c5798SQi Hu 	uint32_t __user *eflags	= (uint32_t *)&ctx->eflags;
351bd3c5798SQi Hu 
352bd3c5798SQi Hu 	return _restore_lbt_context(regs, eflags);
353bd3c5798SQi Hu }
354bd3c5798SQi Hu 
save_hw_ftop_context(struct lbt_context __user * ctx)355bd3c5798SQi Hu static int save_hw_ftop_context(struct lbt_context __user *ctx)
356bd3c5798SQi Hu {
357bd3c5798SQi Hu 	uint32_t __user *ftop	= &ctx->ftop;
358bd3c5798SQi Hu 
359bd3c5798SQi Hu 	return _save_ftop_context(ftop);
360bd3c5798SQi Hu }
361bd3c5798SQi Hu 
restore_hw_ftop_context(struct lbt_context __user * ctx)362bd3c5798SQi Hu static int restore_hw_ftop_context(struct lbt_context __user *ctx)
363bd3c5798SQi Hu {
364bd3c5798SQi Hu 	uint32_t __user *ftop	= &ctx->ftop;
365bd3c5798SQi Hu 
366bd3c5798SQi Hu 	return _restore_ftop_context(ftop);
367bd3c5798SQi Hu }
368bd3c5798SQi Hu #endif
369bd3c5798SQi Hu 
fcsr_pending(unsigned int __user * fcsr)370b74baf4aSHuacai Chen static int fcsr_pending(unsigned int __user *fcsr)
371b74baf4aSHuacai Chen {
372b74baf4aSHuacai Chen 	int err, sig = 0;
373b74baf4aSHuacai Chen 	unsigned int csr, enabled;
374b74baf4aSHuacai Chen 
375b74baf4aSHuacai Chen 	err = __get_user(csr, fcsr);
376b74baf4aSHuacai Chen 	enabled = ((csr & FPU_CSR_ALL_E) << 24);
377b74baf4aSHuacai Chen 	/*
378b74baf4aSHuacai Chen 	 * If the signal handler set some FPU exceptions, clear it and
379b74baf4aSHuacai Chen 	 * send SIGFPE.
380b74baf4aSHuacai Chen 	 */
381b74baf4aSHuacai Chen 	if (csr & enabled) {
382b74baf4aSHuacai Chen 		csr &= ~enabled;
383b74baf4aSHuacai Chen 		err |= __put_user(csr, fcsr);
384b74baf4aSHuacai Chen 		sig = SIGFPE;
385b74baf4aSHuacai Chen 	}
386b74baf4aSHuacai Chen 	return err ?: sig;
387b74baf4aSHuacai Chen }
388b74baf4aSHuacai Chen 
389b74baf4aSHuacai Chen /*
390b74baf4aSHuacai Chen  * Helper routines
391b74baf4aSHuacai Chen  */
protected_save_fpu_context(struct extctx_layout * extctx)392b74baf4aSHuacai Chen static int protected_save_fpu_context(struct extctx_layout *extctx)
393b74baf4aSHuacai Chen {
394b74baf4aSHuacai Chen 	int err = 0;
395b74baf4aSHuacai Chen 	struct sctx_info __user *info = extctx->fpu.addr;
396b74baf4aSHuacai Chen 	struct fpu_context __user *fpu_ctx = (struct fpu_context *)get_ctx_through_ctxinfo(info);
397b74baf4aSHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&fpu_ctx->regs;
398b74baf4aSHuacai Chen 	uint64_t __user *fcc	= &fpu_ctx->fcc;
399b74baf4aSHuacai Chen 	uint32_t __user *fcsr	= &fpu_ctx->fcsr;
400b74baf4aSHuacai Chen 
401b74baf4aSHuacai Chen 	while (1) {
402b74baf4aSHuacai Chen 		lock_fpu_owner();
403b74baf4aSHuacai Chen 		if (is_fpu_owner())
404b74baf4aSHuacai Chen 			err = save_hw_fpu_context(fpu_ctx);
405b74baf4aSHuacai Chen 		else
406b74baf4aSHuacai Chen 			err = copy_fpu_to_sigcontext(fpu_ctx);
407b74baf4aSHuacai Chen 		unlock_fpu_owner();
408b74baf4aSHuacai Chen 
409b74baf4aSHuacai Chen 		err |= __put_user(FPU_CTX_MAGIC, &info->magic);
410b74baf4aSHuacai Chen 		err |= __put_user(extctx->fpu.size, &info->size);
411b74baf4aSHuacai Chen 
412b74baf4aSHuacai Chen 		if (likely(!err))
413b74baf4aSHuacai Chen 			break;
414b74baf4aSHuacai Chen 		/* Touch the FPU context and try again */
415b74baf4aSHuacai Chen 		err = __put_user(0, &regs[0]) |
416b74baf4aSHuacai Chen 			__put_user(0, &regs[31]) |
417b74baf4aSHuacai Chen 			__put_user(0, fcc) |
418b74baf4aSHuacai Chen 			__put_user(0, fcsr);
419b74baf4aSHuacai Chen 		if (err)
420b74baf4aSHuacai Chen 			return err;	/* really bad sigcontext */
421b74baf4aSHuacai Chen 	}
422b74baf4aSHuacai Chen 
423b74baf4aSHuacai Chen 	return err;
424b74baf4aSHuacai Chen }
425b74baf4aSHuacai Chen 
protected_restore_fpu_context(struct extctx_layout * extctx)426b74baf4aSHuacai Chen static int protected_restore_fpu_context(struct extctx_layout *extctx)
427b74baf4aSHuacai Chen {
428b74baf4aSHuacai Chen 	int err = 0, sig = 0, tmp __maybe_unused;
429b74baf4aSHuacai Chen 	struct sctx_info __user *info = extctx->fpu.addr;
430b74baf4aSHuacai Chen 	struct fpu_context __user *fpu_ctx = (struct fpu_context *)get_ctx_through_ctxinfo(info);
431b74baf4aSHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&fpu_ctx->regs;
432b74baf4aSHuacai Chen 	uint64_t __user *fcc	= &fpu_ctx->fcc;
433b74baf4aSHuacai Chen 	uint32_t __user *fcsr	= &fpu_ctx->fcsr;
434b74baf4aSHuacai Chen 
435b74baf4aSHuacai Chen 	err = sig = fcsr_pending(fcsr);
436b74baf4aSHuacai Chen 	if (err < 0)
437b74baf4aSHuacai Chen 		return err;
438b74baf4aSHuacai Chen 
439b74baf4aSHuacai Chen 	while (1) {
440b74baf4aSHuacai Chen 		lock_fpu_owner();
441b74baf4aSHuacai Chen 		if (is_fpu_owner())
442b74baf4aSHuacai Chen 			err = restore_hw_fpu_context(fpu_ctx);
443b74baf4aSHuacai Chen 		else
444b74baf4aSHuacai Chen 			err = copy_fpu_from_sigcontext(fpu_ctx);
445b74baf4aSHuacai Chen 		unlock_fpu_owner();
446b74baf4aSHuacai Chen 
447b74baf4aSHuacai Chen 		if (likely(!err))
448b74baf4aSHuacai Chen 			break;
449b74baf4aSHuacai Chen 		/* Touch the FPU context and try again */
450b74baf4aSHuacai Chen 		err = __get_user(tmp, &regs[0]) |
451b74baf4aSHuacai Chen 			__get_user(tmp, &regs[31]) |
452b74baf4aSHuacai Chen 			__get_user(tmp, fcc) |
453b74baf4aSHuacai Chen 			__get_user(tmp, fcsr);
454b74baf4aSHuacai Chen 		if (err)
455b74baf4aSHuacai Chen 			break;	/* really bad sigcontext */
456b74baf4aSHuacai Chen 	}
457b74baf4aSHuacai Chen 
458b74baf4aSHuacai Chen 	return err ?: sig;
459b74baf4aSHuacai Chen }
460b74baf4aSHuacai Chen 
protected_save_lsx_context(struct extctx_layout * extctx)46161650023SHuacai Chen static int protected_save_lsx_context(struct extctx_layout *extctx)
46261650023SHuacai Chen {
46361650023SHuacai Chen 	int err = 0;
46461650023SHuacai Chen 	struct sctx_info __user *info = extctx->lsx.addr;
46561650023SHuacai Chen 	struct lsx_context __user *lsx_ctx = (struct lsx_context *)get_ctx_through_ctxinfo(info);
46661650023SHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&lsx_ctx->regs;
46761650023SHuacai Chen 	uint64_t __user *fcc	= &lsx_ctx->fcc;
46861650023SHuacai Chen 	uint32_t __user *fcsr	= &lsx_ctx->fcsr;
46961650023SHuacai Chen 
47061650023SHuacai Chen 	while (1) {
47161650023SHuacai Chen 		lock_fpu_owner();
47261650023SHuacai Chen 		if (is_lsx_enabled())
47361650023SHuacai Chen 			err = save_hw_lsx_context(lsx_ctx);
47461650023SHuacai Chen 		else {
47561650023SHuacai Chen 			if (is_fpu_owner())
47661650023SHuacai Chen 				save_fp(current);
47761650023SHuacai Chen 			err = copy_lsx_to_sigcontext(lsx_ctx);
47861650023SHuacai Chen 		}
47961650023SHuacai Chen 		unlock_fpu_owner();
48061650023SHuacai Chen 
48161650023SHuacai Chen 		err |= __put_user(LSX_CTX_MAGIC, &info->magic);
48261650023SHuacai Chen 		err |= __put_user(extctx->lsx.size, &info->size);
48361650023SHuacai Chen 
48461650023SHuacai Chen 		if (likely(!err))
48561650023SHuacai Chen 			break;
48661650023SHuacai Chen 		/* Touch the LSX context and try again */
48761650023SHuacai Chen 		err = __put_user(0, &regs[0]) |
48861650023SHuacai Chen 			__put_user(0, &regs[32*2-1]) |
48961650023SHuacai Chen 			__put_user(0, fcc) |
49061650023SHuacai Chen 			__put_user(0, fcsr);
49161650023SHuacai Chen 		if (err)
49261650023SHuacai Chen 			return err;	/* really bad sigcontext */
49361650023SHuacai Chen 	}
49461650023SHuacai Chen 
49561650023SHuacai Chen 	return err;
49661650023SHuacai Chen }
49761650023SHuacai Chen 
protected_restore_lsx_context(struct extctx_layout * extctx)49861650023SHuacai Chen static int protected_restore_lsx_context(struct extctx_layout *extctx)
49961650023SHuacai Chen {
50061650023SHuacai Chen 	int err = 0, sig = 0, tmp __maybe_unused;
50161650023SHuacai Chen 	struct sctx_info __user *info = extctx->lsx.addr;
50261650023SHuacai Chen 	struct lsx_context __user *lsx_ctx = (struct lsx_context *)get_ctx_through_ctxinfo(info);
50361650023SHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&lsx_ctx->regs;
50461650023SHuacai Chen 	uint64_t __user *fcc	= &lsx_ctx->fcc;
50561650023SHuacai Chen 	uint32_t __user *fcsr	= &lsx_ctx->fcsr;
50661650023SHuacai Chen 
50761650023SHuacai Chen 	err = sig = fcsr_pending(fcsr);
50861650023SHuacai Chen 	if (err < 0)
50961650023SHuacai Chen 		return err;
51061650023SHuacai Chen 
51161650023SHuacai Chen 	while (1) {
51261650023SHuacai Chen 		lock_fpu_owner();
51361650023SHuacai Chen 		if (is_lsx_enabled())
51461650023SHuacai Chen 			err = restore_hw_lsx_context(lsx_ctx);
51561650023SHuacai Chen 		else {
51661650023SHuacai Chen 			err = copy_lsx_from_sigcontext(lsx_ctx);
51761650023SHuacai Chen 			if (is_fpu_owner())
51861650023SHuacai Chen 				restore_fp(current);
51961650023SHuacai Chen 		}
52061650023SHuacai Chen 		unlock_fpu_owner();
52161650023SHuacai Chen 
52261650023SHuacai Chen 		if (likely(!err))
52361650023SHuacai Chen 			break;
52461650023SHuacai Chen 		/* Touch the LSX context and try again */
52561650023SHuacai Chen 		err = __get_user(tmp, &regs[0]) |
52661650023SHuacai Chen 			__get_user(tmp, &regs[32*2-1]) |
52761650023SHuacai Chen 			__get_user(tmp, fcc) |
52861650023SHuacai Chen 			__get_user(tmp, fcsr);
52961650023SHuacai Chen 		if (err)
53061650023SHuacai Chen 			break;	/* really bad sigcontext */
53161650023SHuacai Chen 	}
53261650023SHuacai Chen 
53361650023SHuacai Chen 	return err ?: sig;
53461650023SHuacai Chen }
53561650023SHuacai Chen 
protected_save_lasx_context(struct extctx_layout * extctx)53661650023SHuacai Chen static int protected_save_lasx_context(struct extctx_layout *extctx)
53761650023SHuacai Chen {
53861650023SHuacai Chen 	int err = 0;
53961650023SHuacai Chen 	struct sctx_info __user *info = extctx->lasx.addr;
54061650023SHuacai Chen 	struct lasx_context __user *lasx_ctx =
54161650023SHuacai Chen 		(struct lasx_context *)get_ctx_through_ctxinfo(info);
54261650023SHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&lasx_ctx->regs;
54361650023SHuacai Chen 	uint64_t __user *fcc	= &lasx_ctx->fcc;
54461650023SHuacai Chen 	uint32_t __user *fcsr	= &lasx_ctx->fcsr;
54561650023SHuacai Chen 
54661650023SHuacai Chen 	while (1) {
54761650023SHuacai Chen 		lock_fpu_owner();
54861650023SHuacai Chen 		if (is_lasx_enabled())
54961650023SHuacai Chen 			err = save_hw_lasx_context(lasx_ctx);
55061650023SHuacai Chen 		else {
55161650023SHuacai Chen 			if (is_lsx_enabled())
55261650023SHuacai Chen 				save_lsx(current);
55361650023SHuacai Chen 			else if (is_fpu_owner())
55461650023SHuacai Chen 				save_fp(current);
55561650023SHuacai Chen 			err = copy_lasx_to_sigcontext(lasx_ctx);
55661650023SHuacai Chen 		}
55761650023SHuacai Chen 		unlock_fpu_owner();
55861650023SHuacai Chen 
55961650023SHuacai Chen 		err |= __put_user(LASX_CTX_MAGIC, &info->magic);
56061650023SHuacai Chen 		err |= __put_user(extctx->lasx.size, &info->size);
56161650023SHuacai Chen 
56261650023SHuacai Chen 		if (likely(!err))
56361650023SHuacai Chen 			break;
56461650023SHuacai Chen 		/* Touch the LASX context and try again */
56561650023SHuacai Chen 		err = __put_user(0, &regs[0]) |
56661650023SHuacai Chen 			__put_user(0, &regs[32*4-1]) |
56761650023SHuacai Chen 			__put_user(0, fcc) |
56861650023SHuacai Chen 			__put_user(0, fcsr);
56961650023SHuacai Chen 		if (err)
57061650023SHuacai Chen 			return err;	/* really bad sigcontext */
57161650023SHuacai Chen 	}
57261650023SHuacai Chen 
57361650023SHuacai Chen 	return err;
57461650023SHuacai Chen }
57561650023SHuacai Chen 
protected_restore_lasx_context(struct extctx_layout * extctx)57661650023SHuacai Chen static int protected_restore_lasx_context(struct extctx_layout *extctx)
57761650023SHuacai Chen {
57861650023SHuacai Chen 	int err = 0, sig = 0, tmp __maybe_unused;
57961650023SHuacai Chen 	struct sctx_info __user *info = extctx->lasx.addr;
58061650023SHuacai Chen 	struct lasx_context __user *lasx_ctx =
58161650023SHuacai Chen 		(struct lasx_context *)get_ctx_through_ctxinfo(info);
58261650023SHuacai Chen 	uint64_t __user *regs	= (uint64_t *)&lasx_ctx->regs;
58361650023SHuacai Chen 	uint64_t __user *fcc	= &lasx_ctx->fcc;
58461650023SHuacai Chen 	uint32_t __user *fcsr	= &lasx_ctx->fcsr;
58561650023SHuacai Chen 
58661650023SHuacai Chen 	err = sig = fcsr_pending(fcsr);
58761650023SHuacai Chen 	if (err < 0)
58861650023SHuacai Chen 		return err;
58961650023SHuacai Chen 
59061650023SHuacai Chen 	while (1) {
59161650023SHuacai Chen 		lock_fpu_owner();
59261650023SHuacai Chen 		if (is_lasx_enabled())
59361650023SHuacai Chen 			err = restore_hw_lasx_context(lasx_ctx);
59461650023SHuacai Chen 		else {
59561650023SHuacai Chen 			err = copy_lasx_from_sigcontext(lasx_ctx);
59661650023SHuacai Chen 			if (is_lsx_enabled())
59761650023SHuacai Chen 				restore_lsx(current);
59861650023SHuacai Chen 			else if (is_fpu_owner())
59961650023SHuacai Chen 				restore_fp(current);
60061650023SHuacai Chen 		}
60161650023SHuacai Chen 		unlock_fpu_owner();
60261650023SHuacai Chen 
60361650023SHuacai Chen 		if (likely(!err))
60461650023SHuacai Chen 			break;
60561650023SHuacai Chen 		/* Touch the LASX context and try again */
60661650023SHuacai Chen 		err = __get_user(tmp, &regs[0]) |
60761650023SHuacai Chen 			__get_user(tmp, &regs[32*4-1]) |
60861650023SHuacai Chen 			__get_user(tmp, fcc) |
60961650023SHuacai Chen 			__get_user(tmp, fcsr);
61061650023SHuacai Chen 		if (err)
61161650023SHuacai Chen 			break;	/* really bad sigcontext */
61261650023SHuacai Chen 	}
61361650023SHuacai Chen 
61461650023SHuacai Chen 	return err ?: sig;
61561650023SHuacai Chen }
61661650023SHuacai Chen 
617bd3c5798SQi Hu #ifdef CONFIG_CPU_HAS_LBT
protected_save_lbt_context(struct extctx_layout * extctx)618bd3c5798SQi Hu static int protected_save_lbt_context(struct extctx_layout *extctx)
619bd3c5798SQi Hu {
620bd3c5798SQi Hu 	int err = 0;
621bd3c5798SQi Hu 	struct sctx_info __user *info = extctx->lbt.addr;
622bd3c5798SQi Hu 	struct lbt_context __user *lbt_ctx =
623bd3c5798SQi Hu 		(struct lbt_context *)get_ctx_through_ctxinfo(info);
624bd3c5798SQi Hu 	uint64_t __user *regs	= (uint64_t *)&lbt_ctx->regs;
625bd3c5798SQi Hu 	uint32_t __user *eflags	= (uint32_t *)&lbt_ctx->eflags;
626bd3c5798SQi Hu 
627bd3c5798SQi Hu 	while (1) {
628bd3c5798SQi Hu 		lock_lbt_owner();
629bd3c5798SQi Hu 		if (is_lbt_owner())
630bd3c5798SQi Hu 			err |= save_hw_lbt_context(lbt_ctx);
631bd3c5798SQi Hu 		else
632bd3c5798SQi Hu 			err |= copy_lbt_to_sigcontext(lbt_ctx);
633bd3c5798SQi Hu 		if (is_fpu_owner())
634bd3c5798SQi Hu 			err |= save_hw_ftop_context(lbt_ctx);
635bd3c5798SQi Hu 		else
636bd3c5798SQi Hu 			err |= copy_ftop_to_sigcontext(lbt_ctx);
637bd3c5798SQi Hu 		unlock_lbt_owner();
638bd3c5798SQi Hu 
639bd3c5798SQi Hu 		err |= __put_user(LBT_CTX_MAGIC, &info->magic);
640bd3c5798SQi Hu 		err |= __put_user(extctx->lbt.size, &info->size);
641bd3c5798SQi Hu 
642bd3c5798SQi Hu 		if (likely(!err))
643bd3c5798SQi Hu 			break;
644bd3c5798SQi Hu 		/* Touch the LBT context and try again */
645bd3c5798SQi Hu 		err = __put_user(0, &regs[0]) | __put_user(0, eflags);
646bd3c5798SQi Hu 
647bd3c5798SQi Hu 		if (err)
648bd3c5798SQi Hu 			return err;
649bd3c5798SQi Hu 	}
650bd3c5798SQi Hu 
651bd3c5798SQi Hu 	return err;
652bd3c5798SQi Hu }
653bd3c5798SQi Hu 
protected_restore_lbt_context(struct extctx_layout * extctx)654bd3c5798SQi Hu static int protected_restore_lbt_context(struct extctx_layout *extctx)
655bd3c5798SQi Hu {
656bd3c5798SQi Hu 	int err = 0, tmp __maybe_unused;
657bd3c5798SQi Hu 	struct sctx_info __user *info = extctx->lbt.addr;
658bd3c5798SQi Hu 	struct lbt_context __user *lbt_ctx =
659bd3c5798SQi Hu 		(struct lbt_context *)get_ctx_through_ctxinfo(info);
660bd3c5798SQi Hu 	uint64_t __user *regs	= (uint64_t *)&lbt_ctx->regs;
661bd3c5798SQi Hu 	uint32_t __user *eflags	= (uint32_t *)&lbt_ctx->eflags;
662bd3c5798SQi Hu 
663bd3c5798SQi Hu 	while (1) {
664bd3c5798SQi Hu 		lock_lbt_owner();
665bd3c5798SQi Hu 		if (is_lbt_owner())
666bd3c5798SQi Hu 			err |= restore_hw_lbt_context(lbt_ctx);
667bd3c5798SQi Hu 		else
668bd3c5798SQi Hu 			err |= copy_lbt_from_sigcontext(lbt_ctx);
669bd3c5798SQi Hu 		if (is_fpu_owner())
670bd3c5798SQi Hu 			err |= restore_hw_ftop_context(lbt_ctx);
671bd3c5798SQi Hu 		else
672bd3c5798SQi Hu 			err |= copy_ftop_from_sigcontext(lbt_ctx);
673bd3c5798SQi Hu 		unlock_lbt_owner();
674bd3c5798SQi Hu 
675bd3c5798SQi Hu 		if (likely(!err))
676bd3c5798SQi Hu 			break;
677bd3c5798SQi Hu 		/* Touch the LBT context and try again */
678bd3c5798SQi Hu 		err = __get_user(tmp, &regs[0]) | __get_user(tmp, eflags);
679bd3c5798SQi Hu 
680bd3c5798SQi Hu 		if (err)
681bd3c5798SQi Hu 			return err;
682bd3c5798SQi Hu 	}
683bd3c5798SQi Hu 
684bd3c5798SQi Hu 	return err;
685bd3c5798SQi Hu }
686bd3c5798SQi Hu #endif
687bd3c5798SQi Hu 
setup_sigcontext(struct pt_regs * regs,struct sigcontext __user * sc,struct extctx_layout * extctx)688b74baf4aSHuacai Chen static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
689b74baf4aSHuacai Chen 			    struct extctx_layout *extctx)
690b74baf4aSHuacai Chen {
691b74baf4aSHuacai Chen 	int i, err = 0;
692b74baf4aSHuacai Chen 	struct sctx_info __user *info;
693b74baf4aSHuacai Chen 
694b74baf4aSHuacai Chen 	err |= __put_user(regs->csr_era, &sc->sc_pc);
695b74baf4aSHuacai Chen 	err |= __put_user(extctx->flags, &sc->sc_flags);
696b74baf4aSHuacai Chen 
697b74baf4aSHuacai Chen 	err |= __put_user(0, &sc->sc_regs[0]);
698b74baf4aSHuacai Chen 	for (i = 1; i < 32; i++)
699b74baf4aSHuacai Chen 		err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
700b74baf4aSHuacai Chen 
70161650023SHuacai Chen 	if (extctx->lasx.addr)
70261650023SHuacai Chen 		err |= protected_save_lasx_context(extctx);
70361650023SHuacai Chen 	else if (extctx->lsx.addr)
70461650023SHuacai Chen 		err |= protected_save_lsx_context(extctx);
70561650023SHuacai Chen 	else if (extctx->fpu.addr)
706b74baf4aSHuacai Chen 		err |= protected_save_fpu_context(extctx);
707b74baf4aSHuacai Chen 
708bd3c5798SQi Hu #ifdef CONFIG_CPU_HAS_LBT
709bd3c5798SQi Hu 	if (extctx->lbt.addr)
710bd3c5798SQi Hu 		err |= protected_save_lbt_context(extctx);
711bd3c5798SQi Hu #endif
712bd3c5798SQi Hu 
713b74baf4aSHuacai Chen 	/* Set the "end" magic */
714b74baf4aSHuacai Chen 	info = (struct sctx_info *)extctx->end.addr;
715b74baf4aSHuacai Chen 	err |= __put_user(0, &info->magic);
716b74baf4aSHuacai Chen 	err |= __put_user(0, &info->size);
717b74baf4aSHuacai Chen 
718b74baf4aSHuacai Chen 	return err;
719b74baf4aSHuacai Chen }
720b74baf4aSHuacai Chen 
parse_extcontext(struct sigcontext __user * sc,struct extctx_layout * extctx)721b74baf4aSHuacai Chen static int parse_extcontext(struct sigcontext __user *sc, struct extctx_layout *extctx)
722b74baf4aSHuacai Chen {
723b74baf4aSHuacai Chen 	int err = 0;
724b74baf4aSHuacai Chen 	unsigned int magic, size;
725b74baf4aSHuacai Chen 	struct sctx_info __user *info = (struct sctx_info __user *)&sc->sc_extcontext;
726b74baf4aSHuacai Chen 
727b74baf4aSHuacai Chen 	while(1) {
728b74baf4aSHuacai Chen 		err |= __get_user(magic, &info->magic);
729b74baf4aSHuacai Chen 		err |= __get_user(size, &info->size);
730b74baf4aSHuacai Chen 		if (err)
731b74baf4aSHuacai Chen 			return err;
732b74baf4aSHuacai Chen 
733b74baf4aSHuacai Chen 		switch (magic) {
734b74baf4aSHuacai Chen 		case 0: /* END */
735b74baf4aSHuacai Chen 			goto done;
736b74baf4aSHuacai Chen 
737b74baf4aSHuacai Chen 		case FPU_CTX_MAGIC:
738b74baf4aSHuacai Chen 			if (size < (sizeof(struct sctx_info) +
739b74baf4aSHuacai Chen 				    sizeof(struct fpu_context)))
740b74baf4aSHuacai Chen 				goto invalid;
741b74baf4aSHuacai Chen 			extctx->fpu.addr = info;
742b74baf4aSHuacai Chen 			break;
743b74baf4aSHuacai Chen 
74461650023SHuacai Chen 		case LSX_CTX_MAGIC:
74561650023SHuacai Chen 			if (size < (sizeof(struct sctx_info) +
74661650023SHuacai Chen 				    sizeof(struct lsx_context)))
74761650023SHuacai Chen 				goto invalid;
74861650023SHuacai Chen 			extctx->lsx.addr = info;
74961650023SHuacai Chen 			break;
75061650023SHuacai Chen 
75161650023SHuacai Chen 		case LASX_CTX_MAGIC:
75261650023SHuacai Chen 			if (size < (sizeof(struct sctx_info) +
75361650023SHuacai Chen 				    sizeof(struct lasx_context)))
75461650023SHuacai Chen 				goto invalid;
75561650023SHuacai Chen 			extctx->lasx.addr = info;
75661650023SHuacai Chen 			break;
75761650023SHuacai Chen 
758bd3c5798SQi Hu 		case LBT_CTX_MAGIC:
759bd3c5798SQi Hu 			if (size < (sizeof(struct sctx_info) +
760bd3c5798SQi Hu 				    sizeof(struct lbt_context)))
761bd3c5798SQi Hu 				goto invalid;
762bd3c5798SQi Hu 			extctx->lbt.addr = info;
763bd3c5798SQi Hu 			break;
764bd3c5798SQi Hu 
765b74baf4aSHuacai Chen 		default:
766b74baf4aSHuacai Chen 			goto invalid;
767b74baf4aSHuacai Chen 		}
768b74baf4aSHuacai Chen 
769b74baf4aSHuacai Chen 		info = (struct sctx_info *)((char *)info + size);
770b74baf4aSHuacai Chen 	}
771b74baf4aSHuacai Chen 
772b74baf4aSHuacai Chen done:
773b74baf4aSHuacai Chen 	return 0;
774b74baf4aSHuacai Chen 
775b74baf4aSHuacai Chen invalid:
776b74baf4aSHuacai Chen 	return -EINVAL;
777b74baf4aSHuacai Chen }
778b74baf4aSHuacai Chen 
restore_sigcontext(struct pt_regs * regs,struct sigcontext __user * sc)779b74baf4aSHuacai Chen static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
780b74baf4aSHuacai Chen {
781b74baf4aSHuacai Chen 	int i, err = 0;
782b74baf4aSHuacai Chen 	struct extctx_layout extctx;
783b74baf4aSHuacai Chen 
784b74baf4aSHuacai Chen 	memset(&extctx, 0, sizeof(struct extctx_layout));
785b74baf4aSHuacai Chen 
786b74baf4aSHuacai Chen 	err = __get_user(extctx.flags, &sc->sc_flags);
787b74baf4aSHuacai Chen 	if (err)
788b74baf4aSHuacai Chen 		goto bad;
789b74baf4aSHuacai Chen 
790b74baf4aSHuacai Chen 	err = parse_extcontext(sc, &extctx);
791b74baf4aSHuacai Chen 	if (err)
792b74baf4aSHuacai Chen 		goto bad;
793b74baf4aSHuacai Chen 
794b74baf4aSHuacai Chen 	conditional_used_math(extctx.flags & SC_USED_FP);
795b74baf4aSHuacai Chen 
796b74baf4aSHuacai Chen 	/*
797b74baf4aSHuacai Chen 	 * The signal handler may have used FPU; give it up if the program
798b74baf4aSHuacai Chen 	 * doesn't want it following sigreturn.
799b74baf4aSHuacai Chen 	 */
800b74baf4aSHuacai Chen 	if (!(extctx.flags & SC_USED_FP))
801b74baf4aSHuacai Chen 		lose_fpu(0);
802b74baf4aSHuacai Chen 
803b74baf4aSHuacai Chen 	/* Always make any pending restarted system calls return -EINTR */
804b74baf4aSHuacai Chen 	current->restart_block.fn = do_no_restart_syscall;
805b74baf4aSHuacai Chen 
806b74baf4aSHuacai Chen 	err |= __get_user(regs->csr_era, &sc->sc_pc);
807b74baf4aSHuacai Chen 	for (i = 1; i < 32; i++)
808b74baf4aSHuacai Chen 		err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
809b74baf4aSHuacai Chen 
81061650023SHuacai Chen 	if (extctx.lasx.addr)
81161650023SHuacai Chen 		err |= protected_restore_lasx_context(&extctx);
81261650023SHuacai Chen 	else if (extctx.lsx.addr)
81361650023SHuacai Chen 		err |= protected_restore_lsx_context(&extctx);
81461650023SHuacai Chen 	else if (extctx.fpu.addr)
815b74baf4aSHuacai Chen 		err |= protected_restore_fpu_context(&extctx);
816b74baf4aSHuacai Chen 
817bd3c5798SQi Hu #ifdef CONFIG_CPU_HAS_LBT
818bd3c5798SQi Hu 	if (extctx.lbt.addr)
819bd3c5798SQi Hu 		err |= protected_restore_lbt_context(&extctx);
820bd3c5798SQi Hu #endif
821bd3c5798SQi Hu 
822b74baf4aSHuacai Chen bad:
823b74baf4aSHuacai Chen 	return err;
824b74baf4aSHuacai Chen }
825b74baf4aSHuacai Chen 
handle_flags(void)826b74baf4aSHuacai Chen static unsigned int handle_flags(void)
827b74baf4aSHuacai Chen {
828b74baf4aSHuacai Chen 	unsigned int flags = 0;
829b74baf4aSHuacai Chen 
830b74baf4aSHuacai Chen 	flags = used_math() ? SC_USED_FP : 0;
831b74baf4aSHuacai Chen 
832b74baf4aSHuacai Chen 	switch (current->thread.error_code) {
833b74baf4aSHuacai Chen 	case 1:
834b74baf4aSHuacai Chen 		flags |= SC_ADDRERR_RD;
835b74baf4aSHuacai Chen 		break;
836b74baf4aSHuacai Chen 	case 2:
837b74baf4aSHuacai Chen 		flags |= SC_ADDRERR_WR;
838b74baf4aSHuacai Chen 		break;
839b74baf4aSHuacai Chen 	}
840b74baf4aSHuacai Chen 
841b74baf4aSHuacai Chen 	return flags;
842b74baf4aSHuacai Chen }
843b74baf4aSHuacai Chen 
extframe_alloc(struct extctx_layout * extctx,struct _ctx_layout * layout,size_t size,unsigned int align,unsigned long base)844b74baf4aSHuacai Chen static unsigned long extframe_alloc(struct extctx_layout *extctx,
845b74baf4aSHuacai Chen 				    struct _ctx_layout *layout,
846b74baf4aSHuacai Chen 				    size_t size, unsigned int align, unsigned long base)
847b74baf4aSHuacai Chen {
848b74baf4aSHuacai Chen 	unsigned long new_base = base - size;
849b74baf4aSHuacai Chen 
850b74baf4aSHuacai Chen 	new_base = round_down(new_base, (align < 16 ? 16 : align));
851b74baf4aSHuacai Chen 	new_base -= sizeof(struct sctx_info);
852b74baf4aSHuacai Chen 
853b74baf4aSHuacai Chen 	layout->addr = (void *)new_base;
854b74baf4aSHuacai Chen 	layout->size = (unsigned int)(base - new_base);
855b74baf4aSHuacai Chen 	extctx->size += layout->size;
856b74baf4aSHuacai Chen 
857b74baf4aSHuacai Chen 	return new_base;
858b74baf4aSHuacai Chen }
859b74baf4aSHuacai Chen 
setup_extcontext(struct extctx_layout * extctx,unsigned long sp)860b74baf4aSHuacai Chen static unsigned long setup_extcontext(struct extctx_layout *extctx, unsigned long sp)
861b74baf4aSHuacai Chen {
862b74baf4aSHuacai Chen 	unsigned long new_sp = sp;
863b74baf4aSHuacai Chen 
864b74baf4aSHuacai Chen 	memset(extctx, 0, sizeof(struct extctx_layout));
865b74baf4aSHuacai Chen 
866b74baf4aSHuacai Chen 	extctx->flags = handle_flags();
867b74baf4aSHuacai Chen 
868b74baf4aSHuacai Chen 	/* Grow down, alloc "end" context info first. */
869b74baf4aSHuacai Chen 	new_sp -= sizeof(struct sctx_info);
870b74baf4aSHuacai Chen 	extctx->end.addr = (void *)new_sp;
871b74baf4aSHuacai Chen 	extctx->end.size = (unsigned int)sizeof(struct sctx_info);
872b74baf4aSHuacai Chen 	extctx->size += extctx->end.size;
873b74baf4aSHuacai Chen 
874b74baf4aSHuacai Chen 	if (extctx->flags & SC_USED_FP) {
87561650023SHuacai Chen 		if (cpu_has_lasx && thread_lasx_context_live())
87661650023SHuacai Chen 			new_sp = extframe_alloc(extctx, &extctx->lasx,
87761650023SHuacai Chen 			  sizeof(struct lasx_context), LASX_CTX_ALIGN, new_sp);
87861650023SHuacai Chen 		else if (cpu_has_lsx && thread_lsx_context_live())
87961650023SHuacai Chen 			new_sp = extframe_alloc(extctx, &extctx->lsx,
88061650023SHuacai Chen 			  sizeof(struct lsx_context), LSX_CTX_ALIGN, new_sp);
88161650023SHuacai Chen 		else if (cpu_has_fpu)
882b74baf4aSHuacai Chen 			new_sp = extframe_alloc(extctx, &extctx->fpu,
883b74baf4aSHuacai Chen 			  sizeof(struct fpu_context), FPU_CTX_ALIGN, new_sp);
884b74baf4aSHuacai Chen 	}
885b74baf4aSHuacai Chen 
886bd3c5798SQi Hu #ifdef CONFIG_CPU_HAS_LBT
887bd3c5798SQi Hu 	if (cpu_has_lbt && thread_lbt_context_live()) {
888bd3c5798SQi Hu 		new_sp = extframe_alloc(extctx, &extctx->lbt,
889bd3c5798SQi Hu 			  sizeof(struct lbt_context), LBT_CTX_ALIGN, new_sp);
890bd3c5798SQi Hu 	}
891bd3c5798SQi Hu #endif
892bd3c5798SQi Hu 
893b74baf4aSHuacai Chen 	return new_sp;
894b74baf4aSHuacai Chen }
895b74baf4aSHuacai Chen 
get_sigframe(struct ksignal * ksig,struct pt_regs * regs,struct extctx_layout * extctx)896c718a0baSBibo Mao static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
897b74baf4aSHuacai Chen 				 struct extctx_layout *extctx)
898b74baf4aSHuacai Chen {
899b74baf4aSHuacai Chen 	unsigned long sp;
900b74baf4aSHuacai Chen 
901b74baf4aSHuacai Chen 	/* Default to using normal stack */
902b74baf4aSHuacai Chen 	sp = regs->regs[3];
903b74baf4aSHuacai Chen 
904b74baf4aSHuacai Chen 	/*
905b74baf4aSHuacai Chen 	 * If we are on the alternate signal stack and would overflow it, don't.
906b74baf4aSHuacai Chen 	 * Return an always-bogus address instead so we will die with SIGSEGV.
907b74baf4aSHuacai Chen 	 */
908b74baf4aSHuacai Chen 	if (on_sig_stack(sp) &&
909b74baf4aSHuacai Chen 	    !likely(on_sig_stack(sp - sizeof(struct rt_sigframe))))
910b74baf4aSHuacai Chen 		return (void __user __force *)(-1UL);
911b74baf4aSHuacai Chen 
912b74baf4aSHuacai Chen 	sp = sigsp(sp, ksig);
913b74baf4aSHuacai Chen 	sp = round_down(sp, 16);
914b74baf4aSHuacai Chen 	sp = setup_extcontext(extctx, sp);
915b74baf4aSHuacai Chen 	sp -= sizeof(struct rt_sigframe);
916b74baf4aSHuacai Chen 
917b74baf4aSHuacai Chen 	if (!IS_ALIGNED(sp, 16))
918b74baf4aSHuacai Chen 		BUG();
919b74baf4aSHuacai Chen 
920b74baf4aSHuacai Chen 	return (void __user *)sp;
921b74baf4aSHuacai Chen }
922b74baf4aSHuacai Chen 
923b74baf4aSHuacai Chen /*
924b74baf4aSHuacai Chen  * Atomically swap in the new signal mask, and wait for a signal.
925b74baf4aSHuacai Chen  */
926b74baf4aSHuacai Chen 
SYSCALL_DEFINE0(rt_sigreturn)927c718a0baSBibo Mao SYSCALL_DEFINE0(rt_sigreturn)
928b74baf4aSHuacai Chen {
929b74baf4aSHuacai Chen 	int sig;
930b74baf4aSHuacai Chen 	sigset_t set;
931b74baf4aSHuacai Chen 	struct pt_regs *regs;
932b74baf4aSHuacai Chen 	struct rt_sigframe __user *frame;
933b74baf4aSHuacai Chen 
934b74baf4aSHuacai Chen 	regs = current_pt_regs();
935b74baf4aSHuacai Chen 	frame = (struct rt_sigframe __user *)regs->regs[3];
936b74baf4aSHuacai Chen 	if (!access_ok(frame, sizeof(*frame)))
937b74baf4aSHuacai Chen 		goto badframe;
938b74baf4aSHuacai Chen 	if (__copy_from_user(&set, &frame->rs_uctx.uc_sigmask, sizeof(set)))
939b74baf4aSHuacai Chen 		goto badframe;
940b74baf4aSHuacai Chen 
941b74baf4aSHuacai Chen 	set_current_blocked(&set);
942b74baf4aSHuacai Chen 
943b74baf4aSHuacai Chen 	sig = restore_sigcontext(regs, &frame->rs_uctx.uc_mcontext);
944b74baf4aSHuacai Chen 	if (sig < 0)
945b74baf4aSHuacai Chen 		goto badframe;
946b74baf4aSHuacai Chen 	else if (sig)
947b74baf4aSHuacai Chen 		force_sig(sig);
948b74baf4aSHuacai Chen 
949b74baf4aSHuacai Chen 	regs->regs[0] = 0; /* No syscall restarting */
950b74baf4aSHuacai Chen 	if (restore_altstack(&frame->rs_uctx.uc_stack))
951b74baf4aSHuacai Chen 		goto badframe;
952b74baf4aSHuacai Chen 
953b74baf4aSHuacai Chen 	return regs->regs[4];
954b74baf4aSHuacai Chen 
955b74baf4aSHuacai Chen badframe:
956b74baf4aSHuacai Chen 	force_sig(SIGSEGV);
957b74baf4aSHuacai Chen 	return 0;
958b74baf4aSHuacai Chen }
959b74baf4aSHuacai Chen 
setup_rt_frame(void * sig_return,struct ksignal * ksig,struct pt_regs * regs,sigset_t * set)960b74baf4aSHuacai Chen static int setup_rt_frame(void *sig_return, struct ksignal *ksig,
961b74baf4aSHuacai Chen 			  struct pt_regs *regs, sigset_t *set)
962b74baf4aSHuacai Chen {
963b74baf4aSHuacai Chen 	int err = 0;
964b74baf4aSHuacai Chen 	struct extctx_layout extctx;
965b74baf4aSHuacai Chen 	struct rt_sigframe __user *frame;
966b74baf4aSHuacai Chen 
967b74baf4aSHuacai Chen 	frame = get_sigframe(ksig, regs, &extctx);
968b74baf4aSHuacai Chen 	if (!access_ok(frame, sizeof(*frame) + extctx.size))
969b74baf4aSHuacai Chen 		return -EFAULT;
970b74baf4aSHuacai Chen 
971b74baf4aSHuacai Chen 	/* Create siginfo.  */
972b74baf4aSHuacai Chen 	err |= copy_siginfo_to_user(&frame->rs_info, &ksig->info);
973b74baf4aSHuacai Chen 
974b74baf4aSHuacai Chen 	/* Create the ucontext.	 */
975b74baf4aSHuacai Chen 	err |= __put_user(0, &frame->rs_uctx.uc_flags);
976b74baf4aSHuacai Chen 	err |= __put_user(NULL, &frame->rs_uctx.uc_link);
977b74baf4aSHuacai Chen 	err |= __save_altstack(&frame->rs_uctx.uc_stack, regs->regs[3]);
978b74baf4aSHuacai Chen 	err |= setup_sigcontext(regs, &frame->rs_uctx.uc_mcontext, &extctx);
979b74baf4aSHuacai Chen 	err |= __copy_to_user(&frame->rs_uctx.uc_sigmask, set, sizeof(*set));
980b74baf4aSHuacai Chen 
981b74baf4aSHuacai Chen 	if (err)
982b74baf4aSHuacai Chen 		return -EFAULT;
983b74baf4aSHuacai Chen 
984b74baf4aSHuacai Chen 	/*
985b74baf4aSHuacai Chen 	 * Arguments to signal handler:
986b74baf4aSHuacai Chen 	 *
987b74baf4aSHuacai Chen 	 *   a0 = signal number
988b74baf4aSHuacai Chen 	 *   a1 = pointer to siginfo
989b74baf4aSHuacai Chen 	 *   a2 = pointer to ucontext
990b74baf4aSHuacai Chen 	 *
991b74baf4aSHuacai Chen 	 * c0_era point to the signal handler, $r3 (sp) points to
992b74baf4aSHuacai Chen 	 * the struct rt_sigframe.
993b74baf4aSHuacai Chen 	 */
994b74baf4aSHuacai Chen 	regs->regs[4] = ksig->sig;
995b74baf4aSHuacai Chen 	regs->regs[5] = (unsigned long) &frame->rs_info;
996b74baf4aSHuacai Chen 	regs->regs[6] = (unsigned long) &frame->rs_uctx;
997b74baf4aSHuacai Chen 	regs->regs[3] = (unsigned long) frame;
998b74baf4aSHuacai Chen 	regs->regs[1] = (unsigned long) sig_return;
999b74baf4aSHuacai Chen 	regs->csr_era = (unsigned long) ksig->ka.sa.sa_handler;
1000b74baf4aSHuacai Chen 
1001b74baf4aSHuacai Chen 	DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
1002b74baf4aSHuacai Chen 	       current->comm, current->pid,
1003b74baf4aSHuacai Chen 	       frame, regs->csr_era, regs->regs[1]);
1004b74baf4aSHuacai Chen 
1005b74baf4aSHuacai Chen 	return 0;
1006b74baf4aSHuacai Chen }
1007b74baf4aSHuacai Chen 
handle_signal(struct ksignal * ksig,struct pt_regs * regs)1008b74baf4aSHuacai Chen static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
1009b74baf4aSHuacai Chen {
1010b74baf4aSHuacai Chen 	int ret;
1011b74baf4aSHuacai Chen 	sigset_t *oldset = sigmask_to_save();
1012b74baf4aSHuacai Chen 	void *vdso = current->mm->context.vdso;
1013b74baf4aSHuacai Chen 
1014b74baf4aSHuacai Chen 	/* Are we from a system call? */
1015b74baf4aSHuacai Chen 	if (regs->regs[0]) {
1016b74baf4aSHuacai Chen 		switch (regs->regs[4]) {
1017b74baf4aSHuacai Chen 		case -ERESTART_RESTARTBLOCK:
1018b74baf4aSHuacai Chen 		case -ERESTARTNOHAND:
1019b74baf4aSHuacai Chen 			regs->regs[4] = -EINTR;
1020b74baf4aSHuacai Chen 			break;
1021b74baf4aSHuacai Chen 		case -ERESTARTSYS:
1022b74baf4aSHuacai Chen 			if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {
1023b74baf4aSHuacai Chen 				regs->regs[4] = -EINTR;
1024b74baf4aSHuacai Chen 				break;
1025b74baf4aSHuacai Chen 			}
1026b74baf4aSHuacai Chen 			fallthrough;
1027b74baf4aSHuacai Chen 		case -ERESTARTNOINTR:
1028b74baf4aSHuacai Chen 			regs->regs[4] = regs->orig_a0;
1029b74baf4aSHuacai Chen 			regs->csr_era -= 4;
1030b74baf4aSHuacai Chen 		}
1031b74baf4aSHuacai Chen 
1032b74baf4aSHuacai Chen 		regs->regs[0] = 0;	/* Don't deal with this again.	*/
1033b74baf4aSHuacai Chen 	}
1034b74baf4aSHuacai Chen 
1035b74baf4aSHuacai Chen 	rseq_signal_deliver(ksig, regs);
1036b74baf4aSHuacai Chen 
1037b74baf4aSHuacai Chen 	ret = setup_rt_frame(vdso + current->thread.vdso->offset_sigreturn, ksig, regs, oldset);
1038b74baf4aSHuacai Chen 
1039b74baf4aSHuacai Chen 	signal_setup_done(ret, ksig, 0);
1040b74baf4aSHuacai Chen }
1041b74baf4aSHuacai Chen 
arch_do_signal_or_restart(struct pt_regs * regs)104201630053SHuacai Chen void arch_do_signal_or_restart(struct pt_regs *regs)
1043b74baf4aSHuacai Chen {
1044b74baf4aSHuacai Chen 	struct ksignal ksig;
1045b74baf4aSHuacai Chen 
104601630053SHuacai Chen 	if (get_signal(&ksig)) {
1047b74baf4aSHuacai Chen 		/* Whee!  Actually deliver the signal.	*/
1048b74baf4aSHuacai Chen 		handle_signal(&ksig, regs);
1049b74baf4aSHuacai Chen 		return;
1050b74baf4aSHuacai Chen 	}
1051b74baf4aSHuacai Chen 
1052b74baf4aSHuacai Chen 	/* Are we from a system call? */
1053b74baf4aSHuacai Chen 	if (regs->regs[0]) {
1054b74baf4aSHuacai Chen 		switch (regs->regs[4]) {
1055b74baf4aSHuacai Chen 		case -ERESTARTNOHAND:
1056b74baf4aSHuacai Chen 		case -ERESTARTSYS:
1057b74baf4aSHuacai Chen 		case -ERESTARTNOINTR:
1058b74baf4aSHuacai Chen 			regs->regs[4] = regs->orig_a0;
1059b74baf4aSHuacai Chen 			regs->csr_era -= 4;
1060b74baf4aSHuacai Chen 			break;
1061b74baf4aSHuacai Chen 
1062b74baf4aSHuacai Chen 		case -ERESTART_RESTARTBLOCK:
1063b74baf4aSHuacai Chen 			regs->regs[4] = regs->orig_a0;
1064b74baf4aSHuacai Chen 			regs->regs[11] = __NR_restart_syscall;
1065b74baf4aSHuacai Chen 			regs->csr_era -= 4;
1066b74baf4aSHuacai Chen 			break;
1067b74baf4aSHuacai Chen 		}
1068b74baf4aSHuacai Chen 		regs->regs[0] = 0;	/* Don't deal with this again.	*/
1069b74baf4aSHuacai Chen 	}
1070b74baf4aSHuacai Chen 
1071b74baf4aSHuacai Chen 	/*
1072b74baf4aSHuacai Chen 	 * If there's no signal to deliver, we just put the saved sigmask
1073b74baf4aSHuacai Chen 	 * back
1074b74baf4aSHuacai Chen 	 */
1075b74baf4aSHuacai Chen 	restore_saved_sigmask();
1076b74baf4aSHuacai Chen }
1077