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