xref: /openbmc/linux/arch/mips/kernel/ptrace.c (revision e0d77d0f38aa60ca61b3ce6e60d64fad2aa0853d)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * This file is subject to the terms and conditions of the GNU General Public
31da177e4SLinus Torvalds  * License.  See the file "COPYING" in the main directory of this archive
41da177e4SLinus Torvalds  * for more details.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Copyright (C) 1992 Ross Biro
71da177e4SLinus Torvalds  * Copyright (C) Linus Torvalds
81da177e4SLinus Torvalds  * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
91da177e4SLinus Torvalds  * Copyright (C) 1996 David S. Miller
101da177e4SLinus Torvalds  * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
111da177e4SLinus Torvalds  * Copyright (C) 1999 MIPS Technologies, Inc.
121da177e4SLinus Torvalds  * Copyright (C) 2000 Ulf Carlsson
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  * At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
151da177e4SLinus Torvalds  * binaries.
161da177e4SLinus Torvalds  */
171da177e4SLinus Torvalds #include <linux/compiler.h>
18c3fc5cd5SRalf Baechle #include <linux/context_tracking.h>
197aeb753bSRalf Baechle #include <linux/elf.h>
201da177e4SLinus Torvalds #include <linux/kernel.h>
211da177e4SLinus Torvalds #include <linux/sched.h>
2268db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
231da177e4SLinus Torvalds #include <linux/mm.h>
241da177e4SLinus Torvalds #include <linux/errno.h>
251da177e4SLinus Torvalds #include <linux/ptrace.h>
267aeb753bSRalf Baechle #include <linux/regset.h>
271da177e4SLinus Torvalds #include <linux/smp.h>
281da177e4SLinus Torvalds #include <linux/security.h>
2940e084a5SRalf Baechle #include <linux/stddef.h>
30293c5bd1SRalf Baechle #include <linux/audit.h>
31293c5bd1SRalf Baechle #include <linux/seccomp.h>
321d7bf993SRalf Baechle #include <linux/ftrace.h>
331da177e4SLinus Torvalds 
34fdd12a80SJiaxun Yang #include <asm/branch.h>
35f8280c8dSRalf Baechle #include <asm/byteorder.h>
361da177e4SLinus Torvalds #include <asm/cpu.h>
379b26616cSMaciej W. Rozycki #include <asm/cpu-info.h>
38e50c0a8fSRalf Baechle #include <asm/dsp.h>
391da177e4SLinus Torvalds #include <asm/fpu.h>
401da177e4SLinus Torvalds #include <asm/mipsregs.h>
41101b3531SRalf Baechle #include <asm/mipsmtregs.h>
421da177e4SLinus Torvalds #include <asm/page.h>
4344109c60SMaciej W. Rozycki #include <asm/processor.h>
44bec9b2b2SRalf Baechle #include <asm/syscall.h>
457c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
461da177e4SLinus Torvalds #include <asm/bootinfo.h>
47ea3d710fSDaniel Jacobowitz #include <asm/reg.h>
481da177e4SLinus Torvalds 
491d7bf993SRalf Baechle #define CREATE_TRACE_POINTS
501d7bf993SRalf Baechle #include <trace/events/syscalls.h>
511d7bf993SRalf Baechle 
exception_ip(struct pt_regs * regs)52fdd12a80SJiaxun Yang unsigned long exception_ip(struct pt_regs *regs)
53fdd12a80SJiaxun Yang {
54fdd12a80SJiaxun Yang 	return exception_epc(regs);
55fdd12a80SJiaxun Yang }
56fdd12a80SJiaxun Yang EXPORT_SYMBOL(exception_ip);
57fdd12a80SJiaxun Yang 
581da177e4SLinus Torvalds /*
591da177e4SLinus Torvalds  * Called by kernel/ptrace.c when detaching..
601da177e4SLinus Torvalds  *
611da177e4SLinus Torvalds  * Make sure single step bits etc are not set.
621da177e4SLinus Torvalds  */
ptrace_disable(struct task_struct * child)631da177e4SLinus Torvalds void ptrace_disable(struct task_struct *child)
641da177e4SLinus Torvalds {
650926bf95SDavid Daney 	/* Don't load the watchpoint registers for the ex-child. */
660926bf95SDavid Daney 	clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds 
69ea3d710fSDaniel Jacobowitz /*
70ea3d710fSDaniel Jacobowitz  * Read a general register set.	 We always use the 64-bit format, even
71ea3d710fSDaniel Jacobowitz  * for 32-bit kernels and for 32-bit processes on a 64-bit kernel.
72ea3d710fSDaniel Jacobowitz  * Registers are sign extended to fill the available space.
73ea3d710fSDaniel Jacobowitz  */
ptrace_getregs(struct task_struct * child,struct user_pt_regs __user * data)74a79ebea6SAlex Smith int ptrace_getregs(struct task_struct *child, struct user_pt_regs __user *data)
75ea3d710fSDaniel Jacobowitz {
76ea3d710fSDaniel Jacobowitz 	struct pt_regs *regs;
77ea3d710fSDaniel Jacobowitz 	int i;
78ea3d710fSDaniel Jacobowitz 
7996d4f267SLinus Torvalds 	if (!access_ok(data, 38 * 8))
80ea3d710fSDaniel Jacobowitz 		return -EIO;
81ea3d710fSDaniel Jacobowitz 
8240bc9c67SAl Viro 	regs = task_pt_regs(child);
83ea3d710fSDaniel Jacobowitz 
84ea3d710fSDaniel Jacobowitz 	for (i = 0; i < 32; i++)
85a79ebea6SAlex Smith 		__put_user((long)regs->regs[i], (__s64 __user *)&data->regs[i]);
86a79ebea6SAlex Smith 	__put_user((long)regs->lo, (__s64 __user *)&data->lo);
87a79ebea6SAlex Smith 	__put_user((long)regs->hi, (__s64 __user *)&data->hi);
88a79ebea6SAlex Smith 	__put_user((long)regs->cp0_epc, (__s64 __user *)&data->cp0_epc);
89a79ebea6SAlex Smith 	__put_user((long)regs->cp0_badvaddr, (__s64 __user *)&data->cp0_badvaddr);
90a79ebea6SAlex Smith 	__put_user((long)regs->cp0_status, (__s64 __user *)&data->cp0_status);
91a79ebea6SAlex Smith 	__put_user((long)regs->cp0_cause, (__s64 __user *)&data->cp0_cause);
92ea3d710fSDaniel Jacobowitz 
93ea3d710fSDaniel Jacobowitz 	return 0;
94ea3d710fSDaniel Jacobowitz }
95ea3d710fSDaniel Jacobowitz 
96ea3d710fSDaniel Jacobowitz /*
97ea3d710fSDaniel Jacobowitz  * Write a general register set.  As for PTRACE_GETREGS, we always use
98ea3d710fSDaniel Jacobowitz  * the 64-bit format.  On a 32-bit kernel only the lower order half
99ea3d710fSDaniel Jacobowitz  * (according to endianness) will be used.
100ea3d710fSDaniel Jacobowitz  */
ptrace_setregs(struct task_struct * child,struct user_pt_regs __user * data)101a79ebea6SAlex Smith int ptrace_setregs(struct task_struct *child, struct user_pt_regs __user *data)
102ea3d710fSDaniel Jacobowitz {
103ea3d710fSDaniel Jacobowitz 	struct pt_regs *regs;
104ea3d710fSDaniel Jacobowitz 	int i;
105ea3d710fSDaniel Jacobowitz 
10696d4f267SLinus Torvalds 	if (!access_ok(data, 38 * 8))
107ea3d710fSDaniel Jacobowitz 		return -EIO;
108ea3d710fSDaniel Jacobowitz 
10940bc9c67SAl Viro 	regs = task_pt_regs(child);
110ea3d710fSDaniel Jacobowitz 
111ea3d710fSDaniel Jacobowitz 	for (i = 0; i < 32; i++)
112a79ebea6SAlex Smith 		__get_user(regs->regs[i], (__s64 __user *)&data->regs[i]);
113a79ebea6SAlex Smith 	__get_user(regs->lo, (__s64 __user *)&data->lo);
114a79ebea6SAlex Smith 	__get_user(regs->hi, (__s64 __user *)&data->hi);
115a79ebea6SAlex Smith 	__get_user(regs->cp0_epc, (__s64 __user *)&data->cp0_epc);
116ea3d710fSDaniel Jacobowitz 
117ea3d710fSDaniel Jacobowitz 	/* badvaddr, status, and cause may not be written.  */
118ea3d710fSDaniel Jacobowitz 
119de8cd0dcSJames Hogan 	/* System call number may have been changed */
120de8cd0dcSJames Hogan 	mips_syscall_update_nr(child, regs);
121de8cd0dcSJames Hogan 
122ea3d710fSDaniel Jacobowitz 	return 0;
123ea3d710fSDaniel Jacobowitz }
124ea3d710fSDaniel Jacobowitz 
ptrace_get_watch_regs(struct task_struct * child,struct pt_watch_regs __user * addr)1250926bf95SDavid Daney int ptrace_get_watch_regs(struct task_struct *child,
1260926bf95SDavid Daney 			  struct pt_watch_regs __user *addr)
1270926bf95SDavid Daney {
1280926bf95SDavid Daney 	enum pt_watch_style style;
1290926bf95SDavid Daney 	int i;
1300926bf95SDavid Daney 
13157c7ea51SAlex Smith 	if (!cpu_has_watch || boot_cpu_data.watch_reg_use_cnt == 0)
1320926bf95SDavid Daney 		return -EIO;
13396d4f267SLinus Torvalds 	if (!access_ok(addr, sizeof(struct pt_watch_regs)))
1340926bf95SDavid Daney 		return -EIO;
1350926bf95SDavid Daney 
1360926bf95SDavid Daney #ifdef CONFIG_32BIT
1370926bf95SDavid Daney 	style = pt_watch_style_mips32;
1380926bf95SDavid Daney #define WATCH_STYLE mips32
1390926bf95SDavid Daney #else
1400926bf95SDavid Daney 	style = pt_watch_style_mips64;
1410926bf95SDavid Daney #define WATCH_STYLE mips64
1420926bf95SDavid Daney #endif
1430926bf95SDavid Daney 
1440926bf95SDavid Daney 	__put_user(style, &addr->style);
14557c7ea51SAlex Smith 	__put_user(boot_cpu_data.watch_reg_use_cnt,
1460926bf95SDavid Daney 		   &addr->WATCH_STYLE.num_valid);
14757c7ea51SAlex Smith 	for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) {
1480926bf95SDavid Daney 		__put_user(child->thread.watch.mips3264.watchlo[i],
1490926bf95SDavid Daney 			   &addr->WATCH_STYLE.watchlo[i]);
15050af501cSJames Hogan 		__put_user(child->thread.watch.mips3264.watchhi[i] &
15150af501cSJames Hogan 				(MIPS_WATCHHI_MASK | MIPS_WATCHHI_IRW),
1520926bf95SDavid Daney 			   &addr->WATCH_STYLE.watchhi[i]);
15357c7ea51SAlex Smith 		__put_user(boot_cpu_data.watch_reg_masks[i],
1540926bf95SDavid Daney 			   &addr->WATCH_STYLE.watch_masks[i]);
1550926bf95SDavid Daney 	}
1560926bf95SDavid Daney 	for (; i < 8; i++) {
1570926bf95SDavid Daney 		__put_user(0, &addr->WATCH_STYLE.watchlo[i]);
1580926bf95SDavid Daney 		__put_user(0, &addr->WATCH_STYLE.watchhi[i]);
1590926bf95SDavid Daney 		__put_user(0, &addr->WATCH_STYLE.watch_masks[i]);
1600926bf95SDavid Daney 	}
1610926bf95SDavid Daney 
1620926bf95SDavid Daney 	return 0;
1630926bf95SDavid Daney }
1640926bf95SDavid Daney 
ptrace_set_watch_regs(struct task_struct * child,struct pt_watch_regs __user * addr)1650926bf95SDavid Daney int ptrace_set_watch_regs(struct task_struct *child,
1660926bf95SDavid Daney 			  struct pt_watch_regs __user *addr)
1670926bf95SDavid Daney {
1680926bf95SDavid Daney 	int i;
1690926bf95SDavid Daney 	int watch_active = 0;
1700926bf95SDavid Daney 	unsigned long lt[NUM_WATCH_REGS];
1710926bf95SDavid Daney 	u16 ht[NUM_WATCH_REGS];
1720926bf95SDavid Daney 
17357c7ea51SAlex Smith 	if (!cpu_has_watch || boot_cpu_data.watch_reg_use_cnt == 0)
1740926bf95SDavid Daney 		return -EIO;
17596d4f267SLinus Torvalds 	if (!access_ok(addr, sizeof(struct pt_watch_regs)))
1760926bf95SDavid Daney 		return -EIO;
1770926bf95SDavid Daney 	/* Check the values. */
17857c7ea51SAlex Smith 	for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) {
1790926bf95SDavid Daney 		__get_user(lt[i], &addr->WATCH_STYLE.watchlo[i]);
1800926bf95SDavid Daney #ifdef CONFIG_32BIT
1810926bf95SDavid Daney 		if (lt[i] & __UA_LIMIT)
1820926bf95SDavid Daney 			return -EINVAL;
1830926bf95SDavid Daney #else
1840926bf95SDavid Daney 		if (test_tsk_thread_flag(child, TIF_32BIT_ADDR)) {
1850926bf95SDavid Daney 			if (lt[i] & 0xffffffff80000000UL)
1860926bf95SDavid Daney 				return -EINVAL;
1870926bf95SDavid Daney 		} else {
1880926bf95SDavid Daney 			if (lt[i] & __UA_LIMIT)
1890926bf95SDavid Daney 				return -EINVAL;
1900926bf95SDavid Daney 		}
1910926bf95SDavid Daney #endif
1920926bf95SDavid Daney 		__get_user(ht[i], &addr->WATCH_STYLE.watchhi[i]);
19350af501cSJames Hogan 		if (ht[i] & ~MIPS_WATCHHI_MASK)
1940926bf95SDavid Daney 			return -EINVAL;
1950926bf95SDavid Daney 	}
1960926bf95SDavid Daney 	/* Install them. */
19757c7ea51SAlex Smith 	for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) {
19850af501cSJames Hogan 		if (lt[i] & MIPS_WATCHLO_IRW)
1990926bf95SDavid Daney 			watch_active = 1;
2000926bf95SDavid Daney 		child->thread.watch.mips3264.watchlo[i] = lt[i];
2010926bf95SDavid Daney 		/* Set the G bit. */
2020926bf95SDavid Daney 		child->thread.watch.mips3264.watchhi[i] = ht[i];
2030926bf95SDavid Daney 	}
2040926bf95SDavid Daney 
2050926bf95SDavid Daney 	if (watch_active)
2060926bf95SDavid Daney 		set_tsk_thread_flag(child, TIF_LOAD_WATCH);
2070926bf95SDavid Daney 	else
2080926bf95SDavid Daney 		clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
2090926bf95SDavid Daney 
2100926bf95SDavid Daney 	return 0;
2110926bf95SDavid Daney }
2120926bf95SDavid Daney 
2137aeb753bSRalf Baechle /* regset get/set implementations */
2147aeb753bSRalf Baechle 
215c23b3d1aSAlex Smith #if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
216c23b3d1aSAlex Smith 
gpr32_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)217c23b3d1aSAlex Smith static int gpr32_get(struct task_struct *target,
2187aeb753bSRalf Baechle 		     const struct user_regset *regset,
219a0faf966SAl Viro 		     struct membuf to)
2207aeb753bSRalf Baechle {
2217aeb753bSRalf Baechle 	struct pt_regs *regs = task_pt_regs(target);
222c23b3d1aSAlex Smith 	u32 uregs[ELF_NGREG] = {};
2237aeb753bSRalf Baechle 
22408c941bfSMarcin Nowakowski 	mips_dump_regs32(uregs, regs);
225a0faf966SAl Viro 	return membuf_write(&to, uregs, sizeof(uregs));
226c23b3d1aSAlex Smith }
227c23b3d1aSAlex Smith 
gpr32_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)228c23b3d1aSAlex Smith static int gpr32_set(struct task_struct *target,
2297aeb753bSRalf Baechle 		     const struct user_regset *regset,
2307aeb753bSRalf Baechle 		     unsigned int pos, unsigned int count,
2317aeb753bSRalf Baechle 		     const void *kbuf, const void __user *ubuf)
2327aeb753bSRalf Baechle {
233c23b3d1aSAlex Smith 	struct pt_regs *regs = task_pt_regs(target);
234c23b3d1aSAlex Smith 	u32 uregs[ELF_NGREG];
235c23b3d1aSAlex Smith 	unsigned start, num_regs, i;
236c23b3d1aSAlex Smith 	int err;
2377aeb753bSRalf Baechle 
238c23b3d1aSAlex Smith 	start = pos / sizeof(u32);
239c23b3d1aSAlex Smith 	num_regs = count / sizeof(u32);
2407aeb753bSRalf Baechle 
241c23b3d1aSAlex Smith 	if (start + num_regs > ELF_NGREG)
242c23b3d1aSAlex Smith 		return -EIO;
243c23b3d1aSAlex Smith 
244c23b3d1aSAlex Smith 	err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
245c23b3d1aSAlex Smith 				 sizeof(uregs));
246c23b3d1aSAlex Smith 	if (err)
247c23b3d1aSAlex Smith 		return err;
248c23b3d1aSAlex Smith 
249c23b3d1aSAlex Smith 	for (i = start; i < num_regs; i++) {
250c23b3d1aSAlex Smith 		/*
251c23b3d1aSAlex Smith 		 * Cast all values to signed here so that if this is a 64-bit
252c23b3d1aSAlex Smith 		 * kernel, the supplied 32-bit values will be sign extended.
253c23b3d1aSAlex Smith 		 */
254c23b3d1aSAlex Smith 		switch (i) {
255c23b3d1aSAlex Smith 		case MIPS32_EF_R1 ... MIPS32_EF_R25:
256c23b3d1aSAlex Smith 			/* k0/k1 are ignored. */
257c23b3d1aSAlex Smith 		case MIPS32_EF_R28 ... MIPS32_EF_R31:
258c23b3d1aSAlex Smith 			regs->regs[i - MIPS32_EF_R0] = (s32)uregs[i];
259c23b3d1aSAlex Smith 			break;
260c23b3d1aSAlex Smith 		case MIPS32_EF_LO:
261c23b3d1aSAlex Smith 			regs->lo = (s32)uregs[i];
262c23b3d1aSAlex Smith 			break;
263c23b3d1aSAlex Smith 		case MIPS32_EF_HI:
264c23b3d1aSAlex Smith 			regs->hi = (s32)uregs[i];
265c23b3d1aSAlex Smith 			break;
266c23b3d1aSAlex Smith 		case MIPS32_EF_CP0_EPC:
267c23b3d1aSAlex Smith 			regs->cp0_epc = (s32)uregs[i];
268c23b3d1aSAlex Smith 			break;
269c23b3d1aSAlex Smith 		}
270c23b3d1aSAlex Smith 	}
2717aeb753bSRalf Baechle 
272de8cd0dcSJames Hogan 	/* System call number may have been changed */
273de8cd0dcSJames Hogan 	mips_syscall_update_nr(target, regs);
274de8cd0dcSJames Hogan 
2757aeb753bSRalf Baechle 	return 0;
2767aeb753bSRalf Baechle }
2777aeb753bSRalf Baechle 
278c23b3d1aSAlex Smith #endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
279c23b3d1aSAlex Smith 
280c23b3d1aSAlex Smith #ifdef CONFIG_64BIT
281c23b3d1aSAlex Smith 
gpr64_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)282c23b3d1aSAlex Smith static int gpr64_get(struct task_struct *target,
283c23b3d1aSAlex Smith 		     const struct user_regset *regset,
284a0faf966SAl Viro 		     struct membuf to)
285c23b3d1aSAlex Smith {
286c23b3d1aSAlex Smith 	struct pt_regs *regs = task_pt_regs(target);
287c23b3d1aSAlex Smith 	u64 uregs[ELF_NGREG] = {};
288c23b3d1aSAlex Smith 
28908c941bfSMarcin Nowakowski 	mips_dump_regs64(uregs, regs);
290a0faf966SAl Viro 	return membuf_write(&to, uregs, sizeof(uregs));
291c23b3d1aSAlex Smith }
292c23b3d1aSAlex Smith 
gpr64_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)293c23b3d1aSAlex Smith static int gpr64_set(struct task_struct *target,
294c23b3d1aSAlex Smith 		     const struct user_regset *regset,
295c23b3d1aSAlex Smith 		     unsigned int pos, unsigned int count,
296c23b3d1aSAlex Smith 		     const void *kbuf, const void __user *ubuf)
297c23b3d1aSAlex Smith {
298c23b3d1aSAlex Smith 	struct pt_regs *regs = task_pt_regs(target);
299c23b3d1aSAlex Smith 	u64 uregs[ELF_NGREG];
300c23b3d1aSAlex Smith 	unsigned start, num_regs, i;
301c23b3d1aSAlex Smith 	int err;
302c23b3d1aSAlex Smith 
303c23b3d1aSAlex Smith 	start = pos / sizeof(u64);
304c23b3d1aSAlex Smith 	num_regs = count / sizeof(u64);
305c23b3d1aSAlex Smith 
306c23b3d1aSAlex Smith 	if (start + num_regs > ELF_NGREG)
307c23b3d1aSAlex Smith 		return -EIO;
308c23b3d1aSAlex Smith 
309c23b3d1aSAlex Smith 	err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
310c23b3d1aSAlex Smith 				 sizeof(uregs));
311c23b3d1aSAlex Smith 	if (err)
312c23b3d1aSAlex Smith 		return err;
313c23b3d1aSAlex Smith 
314c23b3d1aSAlex Smith 	for (i = start; i < num_regs; i++) {
315c23b3d1aSAlex Smith 		switch (i) {
316c23b3d1aSAlex Smith 		case MIPS64_EF_R1 ... MIPS64_EF_R25:
317c23b3d1aSAlex Smith 			/* k0/k1 are ignored. */
318c23b3d1aSAlex Smith 		case MIPS64_EF_R28 ... MIPS64_EF_R31:
319c23b3d1aSAlex Smith 			regs->regs[i - MIPS64_EF_R0] = uregs[i];
320c23b3d1aSAlex Smith 			break;
321c23b3d1aSAlex Smith 		case MIPS64_EF_LO:
322c23b3d1aSAlex Smith 			regs->lo = uregs[i];
323c23b3d1aSAlex Smith 			break;
324c23b3d1aSAlex Smith 		case MIPS64_EF_HI:
325c23b3d1aSAlex Smith 			regs->hi = uregs[i];
326c23b3d1aSAlex Smith 			break;
327c23b3d1aSAlex Smith 		case MIPS64_EF_CP0_EPC:
328c23b3d1aSAlex Smith 			regs->cp0_epc = uregs[i];
329c23b3d1aSAlex Smith 			break;
330c23b3d1aSAlex Smith 		}
331c23b3d1aSAlex Smith 	}
332c23b3d1aSAlex Smith 
333de8cd0dcSJames Hogan 	/* System call number may have been changed */
334de8cd0dcSJames Hogan 	mips_syscall_update_nr(target, regs);
335de8cd0dcSJames Hogan 
336c23b3d1aSAlex Smith 	return 0;
337c23b3d1aSAlex Smith }
338c23b3d1aSAlex Smith 
339c23b3d1aSAlex Smith #endif /* CONFIG_64BIT */
340c23b3d1aSAlex Smith 
3416c79759eSPaul Burton 
3426c79759eSPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
3436c79759eSPaul Burton 
3446c79759eSPaul Burton /*
3456c79759eSPaul Burton  * Poke at FCSR according to its mask.  Set the Cause bits even
3466c79759eSPaul Burton  * if a corresponding Enable bit is set.  This will be noticed at
3476c79759eSPaul Burton  * the time the thread is switched to and SIGFPE thrown accordingly.
3486c79759eSPaul Burton  */
ptrace_setfcr31(struct task_struct * child,u32 value)3496c79759eSPaul Burton static void ptrace_setfcr31(struct task_struct *child, u32 value)
3506c79759eSPaul Burton {
3516c79759eSPaul Burton 	u32 fcr31;
3526c79759eSPaul Burton 	u32 mask;
3536c79759eSPaul Burton 
3546c79759eSPaul Burton 	fcr31 = child->thread.fpu.fcr31;
3556c79759eSPaul Burton 	mask = boot_cpu_data.fpu_msk31;
3566c79759eSPaul Burton 	child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask);
3576c79759eSPaul Burton }
3586c79759eSPaul Burton 
ptrace_getfpregs(struct task_struct * child,__u32 __user * data)3596c79759eSPaul Burton int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
3606c79759eSPaul Burton {
3616c79759eSPaul Burton 	int i;
3626c79759eSPaul Burton 
36396d4f267SLinus Torvalds 	if (!access_ok(data, 33 * 8))
3646c79759eSPaul Burton 		return -EIO;
3656c79759eSPaul Burton 
3666c79759eSPaul Burton 	if (tsk_used_math(child)) {
3676c79759eSPaul Burton 		union fpureg *fregs = get_fpu_regs(child);
3686c79759eSPaul Burton 		for (i = 0; i < 32; i++)
3696c79759eSPaul Burton 			__put_user(get_fpr64(&fregs[i], 0),
3706c79759eSPaul Burton 				   i + (__u64 __user *)data);
3716c79759eSPaul Burton 	} else {
3726c79759eSPaul Burton 		for (i = 0; i < 32; i++)
3736c79759eSPaul Burton 			__put_user((__u64) -1, i + (__u64 __user *) data);
3746c79759eSPaul Burton 	}
3756c79759eSPaul Burton 
3766c79759eSPaul Burton 	__put_user(child->thread.fpu.fcr31, data + 64);
3776c79759eSPaul Burton 	__put_user(boot_cpu_data.fpu_id, data + 65);
3786c79759eSPaul Burton 
3796c79759eSPaul Burton 	return 0;
3806c79759eSPaul Burton }
3816c79759eSPaul Burton 
ptrace_setfpregs(struct task_struct * child,__u32 __user * data)3826c79759eSPaul Burton int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
3836c79759eSPaul Burton {
3846c79759eSPaul Burton 	union fpureg *fregs;
3856c79759eSPaul Burton 	u64 fpr_val;
3866c79759eSPaul Burton 	u32 value;
3876c79759eSPaul Burton 	int i;
3886c79759eSPaul Burton 
38996d4f267SLinus Torvalds 	if (!access_ok(data, 33 * 8))
3906c79759eSPaul Burton 		return -EIO;
3916c79759eSPaul Burton 
3926c79759eSPaul Burton 	init_fp_ctx(child);
3936c79759eSPaul Burton 	fregs = get_fpu_regs(child);
3946c79759eSPaul Burton 
3956c79759eSPaul Burton 	for (i = 0; i < 32; i++) {
3966c79759eSPaul Burton 		__get_user(fpr_val, i + (__u64 __user *)data);
3976c79759eSPaul Burton 		set_fpr64(&fregs[i], 0, fpr_val);
3986c79759eSPaul Burton 	}
3996c79759eSPaul Burton 
4006c79759eSPaul Burton 	__get_user(value, data + 64);
4016c79759eSPaul Burton 	ptrace_setfcr31(child, value);
4026c79759eSPaul Burton 
4036c79759eSPaul Burton 	/* FIR may not be written.  */
4046c79759eSPaul Burton 
4056c79759eSPaul Burton 	return 0;
4066c79759eSPaul Burton }
4076c79759eSPaul Burton 
408a03fe725SMaciej W. Rozycki /*
409a03fe725SMaciej W. Rozycki  * Copy the floating-point context to the supplied NT_PRFPREG buffer,
410a03fe725SMaciej W. Rozycki  * !CONFIG_CPU_HAS_MSA variant.  FP context's general register slots
411be07a6a1SMaciej W. Rozycki  * correspond 1:1 to buffer slots.  Only general registers are copied.
412a03fe725SMaciej W. Rozycki  */
fpr_get_fpa(struct task_struct * target,struct membuf * to)413a0faf966SAl Viro static void fpr_get_fpa(struct task_struct *target,
414a0faf966SAl Viro 		       struct membuf *to)
4157aeb753bSRalf Baechle {
416a0faf966SAl Viro 	membuf_write(to, &target->thread.fpu,
417a0faf966SAl Viro 			NUM_FPU_REGS * sizeof(elf_fpreg_t));
418a03fe725SMaciej W. Rozycki }
419a03fe725SMaciej W. Rozycki 
420a03fe725SMaciej W. Rozycki /*
421a03fe725SMaciej W. Rozycki  * Copy the floating-point context to the supplied NT_PRFPREG buffer,
422a03fe725SMaciej W. Rozycki  * CONFIG_CPU_HAS_MSA variant.  Only lower 64 bits of FP context's
423be07a6a1SMaciej W. Rozycki  * general register slots are copied to buffer slots.  Only general
424be07a6a1SMaciej W. Rozycki  * registers are copied.
425a03fe725SMaciej W. Rozycki  */
fpr_get_msa(struct task_struct * target,struct membuf * to)426a0faf966SAl Viro static void fpr_get_msa(struct task_struct *target, struct membuf *to)
427a03fe725SMaciej W. Rozycki {
428a03fe725SMaciej W. Rozycki 	unsigned int i;
42972b22bbaSPaul Burton 
430a0faf966SAl Viro 	BUILD_BUG_ON(sizeof(u64) != sizeof(elf_fpreg_t));
431a0faf966SAl Viro 	for (i = 0; i < NUM_FPU_REGS; i++)
432a0faf966SAl Viro 		membuf_store(to, get_fpr64(&target->thread.fpu.fpr[i], 0));
4337aeb753bSRalf Baechle }
4347aeb753bSRalf Baechle 
435be07a6a1SMaciej W. Rozycki /*
436be07a6a1SMaciej W. Rozycki  * Copy the floating-point context to the supplied NT_PRFPREG buffer.
437be07a6a1SMaciej W. Rozycki  * Choose the appropriate helper for general registers, and then copy
43871e909c0SMaciej W. Rozycki  * the FCSR and FIR registers separately.
439be07a6a1SMaciej W. Rozycki  */
fpr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)440a03fe725SMaciej W. Rozycki static int fpr_get(struct task_struct *target,
4417aeb753bSRalf Baechle 		   const struct user_regset *regset,
442a0faf966SAl Viro 		   struct membuf to)
4437aeb753bSRalf Baechle {
444a03fe725SMaciej W. Rozycki 	if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t))
445a0faf966SAl Viro 		fpr_get_fpa(target, &to);
446a03fe725SMaciej W. Rozycki 	else
447a0faf966SAl Viro 		fpr_get_msa(target, &to);
448be07a6a1SMaciej W. Rozycki 
449a0faf966SAl Viro 	membuf_write(&to, &target->thread.fpu.fcr31, sizeof(u32));
450a0faf966SAl Viro 	membuf_write(&to, &boot_cpu_data.fpu_id, sizeof(u32));
451a0faf966SAl Viro 	return 0;
452a03fe725SMaciej W. Rozycki }
453a03fe725SMaciej W. Rozycki 
454a03fe725SMaciej W. Rozycki /*
455a03fe725SMaciej W. Rozycki  * Copy the supplied NT_PRFPREG buffer to the floating-point context,
456a03fe725SMaciej W. Rozycki  * !CONFIG_CPU_HAS_MSA variant.   Buffer slots correspond 1:1 to FP
457be07a6a1SMaciej W. Rozycki  * context's general register slots.  Only general registers are copied.
458a03fe725SMaciej W. Rozycki  */
fpr_set_fpa(struct task_struct * target,unsigned int * pos,unsigned int * count,const void ** kbuf,const void __user ** ubuf)459a03fe725SMaciej W. Rozycki static int fpr_set_fpa(struct task_struct *target,
460a03fe725SMaciej W. Rozycki 		       unsigned int *pos, unsigned int *count,
461a03fe725SMaciej W. Rozycki 		       const void **kbuf, const void __user **ubuf)
462a03fe725SMaciej W. Rozycki {
463a03fe725SMaciej W. Rozycki 	return user_regset_copyin(pos, count, kbuf, ubuf,
4647aeb753bSRalf Baechle 				  &target->thread.fpu,
465be07a6a1SMaciej W. Rozycki 				  0, NUM_FPU_REGS * sizeof(elf_fpreg_t));
466a03fe725SMaciej W. Rozycki }
467a03fe725SMaciej W. Rozycki 
468a03fe725SMaciej W. Rozycki /*
469a03fe725SMaciej W. Rozycki  * Copy the supplied NT_PRFPREG buffer to the floating-point context,
470a03fe725SMaciej W. Rozycki  * CONFIG_CPU_HAS_MSA variant.  Buffer slots are copied to lower 64
471be07a6a1SMaciej W. Rozycki  * bits only of FP context's general register slots.  Only general
472be07a6a1SMaciej W. Rozycki  * registers are copied.
473a03fe725SMaciej W. Rozycki  */
fpr_set_msa(struct task_struct * target,unsigned int * pos,unsigned int * count,const void ** kbuf,const void __user ** ubuf)474a03fe725SMaciej W. Rozycki static int fpr_set_msa(struct task_struct *target,
475a03fe725SMaciej W. Rozycki 		       unsigned int *pos, unsigned int *count,
476a03fe725SMaciej W. Rozycki 		       const void **kbuf, const void __user **ubuf)
477a03fe725SMaciej W. Rozycki {
478a03fe725SMaciej W. Rozycki 	unsigned int i;
479a03fe725SMaciej W. Rozycki 	u64 fpr_val;
480a03fe725SMaciej W. Rozycki 	int err;
48172b22bbaSPaul Burton 
482d614fd58SDave Martin 	BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t));
48380b3ffceSMaciej W. Rozycki 	for (i = 0; i < NUM_FPU_REGS && *count > 0; i++) {
484a03fe725SMaciej W. Rozycki 		err = user_regset_copyin(pos, count, kbuf, ubuf,
48572b22bbaSPaul Burton 					 &fpr_val, i * sizeof(elf_fpreg_t),
48672b22bbaSPaul Burton 					 (i + 1) * sizeof(elf_fpreg_t));
48772b22bbaSPaul Burton 		if (err)
48872b22bbaSPaul Burton 			return err;
48972b22bbaSPaul Burton 		set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val);
49072b22bbaSPaul Burton 	}
49172b22bbaSPaul Burton 
49272b22bbaSPaul Burton 	return 0;
4937aeb753bSRalf Baechle }
4947aeb753bSRalf Baechle 
495dc24d0edSMaciej W. Rozycki /*
496dc24d0edSMaciej W. Rozycki  * Copy the supplied NT_PRFPREG buffer to the floating-point context.
497be07a6a1SMaciej W. Rozycki  * Choose the appropriate helper for general registers, and then copy
49871e909c0SMaciej W. Rozycki  * the FCSR register separately.  Ignore the incoming FIR register
49971e909c0SMaciej W. Rozycki  * contents though, as the register is read-only.
500dc24d0edSMaciej W. Rozycki  *
501dc24d0edSMaciej W. Rozycki  * We optimize for the case where `count % sizeof(elf_fpreg_t) == 0',
502dc24d0edSMaciej W. Rozycki  * which is supposed to have been guaranteed by the kernel before
503dc24d0edSMaciej W. Rozycki  * calling us, e.g. in `ptrace_regset'.  We enforce that requirement,
504dc24d0edSMaciej W. Rozycki  * so that we can safely avoid preinitializing temporaries for
505dc24d0edSMaciej W. Rozycki  * partial register writes.
506dc24d0edSMaciej W. Rozycki  */
fpr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)507a03fe725SMaciej W. Rozycki static int fpr_set(struct task_struct *target,
508a03fe725SMaciej W. Rozycki 		   const struct user_regset *regset,
509a03fe725SMaciej W. Rozycki 		   unsigned int pos, unsigned int count,
510a03fe725SMaciej W. Rozycki 		   const void *kbuf, const void __user *ubuf)
511a03fe725SMaciej W. Rozycki {
512be07a6a1SMaciej W. Rozycki 	const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t);
51371e909c0SMaciej W. Rozycki 	const int fir_pos = fcr31_pos + sizeof(u32);
514be07a6a1SMaciej W. Rozycki 	u32 fcr31;
515a03fe725SMaciej W. Rozycki 	int err;
516a03fe725SMaciej W. Rozycki 
517dc24d0edSMaciej W. Rozycki 	BUG_ON(count % sizeof(elf_fpreg_t));
518dc24d0edSMaciej W. Rozycki 
519c8c5a3a2SMaciej W. Rozycki 	if (pos + count > sizeof(elf_fpregset_t))
520c8c5a3a2SMaciej W. Rozycki 		return -EIO;
521c8c5a3a2SMaciej W. Rozycki 
522a03fe725SMaciej W. Rozycki 	init_fp_ctx(target);
523a03fe725SMaciej W. Rozycki 
524a03fe725SMaciej W. Rozycki 	if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t))
525a03fe725SMaciej W. Rozycki 		err = fpr_set_fpa(target, &pos, &count, &kbuf, &ubuf);
526a03fe725SMaciej W. Rozycki 	else
527a03fe725SMaciej W. Rozycki 		err = fpr_set_msa(target, &pos, &count, &kbuf, &ubuf);
528be07a6a1SMaciej W. Rozycki 	if (err)
529be07a6a1SMaciej W. Rozycki 		return err;
530be07a6a1SMaciej W. Rozycki 
531be07a6a1SMaciej W. Rozycki 	if (count > 0) {
532be07a6a1SMaciej W. Rozycki 		err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
533be07a6a1SMaciej W. Rozycki 					 &fcr31,
534be07a6a1SMaciej W. Rozycki 					 fcr31_pos, fcr31_pos + sizeof(u32));
535be07a6a1SMaciej W. Rozycki 		if (err)
536be07a6a1SMaciej W. Rozycki 			return err;
537be07a6a1SMaciej W. Rozycki 
538be07a6a1SMaciej W. Rozycki 		ptrace_setfcr31(target, fcr31);
539be07a6a1SMaciej W. Rozycki 	}
540a03fe725SMaciej W. Rozycki 
541540e58d2SSergey Shtylyov 	if (count > 0) {
542540e58d2SSergey Shtylyov 		user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
543540e58d2SSergey Shtylyov 					  fir_pos, fir_pos + sizeof(u32));
544540e58d2SSergey Shtylyov 		return 0;
545540e58d2SSergey Shtylyov 	}
54671e909c0SMaciej W. Rozycki 
547a03fe725SMaciej W. Rozycki 	return err;
548a03fe725SMaciej W. Rozycki }
549a03fe725SMaciej W. Rozycki 
5506c79759eSPaul Burton /* Copy the FP mode setting to the supplied NT_MIPS_FP_MODE buffer.  */
fp_mode_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)5516c79759eSPaul Burton static int fp_mode_get(struct task_struct *target,
5526c79759eSPaul Burton 		       const struct user_regset *regset,
553a0faf966SAl Viro 		       struct membuf to)
5546c79759eSPaul Burton {
555a0faf966SAl Viro 	return membuf_store(&to, (int)mips_get_process_fp_mode(target));
5566c79759eSPaul Burton }
5576c79759eSPaul Burton 
5586c79759eSPaul Burton /*
5596c79759eSPaul Burton  * Copy the supplied NT_MIPS_FP_MODE buffer to the FP mode setting.
5606c79759eSPaul Burton  *
5616c79759eSPaul Burton  * We optimize for the case where `count % sizeof(int) == 0', which
5626c79759eSPaul Burton  * is supposed to have been guaranteed by the kernel before calling
5636c79759eSPaul Burton  * us, e.g. in `ptrace_regset'.  We enforce that requirement, so
5646c79759eSPaul Burton  * that we can safely avoid preinitializing temporaries for partial
5656c79759eSPaul Burton  * mode writes.
5666c79759eSPaul Burton  */
fp_mode_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)5676c79759eSPaul Burton static int fp_mode_set(struct task_struct *target,
5686c79759eSPaul Burton 		       const struct user_regset *regset,
5696c79759eSPaul Burton 		       unsigned int pos, unsigned int count,
5706c79759eSPaul Burton 		       const void *kbuf, const void __user *ubuf)
5716c79759eSPaul Burton {
5726c79759eSPaul Burton 	int fp_mode;
5736c79759eSPaul Burton 	int err;
5746c79759eSPaul Burton 
5756c79759eSPaul Burton 	BUG_ON(count % sizeof(int));
5766c79759eSPaul Burton 
5776c79759eSPaul Burton 	if (pos + count > sizeof(fp_mode))
5786c79759eSPaul Burton 		return -EIO;
5796c79759eSPaul Burton 
5806c79759eSPaul Burton 	err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &fp_mode, 0,
5816c79759eSPaul Burton 				 sizeof(fp_mode));
5826c79759eSPaul Burton 	if (err)
5836c79759eSPaul Burton 		return err;
5846c79759eSPaul Burton 
5856c79759eSPaul Burton 	if (count > 0)
5866c79759eSPaul Burton 		err = mips_set_process_fp_mode(target, fp_mode);
5876c79759eSPaul Burton 
5886c79759eSPaul Burton 	return err;
5896c79759eSPaul Burton }
5906c79759eSPaul Burton 
5916c79759eSPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */
5926c79759eSPaul Burton 
5933cd64083SPaul Burton #ifdef CONFIG_CPU_HAS_MSA
5943cd64083SPaul Burton 
5953cd64083SPaul Burton struct msa_control_regs {
5963cd64083SPaul Burton 	unsigned int fir;
5973cd64083SPaul Burton 	unsigned int fcsr;
5983cd64083SPaul Burton 	unsigned int msair;
5993cd64083SPaul Burton 	unsigned int msacsr;
6003cd64083SPaul Burton };
6013cd64083SPaul Burton 
copy_pad_fprs(struct task_struct * target,const struct user_regset * regset,struct membuf * to,unsigned int live_sz)602a0faf966SAl Viro static void copy_pad_fprs(struct task_struct *target,
6033cd64083SPaul Burton 			 const struct user_regset *regset,
604a0faf966SAl Viro 			 struct membuf *to,
6053cd64083SPaul Burton 			 unsigned int live_sz)
6063cd64083SPaul Burton {
607a0faf966SAl Viro 	int i, j;
6083cd64083SPaul Burton 	unsigned long long fill = ~0ull;
6093cd64083SPaul Burton 	unsigned int cp_sz, pad_sz;
6103cd64083SPaul Burton 
6113cd64083SPaul Burton 	cp_sz = min(regset->size, live_sz);
6123cd64083SPaul Burton 	pad_sz = regset->size - cp_sz;
6133cd64083SPaul Burton 	WARN_ON(pad_sz % sizeof(fill));
6143cd64083SPaul Burton 
615a0faf966SAl Viro 	for (i = 0; i < NUM_FPU_REGS; i++) {
616a0faf966SAl Viro 		membuf_write(to, &target->thread.fpu.fpr[i], cp_sz);
617a0faf966SAl Viro 		for (j = 0; j < (pad_sz / sizeof(fill)); j++)
618a0faf966SAl Viro 			membuf_store(to, fill);
6193cd64083SPaul Burton 	}
6203cd64083SPaul Burton }
6213cd64083SPaul Burton 
msa_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)6223cd64083SPaul Burton static int msa_get(struct task_struct *target,
6233cd64083SPaul Burton 		   const struct user_regset *regset,
624a0faf966SAl Viro 		   struct membuf to)
6253cd64083SPaul Burton {
6263cd64083SPaul Burton 	const unsigned int wr_size = NUM_FPU_REGS * regset->size;
6273cd64083SPaul Burton 	const struct msa_control_regs ctrl_regs = {
6283cd64083SPaul Burton 		.fir = boot_cpu_data.fpu_id,
6293cd64083SPaul Burton 		.fcsr = target->thread.fpu.fcr31,
6303cd64083SPaul Burton 		.msair = boot_cpu_data.msa_id,
6313cd64083SPaul Burton 		.msacsr = target->thread.fpu.msacsr,
6323cd64083SPaul Burton 	};
6333cd64083SPaul Burton 
6343cd64083SPaul Burton 	if (!tsk_used_math(target)) {
6353cd64083SPaul Burton 		/* The task hasn't used FP or MSA, fill with 0xff */
636a0faf966SAl Viro 		copy_pad_fprs(target, regset, &to, 0);
6373cd64083SPaul Burton 	} else if (!test_tsk_thread_flag(target, TIF_MSA_CTX_LIVE)) {
6383cd64083SPaul Burton 		/* Copy scalar FP context, fill the rest with 0xff */
639a0faf966SAl Viro 		copy_pad_fprs(target, regset, &to, 8);
6403cd64083SPaul Burton 	} else if (sizeof(target->thread.fpu.fpr[0]) == regset->size) {
6413cd64083SPaul Burton 		/* Trivially copy the vector registers */
642a0faf966SAl Viro 		membuf_write(&to, &target->thread.fpu.fpr, wr_size);
6433cd64083SPaul Burton 	} else {
6443cd64083SPaul Burton 		/* Copy as much context as possible, fill the rest with 0xff */
645a0faf966SAl Viro 		copy_pad_fprs(target, regset, &to,
6463cd64083SPaul Burton 				sizeof(target->thread.fpu.fpr[0]));
6473cd64083SPaul Burton 	}
6483cd64083SPaul Burton 
649a0faf966SAl Viro 	return membuf_write(&to, &ctrl_regs, sizeof(ctrl_regs));
6503cd64083SPaul Burton }
6513cd64083SPaul Burton 
msa_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)6523cd64083SPaul Burton static int msa_set(struct task_struct *target,
6533cd64083SPaul Burton 		   const struct user_regset *regset,
6543cd64083SPaul Burton 		   unsigned int pos, unsigned int count,
6553cd64083SPaul Burton 		   const void *kbuf, const void __user *ubuf)
6563cd64083SPaul Burton {
6573cd64083SPaul Burton 	const unsigned int wr_size = NUM_FPU_REGS * regset->size;
6583cd64083SPaul Burton 	struct msa_control_regs ctrl_regs;
6593cd64083SPaul Burton 	unsigned int cp_sz;
6603cd64083SPaul Burton 	int i, err, start;
6613cd64083SPaul Burton 
6623cd64083SPaul Burton 	init_fp_ctx(target);
6633cd64083SPaul Burton 
6643cd64083SPaul Burton 	if (sizeof(target->thread.fpu.fpr[0]) == regset->size) {
6653cd64083SPaul Burton 		/* Trivially copy the vector registers */
6663cd64083SPaul Burton 		err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
6673cd64083SPaul Burton 					 &target->thread.fpu.fpr,
6683cd64083SPaul Burton 					 0, wr_size);
6693cd64083SPaul Burton 	} else {
6703cd64083SPaul Burton 		/* Copy as much context as possible */
6713cd64083SPaul Burton 		cp_sz = min_t(unsigned int, regset->size,
6723cd64083SPaul Burton 			      sizeof(target->thread.fpu.fpr[0]));
6733cd64083SPaul Burton 
6743cd64083SPaul Burton 		i = start = err = 0;
6753cd64083SPaul Burton 		for (; i < NUM_FPU_REGS; i++, start += regset->size) {
6763cd64083SPaul Burton 			err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf,
6773cd64083SPaul Burton 						  &target->thread.fpu.fpr[i],
6783cd64083SPaul Burton 						  start, start + cp_sz);
6793cd64083SPaul Burton 		}
6803cd64083SPaul Burton 	}
6813cd64083SPaul Burton 
6823cd64083SPaul Burton 	if (!err)
6833cd64083SPaul Burton 		err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl_regs,
6843cd64083SPaul Burton 					 wr_size, wr_size + sizeof(ctrl_regs));
6853cd64083SPaul Burton 	if (!err) {
6863cd64083SPaul Burton 		target->thread.fpu.fcr31 = ctrl_regs.fcsr & ~FPU_CSR_ALL_X;
6873cd64083SPaul Burton 		target->thread.fpu.msacsr = ctrl_regs.msacsr & ~MSA_CSR_CAUSEF;
6883cd64083SPaul Burton 	}
6893cd64083SPaul Burton 
6903cd64083SPaul Burton 	return err;
6913cd64083SPaul Burton }
6923cd64083SPaul Burton 
6933cd64083SPaul Burton #endif /* CONFIG_CPU_HAS_MSA */
6943cd64083SPaul Burton 
69544109c60SMaciej W. Rozycki #if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
69644109c60SMaciej W. Rozycki 
69744109c60SMaciej W. Rozycki /*
69844109c60SMaciej W. Rozycki  * Copy the DSP context to the supplied 32-bit NT_MIPS_DSP buffer.
69944109c60SMaciej W. Rozycki  */
dsp32_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)70044109c60SMaciej W. Rozycki static int dsp32_get(struct task_struct *target,
70144109c60SMaciej W. Rozycki 		     const struct user_regset *regset,
702a0faf966SAl Viro 		     struct membuf to)
70344109c60SMaciej W. Rozycki {
70444109c60SMaciej W. Rozycki 	u32 dspregs[NUM_DSP_REGS + 1];
705a0faf966SAl Viro 	unsigned int i;
70644109c60SMaciej W. Rozycki 
707a0faf966SAl Viro 	BUG_ON(to.left % sizeof(u32));
70844109c60SMaciej W. Rozycki 
70944109c60SMaciej W. Rozycki 	if (!cpu_has_dsp)
71044109c60SMaciej W. Rozycki 		return -EIO;
71144109c60SMaciej W. Rozycki 
712a0faf966SAl Viro 	for (i = 0; i < NUM_DSP_REGS; i++)
71344109c60SMaciej W. Rozycki 		dspregs[i] = target->thread.dsp.dspr[i];
714a0faf966SAl Viro 	dspregs[NUM_DSP_REGS] = target->thread.dsp.dspcontrol;
715a0faf966SAl Viro 	return membuf_write(&to, dspregs, sizeof(dspregs));
71644109c60SMaciej W. Rozycki }
71744109c60SMaciej W. Rozycki 
71844109c60SMaciej W. Rozycki /*
71944109c60SMaciej W. Rozycki  * Copy the supplied 32-bit NT_MIPS_DSP buffer to the DSP context.
72044109c60SMaciej W. Rozycki  */
dsp32_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)72144109c60SMaciej W. Rozycki static int dsp32_set(struct task_struct *target,
72244109c60SMaciej W. Rozycki 		     const struct user_regset *regset,
72344109c60SMaciej W. Rozycki 		     unsigned int pos, unsigned int count,
72444109c60SMaciej W. Rozycki 		     const void *kbuf, const void __user *ubuf)
72544109c60SMaciej W. Rozycki {
72644109c60SMaciej W. Rozycki 	unsigned int start, num_regs, i;
72744109c60SMaciej W. Rozycki 	u32 dspregs[NUM_DSP_REGS + 1];
72844109c60SMaciej W. Rozycki 	int err;
72944109c60SMaciej W. Rozycki 
73044109c60SMaciej W. Rozycki 	BUG_ON(count % sizeof(u32));
73144109c60SMaciej W. Rozycki 
73244109c60SMaciej W. Rozycki 	if (!cpu_has_dsp)
73344109c60SMaciej W. Rozycki 		return -EIO;
73444109c60SMaciej W. Rozycki 
73544109c60SMaciej W. Rozycki 	start = pos / sizeof(u32);
73644109c60SMaciej W. Rozycki 	num_regs = count / sizeof(u32);
73744109c60SMaciej W. Rozycki 
73844109c60SMaciej W. Rozycki 	if (start + num_regs > NUM_DSP_REGS + 1)
73944109c60SMaciej W. Rozycki 		return -EIO;
74044109c60SMaciej W. Rozycki 
74144109c60SMaciej W. Rozycki 	err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, dspregs, 0,
74244109c60SMaciej W. Rozycki 				 sizeof(dspregs));
74344109c60SMaciej W. Rozycki 	if (err)
74444109c60SMaciej W. Rozycki 		return err;
74544109c60SMaciej W. Rozycki 
74644109c60SMaciej W. Rozycki 	for (i = start; i < num_regs; i++)
74744109c60SMaciej W. Rozycki 		switch (i) {
74844109c60SMaciej W. Rozycki 		case 0 ... NUM_DSP_REGS - 1:
74944109c60SMaciej W. Rozycki 			target->thread.dsp.dspr[i] = (s32)dspregs[i];
75044109c60SMaciej W. Rozycki 			break;
75144109c60SMaciej W. Rozycki 		case NUM_DSP_REGS:
75244109c60SMaciej W. Rozycki 			target->thread.dsp.dspcontrol = (s32)dspregs[i];
75344109c60SMaciej W. Rozycki 			break;
75444109c60SMaciej W. Rozycki 		}
75544109c60SMaciej W. Rozycki 
75644109c60SMaciej W. Rozycki 	return 0;
75744109c60SMaciej W. Rozycki }
75844109c60SMaciej W. Rozycki 
75944109c60SMaciej W. Rozycki #endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
76044109c60SMaciej W. Rozycki 
76144109c60SMaciej W. Rozycki #ifdef CONFIG_64BIT
76244109c60SMaciej W. Rozycki 
76344109c60SMaciej W. Rozycki /*
76444109c60SMaciej W. Rozycki  * Copy the DSP context to the supplied 64-bit NT_MIPS_DSP buffer.
76544109c60SMaciej W. Rozycki  */
dsp64_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)76644109c60SMaciej W. Rozycki static int dsp64_get(struct task_struct *target,
76744109c60SMaciej W. Rozycki 		     const struct user_regset *regset,
768a0faf966SAl Viro 		     struct membuf to)
76944109c60SMaciej W. Rozycki {
77044109c60SMaciej W. Rozycki 	u64 dspregs[NUM_DSP_REGS + 1];
771a0faf966SAl Viro 	unsigned int i;
77244109c60SMaciej W. Rozycki 
773a0faf966SAl Viro 	BUG_ON(to.left % sizeof(u64));
77444109c60SMaciej W. Rozycki 
77544109c60SMaciej W. Rozycki 	if (!cpu_has_dsp)
77644109c60SMaciej W. Rozycki 		return -EIO;
77744109c60SMaciej W. Rozycki 
778a0faf966SAl Viro 	for (i = 0; i < NUM_DSP_REGS; i++)
77944109c60SMaciej W. Rozycki 		dspregs[i] = target->thread.dsp.dspr[i];
780a0faf966SAl Viro 	dspregs[NUM_DSP_REGS] = target->thread.dsp.dspcontrol;
781a0faf966SAl Viro 	return membuf_write(&to, dspregs, sizeof(dspregs));
78244109c60SMaciej W. Rozycki }
78344109c60SMaciej W. Rozycki 
78444109c60SMaciej W. Rozycki /*
78544109c60SMaciej W. Rozycki  * Copy the supplied 64-bit NT_MIPS_DSP buffer to the DSP context.
78644109c60SMaciej W. Rozycki  */
dsp64_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)78744109c60SMaciej W. Rozycki static int dsp64_set(struct task_struct *target,
78844109c60SMaciej W. Rozycki 		     const struct user_regset *regset,
78944109c60SMaciej W. Rozycki 		     unsigned int pos, unsigned int count,
79044109c60SMaciej W. Rozycki 		     const void *kbuf, const void __user *ubuf)
79144109c60SMaciej W. Rozycki {
79244109c60SMaciej W. Rozycki 	unsigned int start, num_regs, i;
79344109c60SMaciej W. Rozycki 	u64 dspregs[NUM_DSP_REGS + 1];
79444109c60SMaciej W. Rozycki 	int err;
79544109c60SMaciej W. Rozycki 
79644109c60SMaciej W. Rozycki 	BUG_ON(count % sizeof(u64));
79744109c60SMaciej W. Rozycki 
79844109c60SMaciej W. Rozycki 	if (!cpu_has_dsp)
79944109c60SMaciej W. Rozycki 		return -EIO;
80044109c60SMaciej W. Rozycki 
80144109c60SMaciej W. Rozycki 	start = pos / sizeof(u64);
80244109c60SMaciej W. Rozycki 	num_regs = count / sizeof(u64);
80344109c60SMaciej W. Rozycki 
80444109c60SMaciej W. Rozycki 	if (start + num_regs > NUM_DSP_REGS + 1)
80544109c60SMaciej W. Rozycki 		return -EIO;
80644109c60SMaciej W. Rozycki 
80744109c60SMaciej W. Rozycki 	err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, dspregs, 0,
80844109c60SMaciej W. Rozycki 				 sizeof(dspregs));
80944109c60SMaciej W. Rozycki 	if (err)
81044109c60SMaciej W. Rozycki 		return err;
81144109c60SMaciej W. Rozycki 
81244109c60SMaciej W. Rozycki 	for (i = start; i < num_regs; i++)
81344109c60SMaciej W. Rozycki 		switch (i) {
81444109c60SMaciej W. Rozycki 		case 0 ... NUM_DSP_REGS - 1:
81544109c60SMaciej W. Rozycki 			target->thread.dsp.dspr[i] = dspregs[i];
81644109c60SMaciej W. Rozycki 			break;
81744109c60SMaciej W. Rozycki 		case NUM_DSP_REGS:
81844109c60SMaciej W. Rozycki 			target->thread.dsp.dspcontrol = dspregs[i];
81944109c60SMaciej W. Rozycki 			break;
82044109c60SMaciej W. Rozycki 		}
82144109c60SMaciej W. Rozycki 
82244109c60SMaciej W. Rozycki 	return 0;
82344109c60SMaciej W. Rozycki }
82444109c60SMaciej W. Rozycki 
82544109c60SMaciej W. Rozycki #endif /* CONFIG_64BIT */
82644109c60SMaciej W. Rozycki 
82744109c60SMaciej W. Rozycki /*
82844109c60SMaciej W. Rozycki  * Determine whether the DSP context is present.
82944109c60SMaciej W. Rozycki  */
dsp_active(struct task_struct * target,const struct user_regset * regset)83044109c60SMaciej W. Rozycki static int dsp_active(struct task_struct *target,
83144109c60SMaciej W. Rozycki 		      const struct user_regset *regset)
83244109c60SMaciej W. Rozycki {
83344109c60SMaciej W. Rozycki 	return cpu_has_dsp ? NUM_DSP_REGS + 1 : -ENODEV;
83444109c60SMaciej W. Rozycki }
83544109c60SMaciej W. Rozycki 
8367aeb753bSRalf Baechle enum mips_regset {
8377aeb753bSRalf Baechle 	REGSET_GPR,
83844109c60SMaciej W. Rozycki 	REGSET_DSP,
8396c79759eSPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
8406c79759eSPaul Burton 	REGSET_FPR,
8411ae22a0eSMaciej W. Rozycki 	REGSET_FP_MODE,
8426c79759eSPaul Burton #endif
8433cd64083SPaul Burton #ifdef CONFIG_CPU_HAS_MSA
8443cd64083SPaul Burton 	REGSET_MSA,
8453cd64083SPaul Burton #endif
8467aeb753bSRalf Baechle };
8477aeb753bSRalf Baechle 
84840e084a5SRalf Baechle struct pt_regs_offset {
84940e084a5SRalf Baechle 	const char *name;
85040e084a5SRalf Baechle 	int offset;
85140e084a5SRalf Baechle };
85240e084a5SRalf Baechle 
85340e084a5SRalf Baechle #define REG_OFFSET_NAME(reg, r) {					\
85440e084a5SRalf Baechle 	.name = #reg,							\
85540e084a5SRalf Baechle 	.offset = offsetof(struct pt_regs, r)				\
85640e084a5SRalf Baechle }
85740e084a5SRalf Baechle 
85840e084a5SRalf Baechle #define REG_OFFSET_END {						\
85940e084a5SRalf Baechle 	.name = NULL,							\
86040e084a5SRalf Baechle 	.offset = 0							\
86140e084a5SRalf Baechle }
86240e084a5SRalf Baechle 
86340e084a5SRalf Baechle static const struct pt_regs_offset regoffset_table[] = {
86440e084a5SRalf Baechle 	REG_OFFSET_NAME(r0, regs[0]),
86540e084a5SRalf Baechle 	REG_OFFSET_NAME(r1, regs[1]),
86640e084a5SRalf Baechle 	REG_OFFSET_NAME(r2, regs[2]),
86740e084a5SRalf Baechle 	REG_OFFSET_NAME(r3, regs[3]),
86840e084a5SRalf Baechle 	REG_OFFSET_NAME(r4, regs[4]),
86940e084a5SRalf Baechle 	REG_OFFSET_NAME(r5, regs[5]),
87040e084a5SRalf Baechle 	REG_OFFSET_NAME(r6, regs[6]),
87140e084a5SRalf Baechle 	REG_OFFSET_NAME(r7, regs[7]),
87240e084a5SRalf Baechle 	REG_OFFSET_NAME(r8, regs[8]),
87340e084a5SRalf Baechle 	REG_OFFSET_NAME(r9, regs[9]),
87440e084a5SRalf Baechle 	REG_OFFSET_NAME(r10, regs[10]),
87540e084a5SRalf Baechle 	REG_OFFSET_NAME(r11, regs[11]),
87640e084a5SRalf Baechle 	REG_OFFSET_NAME(r12, regs[12]),
87740e084a5SRalf Baechle 	REG_OFFSET_NAME(r13, regs[13]),
87840e084a5SRalf Baechle 	REG_OFFSET_NAME(r14, regs[14]),
87940e084a5SRalf Baechle 	REG_OFFSET_NAME(r15, regs[15]),
88040e084a5SRalf Baechle 	REG_OFFSET_NAME(r16, regs[16]),
88140e084a5SRalf Baechle 	REG_OFFSET_NAME(r17, regs[17]),
88240e084a5SRalf Baechle 	REG_OFFSET_NAME(r18, regs[18]),
88340e084a5SRalf Baechle 	REG_OFFSET_NAME(r19, regs[19]),
88440e084a5SRalf Baechle 	REG_OFFSET_NAME(r20, regs[20]),
88540e084a5SRalf Baechle 	REG_OFFSET_NAME(r21, regs[21]),
88640e084a5SRalf Baechle 	REG_OFFSET_NAME(r22, regs[22]),
88740e084a5SRalf Baechle 	REG_OFFSET_NAME(r23, regs[23]),
88840e084a5SRalf Baechle 	REG_OFFSET_NAME(r24, regs[24]),
88940e084a5SRalf Baechle 	REG_OFFSET_NAME(r25, regs[25]),
89040e084a5SRalf Baechle 	REG_OFFSET_NAME(r26, regs[26]),
89140e084a5SRalf Baechle 	REG_OFFSET_NAME(r27, regs[27]),
89240e084a5SRalf Baechle 	REG_OFFSET_NAME(r28, regs[28]),
89340e084a5SRalf Baechle 	REG_OFFSET_NAME(r29, regs[29]),
89440e084a5SRalf Baechle 	REG_OFFSET_NAME(r30, regs[30]),
89540e084a5SRalf Baechle 	REG_OFFSET_NAME(r31, regs[31]),
89640e084a5SRalf Baechle 	REG_OFFSET_NAME(c0_status, cp0_status),
89740e084a5SRalf Baechle 	REG_OFFSET_NAME(hi, hi),
89840e084a5SRalf Baechle 	REG_OFFSET_NAME(lo, lo),
89940e084a5SRalf Baechle #ifdef CONFIG_CPU_HAS_SMARTMIPS
90040e084a5SRalf Baechle 	REG_OFFSET_NAME(acx, acx),
90140e084a5SRalf Baechle #endif
90240e084a5SRalf Baechle 	REG_OFFSET_NAME(c0_badvaddr, cp0_badvaddr),
90340e084a5SRalf Baechle 	REG_OFFSET_NAME(c0_cause, cp0_cause),
90440e084a5SRalf Baechle 	REG_OFFSET_NAME(c0_epc, cp0_epc),
90540e084a5SRalf Baechle #ifdef CONFIG_CPU_CAVIUM_OCTEON
90640e084a5SRalf Baechle 	REG_OFFSET_NAME(mpl0, mpl[0]),
90740e084a5SRalf Baechle 	REG_OFFSET_NAME(mpl1, mpl[1]),
90840e084a5SRalf Baechle 	REG_OFFSET_NAME(mpl2, mpl[2]),
90940e084a5SRalf Baechle 	REG_OFFSET_NAME(mtp0, mtp[0]),
91040e084a5SRalf Baechle 	REG_OFFSET_NAME(mtp1, mtp[1]),
91140e084a5SRalf Baechle 	REG_OFFSET_NAME(mtp2, mtp[2]),
91240e084a5SRalf Baechle #endif
91340e084a5SRalf Baechle 	REG_OFFSET_END,
91440e084a5SRalf Baechle };
91540e084a5SRalf Baechle 
91640e084a5SRalf Baechle /**
91740e084a5SRalf Baechle  * regs_query_register_offset() - query register offset from its name
91840e084a5SRalf Baechle  * @name:       the name of a register
91940e084a5SRalf Baechle  *
92040e084a5SRalf Baechle  * regs_query_register_offset() returns the offset of a register in struct
92140e084a5SRalf Baechle  * pt_regs from its name. If the name is invalid, this returns -EINVAL;
92240e084a5SRalf Baechle  */
regs_query_register_offset(const char * name)92340e084a5SRalf Baechle int regs_query_register_offset(const char *name)
92440e084a5SRalf Baechle {
92540e084a5SRalf Baechle         const struct pt_regs_offset *roff;
92640e084a5SRalf Baechle         for (roff = regoffset_table; roff->name != NULL; roff++)
92740e084a5SRalf Baechle                 if (!strcmp(roff->name, name))
92840e084a5SRalf Baechle                         return roff->offset;
92940e084a5SRalf Baechle         return -EINVAL;
93040e084a5SRalf Baechle }
93140e084a5SRalf Baechle 
932c23b3d1aSAlex Smith #if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
933c23b3d1aSAlex Smith 
9347aeb753bSRalf Baechle static const struct user_regset mips_regsets[] = {
9357aeb753bSRalf Baechle 	[REGSET_GPR] = {
9367aeb753bSRalf Baechle 		.core_note_type	= NT_PRSTATUS,
9377aeb753bSRalf Baechle 		.n		= ELF_NGREG,
9387aeb753bSRalf Baechle 		.size		= sizeof(unsigned int),
9397aeb753bSRalf Baechle 		.align		= sizeof(unsigned int),
940a0faf966SAl Viro 		.regset_get		= gpr32_get,
941c23b3d1aSAlex Smith 		.set		= gpr32_set,
9427aeb753bSRalf Baechle 	},
94344109c60SMaciej W. Rozycki 	[REGSET_DSP] = {
94444109c60SMaciej W. Rozycki 		.core_note_type	= NT_MIPS_DSP,
94544109c60SMaciej W. Rozycki 		.n		= NUM_DSP_REGS + 1,
94644109c60SMaciej W. Rozycki 		.size		= sizeof(u32),
94744109c60SMaciej W. Rozycki 		.align		= sizeof(u32),
948a0faf966SAl Viro 		.regset_get		= dsp32_get,
94944109c60SMaciej W. Rozycki 		.set		= dsp32_set,
95044109c60SMaciej W. Rozycki 		.active		= dsp_active,
95144109c60SMaciej W. Rozycki 	},
9526c79759eSPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
9536c79759eSPaul Burton 	[REGSET_FPR] = {
9546c79759eSPaul Burton 		.core_note_type	= NT_PRFPREG,
9556c79759eSPaul Burton 		.n		= ELF_NFPREG,
9566c79759eSPaul Burton 		.size		= sizeof(elf_fpreg_t),
9576c79759eSPaul Burton 		.align		= sizeof(elf_fpreg_t),
958a0faf966SAl Viro 		.regset_get		= fpr_get,
9596c79759eSPaul Burton 		.set		= fpr_set,
9606c79759eSPaul Burton 	},
9611ae22a0eSMaciej W. Rozycki 	[REGSET_FP_MODE] = {
9621ae22a0eSMaciej W. Rozycki 		.core_note_type	= NT_MIPS_FP_MODE,
9631ae22a0eSMaciej W. Rozycki 		.n		= 1,
9641ae22a0eSMaciej W. Rozycki 		.size		= sizeof(int),
9651ae22a0eSMaciej W. Rozycki 		.align		= sizeof(int),
966a0faf966SAl Viro 		.regset_get		= fp_mode_get,
9671ae22a0eSMaciej W. Rozycki 		.set		= fp_mode_set,
9681ae22a0eSMaciej W. Rozycki 	},
9696c79759eSPaul Burton #endif
9703cd64083SPaul Burton #ifdef CONFIG_CPU_HAS_MSA
9713cd64083SPaul Burton 	[REGSET_MSA] = {
9723cd64083SPaul Burton 		.core_note_type	= NT_MIPS_MSA,
9733cd64083SPaul Burton 		.n		= NUM_FPU_REGS + 1,
9743cd64083SPaul Burton 		.size		= 16,
9753cd64083SPaul Burton 		.align		= 16,
976a0faf966SAl Viro 		.regset_get		= msa_get,
9773cd64083SPaul Burton 		.set		= msa_set,
9783cd64083SPaul Burton 	},
9793cd64083SPaul Burton #endif
9807aeb753bSRalf Baechle };
9817aeb753bSRalf Baechle 
9827aeb753bSRalf Baechle static const struct user_regset_view user_mips_view = {
9837aeb753bSRalf Baechle 	.name		= "mips",
9847aeb753bSRalf Baechle 	.e_machine	= ELF_ARCH,
9857aeb753bSRalf Baechle 	.ei_osabi	= ELF_OSABI,
9867aeb753bSRalf Baechle 	.regsets	= mips_regsets,
9877aeb753bSRalf Baechle 	.n		= ARRAY_SIZE(mips_regsets),
9887aeb753bSRalf Baechle };
9897aeb753bSRalf Baechle 
990c23b3d1aSAlex Smith #endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
991c23b3d1aSAlex Smith 
992c23b3d1aSAlex Smith #ifdef CONFIG_64BIT
993c23b3d1aSAlex Smith 
9947aeb753bSRalf Baechle static const struct user_regset mips64_regsets[] = {
9957aeb753bSRalf Baechle 	[REGSET_GPR] = {
9967aeb753bSRalf Baechle 		.core_note_type	= NT_PRSTATUS,
9977aeb753bSRalf Baechle 		.n		= ELF_NGREG,
9987aeb753bSRalf Baechle 		.size		= sizeof(unsigned long),
9997aeb753bSRalf Baechle 		.align		= sizeof(unsigned long),
1000a0faf966SAl Viro 		.regset_get		= gpr64_get,
1001c23b3d1aSAlex Smith 		.set		= gpr64_set,
10027aeb753bSRalf Baechle 	},
100344109c60SMaciej W. Rozycki 	[REGSET_DSP] = {
100444109c60SMaciej W. Rozycki 		.core_note_type	= NT_MIPS_DSP,
100544109c60SMaciej W. Rozycki 		.n		= NUM_DSP_REGS + 1,
100644109c60SMaciej W. Rozycki 		.size		= sizeof(u64),
100744109c60SMaciej W. Rozycki 		.align		= sizeof(u64),
1008a0faf966SAl Viro 		.regset_get		= dsp64_get,
100944109c60SMaciej W. Rozycki 		.set		= dsp64_set,
101044109c60SMaciej W. Rozycki 		.active		= dsp_active,
101144109c60SMaciej W. Rozycki 	},
10126c79759eSPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
10131ae22a0eSMaciej W. Rozycki 	[REGSET_FP_MODE] = {
10141ae22a0eSMaciej W. Rozycki 		.core_note_type	= NT_MIPS_FP_MODE,
10151ae22a0eSMaciej W. Rozycki 		.n		= 1,
10161ae22a0eSMaciej W. Rozycki 		.size		= sizeof(int),
10171ae22a0eSMaciej W. Rozycki 		.align		= sizeof(int),
1018a0faf966SAl Viro 		.regset_get		= fp_mode_get,
10191ae22a0eSMaciej W. Rozycki 		.set		= fp_mode_set,
10201ae22a0eSMaciej W. Rozycki 	},
10216c79759eSPaul Burton 	[REGSET_FPR] = {
10226c79759eSPaul Burton 		.core_note_type	= NT_PRFPREG,
10236c79759eSPaul Burton 		.n		= ELF_NFPREG,
10246c79759eSPaul Burton 		.size		= sizeof(elf_fpreg_t),
10256c79759eSPaul Burton 		.align		= sizeof(elf_fpreg_t),
1026a0faf966SAl Viro 		.regset_get		= fpr_get,
10276c79759eSPaul Burton 		.set		= fpr_set,
10286c79759eSPaul Burton 	},
10296c79759eSPaul Burton #endif
10303cd64083SPaul Burton #ifdef CONFIG_CPU_HAS_MSA
10313cd64083SPaul Burton 	[REGSET_MSA] = {
10323cd64083SPaul Burton 		.core_note_type	= NT_MIPS_MSA,
10333cd64083SPaul Burton 		.n		= NUM_FPU_REGS + 1,
10343cd64083SPaul Burton 		.size		= 16,
10353cd64083SPaul Burton 		.align		= 16,
1036a0faf966SAl Viro 		.regset_get		= msa_get,
10373cd64083SPaul Burton 		.set		= msa_set,
10383cd64083SPaul Burton 	},
10393cd64083SPaul Burton #endif
10407aeb753bSRalf Baechle };
10417aeb753bSRalf Baechle 
10427aeb753bSRalf Baechle static const struct user_regset_view user_mips64_view = {
1043c23b3d1aSAlex Smith 	.name		= "mips64",
10447aeb753bSRalf Baechle 	.e_machine	= ELF_ARCH,
10457aeb753bSRalf Baechle 	.ei_osabi	= ELF_OSABI,
10467aeb753bSRalf Baechle 	.regsets	= mips64_regsets,
1047c23b3d1aSAlex Smith 	.n		= ARRAY_SIZE(mips64_regsets),
10487aeb753bSRalf Baechle };
10497aeb753bSRalf Baechle 
1050547da673SMaciej W. Rozycki #ifdef CONFIG_MIPS32_N32
1051547da673SMaciej W. Rozycki 
1052547da673SMaciej W. Rozycki static const struct user_regset_view user_mipsn32_view = {
1053547da673SMaciej W. Rozycki 	.name		= "mipsn32",
1054547da673SMaciej W. Rozycki 	.e_flags	= EF_MIPS_ABI2,
1055547da673SMaciej W. Rozycki 	.e_machine	= ELF_ARCH,
1056547da673SMaciej W. Rozycki 	.ei_osabi	= ELF_OSABI,
1057547da673SMaciej W. Rozycki 	.regsets	= mips64_regsets,
1058547da673SMaciej W. Rozycki 	.n		= ARRAY_SIZE(mips64_regsets),
1059547da673SMaciej W. Rozycki };
1060547da673SMaciej W. Rozycki 
1061547da673SMaciej W. Rozycki #endif /* CONFIG_MIPS32_N32 */
1062547da673SMaciej W. Rozycki 
1063c23b3d1aSAlex Smith #endif /* CONFIG_64BIT */
1064c23b3d1aSAlex Smith 
task_user_regset_view(struct task_struct * task)10657aeb753bSRalf Baechle const struct user_regset_view *task_user_regset_view(struct task_struct *task)
10667aeb753bSRalf Baechle {
10677aeb753bSRalf Baechle #ifdef CONFIG_32BIT
10687aeb753bSRalf Baechle 	return &user_mips_view;
1069c23b3d1aSAlex Smith #else
10707aeb753bSRalf Baechle #ifdef CONFIG_MIPS32_O32
107165768a1aSAlex Smith 	if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
10727aeb753bSRalf Baechle 		return &user_mips_view;
10737aeb753bSRalf Baechle #endif
1074547da673SMaciej W. Rozycki #ifdef CONFIG_MIPS32_N32
1075547da673SMaciej W. Rozycki 	if (test_tsk_thread_flag(task, TIF_32BIT_ADDR))
1076547da673SMaciej W. Rozycki 		return &user_mipsn32_view;
1077547da673SMaciej W. Rozycki #endif
10787aeb753bSRalf Baechle 	return &user_mips64_view;
1079c23b3d1aSAlex Smith #endif
10807aeb753bSRalf Baechle }
10817aeb753bSRalf Baechle 
arch_ptrace(struct task_struct * child,long request,unsigned long addr,unsigned long data)10829b05a69eSNamhyung Kim long arch_ptrace(struct task_struct *child, long request,
10839b05a69eSNamhyung Kim 		 unsigned long addr, unsigned long data)
10841da177e4SLinus Torvalds {
10851da177e4SLinus Torvalds 	int ret;
1086fb671139SNamhyung Kim 	void __user *addrp = (void __user *) addr;
1087fb671139SNamhyung Kim 	void __user *datavp = (void __user *) data;
1088fb671139SNamhyung Kim 	unsigned long __user *datalp = (void __user *) data;
10891da177e4SLinus Torvalds 
10901da177e4SLinus Torvalds 	switch (request) {
10911da177e4SLinus Torvalds 	/* when I and D space are separate, these will need to be fixed. */
10921da177e4SLinus Torvalds 	case PTRACE_PEEKTEXT: /* read word at location addr. */
109376647323SAlexey Dobriyan 	case PTRACE_PEEKDATA:
109476647323SAlexey Dobriyan 		ret = generic_ptrace_peekdata(child, addr, data);
10951da177e4SLinus Torvalds 		break;
10961da177e4SLinus Torvalds 
10971da177e4SLinus Torvalds 	/* Read the word at location addr in the USER area. */
10981da177e4SLinus Torvalds 	case PTRACE_PEEKUSR: {
10991da177e4SLinus Torvalds 		struct pt_regs *regs;
11001da177e4SLinus Torvalds 		unsigned long tmp = 0;
11011da177e4SLinus Torvalds 
110240bc9c67SAl Viro 		regs = task_pt_regs(child);
11031da177e4SLinus Torvalds 		ret = 0;  /* Default return value. */
11041da177e4SLinus Torvalds 
11051da177e4SLinus Torvalds 		switch (addr) {
11061da177e4SLinus Torvalds 		case 0 ... 31:
11071da177e4SLinus Torvalds 			tmp = regs->regs[addr];
11081da177e4SLinus Torvalds 			break;
11096c79759eSPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
11106c79759eSPaul Burton 		case FPR_BASE ... FPR_BASE + 31: {
11116c79759eSPaul Burton 			union fpureg *fregs;
11126c79759eSPaul Burton 
1113597ce172SPaul Burton 			if (!tsk_used_math(child)) {
1114597ce172SPaul Burton 				/* FP not yet used */
1115597ce172SPaul Burton 				tmp = -1;
1116597ce172SPaul Burton 				break;
1117597ce172SPaul Burton 			}
1118597ce172SPaul Burton 			fregs = get_fpu_regs(child);
11191da177e4SLinus Torvalds 
1120875d43e7SRalf Baechle #ifdef CONFIG_32BIT
11219a3a92ccSMaciej W. Rozycki 			if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
11221da177e4SLinus Torvalds 				/*
11231da177e4SLinus Torvalds 				 * The odd registers are actually the high
11241da177e4SLinus Torvalds 				 * order bits of the values stored in the even
1125d1157b10SMaciej W. Rozycki 				 * registers.
11261da177e4SLinus Torvalds 				 */
1127bbd426f5SPaul Burton 				tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
1128bbd426f5SPaul Burton 						addr & 1);
1129597ce172SPaul Burton 				break;
11301da177e4SLinus Torvalds 			}
1131597ce172SPaul Burton #endif
1132c7e81462SMaciej W. Rozycki 			tmp = get_fpr64(&fregs[addr - FPR_BASE], 0);
11331da177e4SLinus Torvalds 			break;
11346c79759eSPaul Burton 		}
11356c79759eSPaul Burton 		case FPC_CSR:
11366c79759eSPaul Burton 			tmp = child->thread.fpu.fcr31;
11376c79759eSPaul Burton 			break;
11386c79759eSPaul Burton 		case FPC_EIR:
11396c79759eSPaul Burton 			/* implementation / version register */
11406c79759eSPaul Burton 			tmp = boot_cpu_data.fpu_id;
11416c79759eSPaul Burton 			break;
11426c79759eSPaul Burton #endif
11431da177e4SLinus Torvalds 		case PC:
11441da177e4SLinus Torvalds 			tmp = regs->cp0_epc;
11451da177e4SLinus Torvalds 			break;
11461da177e4SLinus Torvalds 		case CAUSE:
11471da177e4SLinus Torvalds 			tmp = regs->cp0_cause;
11481da177e4SLinus Torvalds 			break;
11491da177e4SLinus Torvalds 		case BADVADDR:
11501da177e4SLinus Torvalds 			tmp = regs->cp0_badvaddr;
11511da177e4SLinus Torvalds 			break;
11521da177e4SLinus Torvalds 		case MMHI:
11531da177e4SLinus Torvalds 			tmp = regs->hi;
11541da177e4SLinus Torvalds 			break;
11551da177e4SLinus Torvalds 		case MMLO:
11561da177e4SLinus Torvalds 			tmp = regs->lo;
11571da177e4SLinus Torvalds 			break;
11589693a853SFranck Bui-Huu #ifdef CONFIG_CPU_HAS_SMARTMIPS
11599693a853SFranck Bui-Huu 		case ACX:
11609693a853SFranck Bui-Huu 			tmp = regs->acx;
11619693a853SFranck Bui-Huu 			break;
11629693a853SFranck Bui-Huu #endif
1163c134a5ecSRalf Baechle 		case DSP_BASE ... DSP_BASE + 5: {
1164c134a5ecSRalf Baechle 			dspreg_t *dregs;
1165c134a5ecSRalf Baechle 
1166e50c0a8fSRalf Baechle 			if (!cpu_has_dsp) {
1167e50c0a8fSRalf Baechle 				tmp = 0;
1168e50c0a8fSRalf Baechle 				ret = -EIO;
1169481bed45SChristoph Hellwig 				goto out;
1170e50c0a8fSRalf Baechle 			}
1171c134a5ecSRalf Baechle 			dregs = __get_dsp_regs(child);
1172f5958b4cSMaciej W. Rozycki 			tmp = dregs[addr - DSP_BASE];
1173e50c0a8fSRalf Baechle 			break;
1174c134a5ecSRalf Baechle 		}
1175e50c0a8fSRalf Baechle 		case DSP_CONTROL:
1176e50c0a8fSRalf Baechle 			if (!cpu_has_dsp) {
1177e50c0a8fSRalf Baechle 				tmp = 0;
1178e50c0a8fSRalf Baechle 				ret = -EIO;
1179481bed45SChristoph Hellwig 				goto out;
1180e50c0a8fSRalf Baechle 			}
1181e50c0a8fSRalf Baechle 			tmp = child->thread.dsp.dspcontrol;
1182e50c0a8fSRalf Baechle 			break;
11831da177e4SLinus Torvalds 		default:
11841da177e4SLinus Torvalds 			tmp = 0;
11851da177e4SLinus Torvalds 			ret = -EIO;
1186481bed45SChristoph Hellwig 			goto out;
11871da177e4SLinus Torvalds 		}
1188fb671139SNamhyung Kim 		ret = put_user(tmp, datalp);
11891da177e4SLinus Torvalds 		break;
11901da177e4SLinus Torvalds 	}
11911da177e4SLinus Torvalds 
11921da177e4SLinus Torvalds 	/* when I and D space are separate, this will have to be fixed. */
11931da177e4SLinus Torvalds 	case PTRACE_POKETEXT: /* write the word at location addr. */
11941da177e4SLinus Torvalds 	case PTRACE_POKEDATA:
1195f284ce72SAlexey Dobriyan 		ret = generic_ptrace_pokedata(child, addr, data);
11961da177e4SLinus Torvalds 		break;
11971da177e4SLinus Torvalds 
11981da177e4SLinus Torvalds 	case PTRACE_POKEUSR: {
11991da177e4SLinus Torvalds 		struct pt_regs *regs;
12001da177e4SLinus Torvalds 		ret = 0;
120140bc9c67SAl Viro 		regs = task_pt_regs(child);
12021da177e4SLinus Torvalds 
12031da177e4SLinus Torvalds 		switch (addr) {
12041da177e4SLinus Torvalds 		case 0 ... 31:
12051da177e4SLinus Torvalds 			regs->regs[addr] = data;
1206de8cd0dcSJames Hogan 			/* System call number may have been changed */
1207de8cd0dcSJames Hogan 			if (addr == 2)
1208de8cd0dcSJames Hogan 				mips_syscall_update_nr(child, regs);
1209de8cd0dcSJames Hogan 			else if (addr == 4 &&
1210de8cd0dcSJames Hogan 				 mips_syscall_is_indirect(child, regs))
1211de8cd0dcSJames Hogan 				mips_syscall_update_nr(child, regs);
12121da177e4SLinus Torvalds 			break;
12136c79759eSPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
12141da177e4SLinus Torvalds 		case FPR_BASE ... FPR_BASE + 31: {
1215bbd426f5SPaul Burton 			union fpureg *fregs = get_fpu_regs(child);
12161da177e4SLinus Torvalds 
1217ac9ad83bSPaul Burton 			init_fp_ctx(child);
1218875d43e7SRalf Baechle #ifdef CONFIG_32BIT
12199a3a92ccSMaciej W. Rozycki 			if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
12201da177e4SLinus Torvalds 				/*
1221597ce172SPaul Burton 				 * The odd registers are actually the high
1222597ce172SPaul Burton 				 * order bits of the values stored in the even
1223d1157b10SMaciej W. Rozycki 				 * registers.
12241da177e4SLinus Torvalds 				 */
1225bbd426f5SPaul Burton 				set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
1226bbd426f5SPaul Burton 					  addr & 1, data);
1227597ce172SPaul Burton 				break;
1228597ce172SPaul Burton 			}
12291da177e4SLinus Torvalds #endif
1230bbd426f5SPaul Burton 			set_fpr64(&fregs[addr - FPR_BASE], 0, data);
12311da177e4SLinus Torvalds 			break;
12321da177e4SLinus Torvalds 		}
12336c79759eSPaul Burton 		case FPC_CSR:
12346c79759eSPaul Burton 			init_fp_ctx(child);
12356c79759eSPaul Burton 			ptrace_setfcr31(child, data);
12366c79759eSPaul Burton 			break;
12376c79759eSPaul Burton #endif
12381da177e4SLinus Torvalds 		case PC:
12391da177e4SLinus Torvalds 			regs->cp0_epc = data;
12401da177e4SLinus Torvalds 			break;
12411da177e4SLinus Torvalds 		case MMHI:
12421da177e4SLinus Torvalds 			regs->hi = data;
12431da177e4SLinus Torvalds 			break;
12441da177e4SLinus Torvalds 		case MMLO:
12451da177e4SLinus Torvalds 			regs->lo = data;
12461da177e4SLinus Torvalds 			break;
12479693a853SFranck Bui-Huu #ifdef CONFIG_CPU_HAS_SMARTMIPS
12489693a853SFranck Bui-Huu 		case ACX:
12499693a853SFranck Bui-Huu 			regs->acx = data;
12509693a853SFranck Bui-Huu 			break;
12519693a853SFranck Bui-Huu #endif
1252c134a5ecSRalf Baechle 		case DSP_BASE ... DSP_BASE + 5: {
1253c134a5ecSRalf Baechle 			dspreg_t *dregs;
1254c134a5ecSRalf Baechle 
1255e50c0a8fSRalf Baechle 			if (!cpu_has_dsp) {
1256e50c0a8fSRalf Baechle 				ret = -EIO;
1257e50c0a8fSRalf Baechle 				break;
1258e50c0a8fSRalf Baechle 			}
1259e50c0a8fSRalf Baechle 
1260c134a5ecSRalf Baechle 			dregs = __get_dsp_regs(child);
1261e50c0a8fSRalf Baechle 			dregs[addr - DSP_BASE] = data;
1262e50c0a8fSRalf Baechle 			break;
1263c134a5ecSRalf Baechle 		}
1264e50c0a8fSRalf Baechle 		case DSP_CONTROL:
1265e50c0a8fSRalf Baechle 			if (!cpu_has_dsp) {
1266e50c0a8fSRalf Baechle 				ret = -EIO;
1267e50c0a8fSRalf Baechle 				break;
1268e50c0a8fSRalf Baechle 			}
1269e50c0a8fSRalf Baechle 			child->thread.dsp.dspcontrol = data;
1270e50c0a8fSRalf Baechle 			break;
12711da177e4SLinus Torvalds 		default:
12721da177e4SLinus Torvalds 			/* The rest are not allowed. */
12731da177e4SLinus Torvalds 			ret = -EIO;
12741da177e4SLinus Torvalds 			break;
12751da177e4SLinus Torvalds 		}
12761da177e4SLinus Torvalds 		break;
12771da177e4SLinus Torvalds 		}
12781da177e4SLinus Torvalds 
1279ea3d710fSDaniel Jacobowitz 	case PTRACE_GETREGS:
1280fb671139SNamhyung Kim 		ret = ptrace_getregs(child, datavp);
1281ea3d710fSDaniel Jacobowitz 		break;
1282ea3d710fSDaniel Jacobowitz 
1283ea3d710fSDaniel Jacobowitz 	case PTRACE_SETREGS:
1284fb671139SNamhyung Kim 		ret = ptrace_setregs(child, datavp);
1285ea3d710fSDaniel Jacobowitz 		break;
1286ea3d710fSDaniel Jacobowitz 
12876c79759eSPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
1288ea3d710fSDaniel Jacobowitz 	case PTRACE_GETFPREGS:
1289fb671139SNamhyung Kim 		ret = ptrace_getfpregs(child, datavp);
1290ea3d710fSDaniel Jacobowitz 		break;
1291ea3d710fSDaniel Jacobowitz 
1292ea3d710fSDaniel Jacobowitz 	case PTRACE_SETFPREGS:
1293fb671139SNamhyung Kim 		ret = ptrace_setfpregs(child, datavp);
1294ea3d710fSDaniel Jacobowitz 		break;
12956c79759eSPaul Burton #endif
12963c37026dSRalf Baechle 	case PTRACE_GET_THREAD_AREA:
1297fb671139SNamhyung Kim 		ret = put_user(task_thread_info(child)->tp_value, datalp);
12983c37026dSRalf Baechle 		break;
12993c37026dSRalf Baechle 
13000926bf95SDavid Daney 	case PTRACE_GET_WATCH_REGS:
1301fb671139SNamhyung Kim 		ret = ptrace_get_watch_regs(child, addrp);
13020926bf95SDavid Daney 		break;
13030926bf95SDavid Daney 
13040926bf95SDavid Daney 	case PTRACE_SET_WATCH_REGS:
1305fb671139SNamhyung Kim 		ret = ptrace_set_watch_regs(child, addrp);
13060926bf95SDavid Daney 		break;
13070926bf95SDavid Daney 
13081da177e4SLinus Torvalds 	default:
13091da177e4SLinus Torvalds 		ret = ptrace_request(child, request, addr, data);
13101da177e4SLinus Torvalds 		break;
13111da177e4SLinus Torvalds 	}
13121da177e4SLinus Torvalds  out:
13131da177e4SLinus Torvalds 	return ret;
13141da177e4SLinus Torvalds }
13151da177e4SLinus Torvalds 
13161da177e4SLinus Torvalds /*
13171da177e4SLinus Torvalds  * Notification of system call entry/exit
13181da177e4SLinus Torvalds  * - triggered by current->work.syscall_trace
13191da177e4SLinus Torvalds  */
syscall_trace_enter(struct pt_regs * regs)1320*f91955daSJiaxun Yang asmlinkage long syscall_trace_enter(struct pt_regs *regs)
13211da177e4SLinus Torvalds {
1322c3fc5cd5SRalf Baechle 	user_exit();
1323c3fc5cd5SRalf Baechle 
1324b6318a90SJames Hogan 	if (test_thread_flag(TIF_SYSCALL_TRACE)) {
1325153474baSEric W. Biederman 		if (ptrace_report_syscall_entry(regs))
13262ac3c8d1SKees Cook 			return -1;
1327b6318a90SJames Hogan 	}
13282ac3c8d1SKees Cook 
1329669c4092SDavid Daney #ifdef CONFIG_SECCOMP
1330669c4092SDavid Daney 	if (unlikely(test_thread_flag(TIF_SECCOMP))) {
1331669c4092SDavid Daney 		int ret, i;
1332669c4092SDavid Daney 		struct seccomp_data sd;
13333d729deaSJames Hogan 		unsigned long args[6];
1334669c4092SDavid Daney 
1335*f91955daSJiaxun Yang 		sd.nr = current_thread_info()->syscall;
133616add411SDmitry V. Levin 		sd.arch = syscall_get_arch(current);
1337b35f549dSSteven Rostedt (Red Hat) 		syscall_get_arguments(current, regs, args);
13383d729deaSJames Hogan 		for (i = 0; i < 6; i++)
13393d729deaSJames Hogan 			sd.args[i] = args[i];
1340669c4092SDavid Daney 		sd.instruction_pointer = KSTK_EIP(current);
1341669c4092SDavid Daney 
1342669c4092SDavid Daney 		ret = __secure_computing(&sd);
1343669c4092SDavid Daney 		if (ret == -1)
1344669c4092SDavid Daney 			return ret;
1345669c4092SDavid Daney 	}
1346669c4092SDavid Daney #endif
1347293c5bd1SRalf Baechle 
13481d7bf993SRalf Baechle 	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
13491d7bf993SRalf Baechle 		trace_sys_enter(regs, regs->regs[2]);
13501d7bf993SRalf Baechle 
1351*f91955daSJiaxun Yang 	audit_syscall_entry(current_thread_info()->syscall,
1352*f91955daSJiaxun Yang 			    regs->regs[4], regs->regs[5],
13532fd6f58bS 			    regs->regs[6], regs->regs[7]);
1354828db212SJames Hogan 
1355828db212SJames Hogan 	/*
1356828db212SJames Hogan 	 * Negative syscall numbers are mistaken for rejected syscalls, but
1357828db212SJames Hogan 	 * won't have had the return value set appropriately, so we do so now.
1358828db212SJames Hogan 	 */
1359*f91955daSJiaxun Yang 	if (current_thread_info()->syscall < 0)
1360828db212SJames Hogan 		syscall_set_return_value(current, regs, -ENOSYS, 0);
1361*f91955daSJiaxun Yang 	return current_thread_info()->syscall;
13621da177e4SLinus Torvalds }
13638b659a39SRalf Baechle 
13648b659a39SRalf Baechle /*
13658b659a39SRalf Baechle  * Notification of system call entry/exit
13668b659a39SRalf Baechle  * - triggered by current->work.syscall_trace
13678b659a39SRalf Baechle  */
syscall_trace_leave(struct pt_regs * regs)13688b659a39SRalf Baechle asmlinkage void syscall_trace_leave(struct pt_regs *regs)
13698b659a39SRalf Baechle {
1370c3fc5cd5SRalf Baechle         /*
1371c3fc5cd5SRalf Baechle 	 * We may come here right after calling schedule_user()
1372c3fc5cd5SRalf Baechle 	 * or do_notify_resume(), in which case we can be in RCU
1373c3fc5cd5SRalf Baechle 	 * user mode.
1374c3fc5cd5SRalf Baechle 	 */
1375c3fc5cd5SRalf Baechle 	user_exit();
1376c3fc5cd5SRalf Baechle 
1377d7e7528bSEric Paris 	audit_syscall_exit(regs);
13788b659a39SRalf Baechle 
13791d7bf993SRalf Baechle 	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
13804f32a39dSJames Hogan 		trace_sys_exit(regs, regs_return_value(regs));
13811d7bf993SRalf Baechle 
1382bc3d22c1SRalf Baechle 	if (test_thread_flag(TIF_SYSCALL_TRACE))
1383153474baSEric W. Biederman 		ptrace_report_syscall_exit(regs, 0);
1384c3fc5cd5SRalf Baechle 
1385c3fc5cd5SRalf Baechle 	user_enter();
13868b659a39SRalf Baechle }
1387