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