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