xref: /openbmc/linux/arch/x86/include/asm/syscall.h (revision fea88a0c)
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 <linux/sched.h>
17 #include <linux/err.h>
18 #include <asm/asm-offsets.h>	/* For NR_syscalls */
19 #include <asm/unistd.h>
20 
21 extern const unsigned long sys_call_table[];
22 
23 /*
24  * Only the low 32 bits of orig_ax are meaningful, so we return int.
25  * This importantly ignores the high bits on 64-bit, so comparisons
26  * sign-extend the low 32 bits.
27  */
28 static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
29 {
30 	return regs->orig_ax & __SYSCALL_MASK;
31 }
32 
33 static inline void syscall_rollback(struct task_struct *task,
34 				    struct pt_regs *regs)
35 {
36 	regs->ax = regs->orig_ax & __SYSCALL_MASK;
37 }
38 
39 static inline long syscall_get_error(struct task_struct *task,
40 				     struct pt_regs *regs)
41 {
42 	unsigned long error = regs->ax;
43 #ifdef CONFIG_IA32_EMULATION
44 	/*
45 	 * TS_COMPAT is set for 32-bit syscall entries and then
46 	 * remains set until we return to user mode.
47 	 */
48 	if (task_thread_info(task)->status & TS_COMPAT)
49 		/*
50 		 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
51 		 * and will match correctly in comparisons.
52 		 */
53 		error = (long) (int) error;
54 #endif
55 	return IS_ERR_VALUE(error) ? error : 0;
56 }
57 
58 static inline long syscall_get_return_value(struct task_struct *task,
59 					    struct pt_regs *regs)
60 {
61 	return regs->ax;
62 }
63 
64 static inline void syscall_set_return_value(struct task_struct *task,
65 					    struct pt_regs *regs,
66 					    int error, long val)
67 {
68 	regs->ax = (long) error ?: val;
69 }
70 
71 #ifdef CONFIG_X86_32
72 
73 static inline void syscall_get_arguments(struct task_struct *task,
74 					 struct pt_regs *regs,
75 					 unsigned int i, unsigned int n,
76 					 unsigned long *args)
77 {
78 	BUG_ON(i + n > 6);
79 	memcpy(args, &regs->bx + i, n * sizeof(args[0]));
80 }
81 
82 static inline void syscall_set_arguments(struct task_struct *task,
83 					 struct pt_regs *regs,
84 					 unsigned int i, unsigned int n,
85 					 const unsigned long *args)
86 {
87 	BUG_ON(i + n > 6);
88 	memcpy(&regs->bx + i, args, n * sizeof(args[0]));
89 }
90 
91 #else	 /* CONFIG_X86_64 */
92 
93 static inline void syscall_get_arguments(struct task_struct *task,
94 					 struct pt_regs *regs,
95 					 unsigned int i, unsigned int n,
96 					 unsigned long *args)
97 {
98 # ifdef CONFIG_IA32_EMULATION
99 	if (task_thread_info(task)->status & TS_COMPAT)
100 		switch (i) {
101 		case 0:
102 			if (!n--) break;
103 			*args++ = regs->bx;
104 		case 1:
105 			if (!n--) break;
106 			*args++ = regs->cx;
107 		case 2:
108 			if (!n--) break;
109 			*args++ = regs->dx;
110 		case 3:
111 			if (!n--) break;
112 			*args++ = regs->si;
113 		case 4:
114 			if (!n--) break;
115 			*args++ = regs->di;
116 		case 5:
117 			if (!n--) break;
118 			*args++ = regs->bp;
119 		case 6:
120 			if (!n--) break;
121 		default:
122 			BUG();
123 			break;
124 		}
125 	else
126 # endif
127 		switch (i) {
128 		case 0:
129 			if (!n--) break;
130 			*args++ = regs->di;
131 		case 1:
132 			if (!n--) break;
133 			*args++ = regs->si;
134 		case 2:
135 			if (!n--) break;
136 			*args++ = regs->dx;
137 		case 3:
138 			if (!n--) break;
139 			*args++ = regs->r10;
140 		case 4:
141 			if (!n--) break;
142 			*args++ = regs->r8;
143 		case 5:
144 			if (!n--) break;
145 			*args++ = regs->r9;
146 		case 6:
147 			if (!n--) break;
148 		default:
149 			BUG();
150 			break;
151 		}
152 }
153 
154 static inline void syscall_set_arguments(struct task_struct *task,
155 					 struct pt_regs *regs,
156 					 unsigned int i, unsigned int n,
157 					 const unsigned long *args)
158 {
159 # ifdef CONFIG_IA32_EMULATION
160 	if (task_thread_info(task)->status & TS_COMPAT)
161 		switch (i) {
162 		case 0:
163 			if (!n--) break;
164 			regs->bx = *args++;
165 		case 1:
166 			if (!n--) break;
167 			regs->cx = *args++;
168 		case 2:
169 			if (!n--) break;
170 			regs->dx = *args++;
171 		case 3:
172 			if (!n--) break;
173 			regs->si = *args++;
174 		case 4:
175 			if (!n--) break;
176 			regs->di = *args++;
177 		case 5:
178 			if (!n--) break;
179 			regs->bp = *args++;
180 		case 6:
181 			if (!n--) break;
182 		default:
183 			BUG();
184 			break;
185 		}
186 	else
187 # endif
188 		switch (i) {
189 		case 0:
190 			if (!n--) break;
191 			regs->di = *args++;
192 		case 1:
193 			if (!n--) break;
194 			regs->si = *args++;
195 		case 2:
196 			if (!n--) break;
197 			regs->dx = *args++;
198 		case 3:
199 			if (!n--) break;
200 			regs->r10 = *args++;
201 		case 4:
202 			if (!n--) break;
203 			regs->r8 = *args++;
204 		case 5:
205 			if (!n--) break;
206 			regs->r9 = *args++;
207 		case 6:
208 			if (!n--) break;
209 		default:
210 			BUG();
211 			break;
212 		}
213 }
214 
215 #endif	/* CONFIG_X86_32 */
216 
217 #endif	/* _ASM_X86_SYSCALL_H */
218