blob: 5757b6c90454ff9bfe57c2a959ddb69b195f5ae4 [file] [log] [blame]
/*
* Copyright (c) 2012 The Native Client Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <float.h>
#include "native_client/src/include/build_config.h"
#if NACL_WINDOWS
/*
* This header declares the _mm_getcsr function.
*/
#include <intrin.h>
#endif
#include "native_client/src/shared/platform/nacl_log.h"
#include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
#include "native_client/src/trusted/service_runtime/nacl_signal.h"
#include "native_client/src/trusted/service_runtime/nacl_tls.h"
#include "native_client/src/trusted/service_runtime/sel_ldr.h"
#include "native_client/src/trusted/service_runtime/sel_rt.h"
#include "native_client/src/trusted/service_runtime/include/sys/errno.h"
#include "native_client/src/trusted/cpu_features/arch/x86/cpu_x86.h"
uint16_t nacl_global_cs = 0;
uint16_t nacl_global_ds = 0;
void NaClInitGlobals(void) {
nacl_global_cs = NaClGetCs();
nacl_global_ds = NaClGetDs();
}
uint16_t NaClGetGlobalDs(void) {
return nacl_global_ds;
}
uint16_t NaClGetGlobalCs(void) {
return nacl_global_cs;
}
int NaClAppThreadInitArchSpecific(struct NaClAppThread *natp,
nacl_reg_t prog_ctr,
nacl_reg_t stack_ptr) {
struct NaClThreadContext *ntcp = &natp->user;
struct NaClApp *nap = natp->nap;
/* TODO(mcgrathr): Use a safe cast here. */
NaClCPUFeaturesX86 *features = (NaClCPUFeaturesX86 *) nap->cpu_features;
NaClThreadContextOffsetCheck();
NaClLog(4, "&nap->code_seg_sel = 0x%08"NACL_PRIxPTR"\n",
(uintptr_t) &nap->code_seg_sel);
NaClLog(4, "&nap->data_seg_sel = 0x%08"NACL_PRIxPTR"\n",
(uintptr_t) &nap->data_seg_sel);
NaClLog(4, "nap->code_seg_sel = 0x%02x\n", nap->code_seg_sel);
NaClLog(4, "nap->data_seg_sel = 0x%02x\n", nap->data_seg_sel);
/*
* initialize registers to appropriate values. most registers just
* get zero, but for the segment register we allocate segment
* selectors for the NaCl app, based on its address space.
*/
ntcp->ebx = 0;
ntcp->esi = 0;
ntcp->edi = 0;
ntcp->frame_ptr = 0;
ntcp->stack_ptr = stack_ptr;
ntcp->prog_ctr = prog_ctr;
ntcp->new_prog_ctr = 0;
ntcp->sysret = (nacl_reg_t) -NACL_ABI_EINVAL;
ntcp->cs = nap->code_seg_sel;
ntcp->ds = nap->data_seg_sel;
ntcp->es = nap->data_seg_sel;
ntcp->fs = 0; /* windows use this for TLS and SEH; linux does not */
ntcp->gs = NaClTlsAllocate(natp);
if (ntcp->gs == NACL_TLS_INDEX_INVALID)
return 0;
ntcp->ss = nap->data_seg_sel;
ntcp->fcw = NACL_X87_FCW_DEFAULT;
ntcp->mxcsr = NACL_MXCSR_DEFAULT;
/*
* Save the system's state of the x87 FPU control word so we can restore
* the same state when returning to trusted code.
*/
#if NACL_WINDOWS
{
uint16_t sys_fcw;
__asm {
fnstcw sys_fcw;
}
ntcp->sys_fcw = sys_fcw;
}
#else
__asm__ __volatile__("fnstcw %0" : "=m" (ntcp->sys_fcw));
#endif
/*
* Likewise for the SSE control word, if SSE is supported.
*/
if (NaClGetCPUFeatureX86(features, NaClCPUFeatureX86_SSE)) {
#if NACL_WINDOWS
ntcp->sys_mxcsr = _mm_getcsr();
#else
/*
* GCC actually defines _mm_getcsr too, in its <xmmintrin.h>.
* But that (and the __builtin_ia32_stmxcsr it uses) are only
* available when compiling with -msse, which also makes the
* compiler generate SSE instructions itself, which would be
* incompatible with systems that don't support SSE.
*/
__asm__("stmxcsr %0" : "=m" (ntcp->sys_mxcsr));
#endif
}
NaClLog(4, "user.cs: 0x%02x\n", ntcp->cs);
NaClLog(4, "user.fs: 0x%02x\n", ntcp->fs);
NaClLog(4, "user.gs: 0x%02x\n", ntcp->gs);
NaClLog(4, "user.ss: 0x%02x\n", ntcp->ss);
return 1;
}
void NaClThreadContextToSignalContext(const struct NaClThreadContext *th_ctx,
struct NaClSignalContext *sig_ctx) {
sig_ctx->eax = 0;
sig_ctx->ecx = 0;
sig_ctx->edx = 0;
sig_ctx->ebx = th_ctx->ebx;
sig_ctx->stack_ptr = th_ctx->stack_ptr;
sig_ctx->ebp = th_ctx->frame_ptr;
sig_ctx->esi = th_ctx->esi;
sig_ctx->edi = th_ctx->edi;
sig_ctx->prog_ctr = th_ctx->new_prog_ctr;
sig_ctx->flags = 0;
sig_ctx->cs = th_ctx->cs;
sig_ctx->ss = th_ctx->ss;
sig_ctx->ds = th_ctx->ds;
sig_ctx->es = th_ctx->es;
sig_ctx->fs = th_ctx->fs;
sig_ctx->gs = th_ctx->gs;
}
void NaClSignalContextUnsetClobberedRegisters(
struct NaClSignalContext *sig_ctx) {
sig_ctx->eax = 0;
sig_ctx->ecx = 0;
sig_ctx->edx = 0;
sig_ctx->flags = 0;
}