Merge tag 'pci-v6.16-fixes-3' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci
[linux-2.6-block.git] / arch / s390 / include / asm / syscall.h
CommitLineData
0b73214f 1/* SPDX-License-Identifier: GPL-2.0 */
753c4dd6
MS
2/*
3 * Access to user system call parameters and results
4 *
5 * Copyright IBM Corp. 2008
6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
753c4dd6
MS
7 */
8
9#ifndef _ASM_SYSCALL_H
10#define _ASM_SYSCALL_H 1
11
579ec9e1 12#include <uapi/linux/audit.h>
9bf1226b 13#include <linux/sched.h>
20b40a79 14#include <linux/err.h>
753c4dd6
MS
15#include <asm/ptrace.h>
16
56e62a73
SS
17extern const sys_call_ptr_t sys_call_table[];
18extern const sys_call_ptr_t sys_call_table_emu[];
e7b8e675 19
753c4dd6
MS
20static inline long syscall_get_nr(struct task_struct *task,
21 struct pt_regs *regs)
22{
d3a73acb 23 return test_pt_regs_flag(regs, PIF_SYSCALL) ?
aa33c8cb 24 (regs->int_code & 0xffff) : -1;
753c4dd6
MS
25}
26
cc662273
DL
27static inline void syscall_set_nr(struct task_struct *task,
28 struct pt_regs *regs,
29 int nr)
30{
31 /*
32 * Unlike syscall_get_nr(), syscall_set_nr() can be called only when
33 * the target task is stopped for tracing on entering syscall, so
34 * there is no need to have the same check syscall_get_nr() has.
35 */
36 regs->int_code = (regs->int_code & ~0xffff) | (nr & 0xffff);
37}
38
753c4dd6
MS
39static inline void syscall_rollback(struct task_struct *task,
40 struct pt_regs *regs)
41{
42 regs->gprs[2] = regs->orig_gpr2;
43}
44
45static inline long syscall_get_error(struct task_struct *task,
46 struct pt_regs *regs)
47{
b3583fca
DL
48 unsigned long error = regs->gprs[2];
49#ifdef CONFIG_COMPAT
50 if (test_tsk_thread_flag(task, TIF_31BIT)) {
51 /*
52 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
53 * and will match correctly in comparisons.
54 */
55 error = (long)(int)error;
56 }
57#endif
58 return IS_ERR_VALUE(error) ? error : 0;
753c4dd6
MS
59}
60
61static inline long syscall_get_return_value(struct task_struct *task,
62 struct pt_regs *regs)
63{
64 return regs->gprs[2];
65}
66
67static inline void syscall_set_return_value(struct task_struct *task,
68 struct pt_regs *regs,
69 int error, long val)
70{
56e62a73 71 set_pt_regs_flag(regs, PIF_SYSCALL_RET_SET);
dc295880 72 regs->gprs[2] = error ? error : val;
753c4dd6
MS
73}
74
75static inline void syscall_get_arguments(struct task_struct *task,
76 struct pt_regs *regs,
753c4dd6
MS
77 unsigned long *args)
78{
59da2139
MS
79 unsigned long mask = -1UL;
80
753c4dd6 81#ifdef CONFIG_COMPAT
59da2139
MS
82 if (test_tsk_thread_flag(task, TIF_31BIT))
83 mask = 0xffffffff;
753c4dd6 84#endif
8751b6e9
SS
85 for (int i = 1; i < 6; i++)
86 args[i] = regs->gprs[2 + i] & mask;
b35f549d
SRRH
87
88 args[0] = regs->orig_gpr2 & mask;
753c4dd6
MS
89}
90
17fc7b8f
DL
91static inline void syscall_set_arguments(struct task_struct *task,
92 struct pt_regs *regs,
93 const unsigned long *args)
94{
95 regs->orig_gpr2 = args[0];
96 for (int n = 1; n < 6; n++)
97 regs->gprs[2 + n] = args[n];
98}
99
16add411 100static inline int syscall_get_arch(struct task_struct *task)
c63cb468
HC
101{
102#ifdef CONFIG_COMPAT
16add411 103 if (test_tsk_thread_flag(task, TIF_31BIT))
c63cb468
HC
104 return AUDIT_ARCH_S390;
105#endif
1a327ffd 106 return AUDIT_ARCH_S390X;
c63cb468 107}
56e62a73
SS
108
109static inline bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs)
110{
111 return false;
112}
113
91f05c27
HC
114#define SYSCALL_FMT_0
115#define SYSCALL_FMT_1 , "0" (r2)
116#define SYSCALL_FMT_2 , "d" (r3) SYSCALL_FMT_1
117#define SYSCALL_FMT_3 , "d" (r4) SYSCALL_FMT_2
118#define SYSCALL_FMT_4 , "d" (r5) SYSCALL_FMT_3
119#define SYSCALL_FMT_5 , "d" (r6) SYSCALL_FMT_4
120#define SYSCALL_FMT_6 , "d" (r7) SYSCALL_FMT_5
121
122#define SYSCALL_PARM_0
123#define SYSCALL_PARM_1 , long arg1
124#define SYSCALL_PARM_2 SYSCALL_PARM_1, long arg2
125#define SYSCALL_PARM_3 SYSCALL_PARM_2, long arg3
126#define SYSCALL_PARM_4 SYSCALL_PARM_3, long arg4
127#define SYSCALL_PARM_5 SYSCALL_PARM_4, long arg5
128#define SYSCALL_PARM_6 SYSCALL_PARM_5, long arg6
129
130#define SYSCALL_REGS_0
131#define SYSCALL_REGS_1 \
132 register long r2 asm("2") = arg1
133#define SYSCALL_REGS_2 \
134 SYSCALL_REGS_1; \
135 register long r3 asm("3") = arg2
136#define SYSCALL_REGS_3 \
137 SYSCALL_REGS_2; \
138 register long r4 asm("4") = arg3
139#define SYSCALL_REGS_4 \
140 SYSCALL_REGS_3; \
141 register long r5 asm("5") = arg4
142#define SYSCALL_REGS_5 \
143 SYSCALL_REGS_4; \
144 register long r6 asm("6") = arg5
145#define SYSCALL_REGS_6 \
146 SYSCALL_REGS_5; \
147 register long r7 asm("7") = arg6
148
149#define GENERATE_SYSCALL_FUNC(nr) \
150static __always_inline \
151long syscall##nr(unsigned long syscall SYSCALL_PARM_##nr) \
152{ \
153 register unsigned long r1 asm ("1") = syscall; \
154 register long rc asm ("2"); \
155 SYSCALL_REGS_##nr; \
156 \
157 asm volatile ( \
158 " svc 0\n" \
159 : "=d" (rc) \
160 : "d" (r1) SYSCALL_FMT_##nr \
161 : "memory"); \
162 return rc; \
163}
164
165GENERATE_SYSCALL_FUNC(0)
166GENERATE_SYSCALL_FUNC(1)
167GENERATE_SYSCALL_FUNC(2)
168GENERATE_SYSCALL_FUNC(3)
169GENERATE_SYSCALL_FUNC(4)
170GENERATE_SYSCALL_FUNC(5)
171GENERATE_SYSCALL_FUNC(6)
172
753c4dd6 173#endif /* _ASM_SYSCALL_H */