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