OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | 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 | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 #include <mach/mach.h> | 7 #include <mach/mach.h> |
8 #include <mach/thread_status.h> | 8 #include <mach/thread_status.h> |
9 | 9 |
10 #include "native_client/src/shared/platform/nacl_check.h" | 10 #include "native_client/src/shared/platform/nacl_check.h" |
11 #include "native_client/src/shared/platform/nacl_sync_checked.h" | 11 #include "native_client/src/shared/platform/nacl_sync_checked.h" |
12 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h" | 12 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h" |
13 #include "native_client/src/trusted/service_runtime/nacl_switch_to_app.h" | 13 #include "native_client/src/trusted/service_runtime/nacl_switch_to_app.h" |
14 #include "native_client/src/trusted/service_runtime/sel_ldr.h" | 14 #include "native_client/src/trusted/service_runtime/sel_ldr.h" |
15 #include "native_client/src/trusted/service_runtime/thread_suspension.h" | 15 #include "native_client/src/trusted/service_runtime/thread_suspension.h" |
16 | 16 |
17 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 | 17 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 |
18 # include "native_client/src/trusted/service_runtime/arch/x86_32/nacl_switch_all
_regs_32.h" | 18 # include "native_client/src/trusted/service_runtime/arch/x86_32/nacl_switch_all
_regs_32.h" |
19 #endif | 19 #endif |
20 | 20 |
21 | 21 |
22 struct NaClAppThreadSuspendedRegisters { | 22 struct NaClAppThreadSuspendedRegisters { |
23 x86_thread_state_t context; | 23 x86_thread_state_t context; |
24 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 | 24 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 |
25 struct NaClSwitchRemainingRegsState switch_state; | 25 struct NaClSwitchRemainingRegsState switch_state; |
26 #endif | 26 #endif |
27 }; | 27 }; |
28 | 28 |
| 29 static mach_port_t GetHostThreadPort(struct NaClAppThread *natp) { |
| 30 CHECK(natp->host_thread_is_defined); |
| 31 return pthread_mach_thread_np(natp->host_thread.tid); |
| 32 } |
| 33 |
29 void NaClAppThreadSetSuspendState(struct NaClAppThread *natp, | 34 void NaClAppThreadSetSuspendState(struct NaClAppThread *natp, |
30 enum NaClSuspendState old_state, | 35 enum NaClSuspendState old_state, |
31 enum NaClSuspendState new_state) { | 36 enum NaClSuspendState new_state) { |
32 /* | 37 /* |
33 * Claiming suspend_mu here blocks a trusted/untrusted context | 38 * Claiming suspend_mu here blocks a trusted/untrusted context |
34 * switch while the thread is suspended or a suspension is in | 39 * switch while the thread is suspended or a suspension is in |
35 * progress. | 40 * progress. |
36 */ | 41 */ |
37 NaClXMutexLock(&natp->suspend_mu); | 42 NaClXMutexLock(&natp->suspend_mu); |
38 DCHECK(natp->suspend_state == (Atomic32) old_state); | 43 DCHECK(natp->suspend_state == (Atomic32) old_state); |
39 natp->suspend_state = new_state; | 44 natp->suspend_state = new_state; |
40 NaClXMutexUnlock(&natp->suspend_mu); | 45 NaClXMutexUnlock(&natp->suspend_mu); |
41 } | 46 } |
42 | 47 |
43 void NaClUntrustedThreadSuspend(struct NaClAppThread *natp, | 48 void NaClUntrustedThreadSuspend(struct NaClAppThread *natp, |
44 int save_registers) { | 49 int save_registers) { |
45 /* | 50 /* |
46 * We claim suspend_mu here to block trusted/untrusted context | 51 * We claim suspend_mu here to block trusted/untrusted context |
47 * switches by blocking NaClAppThreadSetSuspendState(). This blocks | 52 * switches by blocking NaClAppThreadSetSuspendState(). This blocks |
48 * any untrusted->trusted context switch that might happen before | 53 * any untrusted->trusted context switch that might happen before |
49 * SuspendThread() takes effect. It blocks any trusted->untrusted | 54 * SuspendThread() takes effect. It blocks any trusted->untrusted |
50 * context switch that might happen if the syscall running in the | 55 * context switch that might happen if the syscall running in the |
51 * target thread returns. | 56 * target thread returns. |
52 */ | 57 */ |
53 NaClXMutexLock(&natp->suspend_mu); | 58 NaClXMutexLock(&natp->suspend_mu); |
54 if (natp->suspend_state == NACL_APP_THREAD_UNTRUSTED) { | 59 if (natp->suspend_state == NACL_APP_THREAD_UNTRUSTED) { |
55 kern_return_t result; | 60 kern_return_t result; |
56 mach_msg_type_number_t size; | 61 mach_msg_type_number_t size; |
57 mach_port_t thread_port = pthread_mach_thread_np(natp->thread.tid); | 62 mach_port_t thread_port = GetHostThreadPort(natp); |
58 | 63 |
59 result = thread_suspend(thread_port); | 64 result = thread_suspend(thread_port); |
60 if (result != KERN_SUCCESS) { | 65 if (result != KERN_SUCCESS) { |
61 NaClLog(LOG_FATAL, "NaClUntrustedThreadSuspend: " | 66 NaClLog(LOG_FATAL, "NaClUntrustedThreadSuspend: " |
62 "thread_suspend() call failed: error %d\n", (int) result); | 67 "thread_suspend() call failed: error %d\n", (int) result); |
63 } | 68 } |
64 | 69 |
65 if (save_registers) { | 70 if (save_registers) { |
66 if (natp->suspended_registers == NULL) { | 71 if (natp->suspended_registers == NULL) { |
67 natp->suspended_registers = malloc(sizeof(*natp->suspended_registers)); | 72 natp->suspended_registers = malloc(sizeof(*natp->suspended_registers)); |
(...skipping 13 matching lines...) Expand all Loading... |
81 } | 86 } |
82 } | 87 } |
83 /* | 88 /* |
84 * We leave suspend_mu held so that NaClAppThreadSetSuspendState() | 89 * We leave suspend_mu held so that NaClAppThreadSetSuspendState() |
85 * will block. | 90 * will block. |
86 */ | 91 */ |
87 } | 92 } |
88 | 93 |
89 void NaClUntrustedThreadResume(struct NaClAppThread *natp) { | 94 void NaClUntrustedThreadResume(struct NaClAppThread *natp) { |
90 if (natp->suspend_state == NACL_APP_THREAD_UNTRUSTED) { | 95 if (natp->suspend_state == NACL_APP_THREAD_UNTRUSTED) { |
91 mach_port_t thread_port = pthread_mach_thread_np(natp->thread.tid); | 96 kern_return_t result = thread_resume(GetHostThreadPort(natp)); |
92 kern_return_t result = thread_resume(thread_port); | |
93 if (result != KERN_SUCCESS) { | 97 if (result != KERN_SUCCESS) { |
94 NaClLog(LOG_FATAL, "NaClUntrustedThreadResume: " | 98 NaClLog(LOG_FATAL, "NaClUntrustedThreadResume: " |
95 "thread_resume() call failed: error %d\n", (int) result); | 99 "thread_resume() call failed: error %d\n", (int) result); |
96 } | 100 } |
97 } | 101 } |
98 NaClXMutexUnlock(&natp->suspend_mu); | 102 NaClXMutexUnlock(&natp->suspend_mu); |
99 } | 103 } |
100 | 104 |
101 void NaClAppThreadGetSuspendedRegistersInternal( | 105 void NaClAppThreadGetSuspendedRegistersInternal( |
102 struct NaClAppThread *natp, struct NaClSignalContext *regs) { | 106 struct NaClAppThread *natp, struct NaClSignalContext *regs) { |
(...skipping 28 matching lines...) Expand all Loading... |
131 state->context.uts.ts32.__ss = natp->user.ss; | 135 state->context.uts.ts32.__ss = natp->user.ss; |
132 } | 136 } |
133 #endif | 137 #endif |
134 | 138 |
135 NaClSignalContextFromMacThreadState(regs, | 139 NaClSignalContextFromMacThreadState(regs, |
136 &natp->suspended_registers->context); | 140 &natp->suspended_registers->context); |
137 } | 141 } |
138 | 142 |
139 void NaClAppThreadSetSuspendedRegistersInternal( | 143 void NaClAppThreadSetSuspendedRegistersInternal( |
140 struct NaClAppThread *natp, const struct NaClSignalContext *regs) { | 144 struct NaClAppThread *natp, const struct NaClSignalContext *regs) { |
141 mach_port_t thread_port = pthread_mach_thread_np(natp->thread.tid); | |
142 kern_return_t result; | 145 kern_return_t result; |
143 mach_msg_type_number_t size; | 146 mach_msg_type_number_t size; |
144 struct NaClAppThreadSuspendedRegisters *state = natp->suspended_registers; | 147 struct NaClAppThreadSuspendedRegisters *state = natp->suspended_registers; |
145 x86_thread_state_t context_copy; | 148 x86_thread_state_t context_copy; |
146 | 149 |
147 NaClSignalContextToMacThreadState(&state->context, regs); | 150 NaClSignalContextToMacThreadState(&state->context, regs); |
148 context_copy = state->context; | 151 context_copy = state->context; |
149 | 152 |
150 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 | 153 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 |
151 /* | 154 /* |
152 * thread_set_state() ignores the %cs value we supply and always | 155 * thread_set_state() ignores the %cs value we supply and always |
153 * resets %cs back to the trusted-code value. This means we must | 156 * resets %cs back to the trusted-code value. This means we must |
154 * set up the new untrusted register state via a trusted code | 157 * set up the new untrusted register state via a trusted code |
155 * routine which returns to untrusted code via a springboard. | 158 * routine which returns to untrusted code via a springboard. |
156 * | 159 * |
157 * We reset %cs here in case the Mac kernel is ever fixed to not | 160 * We reset %cs here in case the Mac kernel is ever fixed to not |
158 * ignore the supplied %cs value. | 161 * ignore the supplied %cs value. |
159 */ | 162 */ |
160 context_copy.uts.ts32.__cs = NaClGetGlobalCs(); | 163 context_copy.uts.ts32.__cs = NaClGetGlobalCs(); |
161 context_copy.uts.ts32.__ds = NaClGetGlobalDs(); | 164 context_copy.uts.ts32.__ds = NaClGetGlobalDs(); |
162 /* Reset these too just in case. */ | 165 /* Reset these too just in case. */ |
163 context_copy.uts.ts32.__es = NaClGetGlobalDs(); | 166 context_copy.uts.ts32.__es = NaClGetGlobalDs(); |
164 context_copy.uts.ts32.__ss = NaClGetGlobalDs(); | 167 context_copy.uts.ts32.__ss = NaClGetGlobalDs(); |
165 context_copy.uts.ts32.__ecx = (uintptr_t) &state->switch_state; | 168 context_copy.uts.ts32.__ecx = (uintptr_t) &state->switch_state; |
166 context_copy.uts.ts32.__eip = (uintptr_t) NaClSwitchRemainingRegsViaECX; | 169 context_copy.uts.ts32.__eip = (uintptr_t) NaClSwitchRemainingRegsViaECX; |
167 NaClSwitchRemainingRegsSetup(&state->switch_state, natp, regs); | 170 NaClSwitchRemainingRegsSetup(&state->switch_state, natp, regs); |
168 #endif | 171 #endif |
169 | 172 |
170 size = sizeof(context_copy) / sizeof(natural_t); | 173 size = sizeof(context_copy) / sizeof(natural_t); |
171 result = thread_set_state(thread_port, x86_THREAD_STATE, | 174 result = thread_set_state(GetHostThreadPort(natp), x86_THREAD_STATE, |
172 (void *) &context_copy, size); | 175 (void *) &context_copy, size); |
173 if (result != KERN_SUCCESS) { | 176 if (result != KERN_SUCCESS) { |
174 NaClLog(LOG_FATAL, "NaClAppThreadSetSuspendedRegistersInternal: " | 177 NaClLog(LOG_FATAL, "NaClAppThreadSetSuspendedRegistersInternal: " |
175 "thread_set_state() call failed: error %d\n", result); | 178 "thread_set_state() call failed: error %d\n", result); |
176 } | 179 } |
177 } | 180 } |
178 | 181 |
179 int NaClAppThreadUnblockIfFaulted(struct NaClAppThread *natp, int *signal) { | 182 int NaClAppThreadUnblockIfFaulted(struct NaClAppThread *natp, int *signal) { |
180 mach_port_t thread_port; | |
181 kern_return_t result; | 183 kern_return_t result; |
182 if (natp->fault_signal == 0) { | 184 if (natp->fault_signal == 0) { |
183 return 0; | 185 return 0; |
184 } | 186 } |
185 *signal = natp->fault_signal; | 187 *signal = natp->fault_signal; |
186 natp->fault_signal = 0; | 188 natp->fault_signal = 0; |
187 AtomicIncrement(&natp->nap->faulted_thread_count, -1); | 189 AtomicIncrement(&natp->nap->faulted_thread_count, -1); |
188 /* | 190 /* |
189 * Decrement the kernel's suspension count for the thread. This | 191 * Decrement the kernel's suspension count for the thread. This |
190 * undoes the effect of mach_exception_handler.c's thread_suspend() | 192 * undoes the effect of mach_exception_handler.c's thread_suspend() |
191 * call. | 193 * call. |
192 */ | 194 */ |
193 thread_port = pthread_mach_thread_np(natp->thread.tid); | 195 result = thread_resume(GetHostThreadPort(natp)); |
194 result = thread_resume(thread_port); | |
195 if (result != KERN_SUCCESS) { | 196 if (result != KERN_SUCCESS) { |
196 NaClLog(LOG_FATAL, "NaClAppThreadUnblockIfFaulted: " | 197 NaClLog(LOG_FATAL, "NaClAppThreadUnblockIfFaulted: " |
197 "thread_resume() call failed: error %d\n", (int) result); | 198 "thread_resume() call failed: error %d\n", (int) result); |
198 } | 199 } |
199 return 1; | 200 return 1; |
200 } | 201 } |
OLD | NEW |