1 : /*
2 : * Copyright (c) 2012 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 : * NaCl Server Runtime user thread state.
9 : */
10 :
11 : #ifndef NATIVE_CLIENT_SERVICE_RUNTIME_NACL_APP_THREAD_H__
12 : #define NATIVE_CLIENT_SERVICE_RUNTIME_NACL_APP_THREAD_H__ 1
13 :
14 : #include <stddef.h>
15 :
16 : #include "native_client/src/include/atomic_ops.h"
17 : #include "native_client/src/shared/platform/nacl_sync.h"
18 : #include "native_client/src/shared/platform/nacl_threads.h"
19 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
20 : #include "native_client/src/trusted/service_runtime/sel_rt.h"
21 : #include "native_client/src/trusted/service_runtime/sys_futex.h"
22 :
23 :
24 : EXTERN_C_BEGIN
25 :
26 : struct NaClApp;
27 : struct NaClAppThreadSuspendedRegisters;
28 :
29 : /*
30 : * The thread hosting the NaClAppThread may change suspend_state
31 : * between NACL_APP_THREAD_TRUSTED and NACL_APP_THREAD_UNTRUSTED using
32 : * NaClAppThreadSetSuspendState().
33 : *
34 : * On Linux, a controlling thread may change this from:
35 : * NACL_APP_THREAD_UNTRUSTED
36 : * -> NACL_APP_THREAD_UNTRUSTED | NACL_APP_THREAD_SUSPENDING
37 : * or
38 : * NACL_APP_THREAD_TRUSTED
39 : * -> NACL_APP_THREAD_TRUSTED | NACL_APP_THREAD_SUSPENDING
40 : * and back again.
41 : *
42 : * Furthermore, the signal handler in the thread being suspended will
43 : * change suspend_state from:
44 : * NACL_APP_THREAD_UNTRUSTED | NACL_APP_THREAD_SUSPENDING
45 : * -> (NACL_APP_THREAD_UNTRUSTED | NACL_APP_THREAD_SUSPENDING
46 : * | NACL_APP_THREAD_SUSPENDED)
47 : * The controlling thread will later change suspend_thread back to:
48 : * NACL_APP_THREAD_UNTRUSTED
49 : * This tells the signal handler to resume execution.
50 : */
51 : enum NaClSuspendState {
52 : NACL_APP_THREAD_UNTRUSTED = 1,
53 : NACL_APP_THREAD_TRUSTED = 2
54 : #if NACL_LINUX
55 : , NACL_APP_THREAD_SUSPENDING = 4,
56 : NACL_APP_THREAD_SUSPENDED = 8
57 : #endif
58 : };
59 :
60 : /*
61 : * Generally, only the thread itself will need to manipulate this
62 : * structure, but occasionally we may need to blow away a thread for
63 : * some reason, and look inside. While a thread is in the NaCl
64 : * application running untrusted code, the lock must *not* be held.
65 : */
66 : struct NaClAppThread {
67 : /*
68 : * NaClAppThread 'inherits' from NaClThreadContext; the 'user' field
69 : * is first so that NaClAppThreadFromThreadContext() can convert by
70 : * casting.
71 : *
72 : * 'user' contains all the architecture-specific state for this thread.
73 : * TODO(mseaborn): Rename it to a more descriptive name.
74 : */
75 : struct NaClThreadContext user;
76 :
77 : struct NaClMutex mu;
78 :
79 : /*
80 : * The NaCl app that contains this thread. The app must exist as
81 : * long as a thread is still alive.
82 : */
83 : struct NaClApp *nap;
84 :
85 : int thread_num; /* index into nap->threads */
86 :
87 : /*
88 : * If host_thread_is_defined is true, host_thread is initialized and
89 : * owned by the NaClAppThread such that it will be freed by
90 : * NaClAppThreadDelete().
91 : *
92 : * host_thread_is_defined may be false when running untrusted code
93 : * on a borrowed host thread that was not created by
94 : * NaClAppThreadSpawn().
95 : */
96 : int host_thread_is_defined;
97 : struct NaClThread host_thread; /* low level thread representation */
98 :
99 : struct NaClMutex suspend_mu;
100 : Atomic32 suspend_state; /* enum NaClSuspendState */
101 : /*
102 : * suspended_registers contains the register state of the thread if
103 : * it has been suspended with save_registers=1 and if suspend_state
104 : * contains NACL_APP_THREAD_UNTRUSTED. This is for use by the debug
105 : * stub.
106 : *
107 : * To save space, suspended_registers is allocated on demand. It
108 : * may be left allocated after the thread is resumed.
109 : *
110 : * suspended_registers will usually contain untrusted-code register
111 : * state. However, it may contain trusted-code register state if
112 : * the thread suspension kicked in during a trusted/untrusted
113 : * context switch (e.g. while executing the trampoline or
114 : * nacl_syscall_hook.c).
115 : */
116 : struct NaClAppThreadSuspendedRegisters *suspended_registers;
117 : /*
118 : * If fault_signal is non-zero, the thread has faulted and so has
119 : * been suspended. fault_signal indicates the type of fault (it is
120 : * a signal number on Linux and an exception code on Windows).
121 : */
122 : int fault_signal;
123 :
124 : uintptr_t usr_syscall_args;
125 : /*
126 : * user's syscall argument address, relative to untrusted user
127 : * address. the syscall arglist is on the untrusted stack.
128 : */
129 :
130 : /* Stack for signal handling, registered with sigaltstack(). */
131 : void *signal_stack;
132 :
133 : /*
134 : * exception_stack is the address of the top of the untrusted
135 : * exception handler stack, or 0 if no such stack is registered for
136 : * this thread.
137 : */
138 : uint32_t exception_stack;
139 : /*
140 : * exception_flag is a boolean. When it is 1, untrusted exception
141 : * handling is disabled for this thread. It is set to 1 when the
142 : * exception handler is called, in order to prevent the exception
143 : * handler from being re-entered.
144 : */
145 : uint32_t exception_flag;
146 :
147 : /*
148 : * The last generation this thread reported into the service runtime
149 : * Protected by mu
150 : */
151 : int dynamic_delete_generation;
152 :
153 : /*
154 : * If this thread is waiting on a futex, futex_wait_list_node is
155 : * linked into the doubly linked list NaClApp::futex_wait_list_head.
156 : */
157 : struct NaClListNode futex_wait_list_node;
158 : /*
159 : * If this thread is waiting on a futex, futex_wait_addr contains
160 : * the untrusted address that the thread is waiting on.
161 : */
162 : uint32_t futex_wait_addr;
163 : struct NaClCondVar futex_condvar;
164 : };
165 :
166 : void WINAPI NaClAppThreadLauncher(void *state);
167 :
168 : void NaClAppThreadTeardown(struct NaClAppThread *natp);
169 :
170 : /*
171 : * NaClAppThreadMake() creates a NaClAppThread object without invoking
172 : * untrusted code or creating a host thread.
173 : *
174 : * The usr_entry and usr_stack_ptr values are directly used to
175 : * initialize the user register values. The caller is responsible for
176 : * error checking: usr_entry must be a valid entry point (0 mod N).
177 : */
178 : struct NaClAppThread *NaClAppThreadMake(struct NaClApp *nap,
179 : uintptr_t usr_entry,
180 : uintptr_t usr_stack_ptr,
181 : uint32_t user_tls1,
182 : uint32_t user_tls2) NACL_WUR;
183 :
184 : /*
185 : * NaClAppThreadSpawn() creates a NaClAppThread and launches a host
186 : * thread that invokes the given entry point in untrusted code. This
187 : * returns true on success, false on failure.
188 : */
189 : int NaClAppThreadSpawn(struct NaClApp *nap,
190 : uintptr_t usr_entry,
191 : uintptr_t usr_stack_ptr,
192 : uint32_t user_tls1,
193 : uint32_t user_tls2) NACL_WUR;
194 :
195 : void NaClAppThreadDelete(struct NaClAppThread *natp);
196 :
197 : /*
198 : * This function can be called from the thread hosting the
199 : * NaClAppThread. It can be used to switch between the states
200 : * NACL_APP_THREAD_TRUSTED and NACL_APP_THREAD_UNTRUSTED.
201 : */
202 : void NaClAppThreadSetSuspendState(struct NaClAppThread *natp,
203 : enum NaClSuspendState old_state,
204 : enum NaClSuspendState new_state);
205 :
206 : static INLINE struct NaClAppThread *NaClAppThreadFromThreadContext(
207 3568704 : struct NaClThreadContext *ntcp) {
208 7137406 : NACL_COMPILE_TIME_ASSERT(offsetof(struct NaClAppThread, user) == 0);
209 3568705 : return (struct NaClAppThread *) ntcp;
210 : }
211 :
212 : EXTERN_C_END
213 :
214 : #endif /* NATIVE_CLIENT_SERVICE_RUNTIME_NACL_APP_THREAD_H__ */
|