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 static inline int __ecreate(struct sgx_pageinfo *pginfo, void *secs) 140 { 141 return __encls_2(ECREATE, pginfo, secs); 142 } 143 144 static inline int __eextend(void *secs, void *addr) 145 { 146 return __encls_2(EEXTEND, secs, addr); 147 } 148 149 static inline int __eadd(struct sgx_pageinfo *pginfo, void *addr) 150 { 151 return __encls_2(EADD, pginfo, addr); 152 } 153 154 static inline int __einit(void *sigstruct, void *token, void *secs) 155 { 156 return __encls_ret_3(EINIT, sigstruct, secs, token); 157 } 158 159 static inline int __eremove(void *addr) 160 { 161 return __encls_ret_1(EREMOVE, addr); 162 } 163 164 static inline int __edbgwr(void *addr, unsigned long *data) 165 { 166 return __encls_2(EDGBWR, *data, addr); 167 } 168 169 static inline int __edbgrd(void *addr, unsigned long *data) 170 { 171 return __encls_1_1(EDGBRD, *data, addr); 172 } 173 174 static inline int __etrack(void *addr) 175 { 176 return __encls_ret_1(ETRACK, addr); 177 } 178 179 static inline int __eldu(struct sgx_pageinfo *pginfo, void *addr, 180 void *va) 181 { 182 return __encls_ret_3(ELDU, pginfo, addr, va); 183 } 184 185 static inline int __eblock(void *addr) 186 { 187 return __encls_ret_1(EBLOCK, addr); 188 } 189 190 static inline int __epa(void *addr) 191 { 192 unsigned long rbx = SGX_PAGE_TYPE_VA; 193 194 return __encls_2(EPA, rbx, addr); 195 } 196 197 static inline int __ewb(struct sgx_pageinfo *pginfo, void *addr, 198 void *va) 199 { 200 return __encls_ret_3(EWB, pginfo, addr, va); 201 } 202 203 #endif /* _X86_ENCLS_H */ 204