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