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