xref: /openbmc/linux/arch/sparc/include/asm/syscall.h (revision 7962c2ed)
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 */
syscall_get_nr(struct task_struct * task,struct pt_regs * regs)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 
syscall_rollback(struct task_struct * task,struct pt_regs * regs)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
syscall_has_error(struct pt_regs * regs)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 }
syscall_set_error(struct pt_regs * regs)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 }
syscall_clear_error(struct pt_regs * regs)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
syscall_has_error(struct pt_regs * regs)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 }
syscall_set_error(struct pt_regs * regs)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 }
syscall_clear_error(struct pt_regs * regs)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 
syscall_get_error(struct task_struct * task,struct pt_regs * regs)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 
syscall_get_return_value(struct task_struct * task,struct pt_regs * regs)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 
syscall_set_return_value(struct task_struct * task,struct pt_regs * regs,int error,long val)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 
syscall_get_arguments(struct task_struct * task,struct pt_regs * regs,unsigned long * args)97badcbf0eSDavid S. Miller static inline void syscall_get_arguments(struct task_struct *task,
98badcbf0eSDavid S. Miller 					 struct pt_regs *regs,
99badcbf0eSDavid S. Miller 					 unsigned long *args)
100badcbf0eSDavid S. Miller {
101badcbf0eSDavid S. Miller 	int zero_extend = 0;
102badcbf0eSDavid S. Miller 	unsigned int j;
103b35f549dSSteven Rostedt (Red Hat) 	unsigned int n = 6;
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++) {
111b35f549dSSteven Rostedt (Red Hat) 		unsigned long val = regs->u_regs[UREG_I0 + 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 
syscall_get_arch(struct task_struct * task)12016add411SDmitry V. Levin static inline int syscall_get_arch(struct task_struct *task)
121ce5d1128SEric Paris {
122203f7907SAndy Lutomirski #if defined(CONFIG_SPARC64) && defined(CONFIG_COMPAT)
12316add411SDmitry V. Levin 	return test_tsk_thread_flag(task, TIF_32BIT)
12416add411SDmitry V. Levin 		? AUDIT_ARCH_SPARC : AUDIT_ARCH_SPARC64;
125203f7907SAndy Lutomirski #elif defined(CONFIG_SPARC64)
126203f7907SAndy Lutomirski 	return AUDIT_ARCH_SPARC64;
127203f7907SAndy Lutomirski #else
128203f7907SAndy Lutomirski 	return AUDIT_ARCH_SPARC;
129203f7907SAndy Lutomirski #endif
130ce5d1128SEric Paris }
131ce5d1128SEric Paris 
132badcbf0eSDavid S. Miller #endif /* __ASM_SPARC_SYSCALL_H */
133