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 */ 33static 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 */ 46static 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. */ 140static 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. */ 146static 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 */ 155static 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. */ 161static 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. */ 167static 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. */ 173static 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. */ 179static 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. */ 185static inline int __etrack(void *addr) 186{ 187 return __encls_ret_1(ETRACK, addr); 188} 189 190/* Load, verify, and unblock an EPC page. */ 191static 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. */ 198static 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. */ 204static 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. */ 212static 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. */ 219static 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. */ 225static 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. */ 231static 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