Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / native_client / src / nonsfi / linux / linux_sys_private.c
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 /*
8  * This file defines various POSIX-like functions directly using Linux
9  * syscalls.  This is analogous to src/untrusted/nacl/sys_private.c, which
10  * defines functions using NaCl syscalls directly.
11  */
12
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <sched.h>
16 #include <stdarg.h>
17 #include <sys/mman.h>
18 #include <sys/time.h>
19 #include <time.h>
20 #include <unistd.h>
21
22 #include "native_client/src/include/elf32.h"
23 #include "native_client/src/nonsfi/linux/abi_conversion.h"
24 #include "native_client/src/nonsfi/linux/linux_syscall_structs.h"
25 #include "native_client/src/nonsfi/linux/linux_syscall_wrappers.h"
26 #include "native_client/src/nonsfi/linux/linux_syscalls.h"
27 #include "native_client/src/untrusted/nacl/tls.h"
28
29
30 /*
31  * Note that Non-SFI NaCl uses a 4k page size, in contrast to SFI NaCl's
32  * 64k page size.
33  */
34 static const int kPageSize = 0x1000;
35
36 static uintptr_t errno_value_call(uintptr_t result) {
37   if (linux_is_error_result(result)) {
38     errno = -result;
39     return -1;
40   }
41   return result;
42 }
43
44 void _exit(int status) {
45   linux_syscall1(__NR_exit_group, status);
46   __builtin_trap();
47 }
48
49 int gettimeofday(struct timeval *tv, void *tz) {
50   struct linux_abi_timeval linux_tv;
51   int result = errno_value_call(
52       linux_syscall2(__NR_gettimeofday, (uintptr_t) &linux_tv, 0));
53   if (result == 0)
54     linux_timeval_to_nacl_timeval(&linux_tv, tv);
55   return result;
56 }
57
58 int nanosleep(const struct timespec *req, struct timespec *rem) {
59   struct linux_abi_timespec linux_req;
60   nacl_timespec_to_linux_timespec(req, &linux_req);
61   struct linux_abi_timespec linux_rem;
62   int result = errno_value_call(linux_syscall2(__NR_nanosleep,
63                                                (uintptr_t) &linux_req,
64                                                (uintptr_t) &linux_rem));
65
66   /*
67    * NaCl does not support async signals, so we don't fill out rem on
68    * result == -EINTR.
69    */
70   if (result == 0 && rem != NULL)
71     linux_timespec_to_nacl_timespec(&linux_rem, rem);
72   return result;
73 }
74
75 int clock_gettime(clockid_t clk_id, struct timespec *ts) {
76   struct linux_abi_timespec linux_ts;
77   int result = errno_value_call(
78       linux_syscall2(__NR_clock_gettime, clk_id, (uintptr_t) &linux_ts));
79   if (result == 0)
80     linux_timespec_to_nacl_timespec(&linux_ts, ts);
81   return result;
82 }
83
84 int clock_getres(clockid_t clk_id, struct timespec *res) {
85   struct linux_abi_timespec linux_res;
86   int result = errno_value_call(
87       linux_syscall2(__NR_clock_getres, clk_id, (uintptr_t) &linux_res));
88   /* Unlike clock_gettime, clock_getres allows NULL timespecs. */
89   if (result == 0 && res != NULL)
90     linux_timespec_to_nacl_timespec(&linux_res, res);
91   return result;
92 }
93
94 int sched_yield(void) {
95   return errno_value_call(linux_syscall0(__NR_sched_yield));
96 }
97
98 long int sysconf(int name) {
99   switch (name) {
100     case _SC_PAGESIZE:
101       return kPageSize;
102   }
103   errno = EINVAL;
104   return -1;
105 }
106
107 void *mmap(void *start, size_t length, int prot, int flags,
108            int fd, off_t offset) {
109 #if defined(__i386__) || defined(__arm__)
110   static const int kPageBits = 12;
111   if (offset & ((1 << kPageBits) - 1)) {
112     /* An unaligned offset is specified. */
113     errno = EINVAL;
114     return MAP_FAILED;
115   }
116   offset >>= kPageBits;
117
118   return (void *) errno_value_call(
119       linux_syscall6(__NR_mmap2, (uintptr_t) start, length,
120                      prot, flags, fd, offset));
121 #else
122 # error Unsupported architecture
123 #endif
124 }
125
126 int munmap(void *start, size_t length) {
127   return errno_value_call(
128       linux_syscall2(__NR_munmap, (uintptr_t ) start, length));
129 }
130
131 int mprotect(void *start, size_t length, int prot) {
132   return errno_value_call(
133       linux_syscall3(__NR_mprotect, (uintptr_t ) start, length, prot));
134 }
135
136 int read(int fd, void *buf, size_t count) {
137   return errno_value_call(linux_syscall3(__NR_read, fd,
138                                          (uintptr_t) buf, count));
139 }
140
141 int write(int fd, const void *buf, size_t count) {
142   return errno_value_call(linux_syscall3(__NR_write, fd,
143                                          (uintptr_t) buf, count));
144 }
145
146 int open(char const *pathname, int oflag, ...) {
147   mode_t cmode;
148   va_list ap;
149
150   if (oflag & O_CREAT) {
151     va_start(ap, oflag);
152     cmode = va_arg(ap, mode_t);
153     va_end(ap);
154   } else {
155     cmode = 0;
156   }
157
158   return errno_value_call(
159       linux_syscall3(__NR_open, (uintptr_t) pathname, oflag, cmode));
160 }
161
162 int close(int fd) {
163   return errno_value_call(linux_syscall1(__NR_close, fd));
164 }
165
166 ssize_t pread(int fd, void *buf, size_t count, off_t offset) {
167   uint32_t offset_low = (uint32_t) offset;
168   uint32_t offset_high = offset >> 32;
169 #if defined(__i386__)
170   return errno_value_call(
171       linux_syscall5(__NR_pread64, fd, (uintptr_t) buf, count,
172                      offset_low, offset_high));
173 #elif defined(__arm__)
174   /*
175    * On ARM, a 64-bit parameter has to be in an even-odd register
176    * pair. Hence these calls ignore their fourth argument (r3) so that
177    * their fifth and sixth make such a pair (r4,r5).
178    */
179   return errno_value_call(
180       linux_syscall6(__NR_pread64, fd, (uintptr_t) buf, count,
181                      0  /* dummy */, offset_low, offset_high));
182 #else
183 # error Unsupported architecture
184 #endif
185 }
186
187 ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset) {
188   uint32_t offset_low = (uint32_t) offset;
189   uint32_t offset_high = offset >> 32;
190 #if defined(__i386__)
191   return errno_value_call(
192       linux_syscall5(__NR_pwrite64, fd, (uintptr_t) buf, count,
193                      offset_low, offset_high));
194 #elif defined(__arm__)
195   return errno_value_call(
196       linux_syscall6(__NR_pwrite64, fd, (uintptr_t) buf, count,
197                      0  /* dummy */, offset_low, offset_high));
198 #else
199 # error Unsupported architecture
200 #endif
201 }
202
203 off_t lseek(int fd, off_t offset, int whence) {
204 #if defined(__i386__) || defined(__arm__)
205   uint32_t offset_low = (uint32_t) offset;
206   uint32_t offset_high = offset >> 32;
207   off_t result;
208   int rc = errno_value_call(
209       linux_syscall5(__NR__llseek, fd, offset_high, offset_low,
210                      (uintptr_t) &result, whence));
211   if (linux_is_error_result(rc)) {
212     errno = -rc;
213     return -1;
214   }
215   return result;
216 #else
217 # error Unsupported architecture
218 #endif
219 }
220
221 int dup(int fd) {
222   return errno_value_call(linux_syscall1(__NR_dup, fd));
223 }
224
225 int dup2(int oldfd, int newfd) {
226   return errno_value_call(linux_syscall2(__NR_dup2, oldfd, newfd));
227 }
228
229 /*
230  * This is a stub since _start will call it but we don't want to
231  * do the normal initialization.
232  */
233 void __libnacl_irt_init(Elf32_auxv_t *auxv) {
234 }
235
236 int nacl_tls_init(void *thread_ptr) {
237 #if defined(__i386__)
238   struct linux_user_desc desc = create_linux_user_desc(
239       1 /* allocate_new_entry */, thread_ptr);
240   uint32_t result = linux_syscall1(__NR_set_thread_area, (uint32_t) &desc);
241   if (result != 0)
242     __builtin_trap();
243   /*
244    * Leave the segment selector's bit 2 (table indicator) as zero because
245    * set_thread_area() always allocates an entry in the GDT.
246    */
247   int privilege_level = 3;
248   int gs_segment_selector = (desc.entry_number << 3) + privilege_level;
249   __asm__("mov %0, %%gs" : : "r"(gs_segment_selector));
250 #elif defined(__arm__)
251   uint32_t result = linux_syscall1(__NR_ARM_set_tls, (uint32_t) thread_ptr);
252   if (result != 0)
253     __builtin_trap();
254 #else
255 # error Unsupported architecture
256 #endif
257   /*
258    * Sanity check: Ensure that the thread pointer reads back correctly.
259    * This checks that the set_thread_area() syscall worked and that the
260    * thread pointer points to itself, which is required on x86-32.
261    */
262   if (__nacl_read_tp() != thread_ptr)
263     __builtin_trap();
264   return 0;
265 }
266
267 void *nacl_tls_get(void) {
268   void *result;
269 #if defined(__i386__)
270   __asm__("mov %%gs:0, %0" : "=r"(result));
271 #elif defined(__arm__)
272   __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(result));
273 #endif
274   return result;
275 }