a2631d648f548d2586c4196cdd4c9e93e99eafdd
[platform/framework/web/crosswalk.git] / src / native_client / src / nonsfi / linux / linux_syscall_wrappers.h
1 /*
2  * Copyright (c) 2014 The Native Client Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 #ifndef NATIVE_CLIENT_SRC_NONSFI_LINUX_LINUX_SYSCALL_WRAPPERS_H_
8 #define NATIVE_CLIENT_SRC_NONSFI_LINUX_LINUX_SYSCALL_WRAPPERS_H_ 1
9
10 /*
11  * Wrappers for calling Linux syscalls directly.
12  *
13  * This provides functionality similar to linux_syscall_support.h (from
14  * https://code.google.com/p/linux-syscall-support/), also known as LSS.
15  * We are not reusing LSS here because:
16  *
17  *  * LSS depends on Linux kernel headers (and glibc headers, to a lesser
18  *    extent).  We would have to import these into the NaCl build and
19  *    resolve conflicts that they have with nacl-newlib's headers.
20  *
21  *  * We have peculiar requirements such as needing to execute syscalls
22  *    from specific program counter addresses in memory, in order to
23  *    whitelist these addresses in a seccomp-bpf filter.  LSS's
24  *    SYS_SYSCALL_ENTRYPOINT is more complex than what we need, and also
25  *    won't work with clone().
26  *
27  *  * LSS lacks a test suite, so even if we got it working with the
28  *    nacl-newlib toolchain, this usage might easily be broken by future
29  *    changes.
30  */
31
32 #include <stdint.h>
33
34 #if defined(__i386__)
35
36 /*
37  * Registers used for system call parameters on x86-32:
38  *   %eax - system call number and return value
39  *   %ebx - argument 1, preserved
40  *   %ecx - argument 2, preserved
41  *   %edx - argument 3, preserved
42  *   %esi - argument 4, preserved
43  *   %edi - argument 5, preserved
44  *   %ebp - argument 6, preserved
45  */
46
47 static inline uint32_t linux_syscall0(int syscall_number) {
48   uint32_t result;
49   __asm__ __volatile__("int $0x80\n"
50                        : "=a"(result)
51                        : "a"(syscall_number));
52   return result;
53 }
54
55 static inline uint32_t linux_syscall1(int syscall_number, uint32_t arg1) {
56   uint32_t result;
57   __asm__ __volatile__("int $0x80\n"
58                        : "=a"(result)
59                        : "a"(syscall_number), "b"(arg1));
60   return result;
61 }
62
63 static inline uint32_t linux_syscall2(int syscall_number,
64                                       uint32_t arg1, uint32_t arg2) {
65   uint32_t result;
66   __asm__ __volatile__("int $0x80\n"
67                        : "=a"(result)
68                        : "a"(syscall_number), "b"(arg1), "c"(arg2));
69   return result;
70 }
71
72 static inline uint32_t linux_syscall3(int syscall_number,
73                                       uint32_t arg1, uint32_t arg2,
74                                       uint32_t arg3) {
75   uint32_t result;
76   __asm__ __volatile__("int $0x80\n"
77                        : "=a"(result)
78                        : "a"(syscall_number), "b"(arg1), "c"(arg2), "d"(arg3));
79   return result;
80 }
81
82 static inline uint32_t linux_syscall4(int syscall_number,
83                                       uint32_t arg1, uint32_t arg2,
84                                       uint32_t arg3, uint32_t arg4) {
85   uint32_t result;
86   __asm__ __volatile__("int $0x80\n"
87                        : "=a"(result)
88                        : "a"(syscall_number), "b"(arg1), "c"(arg2), "d"(arg3),
89                          "S"(arg4));
90   return result;
91 }
92
93 static inline uint32_t linux_syscall5(int syscall_number,
94                                       uint32_t arg1, uint32_t arg2,
95                                       uint32_t arg3, uint32_t arg4,
96                                       uint32_t arg5) {
97   uint32_t result;
98   __asm__ __volatile__("int $0x80\n"
99                        : "=a"(result)
100                        : "a"(syscall_number), "b"(arg1), "c"(arg2), "d"(arg3),
101                          "S"(arg4), "D"(arg5));
102   return result;
103 }
104
105 static inline uint32_t linux_syscall6(int syscall_number,
106                                       uint32_t arg1, uint32_t arg2,
107                                       uint32_t arg3, uint32_t arg4,
108                                       uint32_t arg5, uint32_t arg6) {
109   /*
110    * Inline assembly doesn't let us use a constraint to set %ebp, which is
111    * the 6th syscall argument on x86-32.  To set %ebp, we use the trick of
112    * saving some registers on the stack.
113    *
114    * Note, however, that this means unwind info will be incorrect during
115    * this syscall.
116    */
117   uint32_t args[2] = { arg1, arg6 };
118   uint32_t result;
119   __asm__ __volatile__("push %%ebp\n"
120                        "movl 4(%%ebx), %%ebp\n" /* arg6 */
121                        "movl 0(%%ebx), %%ebx\n" /* arg1 */
122                        "int $0x80\n"
123                        "pop %%ebp\n"
124                        : "=a"(result)
125                        : "a"(syscall_number), "b"(&args),
126                          "c"(arg2), "d"(arg3), "S"(arg4), "D"(arg5)
127                        : "ebx", "memory");
128   return result;
129 }
130
131 #elif defined(__arm__)
132
133 /*
134  * Registers used for system call parameters on ARM EABI:
135  *   r7 - system call number
136  *   r0 - argument 1 and return value
137  *   r1 - argument 2, preserved
138  *   r2 - argument 3, preserved
139  *   r3 - argument 4, preserved
140  *   r4 - argument 5, preserved
141  *   r5 - argument 6, preserved
142  */
143
144 static inline uint32_t linux_syscall0(int syscall_number) {
145   register uint32_t sysno __asm__("r7") = syscall_number;
146   register uint32_t result __asm__("r0");
147   __asm__ __volatile__("svc #0\n"
148                        : "=r"(result)
149                        : "r"(sysno)
150                        : "memory");
151   return result;
152 }
153
154 static inline uint32_t linux_syscall1(int syscall_number, uint32_t arg1) {
155   register uint32_t sysno __asm__("r7") = syscall_number;
156   register uint32_t a1 __asm__("r0") = arg1;
157   register uint32_t result __asm__("r0");
158   __asm__ __volatile__("svc #0\n"
159                        : "=r"(result)
160                        : "r"(sysno), "r"(a1)
161                        : "memory");
162   return result;
163 }
164
165 static inline uint32_t linux_syscall2(int syscall_number,
166                                       uint32_t arg1, uint32_t arg2) {
167   register uint32_t sysno __asm__("r7") = syscall_number;
168   register uint32_t a1 __asm__("r0") = arg1;
169   register uint32_t a2 __asm__("r1") = arg2;
170   register uint32_t result __asm__("r0");
171   __asm__ __volatile__("svc #0\n"
172                        : "=r"(result)
173                        : "r"(sysno), "r"(a1), "r"(a2)
174                        : "memory");
175   return result;
176 }
177
178 static inline uint32_t linux_syscall3(int syscall_number,
179                                       uint32_t arg1, uint32_t arg2,
180                                       uint32_t arg3) {
181   register uint32_t sysno __asm__("r7") = syscall_number;
182   register uint32_t a1 __asm__("r0") = arg1;
183   register uint32_t a2 __asm__("r1") = arg2;
184   register uint32_t a3 __asm__("r2") = arg3;
185   register uint32_t result __asm__("r0");
186   __asm__ __volatile__("svc #0\n"
187                        : "=r"(result)
188                        : "r"(sysno), "r"(a1), "r"(a2), "r"(a3)
189                        : "memory");
190   return result;
191 }
192
193 static inline uint32_t linux_syscall4(int syscall_number,
194                                       uint32_t arg1, uint32_t arg2,
195                                       uint32_t arg3, uint32_t arg4) {
196   register uint32_t sysno __asm__("r7") = syscall_number;
197   register uint32_t a1 __asm__("r0") = arg1;
198   register uint32_t a2 __asm__("r1") = arg2;
199   register uint32_t a3 __asm__("r2") = arg3;
200   register uint32_t a4 __asm__("r3") = arg4;
201   register uint32_t result __asm__("r0");
202   __asm__ __volatile__("svc #0\n"
203                        : "=r"(result)
204                        : "r"(sysno),
205                          "r"(a1), "r"(a2), "r"(a3), "r"(a4)
206                        : "memory");
207   return result;
208 }
209
210 static inline uint32_t linux_syscall5(int syscall_number,
211                                       uint32_t arg1, uint32_t arg2,
212                                       uint32_t arg3, uint32_t arg4,
213                                       uint32_t arg5) {
214   register uint32_t sysno __asm__("r7") = syscall_number;
215   register uint32_t a1 __asm__("r0") = arg1;
216   register uint32_t a2 __asm__("r1") = arg2;
217   register uint32_t a3 __asm__("r2") = arg3;
218   register uint32_t a4 __asm__("r3") = arg4;
219   register uint32_t a5 __asm__("r4") = arg5;
220   register uint32_t result __asm__("r0");
221   __asm__ __volatile__("svc #0\n"
222                        : "=r"(result)
223                        : "r"(sysno),
224                          "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5)
225                        : "memory");
226   return result;
227 }
228
229 static inline uint32_t linux_syscall6(int syscall_number,
230                                       uint32_t arg1, uint32_t arg2,
231                                       uint32_t arg3, uint32_t arg4,
232                                       uint32_t arg5, uint32_t arg6) {
233   register uint32_t sysno __asm__("r7") = syscall_number;
234   register uint32_t a1 __asm__("r0") = arg1;
235   register uint32_t a2 __asm__("r1") = arg2;
236   register uint32_t a3 __asm__("r2") = arg3;
237   register uint32_t a4 __asm__("r3") = arg4;
238   register uint32_t a5 __asm__("r4") = arg5;
239   register uint32_t a6 __asm__("r5") = arg6;
240   register uint32_t result __asm__("r0");
241   __asm__ __volatile__("svc #0\n"
242                        : "=r"(result)
243                        : "r"(sysno),
244                          "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(a6)
245                        : "memory");
246   return result;
247 }
248
249 #else
250 # error Unsupported architecture
251 #endif
252
253 static inline int linux_is_error_result(uint32_t result) {
254   /*
255    * -0x1000 is the highest address that mmap() can return as a result.
256    * Linux errno values are less than 0x1000.
257    */
258   return result > (uint32_t) -0x1000;
259 }
260
261 #endif