xref: /openbmc/linux/arch/x86/include/asm/syscall.h (revision a8fe58ce)
1 /*
2  * Access to user system call parameters and results
3  *
4  * Copyright (C) 2008-2009 Red Hat, Inc.  All rights reserved.
5  *
6  * This copyrighted material is made available to anyone wishing to use,
7  * modify, copy, or redistribute it subject to the terms and conditions
8  * of the GNU General Public License v.2.
9  *
10  * See asm-generic/syscall.h for descriptions of what we must do here.
11  */
12 
13 #ifndef _ASM_X86_SYSCALL_H
14 #define _ASM_X86_SYSCALL_H
15 
16 #include <uapi/linux/audit.h>
17 #include <linux/sched.h>
18 #include <linux/err.h>
19 #include <asm/asm-offsets.h>	/* For NR_syscalls */
20 #include <asm/thread_info.h>	/* for TS_COMPAT */
21 #include <asm/unistd.h>
22 
23 typedef asmlinkage long (*sys_call_ptr_t)(unsigned long, unsigned long,
24 					  unsigned long, unsigned long,
25 					  unsigned long, unsigned long);
26 extern const sys_call_ptr_t sys_call_table[];
27 
28 #if defined(CONFIG_X86_32)
29 #define ia32_sys_call_table sys_call_table
30 #define __NR_syscall_compat_max __NR_syscall_max
31 #define IA32_NR_syscalls NR_syscalls
32 #endif
33 
34 #if defined(CONFIG_IA32_EMULATION)
35 extern const sys_call_ptr_t ia32_sys_call_table[];
36 #endif
37 
38 /*
39  * Only the low 32 bits of orig_ax are meaningful, so we return int.
40  * This importantly ignores the high bits on 64-bit, so comparisons
41  * sign-extend the low 32 bits.
42  */
43 static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
44 {
45 	return regs->orig_ax;
46 }
47 
48 static inline void syscall_rollback(struct task_struct *task,
49 				    struct pt_regs *regs)
50 {
51 	regs->ax = regs->orig_ax;
52 }
53 
54 static inline long syscall_get_error(struct task_struct *task,
55 				     struct pt_regs *regs)
56 {
57 	unsigned long error = regs->ax;
58 #ifdef CONFIG_IA32_EMULATION
59 	/*
60 	 * TS_COMPAT is set for 32-bit syscall entries and then
61 	 * remains set until we return to user mode.
62 	 */
63 	if (task_thread_info(task)->status & TS_COMPAT)
64 		/*
65 		 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
66 		 * and will match correctly in comparisons.
67 		 */
68 		error = (long) (int) error;
69 #endif
70 	return IS_ERR_VALUE(error) ? error : 0;
71 }
72 
73 static inline long syscall_get_return_value(struct task_struct *task,
74 					    struct pt_regs *regs)
75 {
76 	return regs->ax;
77 }
78 
79 static inline void syscall_set_return_value(struct task_struct *task,
80 					    struct pt_regs *regs,
81 					    int error, long val)
82 {
83 	regs->ax = (long) error ?: val;
84 }
85 
86 #ifdef CONFIG_X86_32
87 
88 static inline void syscall_get_arguments(struct task_struct *task,
89 					 struct pt_regs *regs,
90 					 unsigned int i, unsigned int n,
91 					 unsigned long *args)
92 {
93 	BUG_ON(i + n > 6);
94 	memcpy(args, &regs->bx + i, n * sizeof(args[0]));
95 }
96 
97 static inline void syscall_set_arguments(struct task_struct *task,
98 					 struct pt_regs *regs,
99 					 unsigned int i, unsigned int n,
100 					 const unsigned long *args)
101 {
102 	BUG_ON(i + n > 6);
103 	memcpy(&regs->bx + i, args, n * sizeof(args[0]));
104 }
105 
106 static inline int syscall_get_arch(void)
107 {
108 	return AUDIT_ARCH_I386;
109 }
110 
111 #else	 /* CONFIG_X86_64 */
112 
113 static inline void syscall_get_arguments(struct task_struct *task,
114 					 struct pt_regs *regs,
115 					 unsigned int i, unsigned int n,
116 					 unsigned long *args)
117 {
118 # ifdef CONFIG_IA32_EMULATION
119 	if (task_thread_info(task)->status & TS_COMPAT)
120 		switch (i) {
121 		case 0:
122 			if (!n--) break;
123 			*args++ = regs->bx;
124 		case 1:
125 			if (!n--) break;
126 			*args++ = regs->cx;
127 		case 2:
128 			if (!n--) break;
129 			*args++ = regs->dx;
130 		case 3:
131 			if (!n--) break;
132 			*args++ = regs->si;
133 		case 4:
134 			if (!n--) break;
135 			*args++ = regs->di;
136 		case 5:
137 			if (!n--) break;
138 			*args++ = regs->bp;
139 		case 6:
140 			if (!n--) break;
141 		default:
142 			BUG();
143 			break;
144 		}
145 	else
146 # endif
147 		switch (i) {
148 		case 0:
149 			if (!n--) break;
150 			*args++ = regs->di;
151 		case 1:
152 			if (!n--) break;
153 			*args++ = regs->si;
154 		case 2:
155 			if (!n--) break;
156 			*args++ = regs->dx;
157 		case 3:
158 			if (!n--) break;
159 			*args++ = regs->r10;
160 		case 4:
161 			if (!n--) break;
162 			*args++ = regs->r8;
163 		case 5:
164 			if (!n--) break;
165 			*args++ = regs->r9;
166 		case 6:
167 			if (!n--) break;
168 		default:
169 			BUG();
170 			break;
171 		}
172 }
173 
174 static inline void syscall_set_arguments(struct task_struct *task,
175 					 struct pt_regs *regs,
176 					 unsigned int i, unsigned int n,
177 					 const unsigned long *args)
178 {
179 # ifdef CONFIG_IA32_EMULATION
180 	if (task_thread_info(task)->status & TS_COMPAT)
181 		switch (i) {
182 		case 0:
183 			if (!n--) break;
184 			regs->bx = *args++;
185 		case 1:
186 			if (!n--) break;
187 			regs->cx = *args++;
188 		case 2:
189 			if (!n--) break;
190 			regs->dx = *args++;
191 		case 3:
192 			if (!n--) break;
193 			regs->si = *args++;
194 		case 4:
195 			if (!n--) break;
196 			regs->di = *args++;
197 		case 5:
198 			if (!n--) break;
199 			regs->bp = *args++;
200 		case 6:
201 			if (!n--) break;
202 		default:
203 			BUG();
204 			break;
205 		}
206 	else
207 # endif
208 		switch (i) {
209 		case 0:
210 			if (!n--) break;
211 			regs->di = *args++;
212 		case 1:
213 			if (!n--) break;
214 			regs->si = *args++;
215 		case 2:
216 			if (!n--) break;
217 			regs->dx = *args++;
218 		case 3:
219 			if (!n--) break;
220 			regs->r10 = *args++;
221 		case 4:
222 			if (!n--) break;
223 			regs->r8 = *args++;
224 		case 5:
225 			if (!n--) break;
226 			regs->r9 = *args++;
227 		case 6:
228 			if (!n--) break;
229 		default:
230 			BUG();
231 			break;
232 		}
233 }
234 
235 static inline int syscall_get_arch(void)
236 {
237 #ifdef CONFIG_IA32_EMULATION
238 	/*
239 	 * TS_COMPAT is set for 32-bit syscall entry and then
240 	 * remains set until we return to user mode.
241 	 *
242 	 * TIF_IA32 tasks should always have TS_COMPAT set at
243 	 * system call time.
244 	 *
245 	 * x32 tasks should be considered AUDIT_ARCH_X86_64.
246 	 */
247 	if (task_thread_info(current)->status & TS_COMPAT)
248 		return AUDIT_ARCH_I386;
249 #endif
250 	/* Both x32 and x86_64 are considered "64-bit". */
251 	return AUDIT_ARCH_X86_64;
252 }
253 #endif	/* CONFIG_X86_32 */
254 
255 #endif	/* _ASM_X86_SYSCALL_H */
256