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.
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.
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"
31 * Note that Non-SFI NaCl uses a 4k page size, in contrast to SFI NaCl's
34 static const int kPageSize = 0x1000;
36 static uintptr_t errno_value_call(uintptr_t result) {
37 if (linux_is_error_result(result)) {
44 void _exit(int status) {
45 linux_syscall1(__NR_exit_group, status);
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));
54 linux_timeval_to_nacl_timeval(&linux_tv, tv);
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));
67 * NaCl does not support async signals, so we don't fill out rem on
70 if (result == 0 && rem != NULL)
71 linux_timespec_to_nacl_timespec(&linux_rem, rem);
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));
80 linux_timespec_to_nacl_timespec(&linux_ts, ts);
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);
94 int sched_yield(void) {
95 return errno_value_call(linux_syscall0(__NR_sched_yield));
98 long int sysconf(int name) {
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. */
116 offset >>= kPageBits;
118 return (void *) errno_value_call(
119 linux_syscall6(__NR_mmap2, (uintptr_t) start, length,
120 prot, flags, fd, offset));
122 # error Unsupported architecture
126 int munmap(void *start, size_t length) {
127 return errno_value_call(
128 linux_syscall2(__NR_munmap, (uintptr_t ) start, length));
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));
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));
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));
146 int open(char const *pathname, int oflag, ...) {
150 if (oflag & O_CREAT) {
152 cmode = va_arg(ap, mode_t);
158 return errno_value_call(
159 linux_syscall3(__NR_open, (uintptr_t) pathname, oflag, cmode));
163 return errno_value_call(linux_syscall1(__NR_close, fd));
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__)
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).
179 return errno_value_call(
180 linux_syscall6(__NR_pread64, fd, (uintptr_t) buf, count,
181 0 /* dummy */, offset_low, offset_high));
183 # error Unsupported architecture
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));
199 # error Unsupported architecture
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;
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)) {
217 # error Unsupported architecture
222 return errno_value_call(linux_syscall1(__NR_dup, fd));
225 int dup2(int oldfd, int newfd) {
226 return errno_value_call(linux_syscall2(__NR_dup2, oldfd, newfd));
230 * This is a stub since _start will call it but we don't want to
231 * do the normal initialization.
233 void __libnacl_irt_init(Elf32_auxv_t *auxv) {
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);
244 * Leave the segment selector's bit 2 (table indicator) as zero because
245 * set_thread_area() always allocates an entry in the GDT.
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);
255 # error Unsupported architecture
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.
262 if (__nacl_read_tp() != thread_ptr)
267 void *nacl_tls_get(void) {
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));