| 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 |