]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/sgx/abi/entry.S
Add comment to SGX entry code
[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 /* MXCSR initialization value for ABI */
34 .Lmxcsr_init:
35     .int 0x1f80
36
37 /* x87 FPU control word initialization value for ABI */
38 .Lfpucw_init:
39     .int 0x037f
40
41 /*  The following symbols point at read-only data that will be filled in by the */
42 /*  post-linker. */
43
44 /*  When using this macro, don't forget to adjust the linker version script! */
45 .macro globvar name:req size:req
46     .global \name
47     .protected \name
48     .align \size
49     .size \name , \size
50     \name :
51         .org .+\size
52 .endm
53     /*  The base address (relative to enclave start) of the heap area */
54     globvar HEAP_BASE 8
55     /*  The heap size in bytes */
56     globvar HEAP_SIZE 8
57     /*  Value of the RELA entry in the dynamic table */
58     globvar RELA 8
59     /*  Value of the RELACOUNT entry in the dynamic table */
60     globvar RELACOUNT 8
61     /*  The enclave size in bytes */
62     globvar ENCLAVE_SIZE 8
63     /*  The base address (relative to enclave start) of the enclave configuration area */
64     globvar CFGDATA_BASE 8
65     /*  Non-zero if debugging is enabled, zero otherwise */
66     globvar DEBUG 1
67     /*  The base address (relative to enclave start) of the enclave text section */
68     globvar TEXT_BASE 8
69     /*  The size in bytes of enclacve text section */
70     globvar TEXT_SIZE 8
71     /*  The base address (relative to enclave start) of the enclave EH_FRM_HDR section */
72     globvar EH_FRM_HDR_BASE 8
73     /*  The size in bytes of enclacve EH_FRM_HDR section */
74     globvar EH_FRM_HDR_SIZE 8
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 .Laborted:
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 /* We place the ELF entry point in a separate section so it can be removed by
116    elf2sgxs */
117 .section .text_no_sgx, "ax"
118 .Lelf_entry_error_msg:
119     .ascii "Error: This file is an SGX enclave which cannot be executed as a standard Linux binary.\nSee the installation guide at https://edp.fortanix.com/docs/installation/guide/ on how to use 'cargo run' or follow the steps at https://edp.fortanix.com/docs/tasks/deployment/ for manual deployment.\n"
120 .Lelf_entry_error_msg_end:
121
122 .global elf_entry
123 .type elf_entry,function
124 elf_entry:
125 /* print error message */
126     movq $2,%rdi                      /* write to stderr (fd 2) */
127     lea .Lelf_entry_error_msg(%rip),%rsi
128     movq $.Lelf_entry_error_msg_end-.Lelf_entry_error_msg,%rdx
129 .Lelf_entry_call:
130     movq $1,%rax                      /* write() syscall        */
131     syscall
132     test %rax,%rax
133     jle .Lelf_exit                    /* exit on error          */
134     add %rax,%rsi
135     sub %rax,%rdx                     /* all chars written?     */
136     jnz .Lelf_entry_call
137
138 .Lelf_exit:    
139     movq $60,%rax                     /* exit() syscall         */
140     movq $1,%rdi                      /* exit code 1            */
141     syscall
142     ud2                               /* should not be reached  */
143 /*  end elf_entry */
144
145 /* This code needs to be called *after* the enclave stack has been setup. */
146 /* There are 3 places where this needs to happen, so this is put in a macro. */
147 .macro entry_sanitize_final
148 /*  Sanitize rflags received from user */
149 /*    - DF flag: x86-64 ABI requires DF to be unset at function entry/exit */
150 /*    - AC flag: AEX on misaligned memory accesses leaks side channel info */
151     pushfq
152     andq $~0x40400, (%rsp)
153     popfq
154 /*  check for abort */
155     bt $0,.Laborted(%rip)
156     jc .Lreentry_panic
157 .endm
158
159 .text
160 .global sgx_entry
161 .type sgx_entry,function
162 sgx_entry:
163 /*  save user registers */
164     mov %rcx,%gs:tcsls_user_retip
165     mov %rsp,%gs:tcsls_user_rsp
166     mov %rbp,%gs:tcsls_user_rbp
167     mov %r12,%gs:tcsls_user_r12
168     mov %r13,%gs:tcsls_user_r13
169     mov %r14,%gs:tcsls_user_r14
170     mov %r15,%gs:tcsls_user_r15
171     mov %rbx,%gs:tcsls_tcs_addr
172     stmxcsr %gs:tcsls_user_mxcsr
173     fnstcw %gs:tcsls_user_fcw
174
175 /*  check for debug buffer pointer */
176     testb  $0xff,DEBUG(%rip)
177     jz .Lskip_debug_init
178     mov %r10,%gs:tcsls_debug_panic_buf_ptr
179 .Lskip_debug_init:
180 /*  check if returning from usercall */
181     mov %gs:tcsls_last_rsp,%r11
182     test %r11,%r11
183     jnz .Lusercall_ret
184 /*  reset user state */
185     ldmxcsr .Lmxcsr_init(%rip)
186     fldcw .Lfpucw_init(%rip)
187 /*  setup stack */
188     mov %gs:tcsls_tos,%rsp /*  initially, RSP is not set to the correct value */
189                            /*  here. This is fixed below under "adjust stack". */
190 /*  check for thread init */
191     bts $tcsls_flag_init_once,%gs:tcsls_flags
192     jc .Lskip_init
193 /*  adjust stack */
194     lea IMAGE_BASE(%rip),%rax
195     add %rax,%rsp
196     mov %rsp,%gs:tcsls_tos
197     entry_sanitize_final
198 /*  call tcs_init */
199 /*  store caller-saved registers in callee-saved registers */
200     mov %rdi,%rbx
201     mov %rsi,%r12
202     mov %rdx,%r13
203     mov %r8,%r14
204     mov %r9,%r15
205     load_tcsls_flag_secondary_bool di /* RDI = tcs_init() argument: secondary: bool */
206     call tcs_init
207 /*  reload caller-saved registers */
208     mov %rbx,%rdi
209     mov %r12,%rsi
210     mov %r13,%rdx
211     mov %r14,%r8
212     mov %r15,%r9
213     jmp .Lafter_init
214 .Lskip_init:
215     entry_sanitize_final
216 .Lafter_init:
217 /*  call into main entry point */
218     load_tcsls_flag_secondary_bool cx /* RCX = entry() argument: secondary: bool */
219     call entry /* RDI, RSI, RDX, R8, R9 passed in from userspace */
220     mov %rax,%rsi  /* RSI = return value */
221     /* NOP: mov %rdx,%rdx */ /*  RDX = return value */
222     xor %rdi,%rdi  /* RDI = normal exit */
223 .Lexit:
224 /*  clear general purpose register state */
225     /*  RAX overwritten by ENCLU */
226     /*  RBX set later */
227     /*  RCX overwritten by ENCLU */
228     /*  RDX contains return value */
229     /*  RSP set later */
230     /*  RBP set later */
231     /*  RDI contains exit mode */
232     /*  RSI contains return value */
233     xor %r8,%r8
234     xor %r9,%r9
235     xor %r10,%r10
236     xor %r11,%r11
237     /*  R12 ~ R15 set by sgx_exit */
238 .Lsgx_exit:
239 /*  clear extended register state */
240     mov %rdx, %rcx /*  save RDX */
241     mov $-1, %rax
242     mov %rax, %rdx
243     xrstor .Lxsave_clear(%rip)
244     mov %rcx, %rdx /*  restore RDX */
245 /*  clear flags */
246     pushq $0
247     popfq
248 /*  restore user registers */
249     mov %gs:tcsls_user_r12,%r12
250     mov %gs:tcsls_user_r13,%r13
251     mov %gs:tcsls_user_r14,%r14
252     mov %gs:tcsls_user_r15,%r15
253     mov %gs:tcsls_user_retip,%rbx
254     mov %gs:tcsls_user_rsp,%rsp
255     mov %gs:tcsls_user_rbp,%rbp
256     fldcw %gs:tcsls_user_fcw
257     ldmxcsr %gs:tcsls_user_mxcsr
258 /*  exit enclave */
259     mov $0x4,%eax /*  EEXIT */
260     enclu
261 /*  end sgx_entry */
262
263 .Lreentry_panic:
264     orq $8,%rsp
265     jmp abort_reentry
266
267 /*  This *MUST* be called with 6 parameters, otherwise register information */
268 /*  might leak! */
269 .global usercall
270 usercall:
271     test %rcx,%rcx            /* check `abort` function argument */
272     jnz .Lusercall_abort      /* abort is set, jump to abort code (unlikely forward conditional) */
273     jmp .Lusercall_save_state /* non-aborting usercall */
274 .Lusercall_abort:
275 /* set aborted bit */
276     movb $1,.Laborted(%rip)
277 /* save registers in DEBUG mode, so that debugger can reconstruct the stack */
278     testb $0xff,DEBUG(%rip)
279     jz .Lusercall_noreturn
280 .Lusercall_save_state:
281 /*  save callee-saved state */
282     push %r15
283     push %r14
284     push %r13
285     push %r12
286     push %rbp
287     push %rbx
288     sub $8, %rsp
289     fstcw 4(%rsp)
290     stmxcsr (%rsp)
291     movq %rsp,%gs:tcsls_last_rsp
292 .Lusercall_noreturn:
293 /*  clear general purpose register state */
294     /*  RAX overwritten by ENCLU */
295     /*  RBX set by sgx_exit */
296     /*  RCX overwritten by ENCLU */
297     /*  RDX contains parameter */
298     /*  RSP set by sgx_exit */
299     /*  RBP set by sgx_exit */
300     /*  RDI contains parameter */
301     /*  RSI contains parameter */
302     /*  R8 contains parameter */
303     /*  R9 contains parameter */
304     xor %r10,%r10
305     xor %r11,%r11
306     /*  R12 ~ R15 set by sgx_exit */
307 /*  extended registers/flags cleared by sgx_exit */
308 /*  exit */
309     jmp .Lsgx_exit
310 .Lusercall_ret:
311     movq $0,%gs:tcsls_last_rsp
312 /*  restore callee-saved state, cf. "save" above */
313     mov %r11,%rsp
314     ldmxcsr (%rsp)
315     fldcw 4(%rsp)
316     add $8, %rsp
317     entry_sanitize_final
318     pop %rbx
319     pop %rbp
320     pop %r12
321     pop %r13
322     pop %r14
323     pop %r15
324 /*  return */
325     mov %rsi,%rax /*  RAX = return value */
326     /* NOP: mov %rdx,%rdx */ /*  RDX = return value */
327     ret
328
329 /*
330 The following functions need to be defined externally:
331 ```
332 // Called by entry code on re-entry after exit
333 extern "C" fn abort_reentry() -> !;
334
335 // Called once when a TCS is first entered
336 extern "C" fn tcs_init(secondary: bool);
337
338 // Standard TCS entrypoint
339 extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64);
340 ```
341 */
342
343 .global get_tcs_addr
344 get_tcs_addr:
345     mov %gs:tcsls_tcs_addr,%rax
346     ret
347
348 .global get_tls_ptr
349 get_tls_ptr:
350     mov %gs:tcsls_tls_ptr,%rax
351     ret
352
353 .global set_tls_ptr
354 set_tls_ptr:
355     mov %rdi,%gs:tcsls_tls_ptr
356     ret
357
358 .global take_debug_panic_buf_ptr
359 take_debug_panic_buf_ptr:
360     xor %rax,%rax
361     xchg %gs:tcsls_debug_panic_buf_ptr,%rax
362     ret