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 */
encls_faulted(int ret)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 */
encls_failed(int ret)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
__ecreate(struct sgx_pageinfo * pginfo,void * secs)165 static inline int __ecreate(struct sgx_pageinfo *pginfo, void *secs)
166 {
167 return __encls_2(ECREATE, pginfo, secs);
168 }
169
__eextend(void * secs,void * addr)170 static inline int __eextend(void *secs, void *addr)
171 {
172 return __encls_2(EEXTEND, secs, addr);
173 }
174
__eadd(struct sgx_pageinfo * pginfo,void * addr)175 static inline int __eadd(struct sgx_pageinfo *pginfo, void *addr)
176 {
177 return __encls_2(EADD, pginfo, addr);
178 }
179
__einit(void * sigstruct,void * token,void * secs)180 static inline int __einit(void *sigstruct, void *token, void *secs)
181 {
182 return __encls_ret_3(EINIT, sigstruct, secs, token);
183 }
184
__eremove(void * addr)185 static inline int __eremove(void *addr)
186 {
187 return __encls_ret_1(EREMOVE, addr);
188 }
189
__edbgwr(void * addr,unsigned long * data)190 static inline int __edbgwr(void *addr, unsigned long *data)
191 {
192 return __encls_2(EDGBWR, *data, addr);
193 }
194
__edbgrd(void * addr,unsigned long * data)195 static inline int __edbgrd(void *addr, unsigned long *data)
196 {
197 return __encls_1_1(EDGBRD, *data, addr);
198 }
199
__etrack(void * addr)200 static inline int __etrack(void *addr)
201 {
202 return __encls_ret_1(ETRACK, addr);
203 }
204
__eldu(struct sgx_pageinfo * pginfo,void * addr,void * va)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
__eblock(void * addr)211 static inline int __eblock(void *addr)
212 {
213 return __encls_ret_1(EBLOCK, addr);
214 }
215
__epa(void * addr)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
__ewb(struct sgx_pageinfo * pginfo,void * addr,void * va)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