xref: /openbmc/linux/arch/x86/kernel/cpu/sgx/encls.h (revision c2a5a45c)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _X86_ENCLS_H
3 #define _X86_ENCLS_H
4 
5 #include <linux/bitops.h>
6 #include <linux/err.h>
7 #include <linux/io.h>
8 #include <linux/rwsem.h>
9 #include <linux/types.h>
10 #include <asm/asm.h>
11 #include <asm/traps.h>
12 #include "sgx.h"
13 
14 enum sgx_encls_function {
15 	ECREATE	= 0x00,
16 	EADD	= 0x01,
17 	EINIT	= 0x02,
18 	EREMOVE	= 0x03,
19 	EDGBRD	= 0x04,
20 	EDGBWR	= 0x05,
21 	EEXTEND	= 0x06,
22 	ELDU	= 0x08,
23 	EBLOCK	= 0x09,
24 	EPA	= 0x0A,
25 	EWB	= 0x0B,
26 	ETRACK	= 0x0C,
27 };
28 
29 /**
30  * ENCLS_FAULT_FLAG - flag signifying an ENCLS return code is a trapnr
31  *
32  * ENCLS has its own (positive value) error codes and also generates
33  * ENCLS specific #GP and #PF faults.  And the ENCLS values get munged
34  * with system error codes as everything percolates back up the stack.
35  * Unfortunately (for us), we need to precisely identify each unique
36  * error code, e.g. the action taken if EWB fails varies based on the
37  * type of fault and on the exact SGX error code, i.e. we can't simply
38  * convert all faults to -EFAULT.
39  *
40  * To make all three error types coexist, we set bit 30 to identify an
41  * ENCLS fault.  Bit 31 (technically bits N:31) is used to differentiate
42  * between positive (faults and SGX error codes) and negative (system
43  * error codes) values.
44  */
45 #define ENCLS_FAULT_FLAG 0x40000000
46 
47 /* Retrieve the encoded trapnr from the specified return code. */
48 #define ENCLS_TRAPNR(r) ((r) & ~ENCLS_FAULT_FLAG)
49 
50 /* Issue a WARN() about an ENCLS function. */
51 #define ENCLS_WARN(r, name) {						  \
52 	do {								  \
53 		int _r = (r);						  \
54 		WARN_ONCE(_r, "%s returned %d (0x%x)\n", (name), _r, _r); \
55 	} while (0);							  \
56 }
57 
58 /**
59  * encls_failed() - Check if an ENCLS function failed
60  * @ret:	the return value of an ENCLS function call
61  *
62  * Check if an ENCLS function failed. This happens when the function causes a
63  * fault that is not caused by an EPCM conflict or when the function returns a
64  * non-zero value.
65  */
66 static inline bool encls_failed(int ret)
67 {
68 	if (ret & ENCLS_FAULT_FLAG)
69 		return ENCLS_TRAPNR(ret) != X86_TRAP_PF;
70 
71 	return !!ret;
72 }
73 
74 /**
75  * __encls_ret_N - encode an ENCLS function that returns an error code in EAX
76  * @rax:	function number
77  * @inputs:	asm inputs for the function
78  *
79  * Emit assembly for an ENCLS function that returns an error code, e.g. EREMOVE.
80  * And because SGX isn't complex enough as it is, function that return an error
81  * code also modify flags.
82  *
83  * Return:
84  *	0 on success,
85  *	SGX error code on failure
86  */
87 #define __encls_ret_N(rax, inputs...)				\
88 	({							\
89 	int ret;						\
90 	asm volatile(						\
91 	"1: .byte 0x0f, 0x01, 0xcf;\n\t"			\
92 	"2:\n"							\
93 	".section .fixup,\"ax\"\n"				\
94 	"3: orl $"__stringify(ENCLS_FAULT_FLAG)",%%eax\n"	\
95 	"   jmp 2b\n"						\
96 	".previous\n"						\
97 	_ASM_EXTABLE_FAULT(1b, 3b)				\
98 	: "=a"(ret)						\
99 	: "a"(rax), inputs					\
100 	: "memory", "cc");					\
101 	ret;							\
102 	})
103 
104 #define __encls_ret_1(rax, rcx)		\
105 	({				\
106 	__encls_ret_N(rax, "c"(rcx));	\
107 	})
108 
109 #define __encls_ret_2(rax, rbx, rcx)		\
110 	({					\
111 	__encls_ret_N(rax, "b"(rbx), "c"(rcx));	\
112 	})
113 
114 #define __encls_ret_3(rax, rbx, rcx, rdx)			\
115 	({							\
116 	__encls_ret_N(rax, "b"(rbx), "c"(rcx), "d"(rdx));	\
117 	})
118 
119 /**
120  * __encls_N - encode an ENCLS function that doesn't return an error code
121  * @rax:	function number
122  * @rbx_out:	optional output variable
123  * @inputs:	asm inputs for the function
124  *
125  * Emit assembly for an ENCLS function that does not return an error code, e.g.
126  * ECREATE.  Leaves without error codes either succeed or fault.  @rbx_out is an
127  * optional parameter for use by EDGBRD, which returns the requested value in
128  * RBX.
129  *
130  * Return:
131  *   0 on success,
132  *   trapnr with ENCLS_FAULT_FLAG set on fault
133  */
134 #define __encls_N(rax, rbx_out, inputs...)			\
135 	({							\
136 	int ret;						\
137 	asm volatile(						\
138 	"1: .byte 0x0f, 0x01, 0xcf;\n\t"			\
139 	"   xor %%eax,%%eax;\n"					\
140 	"2:\n"							\
141 	".section .fixup,\"ax\"\n"				\
142 	"3: orl $"__stringify(ENCLS_FAULT_FLAG)",%%eax\n"	\
143 	"   jmp 2b\n"						\
144 	".previous\n"						\
145 	_ASM_EXTABLE_FAULT(1b, 3b)				\
146 	: "=a"(ret), "=b"(rbx_out)				\
147 	: "a"(rax), inputs					\
148 	: "memory");						\
149 	ret;							\
150 	})
151 
152 #define __encls_2(rax, rbx, rcx)				\
153 	({							\
154 	unsigned long ign_rbx_out;				\
155 	__encls_N(rax, ign_rbx_out, "b"(rbx), "c"(rcx));	\
156 	})
157 
158 #define __encls_1_1(rax, data, rcx)			\
159 	({						\
160 	unsigned long rbx_out;				\
161 	int ret = __encls_N(rax, rbx_out, "c"(rcx));	\
162 	if (!ret)					\
163 		data = rbx_out;				\
164 	ret;						\
165 	})
166 
167 static inline int __ecreate(struct sgx_pageinfo *pginfo, void *secs)
168 {
169 	return __encls_2(ECREATE, pginfo, secs);
170 }
171 
172 static inline int __eextend(void *secs, void *addr)
173 {
174 	return __encls_2(EEXTEND, secs, addr);
175 }
176 
177 static inline int __eadd(struct sgx_pageinfo *pginfo, void *addr)
178 {
179 	return __encls_2(EADD, pginfo, addr);
180 }
181 
182 static inline int __einit(void *sigstruct, void *token, void *secs)
183 {
184 	return __encls_ret_3(EINIT, sigstruct, secs, token);
185 }
186 
187 static inline int __eremove(void *addr)
188 {
189 	return __encls_ret_1(EREMOVE, addr);
190 }
191 
192 static inline int __edbgwr(void *addr, unsigned long *data)
193 {
194 	return __encls_2(EDGBWR, *data, addr);
195 }
196 
197 static inline int __edbgrd(void *addr, unsigned long *data)
198 {
199 	return __encls_1_1(EDGBRD, *data, addr);
200 }
201 
202 static inline int __etrack(void *addr)
203 {
204 	return __encls_ret_1(ETRACK, addr);
205 }
206 
207 static inline int __eldu(struct sgx_pageinfo *pginfo, void *addr,
208 			 void *va)
209 {
210 	return __encls_ret_3(ELDU, pginfo, addr, va);
211 }
212 
213 static inline int __eblock(void *addr)
214 {
215 	return __encls_ret_1(EBLOCK, addr);
216 }
217 
218 static inline int __epa(void *addr)
219 {
220 	unsigned long rbx = SGX_PAGE_TYPE_VA;
221 
222 	return __encls_2(EPA, rbx, addr);
223 }
224 
225 static inline int __ewb(struct sgx_pageinfo *pginfo, void *addr,
226 			void *va)
227 {
228 	return __encls_ret_3(EWB, pginfo, addr, va);
229 }
230 
231 #endif /* _X86_ENCLS_H */
232