xref: /openbmc/linux/arch/sparc/include/asm/syscall.h (revision b2441318)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
2badcbf0eSDavid S. Miller #ifndef __ASM_SPARC_SYSCALL_H
3badcbf0eSDavid S. Miller #define __ASM_SPARC_SYSCALL_H
4badcbf0eSDavid S. Miller 
5ce5d1128SEric Paris #include <uapi/linux/audit.h>
6badcbf0eSDavid S. Miller #include <linux/kernel.h>
7203f7907SAndy Lutomirski #include <linux/compat.h>
8badcbf0eSDavid S. Miller #include <linux/sched.h>
9badcbf0eSDavid S. Miller #include <asm/ptrace.h>
10ce5d1128SEric Paris #include <asm/thread_info.h>
11badcbf0eSDavid S. Miller 
12e7b8e675SMike Frysinger /*
13e7b8e675SMike Frysinger  * The syscall table always contains 32 bit pointers since we know that the
14e7b8e675SMike Frysinger  * address of the function to be called is (way) below 4GB.  So the "int"
15e7b8e675SMike Frysinger  * type here is what we want [need] for both 32 bit and 64 bit systems.
16e7b8e675SMike Frysinger  */
17e7b8e675SMike Frysinger extern const unsigned int sys_call_table[];
18e7b8e675SMike Frysinger 
19badcbf0eSDavid S. Miller /* The system call number is given by the user in %g1 */
20badcbf0eSDavid S. Miller static inline long syscall_get_nr(struct task_struct *task,
21badcbf0eSDavid S. Miller 				  struct pt_regs *regs)
22badcbf0eSDavid S. Miller {
23badcbf0eSDavid S. Miller 	int syscall_p = pt_regs_is_syscall(regs);
24badcbf0eSDavid S. Miller 
25badcbf0eSDavid S. Miller 	return (syscall_p ? regs->u_regs[UREG_G1] : -1L);
26badcbf0eSDavid S. Miller }
27badcbf0eSDavid S. Miller 
28badcbf0eSDavid S. Miller static inline void syscall_rollback(struct task_struct *task,
29badcbf0eSDavid S. Miller 				    struct pt_regs *regs)
30badcbf0eSDavid S. Miller {
31badcbf0eSDavid S. Miller 	/* XXX This needs some thought.  On Sparc we don't
32badcbf0eSDavid S. Miller 	 * XXX save away the original %o0 value somewhere.
33badcbf0eSDavid S. Miller 	 * XXX Instead we hold it in register %l5 at the top
34badcbf0eSDavid S. Miller 	 * XXX level trap frame and pass this down to the signal
35badcbf0eSDavid S. Miller 	 * XXX dispatch code which is the only place that value
36badcbf0eSDavid S. Miller 	 * XXX ever was needed.
37badcbf0eSDavid S. Miller 	 */
38badcbf0eSDavid S. Miller }
39badcbf0eSDavid S. Miller 
40badcbf0eSDavid S. Miller #ifdef CONFIG_SPARC32
41badcbf0eSDavid S. Miller static inline bool syscall_has_error(struct pt_regs *regs)
42badcbf0eSDavid S. Miller {
43badcbf0eSDavid S. Miller 	return (regs->psr & PSR_C) ? true : false;
44badcbf0eSDavid S. Miller }
45badcbf0eSDavid S. Miller static inline void syscall_set_error(struct pt_regs *regs)
46badcbf0eSDavid S. Miller {
47badcbf0eSDavid S. Miller 	regs->psr |= PSR_C;
48badcbf0eSDavid S. Miller }
49badcbf0eSDavid S. Miller static inline void syscall_clear_error(struct pt_regs *regs)
50badcbf0eSDavid S. Miller {
51badcbf0eSDavid S. Miller 	regs->psr &= ~PSR_C;
52badcbf0eSDavid S. Miller }
53badcbf0eSDavid S. Miller #else
54badcbf0eSDavid S. Miller static inline bool syscall_has_error(struct pt_regs *regs)
55badcbf0eSDavid S. Miller {
56badcbf0eSDavid S. Miller 	return (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY)) ? true : false;
57badcbf0eSDavid S. Miller }
58badcbf0eSDavid S. Miller static inline void syscall_set_error(struct pt_regs *regs)
59badcbf0eSDavid S. Miller {
60badcbf0eSDavid S. Miller 	regs->tstate |= (TSTATE_XCARRY | TSTATE_ICARRY);
61badcbf0eSDavid S. Miller }
62badcbf0eSDavid S. Miller static inline void syscall_clear_error(struct pt_regs *regs)
63badcbf0eSDavid S. Miller {
64badcbf0eSDavid S. Miller 	regs->tstate &= ~(TSTATE_XCARRY | TSTATE_ICARRY);
65badcbf0eSDavid S. Miller }
66badcbf0eSDavid S. Miller #endif
67badcbf0eSDavid S. Miller 
68badcbf0eSDavid S. Miller static inline long syscall_get_error(struct task_struct *task,
69badcbf0eSDavid S. Miller 				     struct pt_regs *regs)
70badcbf0eSDavid S. Miller {
71badcbf0eSDavid S. Miller 	long val = regs->u_regs[UREG_I0];
72badcbf0eSDavid S. Miller 
73badcbf0eSDavid S. Miller 	return (syscall_has_error(regs) ? -val : 0);
74badcbf0eSDavid S. Miller }
75badcbf0eSDavid S. Miller 
76badcbf0eSDavid S. Miller static inline long syscall_get_return_value(struct task_struct *task,
77badcbf0eSDavid S. Miller 					    struct pt_regs *regs)
78badcbf0eSDavid S. Miller {
79badcbf0eSDavid S. Miller 	long val = regs->u_regs[UREG_I0];
80badcbf0eSDavid S. Miller 
81badcbf0eSDavid S. Miller 	return val;
82badcbf0eSDavid S. Miller }
83badcbf0eSDavid S. Miller 
84badcbf0eSDavid S. Miller static inline void syscall_set_return_value(struct task_struct *task,
85badcbf0eSDavid S. Miller 					    struct pt_regs *regs,
86badcbf0eSDavid S. Miller 					    int error, long val)
87badcbf0eSDavid S. Miller {
88badcbf0eSDavid S. Miller 	if (error) {
89badcbf0eSDavid S. Miller 		syscall_set_error(regs);
90badcbf0eSDavid S. Miller 		regs->u_regs[UREG_I0] = -error;
91badcbf0eSDavid S. Miller 	} else {
92badcbf0eSDavid S. Miller 		syscall_clear_error(regs);
93badcbf0eSDavid S. Miller 		regs->u_regs[UREG_I0] = val;
94badcbf0eSDavid S. Miller 	}
95badcbf0eSDavid S. Miller }
96badcbf0eSDavid S. Miller 
97badcbf0eSDavid S. Miller static inline void syscall_get_arguments(struct task_struct *task,
98badcbf0eSDavid S. Miller 					 struct pt_regs *regs,
99badcbf0eSDavid S. Miller 					 unsigned int i, unsigned int n,
100badcbf0eSDavid S. Miller 					 unsigned long *args)
101badcbf0eSDavid S. Miller {
102badcbf0eSDavid S. Miller 	int zero_extend = 0;
103badcbf0eSDavid S. Miller 	unsigned int j;
104badcbf0eSDavid S. Miller 
105badcbf0eSDavid S. Miller #ifdef CONFIG_SPARC64
106badcbf0eSDavid S. Miller 	if (test_tsk_thread_flag(task, TIF_32BIT))
107badcbf0eSDavid S. Miller 		zero_extend = 1;
108badcbf0eSDavid S. Miller #endif
109badcbf0eSDavid S. Miller 
110badcbf0eSDavid S. Miller 	for (j = 0; j < n; j++) {
111badcbf0eSDavid S. Miller 		unsigned long val = regs->u_regs[UREG_I0 + i + j];
112badcbf0eSDavid S. Miller 
113badcbf0eSDavid S. Miller 		if (zero_extend)
114badcbf0eSDavid S. Miller 			args[j] = (u32) val;
115badcbf0eSDavid S. Miller 		else
116badcbf0eSDavid S. Miller 			args[j] = val;
117badcbf0eSDavid S. Miller 	}
118badcbf0eSDavid S. Miller }
119badcbf0eSDavid S. Miller 
120badcbf0eSDavid S. Miller static inline void syscall_set_arguments(struct task_struct *task,
121badcbf0eSDavid S. Miller 					 struct pt_regs *regs,
122badcbf0eSDavid S. Miller 					 unsigned int i, unsigned int n,
123badcbf0eSDavid S. Miller 					 const unsigned long *args)
124badcbf0eSDavid S. Miller {
125badcbf0eSDavid S. Miller 	unsigned int j;
126badcbf0eSDavid S. Miller 
127badcbf0eSDavid S. Miller 	for (j = 0; j < n; j++)
128badcbf0eSDavid S. Miller 		regs->u_regs[UREG_I0 + i + j] = args[j];
129badcbf0eSDavid S. Miller }
130badcbf0eSDavid S. Miller 
131ce5d1128SEric Paris static inline int syscall_get_arch(void)
132ce5d1128SEric Paris {
133203f7907SAndy Lutomirski #if defined(CONFIG_SPARC64) && defined(CONFIG_COMPAT)
134203f7907SAndy Lutomirski 	return in_compat_syscall() ? AUDIT_ARCH_SPARC : AUDIT_ARCH_SPARC64;
135203f7907SAndy Lutomirski #elif defined(CONFIG_SPARC64)
136203f7907SAndy Lutomirski 	return AUDIT_ARCH_SPARC64;
137203f7907SAndy Lutomirski #else
138203f7907SAndy Lutomirski 	return AUDIT_ARCH_SPARC;
139203f7907SAndy Lutomirski #endif
140ce5d1128SEric Paris }
141ce5d1128SEric Paris 
142badcbf0eSDavid S. Miller #endif /* __ASM_SPARC_SYSCALL_H */
143