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