xref: /openbmc/linux/arch/x86/include/asm/syscall.h (revision 579ec9e1ab0bdca2dbc3c942aa1a530a6ec8c349)
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 
16*579ec9e1SEric Paris #include <uapi/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 
231599e8fcSAndi Kleen typedef void (*sys_call_ptr_t)(void);
241599e8fcSAndi Kleen extern const sys_call_ptr_t sys_call_table[];
25e7b8e675SMike Frysinger 
26bb898558SAl Viro /*
2718c1e2c8SRoland McGrath  * Only the low 32 bits of orig_ax are meaningful, so we return int.
2818c1e2c8SRoland McGrath  * This importantly ignores the high bits on 64-bit, so comparisons
2918c1e2c8SRoland McGrath  * sign-extend the low 32 bits.
30bb898558SAl Viro  */
3118c1e2c8SRoland McGrath static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
3218c1e2c8SRoland McGrath {
338b4b9f27SPaul Moore 	return regs->orig_ax;
34bb898558SAl Viro }
35bb898558SAl Viro 
36bb898558SAl Viro static inline void syscall_rollback(struct task_struct *task,
37bb898558SAl Viro 				    struct pt_regs *regs)
38bb898558SAl Viro {
398b4b9f27SPaul Moore 	regs->ax = regs->orig_ax;
40bb898558SAl Viro }
41bb898558SAl Viro 
42bb898558SAl Viro static inline long syscall_get_error(struct task_struct *task,
43bb898558SAl Viro 				     struct pt_regs *regs)
44bb898558SAl Viro {
45bb898558SAl Viro 	unsigned long error = regs->ax;
46bb898558SAl Viro #ifdef CONFIG_IA32_EMULATION
47bb898558SAl Viro 	/*
48bb898558SAl Viro 	 * TS_COMPAT is set for 32-bit syscall entries and then
49bb898558SAl Viro 	 * remains set until we return to user mode.
50bb898558SAl Viro 	 */
51bb898558SAl Viro 	if (task_thread_info(task)->status & TS_COMPAT)
52bb898558SAl Viro 		/*
53bb898558SAl Viro 		 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
54bb898558SAl Viro 		 * and will match correctly in comparisons.
55bb898558SAl Viro 		 */
56bb898558SAl Viro 		error = (long) (int) error;
57bb898558SAl Viro #endif
58bb898558SAl Viro 	return IS_ERR_VALUE(error) ? error : 0;
59bb898558SAl Viro }
60bb898558SAl Viro 
61bb898558SAl Viro static inline long syscall_get_return_value(struct task_struct *task,
62bb898558SAl Viro 					    struct pt_regs *regs)
63bb898558SAl Viro {
64bb898558SAl Viro 	return regs->ax;
65bb898558SAl Viro }
66bb898558SAl Viro 
67bb898558SAl Viro static inline void syscall_set_return_value(struct task_struct *task,
68bb898558SAl Viro 					    struct pt_regs *regs,
69bb898558SAl Viro 					    int error, long val)
70bb898558SAl Viro {
71bb898558SAl Viro 	regs->ax = (long) error ?: val;
72bb898558SAl Viro }
73bb898558SAl Viro 
74bb898558SAl Viro #ifdef CONFIG_X86_32
75bb898558SAl Viro 
76bb898558SAl Viro static inline void syscall_get_arguments(struct task_struct *task,
77bb898558SAl Viro 					 struct pt_regs *regs,
78bb898558SAl Viro 					 unsigned int i, unsigned int n,
79bb898558SAl Viro 					 unsigned long *args)
80bb898558SAl Viro {
81bb898558SAl Viro 	BUG_ON(i + n > 6);
82bb898558SAl Viro 	memcpy(args, &regs->bx + i, n * sizeof(args[0]));
83bb898558SAl Viro }
84bb898558SAl Viro 
85bb898558SAl Viro static inline void syscall_set_arguments(struct task_struct *task,
86bb898558SAl Viro 					 struct pt_regs *regs,
87bb898558SAl Viro 					 unsigned int i, unsigned int n,
88bb898558SAl Viro 					 const unsigned long *args)
89bb898558SAl Viro {
90bb898558SAl Viro 	BUG_ON(i + n > 6);
91bb898558SAl Viro 	memcpy(&regs->bx + i, args, n * sizeof(args[0]));
92bb898558SAl Viro }
93bb898558SAl Viro 
945e937a9aSEric Paris static inline int syscall_get_arch(void)
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 
2235e937a9aSEric Paris static inline int syscall_get_arch(void)
224b7456536SWill Drewry {
225b7456536SWill Drewry #ifdef CONFIG_IA32_EMULATION
226b7456536SWill Drewry 	/*
227b7456536SWill Drewry 	 * TS_COMPAT is set for 32-bit syscall entry and then
228b7456536SWill Drewry 	 * remains set until we return to user mode.
229b7456536SWill Drewry 	 *
230b7456536SWill Drewry 	 * TIF_IA32 tasks should always have TS_COMPAT set at
231b7456536SWill Drewry 	 * system call time.
232b7456536SWill Drewry 	 *
233b7456536SWill Drewry 	 * x32 tasks should be considered AUDIT_ARCH_X86_64.
234b7456536SWill Drewry 	 */
2355e937a9aSEric Paris 	if (task_thread_info(current)->status & TS_COMPAT)
236b7456536SWill Drewry 		return AUDIT_ARCH_I386;
237b7456536SWill Drewry #endif
238b7456536SWill Drewry 	/* Both x32 and x86_64 are considered "64-bit". */
239b7456536SWill Drewry 	return AUDIT_ARCH_X86_64;
240b7456536SWill Drewry }
241bb898558SAl Viro #endif	/* CONFIG_X86_32 */
242bb898558SAl Viro 
2435e1b0075SH. Peter Anvin #endif	/* _ASM_X86_SYSCALL_H */
244