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 /* Retrieve the encoded trapnr from the specified return code. */ 15 #define ENCLS_TRAPNR(r) ((r) & ~SGX_ENCLS_FAULT_FLAG) 16 17 /* Issue a WARN() about an ENCLS function. */ 18 #define ENCLS_WARN(r, name) { \ 19 do { \ 20 int _r = (r); \ 21 WARN_ONCE(_r, "%s returned %d (0x%x)\n", (name), _r, _r); \ 22 } while (0); \ 23 } 24 25 /* 26 * encls_faulted() - Check if an ENCLS leaf faulted given an error code 27 * @ret: the return value of an ENCLS leaf function call 28 * 29 * Return: 30 * - true: ENCLS leaf faulted. 31 * - false: Otherwise. 32 */ 33 static inline bool encls_faulted(int ret) 34 { 35 return ret & SGX_ENCLS_FAULT_FLAG; 36 } 37 38 /** 39 * encls_failed() - Check if an ENCLS function failed 40 * @ret: the return value of an ENCLS function call 41 * 42 * Check if an ENCLS function failed. This happens when the function causes a 43 * fault that is not caused by an EPCM conflict or when the function returns a 44 * non-zero value. 45 */ 46 static inline bool encls_failed(int ret) 47 { 48 if (encls_faulted(ret)) 49 return ENCLS_TRAPNR(ret) != X86_TRAP_PF; 50 51 return !!ret; 52 } 53 54 /** 55 * __encls_ret_N - encode an ENCLS function that returns an error code in EAX 56 * @rax: function number 57 * @inputs: asm inputs for the function 58 * 59 * Emit assembly for an ENCLS function that returns an error code, e.g. EREMOVE. 60 * And because SGX isn't complex enough as it is, function that return an error 61 * code also modify flags. 62 * 63 * Return: 64 * 0 on success, 65 * SGX error code on failure 66 */ 67 #define __encls_ret_N(rax, inputs...) \ 68 ({ \ 69 int ret; \ 70 asm volatile( \ 71 "1: .byte 0x0f, 0x01, 0xcf;\n\t" \ 72 "2:\n" \ 73 _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FAULT_SGX) \ 74 : "=a"(ret) \ 75 : "a"(rax), inputs \ 76 : "memory", "cc"); \ 77 ret; \ 78 }) 79 80 #define __encls_ret_1(rax, rcx) \ 81 ({ \ 82 __encls_ret_N(rax, "c"(rcx)); \ 83 }) 84 85 #define __encls_ret_2(rax, rbx, rcx) \ 86 ({ \ 87 __encls_ret_N(rax, "b"(rbx), "c"(rcx)); \ 88 }) 89 90 #define __encls_ret_3(rax, rbx, rcx, rdx) \ 91 ({ \ 92 __encls_ret_N(rax, "b"(rbx), "c"(rcx), "d"(rdx)); \ 93 }) 94 95 /** 96 * __encls_N - encode an ENCLS function that doesn't return an error code 97 * @rax: function number 98 * @rbx_out: optional output variable 99 * @inputs: asm inputs for the function 100 * 101 * Emit assembly for an ENCLS function that does not return an error code, e.g. 102 * ECREATE. Leaves without error codes either succeed or fault. @rbx_out is an 103 * optional parameter for use by EDGBRD, which returns the requested value in 104 * RBX. 105 * 106 * Return: 107 * 0 on success, 108 * trapnr with SGX_ENCLS_FAULT_FLAG set on fault 109 */ 110 #define __encls_N(rax, rbx_out, inputs...) \ 111 ({ \ 112 int ret; \ 113 asm volatile( \ 114 "1: .byte 0x0f, 0x01, 0xcf;\n\t" \ 115 " xor %%eax,%%eax;\n" \ 116 "2:\n" \ 117 _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FAULT_SGX) \ 118 : "=a"(ret), "=b"(rbx_out) \ 119 : "a"(rax), inputs \ 120 : "memory"); \ 121 ret; \ 122 }) 123 124 #define __encls_2(rax, rbx, rcx) \ 125 ({ \ 126 unsigned long ign_rbx_out; \ 127 __encls_N(rax, ign_rbx_out, "b"(rbx), "c"(rcx)); \ 128 }) 129 130 #define __encls_1_1(rax, data, rcx) \ 131 ({ \ 132 unsigned long rbx_out; \ 133 int ret = __encls_N(rax, rbx_out, "c"(rcx)); \ 134 if (!ret) \ 135 data = rbx_out; \ 136 ret; \ 137 }) 138 139 /* Initialize an EPC page into an SGX Enclave Control Structure (SECS) page. */ 140 static inline int __ecreate(struct sgx_pageinfo *pginfo, void *secs) 141 { 142 return __encls_2(ECREATE, pginfo, secs); 143 } 144 145 /* Hash a 256 byte region of an enclave page to SECS:MRENCLAVE. */ 146 static inline int __eextend(void *secs, void *addr) 147 { 148 return __encls_2(EEXTEND, secs, addr); 149 } 150 151 /* 152 * Associate an EPC page to an enclave either as a REG or TCS page 153 * populated with the provided data. 154 */ 155 static inline int __eadd(struct sgx_pageinfo *pginfo, void *addr) 156 { 157 return __encls_2(EADD, pginfo, addr); 158 } 159 160 /* Finalize enclave build, initialize enclave for user code execution. */ 161 static inline int __einit(void *sigstruct, void *token, void *secs) 162 { 163 return __encls_ret_3(EINIT, sigstruct, secs, token); 164 } 165 166 /* Disassociate EPC page from its enclave and mark it as unused. */ 167 static inline int __eremove(void *addr) 168 { 169 return __encls_ret_1(EREMOVE, addr); 170 } 171 172 /* Copy data to an EPC page belonging to a debug enclave. */ 173 static inline int __edbgwr(void *addr, unsigned long *data) 174 { 175 return __encls_2(EDGBWR, *data, addr); 176 } 177 178 /* Copy data from an EPC page belonging to a debug enclave. */ 179 static inline int __edbgrd(void *addr, unsigned long *data) 180 { 181 return __encls_1_1(EDGBRD, *data, addr); 182 } 183 184 /* Track that software has completed the required TLB address clears. */ 185 static inline int __etrack(void *addr) 186 { 187 return __encls_ret_1(ETRACK, addr); 188 } 189 190 /* Load, verify, and unblock an EPC page. */ 191 static inline int __eldu(struct sgx_pageinfo *pginfo, void *addr, 192 void *va) 193 { 194 return __encls_ret_3(ELDU, pginfo, addr, va); 195 } 196 197 /* Make EPC page inaccessible to enclave, ready to be written to memory. */ 198 static inline int __eblock(void *addr) 199 { 200 return __encls_ret_1(EBLOCK, addr); 201 } 202 203 /* Initialize an EPC page into a Version Array (VA) page. */ 204 static inline int __epa(void *addr) 205 { 206 unsigned long rbx = SGX_PAGE_TYPE_VA; 207 208 return __encls_2(EPA, rbx, addr); 209 } 210 211 /* Invalidate an EPC page and write it out to main memory. */ 212 static inline int __ewb(struct sgx_pageinfo *pginfo, void *addr, 213 void *va) 214 { 215 return __encls_ret_3(EWB, pginfo, addr, va); 216 } 217 218 /* Restrict the EPCM permissions of an EPC page. */ 219 static inline int __emodpr(struct sgx_secinfo *secinfo, void *addr) 220 { 221 return __encls_ret_2(EMODPR, secinfo, addr); 222 } 223 224 /* Change the type of an EPC page. */ 225 static inline int __emodt(struct sgx_secinfo *secinfo, void *addr) 226 { 227 return __encls_ret_2(EMODT, secinfo, addr); 228 } 229 230 /* Zero a page of EPC memory and add it to an initialized enclave. */ 231 static inline int __eaug(struct sgx_pageinfo *pginfo, void *addr) 232 { 233 return __encls_2(EAUG, pginfo, addr); 234 } 235 236 #endif /* _X86_ENCLS_H */ 237