summaryrefslogtreecommitdiffstats
path: root/arch/x86/entry/vdso/vsgx.S
blob: d77d278ee9dd6d2c9745d564ae22e16dfe1b060b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* SPDX-License-Identifier: GPL-2.0 */

#include <linux/linkage.h>
#include <asm/export.h>
#include <asm/errno.h>
#include <asm/enclu.h>

#include "extable.h"

/* Relative to %rbp. */
#define SGX_ENCLAVE_OFFSET_OF_RUN		16

/* The offsets relative to struct sgx_enclave_run. */
#define SGX_ENCLAVE_RUN_TCS			0
#define SGX_ENCLAVE_RUN_LEAF			8
#define SGX_ENCLAVE_RUN_EXCEPTION_VECTOR	12
#define SGX_ENCLAVE_RUN_EXCEPTION_ERROR_CODE	14
#define SGX_ENCLAVE_RUN_EXCEPTION_ADDR		16
#define SGX_ENCLAVE_RUN_USER_HANDLER		24
#define SGX_ENCLAVE_RUN_USER_DATA		32	/* not used */
#define SGX_ENCLAVE_RUN_RESERVED_START		40
#define SGX_ENCLAVE_RUN_RESERVED_END		256

.code64
.section .text, "ax"

SYM_FUNC_START(__vdso_sgx_enter_enclave)
	/* Prolog */
	.cfi_startproc
	push	%rbp
	.cfi_adjust_cfa_offset	8
	.cfi_rel_offset		%rbp, 0
	mov	%rsp, %rbp
	.cfi_def_cfa_register	%rbp
	push	%rbx
	.cfi_rel_offset		%rbx, -8

	mov	%ecx, %eax
.Lenter_enclave:
	/* EENTER <= function <= ERESUME */
	cmp	$EENTER, %eax
	jb	.Linvalid_input
	cmp	$ERESUME, %eax
	ja	.Linvalid_input

	mov	SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rcx

	/* Validate that the reserved area contains only zeros. */
	mov	$SGX_ENCLAVE_RUN_RESERVED_START, %rbx
1:
	cmpq	$0, (%rcx, %rbx)
	jne	.Linvalid_input
	add	$8, %rbx
	cmpq	$SGX_ENCLAVE_RUN_RESERVED_END, %rbx
	jne	1b

	/* Load TCS and AEP */
	mov	SGX_ENCLAVE_RUN_TCS(%rcx), %rbx
	lea	.Lasync_exit_pointer(%rip), %rcx

	/* Single ENCLU serving as both EENTER and AEP (ERESUME) */
.Lasync_exit_pointer:
.Lenclu_eenter_eresume:
	enclu

	/* EEXIT jumps here unless the enclave is doing something fancy. */
	mov	SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rbx

	/* Set exit_reason. */
	movl	$EEXIT, SGX_ENCLAVE_RUN_LEAF(%rbx)

	/* Invoke userspace's exit handler if one was provided. */
.Lhandle_exit:
	cmpq	$0, SGX_ENCLAVE_RUN_USER_HANDLER(%rbx)
	jne	.Linvoke_userspace_handler

	/* Success, in the sense that ENCLU was attempted. */
	xor	%eax, %eax

.Lout:
	pop	%rbx
	leave
	.cfi_def_cfa		%rsp, 8
	RET

	/* The out-of-line code runs with the pre-leave stack frame. */
	.cfi_def_cfa		%rbp, 16

.Linvalid_input:
	mov	$(-EINVAL), %eax
	jmp	.Lout

.Lhandle_exception:
	mov	SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rbx

	/* Set the exception info. */
	mov	%eax, (SGX_ENCLAVE_RUN_LEAF)(%rbx)
	mov	%di,  (SGX_ENCLAVE_RUN_EXCEPTION_VECTOR)(%rbx)
	mov	%si,  (SGX_ENCLAVE_RUN_EXCEPTION_ERROR_CODE)(%rbx)
	mov	%rdx, (SGX_ENCLAVE_RUN_EXCEPTION_ADDR)(%rbx)
	jmp	.Lhandle_exit

.Linvoke_userspace_handler:
	/* Pass the untrusted RSP (at exit) to the callback via %rcx. */
	mov	%rsp, %rcx

	/* Save struct sgx_enclave_exception %rbx is about to be clobbered. */
	mov	%rbx, %rax

	/* Save the untrusted RSP offset in %rbx (non-volatile register). */
	mov	%rsp, %rbx
	and	$0xf, %rbx

	/*
	 * Align stack per x86_64 ABI. Note, %rsp needs to be 16-byte aligned
	 * _after_ pushing the parameters on the stack, hence the bonus push.
	 */
	and	$-0x10, %rsp
	push	%rax

	/* Push struct sgx_enclave_exception as a param to the callback. */
	push	%rax

	/* Clear RFLAGS.DF per x86_64 ABI */
	cld

	/*
	 * Load the callback pointer to %rax and lfence for LVI (load value
	 * injection) protection before making the call.
	 */
	mov	SGX_ENCLAVE_RUN_USER_HANDLER(%rax), %rax
	lfence
	call	*%rax

	/* Undo the post-exit %rsp adjustment. */
	lea	0x10(%rsp, %rbx), %rsp

	/*
	 * If the return from callback is zero or negative, return immediately,
	 * else re-execute ENCLU with the positive return value interpreted as
	 * the requested ENCLU function.
	 */
	cmp	$0, %eax
	jle	.Lout
	jmp	.Lenter_enclave

	.cfi_endproc

_ASM_VDSO_EXTABLE_HANDLE(.Lenclu_eenter_eresume, .Lhandle_exception)

SYM_FUNC_END(__vdso_sgx_enter_enclave)