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