]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/sgx/abi/entry.S
ac7f95d4eae80fc587edbc548a21f18a66707f04
[rust.git] / src / libstd / sys / sgx / abi / entry.S
1 /*  This symbol is used at runtime to figure out the virtual address that the */
2 /*  enclave is loaded at. */
3 .section absolute
4 .global IMAGE_BASE
5 IMAGE_BASE:
6
7 .section ".note.x86_64-fortanix-unknown-sgx", "", @note
8     .align 4
9     .long 1f - 0f              /* name length (not including padding) */
10     .long 3f - 2f              /* desc length (not including padding) */
11     .long 1                    /* type = NT_VERSION */
12 0:  .asciz "toolchain-version" /* name */
13 1:  .align 4
14 2:  .long 0                    /* desc - toolchain version number, 32-bit LE */
15 3:  .align 4
16
17 .section .rodata
18 /*  The XSAVE area needs to be a large chunk of readable memory, but since we are */
19 /*  going to restore everything to its initial state (XSTATE_BV=0), only certain */
20 /*  parts need to have a defined value. In particular: */
21 /*  */
22 /*    * MXCSR in the legacy area. This register is always restored if RFBM[1] or */
23 /*      RFBM[2] is set, regardless of the value of XSTATE_BV */
24 /*    * XSAVE header */
25 .align 64
26 .Lxsave_clear:
27 .org .+24
28 .Lxsave_mxcsr:
29     .int 0
30
31 /*  We can store a bunch of data in the gap between MXCSR and the XSAVE header */
32
33 /*  The following symbols point at read-only data that will be filled in by the */
34 /*  post-linker. */
35
36 /*  When using this macro, don't forget to adjust the linker version script! */
37 .macro globvar name:req size:req
38     .global \name
39     .protected \name
40     .align \size
41     .size \name , \size
42     \name :
43         .org .+\size
44 .endm
45     /*  The base address (relative to enclave start) of the heap area */
46     globvar HEAP_BASE 8
47     /*  The heap size in bytes */
48     globvar HEAP_SIZE 8
49     /*  Value of the RELA entry in the dynamic table */
50     globvar RELA 8
51     /*  Value of the RELACOUNT entry in the dynamic table */
52     globvar RELACOUNT 8
53     /*  The enclave size in bytes */
54     globvar ENCLAVE_SIZE 8
55     /*  The base address (relative to enclave start) of the enclave configuration area */
56     globvar CFGDATA_BASE 8
57     /*  Non-zero if debugging is enabled, zero otherwise */
58     globvar DEBUG 1
59     /*  The base address (relative to enclave start) of the enclave text section */
60     globvar TEXT_BASE 8
61     /*  The size in bytes of enclacve text section */
62     globvar TEXT_SIZE 8
63     /*  The base address (relative to enclave start) of the enclave EH_FRM_HDR section */
64     globvar EH_FRM_HDR_BASE 8
65     /*  The size in bytes of enclacve EH_FRM_HDR section */
66     globvar EH_FRM_HDR_SIZE 8
67
68 .Lreentry_panic_msg:
69     .asciz "Re-entered panicked enclave!"
70 .Lreentry_panic_msg_end:
71
72 .Lusercall_panic_msg:
73     .asciz "Invalid usercall#!"
74 .Lusercall_panic_msg_end:
75
76 .org .Lxsave_clear+512
77 .Lxsave_header:
78     .int 0, 0 /*  XSTATE_BV */
79     .int 0, 0 /*  XCOMP_BV */
80     .org .+48 /*  reserved bits */
81
82 .data
83 .Lpanicked:
84     .byte 0
85
86 /*  TCS local storage section */
87 .equ tcsls_tos,                 0x00 /*  initialized by loader to *offset* from image base to TOS */
88 .equ tcsls_flags,               0x08 /*  initialized by loader */
89 .equ tcsls_flag_secondary,      0    /*  initialized by loader; 0 = standard TCS, 1 = secondary TCS */
90 .equ tcsls_flag_init_once,      1    /*  initialized by loader to 0 */
91 /*  14 unused bits */
92 .equ tcsls_user_fcw,            0x0a
93 .equ tcsls_user_mxcsr,          0x0c
94 .equ tcsls_last_rsp,            0x10 /*  initialized by loader to 0 */
95 .equ tcsls_panic_last_rsp,      0x18 /*  initialized by loader to 0 */
96 .equ tcsls_debug_panic_buf_ptr, 0x20 /*  initialized by loader to 0 */
97 .equ tcsls_user_rsp,            0x28
98 .equ tcsls_user_retip,          0x30
99 .equ tcsls_user_rbp,            0x38
100 .equ tcsls_user_r12,            0x40
101 .equ tcsls_user_r13,            0x48
102 .equ tcsls_user_r14,            0x50
103 .equ tcsls_user_r15,            0x58
104 .equ tcsls_tls_ptr,             0x60
105 .equ tcsls_tcs_addr,            0x68
106
107 .macro load_tcsls_flag_secondary_bool reg:req comments:vararg
108     .ifne tcsls_flag_secondary /* to convert to a bool, must be the first bit */
109     .abort
110     .endif
111         mov $(1<<tcsls_flag_secondary),%e\reg
112         and %gs:tcsls_flags,%\reg
113 .endm
114
115 .text
116 .global sgx_entry
117 .type sgx_entry,function
118 sgx_entry:
119 /*  save user registers */
120     mov %rcx,%gs:tcsls_user_retip
121     mov %rsp,%gs:tcsls_user_rsp
122     mov %rbp,%gs:tcsls_user_rbp
123     mov %r12,%gs:tcsls_user_r12
124     mov %r13,%gs:tcsls_user_r13
125     mov %r14,%gs:tcsls_user_r14
126     mov %r15,%gs:tcsls_user_r15
127     mov %rbx,%gs:tcsls_tcs_addr
128     stmxcsr %gs:tcsls_user_mxcsr
129     fnstcw %gs:tcsls_user_fcw
130 /*  reset user state */
131     cld /* x86-64 ABI requires DF to be unset at function entry/exit */
132 /*  check for debug buffer pointer */
133     testb  $0xff,DEBUG(%rip)
134     jz .Lskip_debug_init
135     mov %r10,%gs:tcsls_debug_panic_buf_ptr
136 .Lskip_debug_init:
137 /*  check if returning from usercall */
138     mov %gs:tcsls_last_rsp,%r11
139     test %r11,%r11
140     jnz .Lusercall_ret
141 /*  setup stack */
142     mov %gs:tcsls_tos,%rsp /*  initially, RSP is not set to the correct value */
143                            /*  here. This is fixed below under "adjust stack". */
144 /*  check for thread init */
145     bts $tcsls_flag_init_once,%gs:tcsls_flags
146     jc .Lskip_init
147 /*  adjust stack */
148     lea IMAGE_BASE(%rip),%rax
149     add %rax,%rsp
150     mov %rsp,%gs:tcsls_tos
151 /*  call tcs_init */
152 /*  store caller-saved registers in callee-saved registers */
153     mov %rdi,%rbx
154     mov %rsi,%r12
155     mov %rdx,%r13
156     mov %r8,%r14
157     mov %r9,%r15
158     load_tcsls_flag_secondary_bool di /* RDI = tcs_init() argument: secondary: bool */
159     call tcs_init
160 /*  reload caller-saved registers */
161     mov %rbx,%rdi
162     mov %r12,%rsi
163     mov %r13,%rdx
164     mov %r14,%r8
165     mov %r15,%r9
166 .Lskip_init:
167 /*  check for panic */
168     bt $0,.Lpanicked(%rip)
169     jc .Lreentry_panic
170 /*  call into main entry point */
171     load_tcsls_flag_secondary_bool cx /* RCX = entry() argument: secondary: bool */
172     call entry /* RDI, RSI, RDX, R8, R9 passed in from userspace */
173     mov %rax,%rsi  /* RSI = return value */
174     /* NOP: mov %rdx,%rdx */ /*  RDX = return value */
175     xor %rdi,%rdi  /* RDI = normal exit */
176 .Lexit:
177 /*  clear general purpose register state */
178     /*  RAX overwritten by ENCLU */
179     /*  RBX set later */
180     /*  RCX overwritten by ENCLU */
181     /*  RDX contains return value */
182     /*  RSP set later */
183     /*  RBP set later */
184     /*  RDI contains exit mode */
185     /*  RSI contains return value */
186     xor %r8,%r8
187     xor %r9,%r9
188     xor %r10,%r10
189     xor %r11,%r11
190     /*  R12 ~ R15 set by sgx_exit */
191 .Lsgx_exit:
192 /*  clear extended register state */
193     mov %rdx, %rcx /*  save RDX */
194     mov $-1, %rax
195     mov %rax, %rdx
196     xrstor .Lxsave_clear(%rip)
197     mov %rcx, %rdx /*  restore RDX */
198 /*  clear flags */
199     pushq $0
200     popfq
201 /*  restore user registers */
202     mov %gs:tcsls_user_r12,%r12
203     mov %gs:tcsls_user_r13,%r13
204     mov %gs:tcsls_user_r14,%r14
205     mov %gs:tcsls_user_r15,%r15
206     mov %gs:tcsls_user_retip,%rbx
207     mov %gs:tcsls_user_rsp,%rsp
208     mov %gs:tcsls_user_rbp,%rbp
209     fldcw %gs:tcsls_user_fcw
210     ldmxcsr %gs:tcsls_user_mxcsr
211 /*  exit enclave */
212     mov $0x4,%eax /*  EEXIT */
213     enclu
214 /*  end sgx_entry */
215
216 .Lreentry_panic:
217     lea .Lreentry_panic_msg(%rip),%rdi
218     mov $.Lreentry_panic_msg_end-.Lreentry_panic_msg,%esi
219     orq $8,%rsp
220     jmp panic_msg
221
222 .Lusercall_panic:
223     lea .Lusercall_panic_msg(%rip),%rdi
224     mov $.Lusercall_panic_msg_end-.Lusercall_panic_msg,%esi
225     orq $8,%rsp
226     jmp panic_msg
227
228 .macro push_callee_saved_registers
229     push %r15
230     push %r14
231     push %r13
232     push %r12
233     push %rbp
234     push %rbx
235     sub $8, %rsp
236     fstcw 4(%rsp)
237     stmxcsr (%rsp)
238 .endm
239
240 .global panic_exit
241 panic_exit:
242 /* save registers in DEBUG mode, so that debugger can reconstruct the stack */
243     testb $0xff,DEBUG(%rip)
244     jz .Lskip_save_registers
245     push_callee_saved_registers
246     movq %rsp,%gs:tcsls_panic_last_rsp
247 .Lskip_save_registers:
248 /* set panicked bit */
249     movb $1,.Lpanicked(%rip)
250 /* call usercall exit(true) */
251     mov $1,%esi   /*  RSI = usercall() argument: panic = true */
252     xor %rdx,%rdx /*  RDX cleared */
253     movq $usercall_nr_exit,%rdi /*  RDI = usercall exit */
254     jmp .Lexit
255
256 /*  This *MUST* be called with 6 parameters, otherwise register information */
257 /*  might leak! */
258 .global usercall
259 usercall:
260     test %rdi,%rdi
261     jle .Lusercall_panic
262 /*  save callee-saved state */
263     push_callee_saved_registers
264     movq %rsp,%gs:tcsls_last_rsp
265 /*  clear general purpose register state */
266     /*  RAX overwritten by ENCLU */
267     /*  RBX set by sgx_exit */
268     /*  RCX overwritten by ENCLU */
269     /*  RDX contains parameter */
270     /*  RSP set by sgx_exit */
271     /*  RBP set by sgx_exit */
272     /*  RDI contains parameter */
273     /*  RSI contains parameter */
274     /*  R8 contains parameter */
275     /*  R9 contains parameter */
276     xor %r10,%r10
277     xor %r11,%r11
278     /*  R12 ~ R15 set by sgx_exit */
279 /*  extended registers/flags cleared by sgx_exit */
280 /*  exit */
281     jmp .Lsgx_exit
282 .Lusercall_ret:
283     movq $0,%gs:tcsls_last_rsp
284 /*  restore callee-saved state, cf. push_callee_saved_registers */
285     mov %r11,%rsp
286     ldmxcsr (%rsp)
287     fldcw 4(%rsp)
288     add $8, %rsp
289     pop %rbx
290     pop %rbp
291     pop %r12
292     pop %r13
293     pop %r14
294     pop %r15
295 /*  return */
296     mov %rsi,%rax /*  RAX = return value */
297     /* NOP: mov %rdx,%rdx */ /*  RDX = return value */
298     ret
299
300 /*
301 The following functions need to be defined externally:
302 ```
303 // Called by entry code when it needs to panic
304 extern "C" fn panic_msg(msg: &'static str) -> ! {
305     panic!(msg)
306 }
307
308 // Called once when a TCS is first entered
309 extern "C" fn tcs_init(secondary: bool);
310
311 // Standard TCS entrypoint
312 extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64);
313 ```
314 */
315
316 .global get_tcs_addr
317 get_tcs_addr:
318     mov %gs:tcsls_tcs_addr,%rax
319     ret
320
321 .global get_tls_ptr
322 get_tls_ptr:
323     mov %gs:tcsls_tls_ptr,%rax
324     ret
325
326 .global set_tls_ptr
327 set_tls_ptr:
328     mov %rdi,%gs:tcsls_tls_ptr
329     ret
330
331 .global take_debug_panic_buf_ptr
332 take_debug_panic_buf_ptr:
333     xor %rax,%rax
334     xchg %gs:tcsls_debug_panic_buf_ptr,%rax
335     ret