/* SPDX-License-Identifier: GPL-2.0 */1#ifndef _X86_ENCLS_H2#define _X86_ENCLS_H34#include <linux/bitops.h>5#include <linux/err.h>6#include <linux/io.h>7#include <linux/rwsem.h>8#include <linux/types.h>9#include <asm/asm.h>10#include <asm/traps.h>11#include "sgx.h"1213/* Retrieve the encoded trapnr from the specified return code. */14#define ENCLS_TRAPNR(r) ((r) & ~SGX_ENCLS_FAULT_FLAG)1516/* Issue a WARN() about an ENCLS function. */17#define ENCLS_WARN(r, name) { \18do { \19int _r = (r); \20WARN_ONCE(_r, "%s returned %d (0x%x)\n", (name), _r, _r); \21} while (0); \22}2324/*25* encls_faulted() - Check if an ENCLS leaf faulted given an error code26* @ret: the return value of an ENCLS leaf function call27*28* Return:29* - true: ENCLS leaf faulted.30* - false: Otherwise.31*/32static inline bool encls_faulted(int ret)33{34return ret & SGX_ENCLS_FAULT_FLAG;35}3637/**38* encls_failed() - Check if an ENCLS function failed39* @ret: the return value of an ENCLS function call40*41* Check if an ENCLS function failed. This happens when the function causes a42* fault that is not caused by an EPCM conflict or when the function returns a43* non-zero value.44*/45static inline bool encls_failed(int ret)46{47if (encls_faulted(ret))48return ENCLS_TRAPNR(ret) != X86_TRAP_PF;4950return !!ret;51}5253/**54* __encls_ret_N - encode an ENCLS function that returns an error code in EAX55* @rax: function number56* @inputs: asm inputs for the function57*58* Emit assembly for an ENCLS function that returns an error code, e.g. EREMOVE.59* And because SGX isn't complex enough as it is, function that return an error60* code also modify flags.61*62* Return:63* 0 on success,64* SGX error code on failure65*/66#define __encls_ret_N(rax, inputs...) \67({ \68int ret; \69asm volatile( \70"1: .byte 0x0f, 0x01, 0xcf;\n\t" \71"2:\n" \72_ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FAULT_SGX) \73: "=a"(ret) \74: "a"(rax), inputs \75: "memory", "cc"); \76ret; \77})7879#define __encls_ret_1(rax, rcx) \80({ \81__encls_ret_N(rax, "c"(rcx)); \82})8384#define __encls_ret_2(rax, rbx, rcx) \85({ \86__encls_ret_N(rax, "b"(rbx), "c"(rcx)); \87})8889#define __encls_ret_3(rax, rbx, rcx, rdx) \90({ \91__encls_ret_N(rax, "b"(rbx), "c"(rcx), "d"(rdx)); \92})9394/**95* __encls_N - encode an ENCLS function that doesn't return an error code96* @rax: function number97* @rbx_out: optional output variable98* @inputs: asm inputs for the function99*100* Emit assembly for an ENCLS function that does not return an error code, e.g.101* ECREATE. Leaves without error codes either succeed or fault. @rbx_out is an102* optional parameter for use by EDGBRD, which returns the requested value in103* RBX.104*105* Return:106* 0 on success,107* trapnr with SGX_ENCLS_FAULT_FLAG set on fault108*/109#define __encls_N(rax, rbx_out, inputs...) \110({ \111int ret; \112asm volatile( \113"1: .byte 0x0f, 0x01, 0xcf;\n\t" \114" xor %%eax,%%eax;\n" \115"2:\n" \116_ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FAULT_SGX) \117: "=a"(ret), "=b"(rbx_out) \118: "a"(rax), inputs \119: "memory"); \120ret; \121})122123#define __encls_2(rax, rbx, rcx) \124({ \125unsigned long ign_rbx_out; \126__encls_N(rax, ign_rbx_out, "b"(rbx), "c"(rcx)); \127})128129#define __encls_1_1(rax, data, rcx) \130({ \131unsigned long rbx_out; \132int ret = __encls_N(rax, rbx_out, "c"(rcx)); \133if (!ret) \134data = rbx_out; \135ret; \136})137138/* Initialize an EPC page into an SGX Enclave Control Structure (SECS) page. */139static inline int __ecreate(struct sgx_pageinfo *pginfo, void *secs)140{141return __encls_2(ECREATE, pginfo, secs);142}143144/* Hash a 256 byte region of an enclave page to SECS:MRENCLAVE. */145static inline int __eextend(void *secs, void *addr)146{147return __encls_2(EEXTEND, secs, addr);148}149150/*151* Associate an EPC page to an enclave either as a REG or TCS page152* populated with the provided data.153*/154static inline int __eadd(struct sgx_pageinfo *pginfo, void *addr)155{156return __encls_2(EADD, pginfo, addr);157}158159/* Finalize enclave build, initialize enclave for user code execution. */160static inline int __einit(void *sigstruct, void *token, void *secs)161{162return __encls_ret_3(EINIT, sigstruct, secs, token);163}164165/* Disassociate EPC page from its enclave and mark it as unused. */166static inline int __eremove(void *addr)167{168return __encls_ret_1(EREMOVE, addr);169}170171/* Copy data to an EPC page belonging to a debug enclave. */172static inline int __edbgwr(void *addr, unsigned long *data)173{174return __encls_2(EDGBWR, *data, addr);175}176177/* Copy data from an EPC page belonging to a debug enclave. */178static inline int __edbgrd(void *addr, unsigned long *data)179{180return __encls_1_1(EDGBRD, *data, addr);181}182183/* Track that software has completed the required TLB address clears. */184static inline int __etrack(void *addr)185{186return __encls_ret_1(ETRACK, addr);187}188189/* Load, verify, and unblock an EPC page. */190static inline int __eldu(struct sgx_pageinfo *pginfo, void *addr,191void *va)192{193return __encls_ret_3(ELDU, pginfo, addr, va);194}195196/* Make EPC page inaccessible to enclave, ready to be written to memory. */197static inline int __eblock(void *addr)198{199return __encls_ret_1(EBLOCK, addr);200}201202/* Initialize an EPC page into a Version Array (VA) page. */203static inline int __epa(void *addr)204{205unsigned long rbx = SGX_PAGE_TYPE_VA;206207return __encls_2(EPA, rbx, addr);208}209210/* Invalidate an EPC page and write it out to main memory. */211static inline int __ewb(struct sgx_pageinfo *pginfo, void *addr,212void *va)213{214return __encls_ret_3(EWB, pginfo, addr, va);215}216217/* Restrict the EPCM permissions of an EPC page. */218static inline int __emodpr(struct sgx_secinfo *secinfo, void *addr)219{220return __encls_ret_2(EMODPR, secinfo, addr);221}222223/* Change the type of an EPC page. */224static inline int __emodt(struct sgx_secinfo *secinfo, void *addr)225{226return __encls_ret_2(EMODT, secinfo, addr);227}228229/* Zero a page of EPC memory and add it to an initialized enclave. */230static inline int __eaug(struct sgx_pageinfo *pginfo, void *addr)231{232return __encls_2(EAUG, pginfo, addr);233}234235#endif /* _X86_ENCLS_H */236237238