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.
8 * This code gets executed when switching from the service
9 * runtime to the NaCl module. NaClSwitch has one parameter only,
10 * which is a struct passed by reference.
12 * NB: this is not the only place where context switches from trusted
13 * to untrusted code. The NaClGetTlsFastPath* code (nacl_syscall_64.S)
14 * also performs a partial switch (to and fro).
17 #include "native_client/src/trusted/service_runtime/arch/x86_64/sel_rt_64.h"
18 #include "native_client/src/trusted/service_runtime/nacl_config.h"
21 * This function does not return. Thus, we need to preserve
22 * any callee-saved registers.
27 .macro switcher arg1, arg2
28 DEFINE_GLOBAL_HIDDEN_FUNCTION(\arg1):
30 /* On Windows, 1st param is in %rcx. */
32 #elif NACL_LINUX || NACL_OSX
33 /* On Linux/OSX, 1st param is in %rdi. */
36 # error "What OS/compiler is the service runtime being compiled with?"
40 * TODO(mcgrathr): Perhaps drop callee-saved registers (these six)
41 * from this restore and instead just clear them at startup
42 * (i.e. have NaClStartThreadInApp call a NaClStartSwitch that
43 * clears them and calls NaClSwitch).
45 movq NACL_THREAD_CONTEXT_OFFSET_RBX(%r11), %rbx
46 movq NACL_THREAD_CONTEXT_OFFSET_RBP(%r11), %rbp
47 movq NACL_THREAD_CONTEXT_OFFSET_R12(%r11), %r12
48 movq NACL_THREAD_CONTEXT_OFFSET_R13(%r11), %r13
49 movq NACL_THREAD_CONTEXT_OFFSET_R14(%r11), %r14
50 movq NACL_THREAD_CONTEXT_OFFSET_R15(%r11), %r15
52 /* there is no springboard for x86_64 */
53 movq NACL_THREAD_CONTEXT_OFFSET_RSP(%r11), %rsp
54 movq NACL_THREAD_CONTEXT_OFFSET_SYSRET(%r11), %rax
57 * %rdi is the first argument in the user calling convention.
58 * When starting the initial thread, we are passing the address
59 * of the parameter block here. The initial stack pointer has
60 * been adjusted to one word below there, to insert a dummy
61 * return address for the user entry point function.
66 * Zero all unused registers. The 32-bit instructions
67 * are a byte shorter than their 64-bit counterparts
68 * when the target register is one of the first eight,
69 * and they implicitly zero the high halves.
71 * The 'xorl' instruction also resets most flags to known
82 * Clear the x87, MMX, and SSE state.
83 * Then restore the untrusted code's x87 and SSE control words.
84 * We could roll them together by storing a 512-byte per-thread
85 * buffer and setting the control words in that in NaClSyscallSeg.
86 * But that would bloat struct NaClThreadContext by 504 bytes or so,
87 * and the performance cost of these two instructions after fxrstor
88 * seems to be immeasurably small.
90 fxrstor fxrstor_default_state(%rip)
91 fldcw NACL_THREAD_CONTEXT_OFFSET_FCW(%r11)
92 ldmxcsr NACL_THREAD_CONTEXT_OFFSET_MXCSR(%r11)
96 * Clear the AVX state that the "fxrstor" instruction doesn't cover.
97 * We could roll them together by using the "xrstor" instruction, but
98 * that has a complicated protocol and this seems to perform fine.
100 * This is "vzeroupper".
101 * Some assembler versions don't know the AVX instructions.
103 .byte 0xc5, 0xf8, 0x77
107 * Load the return address into %r11 rather than doing
108 * "jmp *XXX(%r11)" so that we do not leak the address of the
109 * struct NaClThreadContext to untrusted code. Knowing this
110 * address would make bugs in the sandbox easier to exploit.
112 movq NACL_THREAD_CONTEXT_OFFSET_NEW_PROG_CTR(%r11), %r11
116 switcher NaClSwitchSSE, 0
117 switcher NaClSwitchAVX, 1
122 * This is the memory block for "fxrstor" to read. The only
123 * contents that matter are the fcw and mxcsr words, which we
124 * store separately. The mxcsr_mask word is ignored by the
125 * hardware, so there is no need to get the hardware-supplied
126 * value for that. The hardware requires that this address be
127 * aligned to 16 bytes. Align it further to 64 bytes because
128 * that is the usual size of a cache line; this might help
129 * performance and is very unlikely to hurt it.
132 fxrstor_default_state: