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