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