Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / native_client / src / nonsfi / linux / linux_pthread_private.c
1 /*
2  * Copyright 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 #include <errno.h>
8
9 #include "native_client/src/nonsfi/linux/linux_syscall_defines.h"
10 #include "native_client/src/nonsfi/linux/linux_syscall_structs.h"
11 #include "native_client/src/nonsfi/linux/linux_syscall_wrappers.h"
12 #include "native_client/src/nonsfi/linux/linux_syscalls.h"
13 #include "native_client/src/untrusted/nacl/nacl_thread.h"
14 #include "native_client/src/untrusted/pthread/pthread_internal.h"
15
16 /* Convert a return value of a Linux syscall to the one of an IRT call. */
17 static uint32_t irt_return_call(uintptr_t result) {
18   if (linux_is_error_result(result))
19     return -result;
20   return 0;
21 }
22
23 static int nacl_irt_thread_create(void (*start_func)(void), void *stack,
24                                   void *thread_ptr) {
25   /*
26    * The prototype of clone(2) is
27    *
28    * clone(int flags, void *stack, pid_t *ptid, void *tls, pid_t *ctid);
29    *
30    * See linux_syscall_wrappers.h for syscalls' calling conventions.
31    */
32
33   /*
34    * We do not use CLONE_CHILD_CLEARTID as we do not want any
35    * non-private futex signaling. Also, NaCl ABI does not require us
36    * to signal the futex on stack_flag.
37    */
38   int flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
39                CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS);
40   /*
41    * Make sure we can access stack[0] and align the stack address to a
42    * 16-byte boundary.
43    */
44   static const int kStackAlignmentMask = ~15;
45   stack = (void *) (((uintptr_t) stack - sizeof(uintptr_t)) &
46                     kStackAlignmentMask);
47   /* We pass start_func using the stack top. */
48   ((uintptr_t *) stack)[0] = (uintptr_t) start_func;
49
50 #if defined(__i386__)
51   uint32_t result;
52   struct linux_user_desc desc = create_linux_user_desc(
53       0 /* allocate_new_entry */, thread_ptr);
54   __asm__ __volatile__("int $0x80\n"
55                        /*
56                         * If the return value of clone is non-zero, we are
57                         * in the parent thread of clone.
58                         */
59                        "cmp $0, %%eax\n"
60                        "jne 0f\n"
61                        /*
62                         * In child thread. Clear the frame pointer to
63                         * prevent debuggers from unwinding beyond this,
64                         * pop the stack to get start_func and call it.
65                         */
66                        "mov $0, %%ebp\n"
67                        "call *(%%esp)\n"
68                        /* start_func never finishes. */
69                        "hlt\n"
70                        "0:\n"
71                        : "=a"(result)
72                        : "a"(__NR_clone), "b"(flags), "c"(stack),
73                          /* We do not use CLONE_PARENT_SETTID. */
74                          "d"(0),
75                          "S"(&desc),
76                          /* We do not use CLONE_CHILD_CLEARTID. */
77                          "D"(0)
78                        : "memory");
79 #elif defined(__arm__)
80   register uint32_t result __asm__("r0");
81   register uint32_t sysno __asm__("r7") = __NR_clone;
82   register uint32_t a1 __asm__("r0") = flags;
83   register uint32_t a2 __asm__("r1") = (uint32_t) stack;
84   register uint32_t a3 __asm__("r2") = 0;  /* No CLONE_PARENT_SETTID. */
85   register uint32_t a4 __asm__("r3") = (uint32_t) thread_ptr;
86   register uint32_t a5 __asm__("r4") = 0;  /* No CLONE_CHILD_CLEARTID. */
87   __asm__ __volatile__("svc #0\n"
88                        /*
89                         * If the return value of clone is non-zero, we are
90                         * in the parent thread of clone.
91                         */
92                        "cmp r0, #0\n"
93                        "bne 0f\n"
94                        /*
95                         * In child thread. Clear the frame pointer to
96                         * prevent debuggers from unwinding beyond this,
97                         * pop the stack to get start_func and call it.
98                         */
99                        "mov fp, #0\n"
100                        "pop {r0}\n"
101                        "blx r0\n"
102                        /* start_func never finishes. */
103                        "bkpt #0\n"
104                        "0:\n"
105                        : "=r"(result)
106                        : "r"(sysno),
107                          "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5)
108                        : "memory");
109 #else
110 # error Unsupported architecture
111 #endif
112   return irt_return_call(result);
113 }
114
115 static void nacl_irt_thread_exit(int32_t *stack_flag) {
116   /*
117    * We fill zero to stack_flag by ourselves instead of relying
118    * on CLONE_CHILD_CLEARTID. We do everything in the following inline
119    * assembly because we need to make sure we will never touch stack.
120    *
121    * We will set the stack pointer to zero at the beginning of the
122    * assembly code just in case an async signal arrives after setting
123    * *stack_flag=0 but before calling the syscall, so that any signal
124    * handler crashes rather than running on a stack that has been
125    * reallocated to another thread.
126    */
127 #if defined(__i386__)
128   __asm__ __volatile__("mov $0, %%esp\n"
129                        "movl $0, (%[stack_flag])\n"
130                        "int $0x80\n"
131                        "hlt\n"
132                        :: [stack_flag]"r"(stack_flag), "a"(__NR_exit));
133 #elif defined(__arm__)
134   __asm__ __volatile__("mov sp, #0\n"
135                        "mov r7, #0\n"
136                        "str r7, [%[stack_flag]]\n"
137                        "mov r7, %[sysno]\n"
138                        "svc #0\n"
139                        "bkpt #0\n"
140                        :: [stack_flag]"r"(stack_flag), [sysno]"i"(__NR_exit)
141                        : "r7");
142 #else
143 # error Unsupported architecture
144 #endif
145 }
146
147 static int nacl_irt_thread_nice(const int nice) {
148   return 0;
149 }
150
151 void __nc_initialize_interfaces(struct nacl_irt_thread *irt_thread) {
152   const struct nacl_irt_thread init = {
153     nacl_irt_thread_create,
154     nacl_irt_thread_exit,
155     nacl_irt_thread_nice,
156   };
157   *irt_thread = init;
158 }