]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - arch/x86/include/asm/syscall.h
Merge remote-tracking branch 'sound-current/for-linus'
[karo-tx-linux.git] / arch / x86 / include / asm / syscall.h
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 */