xref: /drstd/src/std/sys/sgx/abi/entry.S (revision 9670759b785600bf6315e4173e46a602f16add7a)
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
5IMAGE_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 */
120:  .asciz "toolchain-version" /* name */
131:  .align 4
142:  .long 1                    /* desc - toolchain version number, 32-bit LE */
153:  .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    .short 0x1fbf
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 enclave text section */
62    globvar TEXT_SIZE 8
63    /*  The base address (relative to enclave start) of the enclave .eh_frame_hdr section */
64    globvar EH_FRM_HDR_OFFSET 8
65    /*  The size in bytes of enclave .eh_frame_hdr section */
66    globvar EH_FRM_HDR_LEN 8
67    /*  The base address (relative to enclave start) of the enclave .eh_frame section */
68    globvar EH_FRM_OFFSET 8
69    /*  The size in bytes of enclave .eh_frame section */
70    globvar EH_FRM_LEN 8
71
72.org .Lxsave_clear+512
73.Lxsave_header:
74    .int 0, 0 /*  XSTATE_BV */
75    .int 0, 0 /*  XCOMP_BV */
76    .org .+48 /*  reserved bits */
77
78.data
79.Laborted:
80    .byte 0
81
82/*  TCS local storage section */
83.equ tcsls_tos,                 0x00 /*  initialized by loader to *offset* from image base to TOS */
84.equ tcsls_flags,               0x08 /*  initialized by loader */
85.equ tcsls_flag_secondary,      0    /*  initialized by loader; 0 = standard TCS, 1 = secondary TCS */
86.equ tcsls_flag_init_once,      1    /*  initialized by loader to 0 */
87/*  14 unused bits */
88.equ tcsls_user_fcw,            0x0a
89.equ tcsls_user_mxcsr,          0x0c
90.equ tcsls_last_rsp,            0x10 /*  initialized by loader to 0 */
91.equ tcsls_panic_last_rsp,      0x18 /*  initialized by loader to 0 */
92.equ tcsls_debug_panic_buf_ptr, 0x20 /*  initialized by loader to 0 */
93.equ tcsls_user_rsp,            0x28
94.equ tcsls_user_retip,          0x30
95.equ tcsls_user_rbp,            0x38
96.equ tcsls_user_r12,            0x40
97.equ tcsls_user_r13,            0x48
98.equ tcsls_user_r14,            0x50
99.equ tcsls_user_r15,            0x58
100.equ tcsls_tls_ptr,             0x60
101.equ tcsls_tcs_addr,            0x68
102
103.macro load_tcsls_flag_secondary_bool reg:req comments:vararg
104    .ifne tcsls_flag_secondary /* to convert to a bool, must be the first bit */
105    .abort
106    .endif
107        mov $(1<<tcsls_flag_secondary),%e\reg
108        and %gs:tcsls_flags,%\reg
109.endm
110
111/* We place the ELF entry point in a separate section so it can be removed by
112   elf2sgxs */
113.section .text_no_sgx, "ax"
114.Lelf_entry_error_msg:
115    .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"
116.Lelf_entry_error_msg_end:
117
118.global elf_entry
119.type elf_entry,function
120elf_entry:
121/* print error message */
122    movq $2,%rdi                      /* write to stderr (fd 2) */
123    lea .Lelf_entry_error_msg(%rip),%rsi
124    movq $.Lelf_entry_error_msg_end-.Lelf_entry_error_msg,%rdx
125.Lelf_entry_call:
126    movq $1,%rax                      /* write() syscall        */
127    syscall
128    test %rax,%rax
129    jle .Lelf_exit                    /* exit on error          */
130    add %rax,%rsi
131    sub %rax,%rdx                     /* all chars written?     */
132    jnz .Lelf_entry_call
133
134.Lelf_exit:
135    movq $60,%rax                     /* exit() syscall         */
136    movq $1,%rdi                      /* exit code 1            */
137    syscall
138    ud2                               /* should not be reached  */
139/*  end elf_entry */
140
141/* This code needs to be called *after* the enclave stack has been setup. */
142/* There are 3 places where this needs to happen, so this is put in a macro. */
143.macro entry_sanitize_final
144/*  Sanitize rflags received from user */
145/*    - DF flag: x86-64 ABI requires DF to be unset at function entry/exit */
146/*    - AC flag: AEX on misaligned memory accesses leaks side channel info */
147    pushfq
148    andq $~0x40400, (%rsp)
149    popfq
150/*  check for abort */
151    bt $0,.Laborted(%rip)
152    jc .Lreentry_panic
153.endm
154
155.text
156.global sgx_entry
157.type sgx_entry,function
158sgx_entry:
159/*  save user registers */
160    mov %rcx,%gs:tcsls_user_retip
161    mov %rsp,%gs:tcsls_user_rsp
162    mov %rbp,%gs:tcsls_user_rbp
163    mov %r12,%gs:tcsls_user_r12
164    mov %r13,%gs:tcsls_user_r13
165    mov %r14,%gs:tcsls_user_r14
166    mov %r15,%gs:tcsls_user_r15
167    mov %rbx,%gs:tcsls_tcs_addr
168    stmxcsr %gs:tcsls_user_mxcsr
169    fnstcw %gs:tcsls_user_fcw
170
171/*  check for debug buffer pointer */
172    testb  $0xff,DEBUG(%rip)
173    jz .Lskip_debug_init
174    mov %r10,%gs:tcsls_debug_panic_buf_ptr
175.Lskip_debug_init:
176/*  reset cpu state */
177    mov %rdx, %r10
178    mov $-1, %rax
179    mov $-1, %rdx
180    xrstor .Lxsave_clear(%rip)
181    lfence
182    mov %r10, %rdx
183
184/*  check if returning from usercall */
185    mov %gs:tcsls_last_rsp,%r11
186    test %r11,%r11
187    jnz .Lusercall_ret
188/*  setup stack */
189    mov %gs:tcsls_tos,%rsp /*  initially, RSP is not set to the correct value */
190                           /*  here. This is fixed below under "adjust stack". */
191/*  check for thread init */
192    bts $tcsls_flag_init_once,%gs:tcsls_flags
193    jc .Lskip_init
194/*  adjust stack */
195    lea IMAGE_BASE(%rip),%rax
196    add %rax,%rsp
197    mov %rsp,%gs:tcsls_tos
198    entry_sanitize_final
199/*  call tcs_init */
200/*  store caller-saved registers in callee-saved registers */
201    mov %rdi,%rbx
202    mov %rsi,%r12
203    mov %rdx,%r13
204    mov %r8,%r14
205    mov %r9,%r15
206    load_tcsls_flag_secondary_bool di /* RDI = tcs_init() argument: secondary: bool */
207    call tcs_init
208/*  reload caller-saved registers */
209    mov %rbx,%rdi
210    mov %r12,%rsi
211    mov %r13,%rdx
212    mov %r14,%r8
213    mov %r15,%r9
214    jmp .Lafter_init
215.Lskip_init:
216    entry_sanitize_final
217.Lafter_init:
218/*  call into main entry point */
219    load_tcsls_flag_secondary_bool cx /* RCX = entry() argument: secondary: bool */
220    call entry /* RDI, RSI, RDX, R8, R9 passed in from userspace */
221    mov %rax,%rsi  /* RSI = return value */
222    /* NOP: mov %rdx,%rdx */ /*  RDX = return value */
223    xor %rdi,%rdi  /* RDI = normal exit */
224.Lexit:
225/*  clear general purpose register state */
226    /*  RAX overwritten by ENCLU */
227    /*  RBX set later */
228    /*  RCX overwritten by ENCLU */
229    /*  RDX contains return value */
230    /*  RSP set later */
231    /*  RBP set later */
232    /*  RDI contains exit mode */
233    /*  RSI contains return value */
234    xor %r8,%r8
235    xor %r9,%r9
236    xor %r10,%r10
237    xor %r11,%r11
238    /*  R12 ~ R15 set by sgx_exit */
239.Lsgx_exit:
240/*  clear extended register state */
241    mov %rdx, %rcx /*  save RDX */
242    mov $-1, %rax
243    mov %rax, %rdx
244    xrstor .Lxsave_clear(%rip)
245    mov %rcx, %rdx /*  restore RDX */
246/*  clear flags */
247    pushq $0
248    popfq
249/*  restore user registers */
250    mov %gs:tcsls_user_r12,%r12
251    mov %gs:tcsls_user_r13,%r13
252    mov %gs:tcsls_user_r14,%r14
253    mov %gs:tcsls_user_r15,%r15
254    mov %gs:tcsls_user_retip,%rbx
255    mov %gs:tcsls_user_rsp,%rsp
256    mov %gs:tcsls_user_rbp,%rbp
257    fldcw %gs:tcsls_user_fcw
258    ldmxcsr %gs:tcsls_user_mxcsr
259/*  exit enclave */
260    mov $0x4,%eax /*  EEXIT */
261    enclu
262/*  end sgx_entry */
263
264.Lreentry_panic:
265    orq $8,%rsp
266    jmp abort_reentry
267
268/*  This *MUST* be called with 6 parameters, otherwise register information */
269/*  might leak! */
270.global usercall
271usercall:
272    test %rcx,%rcx            /* check `abort` function argument */
273    jnz .Lusercall_abort      /* abort is set, jump to abort code (unlikely forward conditional) */
274    jmp .Lusercall_save_state /* non-aborting usercall */
275.Lusercall_abort:
276/* set aborted bit */
277    movb $1,.Laborted(%rip)
278/* save registers in DEBUG mode, so that debugger can reconstruct the stack */
279    testb $0xff,DEBUG(%rip)
280    jz .Lusercall_noreturn
281.Lusercall_save_state:
282/*  save callee-saved state */
283    push %r15
284    push %r14
285    push %r13
286    push %r12
287    push %rbp
288    push %rbx
289    sub $8, %rsp
290    fstcw 4(%rsp)
291    stmxcsr (%rsp)
292    movq %rsp,%gs:tcsls_last_rsp
293.Lusercall_noreturn:
294/*  clear general purpose register state */
295    /*  RAX overwritten by ENCLU */
296    /*  RBX set by sgx_exit */
297    /*  RCX overwritten by ENCLU */
298    /*  RDX contains parameter */
299    /*  RSP set by sgx_exit */
300    /*  RBP set by sgx_exit */
301    /*  RDI contains parameter */
302    /*  RSI contains parameter */
303    /*  R8 contains parameter */
304    /*  R9 contains parameter */
305    xor %r10,%r10
306    xor %r11,%r11
307    /*  R12 ~ R15 set by sgx_exit */
308/*  extended registers/flags cleared by sgx_exit */
309/*  exit */
310    jmp .Lsgx_exit
311.Lusercall_ret:
312    movq $0,%gs:tcsls_last_rsp
313/*  restore callee-saved state, cf. "save" above */
314    mov %r11,%rsp
315    /* MCDT mitigation requires an lfence after ldmxcsr _before_ any of the affected  */
316    /* vector instructions is used. We omit the lfence here as one is required before */
317    /* the jmp instruction anyway. */
318    ldmxcsr (%rsp)
319    fldcw 4(%rsp)
320    add $8, %rsp
321    entry_sanitize_final
322    pop %rbx
323    pop %rbp
324    pop %r12
325    pop %r13
326    pop %r14
327    pop %r15
328/*  return */
329    mov %rsi,%rax /*  RAX = return value */
330    /* NOP: mov %rdx,%rdx */ /*  RDX = return value */
331    pop %r11
332    lfence
333    jmp *%r11
334
335/*
336The following functions need to be defined externally:
337```
338// Called by entry code on re-entry after exit
339extern "C" fn abort_reentry() -> !;
340
341// Called once when a TCS is first entered
342extern "C" fn tcs_init(secondary: bool);
343
344// Standard TCS entrypoint
345extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64);
346```
347*/
348
349.global get_tcs_addr
350get_tcs_addr:
351    mov %gs:tcsls_tcs_addr,%rax
352    pop %r11
353    lfence
354    jmp *%r11
355
356.global get_tls_ptr
357get_tls_ptr:
358    mov %gs:tcsls_tls_ptr,%rax
359    pop %r11
360    lfence
361    jmp *%r11
362
363.global set_tls_ptr
364set_tls_ptr:
365    mov %rdi,%gs:tcsls_tls_ptr
366    pop %r11
367    lfence
368    jmp *%r11
369
370.global take_debug_panic_buf_ptr
371take_debug_panic_buf_ptr:
372    xor %rax,%rax
373    xchg %gs:tcsls_debug_panic_buf_ptr,%rax
374    pop %r11
375    lfence
376    jmp *%r11
377