Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
badcbf0e DM |
2 | #ifndef __ASM_SPARC_SYSCALL_H |
3 | #define __ASM_SPARC_SYSCALL_H | |
4 | ||
ce5d1128 | 5 | #include <uapi/linux/audit.h> |
badcbf0e | 6 | #include <linux/kernel.h> |
203f7907 | 7 | #include <linux/compat.h> |
badcbf0e DM |
8 | #include <linux/sched.h> |
9 | #include <asm/ptrace.h> | |
ce5d1128 | 10 | #include <asm/thread_info.h> |
badcbf0e | 11 | |
e7b8e675 MF |
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 | ||
badcbf0e DM |
19 | /* The system call number is given by the user in %g1 */ |
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 | ||
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 | |
41 | static inline bool syscall_has_error(struct pt_regs *regs) | |
42 | { | |
43 | return (regs->psr & PSR_C) ? true : false; | |
44 | } | |
45 | static inline void syscall_set_error(struct pt_regs *regs) | |
46 | { | |
47 | regs->psr |= PSR_C; | |
48 | } | |
49 | static inline void syscall_clear_error(struct pt_regs *regs) | |
50 | { | |
51 | regs->psr &= ~PSR_C; | |
52 | } | |
53 | #else | |
54 | static inline bool syscall_has_error(struct pt_regs *regs) | |
55 | { | |
56 | return (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY)) ? true : false; | |
57 | } | |
58 | static inline void syscall_set_error(struct pt_regs *regs) | |
59 | { | |
60 | regs->tstate |= (TSTATE_XCARRY | TSTATE_ICARRY); | |
61 | } | |
62 | static inline void syscall_clear_error(struct pt_regs *regs) | |
63 | { | |
64 | regs->tstate &= ~(TSTATE_XCARRY | TSTATE_ICARRY); | |
65 | } | |
66 | #endif | |
67 | ||
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 | ||
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 | ||
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 | ||
97 | static inline void syscall_get_arguments(struct task_struct *task, | |
98 | struct pt_regs *regs, | |
99 | unsigned int i, unsigned int n, | |
100 | unsigned long *args) | |
101 | { | |
102 | int zero_extend = 0; | |
103 | unsigned int j; | |
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 + i + j]; | |
112 | ||
113 | if (zero_extend) | |
114 | args[j] = (u32) val; | |
115 | else | |
116 | args[j] = val; | |
117 | } | |
118 | } | |
119 | ||
120 | static inline void syscall_set_arguments(struct task_struct *task, | |
121 | struct pt_regs *regs, | |
122 | unsigned int i, unsigned int n, | |
123 | const unsigned long *args) | |
124 | { | |
125 | unsigned int j; | |
126 | ||
127 | for (j = 0; j < n; j++) | |
128 | regs->u_regs[UREG_I0 + i + j] = args[j]; | |
129 | } | |
130 | ||
16add411 | 131 | static inline int syscall_get_arch(struct task_struct *task) |
ce5d1128 | 132 | { |
203f7907 | 133 | #if defined(CONFIG_SPARC64) && defined(CONFIG_COMPAT) |
16add411 DL |
134 | return test_tsk_thread_flag(task, TIF_32BIT) |
135 | ? AUDIT_ARCH_SPARC : AUDIT_ARCH_SPARC64; | |
203f7907 AL |
136 | #elif defined(CONFIG_SPARC64) |
137 | return AUDIT_ARCH_SPARC64; | |
138 | #else | |
139 | return AUDIT_ARCH_SPARC; | |
140 | #endif | |
ce5d1128 EP |
141 | } |
142 | ||
badcbf0e | 143 | #endif /* __ASM_SPARC_SYSCALL_H */ |