1/* SPDX-License-Identifier: GPL-2.0 */
2
3#include <linux/linkage.h>
4#include <asm/errno.h>
5#include <asm/enclu.h>
6
7#include "extable.h"
8
9/* Relative to %rbp. */
10#define SGX_ENCLAVE_OFFSET_OF_RUN 16
11
12/* The offsets relative to struct sgx_enclave_run. */
13#define SGX_ENCLAVE_RUN_TCS 0
14#define SGX_ENCLAVE_RUN_LEAF 8
15#define SGX_ENCLAVE_RUN_EXCEPTION_VECTOR 12
16#define SGX_ENCLAVE_RUN_EXCEPTION_ERROR_CODE 14
17#define SGX_ENCLAVE_RUN_EXCEPTION_ADDR 16
18#define SGX_ENCLAVE_RUN_USER_HANDLER 24
19#define SGX_ENCLAVE_RUN_USER_DATA 32 /* not used */
20#define SGX_ENCLAVE_RUN_RESERVED_START 40
21#define SGX_ENCLAVE_RUN_RESERVED_END 256
22
23.code64
24.section .text, "ax"
25
26SYM_FUNC_START(__vdso_sgx_enter_enclave)
27 /* Prolog */
28 .cfi_startproc
29 push %rbp
30 .cfi_adjust_cfa_offset 8
31 .cfi_rel_offset %rbp, 0
32 mov %rsp, %rbp
33 .cfi_def_cfa_register %rbp
34 push %rbx
35 .cfi_rel_offset %rbx, -8
36
37 mov %ecx, %eax
38.Lenter_enclave:
39 /* EENTER <= function <= ERESUME */
40 cmp $EENTER, %eax
41 jb .Linvalid_input
42 cmp $ERESUME, %eax
43 ja .Linvalid_input
44
45 mov SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rcx
46
47 /* Validate that the reserved area contains only zeros. */
48 mov $SGX_ENCLAVE_RUN_RESERVED_START, %rbx
491:
50 cmpq $0, (%rcx, %rbx)
51 jne .Linvalid_input
52 add $8, %rbx
53 cmpq $SGX_ENCLAVE_RUN_RESERVED_END, %rbx
54 jne 1b
55
56 /* Load TCS and AEP */
57 mov SGX_ENCLAVE_RUN_TCS(%rcx), %rbx
58 lea .Lasync_exit_pointer(%rip), %rcx
59
60 /* Single ENCLU serving as both EENTER and AEP (ERESUME) */
61.Lasync_exit_pointer:
62.Lenclu_eenter_eresume:
63 enclu
64
65 /* EEXIT jumps here unless the enclave is doing something fancy. */
66 mov SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rbx
67
68 /* Set exit_reason. */
69 movl $EEXIT, SGX_ENCLAVE_RUN_LEAF(%rbx)
70
71 /* Invoke userspace's exit handler if one was provided. */
72.Lhandle_exit:
73 cmpq $0, SGX_ENCLAVE_RUN_USER_HANDLER(%rbx)
74 jne .Linvoke_userspace_handler
75
76 /* Success, in the sense that ENCLU was attempted. */
77 xor %eax, %eax
78
79.Lout:
80 pop %rbx
81 leave
82 .cfi_def_cfa %rsp, 8
83 RET
84
85 /* The out-of-line code runs with the pre-leave stack frame. */
86 .cfi_def_cfa %rbp, 16
87
88.Linvalid_input:
89 mov $(-EINVAL), %eax
90 jmp .Lout
91
92.Lhandle_exception:
93 mov SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rbx
94
95 /* Set the exception info. */
96 mov %eax, (SGX_ENCLAVE_RUN_LEAF)(%rbx)
97 mov %di, (SGX_ENCLAVE_RUN_EXCEPTION_VECTOR)(%rbx)
98 mov %si, (SGX_ENCLAVE_RUN_EXCEPTION_ERROR_CODE)(%rbx)
99 mov %rdx, (SGX_ENCLAVE_RUN_EXCEPTION_ADDR)(%rbx)
100 jmp .Lhandle_exit
101
102.Linvoke_userspace_handler:
103 /* Pass the untrusted RSP (at exit) to the callback via %rcx. */
104 mov %rsp, %rcx
105
106 /* Save struct sgx_enclave_exception %rbx is about to be clobbered. */
107 mov %rbx, %rax
108
109 /* Save the untrusted RSP offset in %rbx (non-volatile register). */
110 mov %rsp, %rbx
111 and $0xf, %rbx
112
113 /*
114 * Align stack per x86_64 ABI. Note, %rsp needs to be 16-byte aligned
115 * _after_ pushing the parameters on the stack, hence the bonus push.
116 */
117 and $-0x10, %rsp
118 push %rax
119
120 /* Push struct sgx_enclave_exception as a param to the callback. */
121 push %rax
122
123 /* Clear RFLAGS.DF per x86_64 ABI */
124 cld
125
126 /*
127 * Load the callback pointer to %rax and lfence for LVI (load value
128 * injection) protection before making the call.
129 */
130 mov SGX_ENCLAVE_RUN_USER_HANDLER(%rax), %rax
131 lfence
132 call *%rax
133
134 /* Undo the post-exit %rsp adjustment. */
135 lea 0x10(%rsp, %rbx), %rsp
136
137 /*
138 * If the return from callback is zero or negative, return immediately,
139 * else re-execute ENCLU with the positive return value interpreted as
140 * the requested ENCLU function.
141 */
142 cmp $0, %eax
143 jle .Lout
144 jmp .Lenter_enclave
145
146 .cfi_endproc
147
148_ASM_VDSO_EXTABLE_HANDLE(.Lenclu_eenter_eresume, .Lhandle_exception)
149
150SYM_FUNC_END(__vdso_sgx_enter_enclave)
151

source code of linux/arch/x86/entry/vdso/vsgx.S