xref: /linux/arch/x86/kernel/cpu/sgx/encls.h (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
12c273671SJarkko Sakkinen /* SPDX-License-Identifier: GPL-2.0 */
22c273671SJarkko Sakkinen #ifndef _X86_ENCLS_H
32c273671SJarkko Sakkinen #define _X86_ENCLS_H
42c273671SJarkko Sakkinen 
52c273671SJarkko Sakkinen #include <linux/bitops.h>
62c273671SJarkko Sakkinen #include <linux/err.h>
72c273671SJarkko Sakkinen #include <linux/io.h>
82c273671SJarkko Sakkinen #include <linux/rwsem.h>
92c273671SJarkko Sakkinen #include <linux/types.h>
102c273671SJarkko Sakkinen #include <asm/asm.h>
112c273671SJarkko Sakkinen #include <asm/traps.h>
122c273671SJarkko Sakkinen #include "sgx.h"
132c273671SJarkko Sakkinen 
142c273671SJarkko Sakkinen /* Retrieve the encoded trapnr from the specified return code. */
155ce8e39fSPeter Zijlstra #define ENCLS_TRAPNR(r) ((r) & ~SGX_ENCLS_FAULT_FLAG)
162c273671SJarkko Sakkinen 
172c273671SJarkko Sakkinen /* Issue a WARN() about an ENCLS function. */
182c273671SJarkko Sakkinen #define ENCLS_WARN(r, name) {						  \
192c273671SJarkko Sakkinen 	do {								  \
202c273671SJarkko Sakkinen 		int _r = (r);						  \
212c273671SJarkko Sakkinen 		WARN_ONCE(_r, "%s returned %d (0x%x)\n", (name), _r, _r); \
222c273671SJarkko Sakkinen 	} while (0);							  \
232c273671SJarkko Sakkinen }
242c273671SJarkko Sakkinen 
25a67136b4SSean Christopherson /*
26a67136b4SSean Christopherson  * encls_faulted() - Check if an ENCLS leaf faulted given an error code
27a67136b4SSean Christopherson  * @ret:	the return value of an ENCLS leaf function call
28a67136b4SSean Christopherson  *
29a67136b4SSean Christopherson  * Return:
30a67136b4SSean Christopherson  * - true:	ENCLS leaf faulted.
31a67136b4SSean Christopherson  * - false:	Otherwise.
32a67136b4SSean Christopherson  */
encls_faulted(int ret)33a67136b4SSean Christopherson static inline bool encls_faulted(int ret)
34a67136b4SSean Christopherson {
355ce8e39fSPeter Zijlstra 	return ret & SGX_ENCLS_FAULT_FLAG;
36a67136b4SSean Christopherson }
37a67136b4SSean Christopherson 
382c273671SJarkko Sakkinen /**
392c273671SJarkko Sakkinen  * encls_failed() - Check if an ENCLS function failed
402c273671SJarkko Sakkinen  * @ret:	the return value of an ENCLS function call
412c273671SJarkko Sakkinen  *
422c273671SJarkko Sakkinen  * Check if an ENCLS function failed. This happens when the function causes a
432c273671SJarkko Sakkinen  * fault that is not caused by an EPCM conflict or when the function returns a
442c273671SJarkko Sakkinen  * non-zero value.
452c273671SJarkko Sakkinen  */
encls_failed(int ret)462c273671SJarkko Sakkinen static inline bool encls_failed(int ret)
472c273671SJarkko Sakkinen {
48a67136b4SSean Christopherson 	if (encls_faulted(ret))
492c273671SJarkko Sakkinen 		return ENCLS_TRAPNR(ret) != X86_TRAP_PF;
502c273671SJarkko Sakkinen 
512c273671SJarkko Sakkinen 	return !!ret;
522c273671SJarkko Sakkinen }
532c273671SJarkko Sakkinen 
542c273671SJarkko Sakkinen /**
552c273671SJarkko Sakkinen  * __encls_ret_N - encode an ENCLS function that returns an error code in EAX
562c273671SJarkko Sakkinen  * @rax:	function number
572c273671SJarkko Sakkinen  * @inputs:	asm inputs for the function
582c273671SJarkko Sakkinen  *
592c273671SJarkko Sakkinen  * Emit assembly for an ENCLS function that returns an error code, e.g. EREMOVE.
602c273671SJarkko Sakkinen  * And because SGX isn't complex enough as it is, function that return an error
612c273671SJarkko Sakkinen  * code also modify flags.
622c273671SJarkko Sakkinen  *
632c273671SJarkko Sakkinen  * Return:
642c273671SJarkko Sakkinen  *	0 on success,
652c273671SJarkko Sakkinen  *	SGX error code on failure
662c273671SJarkko Sakkinen  */
672c273671SJarkko Sakkinen #define __encls_ret_N(rax, inputs...)				\
682c273671SJarkko Sakkinen 	({							\
692c273671SJarkko Sakkinen 	int ret;						\
702c273671SJarkko Sakkinen 	asm volatile(						\
712c273671SJarkko Sakkinen 	"1: .byte 0x0f, 0x01, 0xcf;\n\t"			\
722c273671SJarkko Sakkinen 	"2:\n"							\
735ce8e39fSPeter Zijlstra 	_ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FAULT_SGX)		\
742c273671SJarkko Sakkinen 	: "=a"(ret)						\
752c273671SJarkko Sakkinen 	: "a"(rax), inputs					\
762c273671SJarkko Sakkinen 	: "memory", "cc");					\
772c273671SJarkko Sakkinen 	ret;							\
782c273671SJarkko Sakkinen 	})
792c273671SJarkko Sakkinen 
802c273671SJarkko Sakkinen #define __encls_ret_1(rax, rcx)		\
812c273671SJarkko Sakkinen 	({				\
822c273671SJarkko Sakkinen 	__encls_ret_N(rax, "c"(rcx));	\
832c273671SJarkko Sakkinen 	})
842c273671SJarkko Sakkinen 
852c273671SJarkko Sakkinen #define __encls_ret_2(rax, rbx, rcx)		\
862c273671SJarkko Sakkinen 	({					\
872c273671SJarkko Sakkinen 	__encls_ret_N(rax, "b"(rbx), "c"(rcx));	\
882c273671SJarkko Sakkinen 	})
892c273671SJarkko Sakkinen 
902c273671SJarkko Sakkinen #define __encls_ret_3(rax, rbx, rcx, rdx)			\
912c273671SJarkko Sakkinen 	({							\
922c273671SJarkko Sakkinen 	__encls_ret_N(rax, "b"(rbx), "c"(rcx), "d"(rdx));	\
932c273671SJarkko Sakkinen 	})
942c273671SJarkko Sakkinen 
952c273671SJarkko Sakkinen /**
962c273671SJarkko Sakkinen  * __encls_N - encode an ENCLS function that doesn't return an error code
972c273671SJarkko Sakkinen  * @rax:	function number
982c273671SJarkko Sakkinen  * @rbx_out:	optional output variable
992c273671SJarkko Sakkinen  * @inputs:	asm inputs for the function
1002c273671SJarkko Sakkinen  *
1012c273671SJarkko Sakkinen  * Emit assembly for an ENCLS function that does not return an error code, e.g.
1022c273671SJarkko Sakkinen  * ECREATE.  Leaves without error codes either succeed or fault.  @rbx_out is an
1032c273671SJarkko Sakkinen  * optional parameter for use by EDGBRD, which returns the requested value in
1042c273671SJarkko Sakkinen  * RBX.
1052c273671SJarkko Sakkinen  *
1062c273671SJarkko Sakkinen  * Return:
1072c273671SJarkko Sakkinen  *   0 on success,
1085ce8e39fSPeter Zijlstra  *   trapnr with SGX_ENCLS_FAULT_FLAG set on fault
1092c273671SJarkko Sakkinen  */
1102c273671SJarkko Sakkinen #define __encls_N(rax, rbx_out, inputs...)			\
1112c273671SJarkko Sakkinen 	({							\
1122c273671SJarkko Sakkinen 	int ret;						\
1132c273671SJarkko Sakkinen 	asm volatile(						\
1142c273671SJarkko Sakkinen 	"1: .byte 0x0f, 0x01, 0xcf;\n\t"			\
1152c273671SJarkko Sakkinen 	"   xor %%eax,%%eax;\n"					\
1162c273671SJarkko Sakkinen 	"2:\n"							\
1175ce8e39fSPeter Zijlstra 	_ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FAULT_SGX)		\
1182c273671SJarkko Sakkinen 	: "=a"(ret), "=b"(rbx_out)				\
1192c273671SJarkko Sakkinen 	: "a"(rax), inputs					\
1202c273671SJarkko Sakkinen 	: "memory");						\
1212c273671SJarkko Sakkinen 	ret;							\
1222c273671SJarkko Sakkinen 	})
1232c273671SJarkko Sakkinen 
1242c273671SJarkko Sakkinen #define __encls_2(rax, rbx, rcx)				\
1252c273671SJarkko Sakkinen 	({							\
1262c273671SJarkko Sakkinen 	unsigned long ign_rbx_out;				\
1272c273671SJarkko Sakkinen 	__encls_N(rax, ign_rbx_out, "b"(rbx), "c"(rcx));	\
1282c273671SJarkko Sakkinen 	})
1292c273671SJarkko Sakkinen 
1302c273671SJarkko Sakkinen #define __encls_1_1(rax, data, rcx)			\
1312c273671SJarkko Sakkinen 	({						\
1322c273671SJarkko Sakkinen 	unsigned long rbx_out;				\
1332c273671SJarkko Sakkinen 	int ret = __encls_N(rax, rbx_out, "c"(rcx));	\
1342c273671SJarkko Sakkinen 	if (!ret)					\
1352c273671SJarkko Sakkinen 		data = rbx_out;				\
1362c273671SJarkko Sakkinen 	ret;						\
1372c273671SJarkko Sakkinen 	})
1382c273671SJarkko Sakkinen 
1394c3f7358SReinette Chatre /* Initialize an EPC page into an SGX Enclave Control Structure (SECS) page. */
__ecreate(struct sgx_pageinfo * pginfo,void * secs)1402c273671SJarkko Sakkinen static inline int __ecreate(struct sgx_pageinfo *pginfo, void *secs)
1412c273671SJarkko Sakkinen {
1422c273671SJarkko Sakkinen 	return __encls_2(ECREATE, pginfo, secs);
1432c273671SJarkko Sakkinen }
1442c273671SJarkko Sakkinen 
1454c3f7358SReinette Chatre /* Hash a 256 byte region of an enclave page to SECS:MRENCLAVE. */
__eextend(void * secs,void * addr)1462c273671SJarkko Sakkinen static inline int __eextend(void *secs, void *addr)
1472c273671SJarkko Sakkinen {
1482c273671SJarkko Sakkinen 	return __encls_2(EEXTEND, secs, addr);
1492c273671SJarkko Sakkinen }
1502c273671SJarkko Sakkinen 
1514c3f7358SReinette Chatre /*
1524c3f7358SReinette Chatre  * Associate an EPC page to an enclave either as a REG or TCS page
1534c3f7358SReinette Chatre  * populated with the provided data.
1544c3f7358SReinette Chatre  */
__eadd(struct sgx_pageinfo * pginfo,void * addr)1552c273671SJarkko Sakkinen static inline int __eadd(struct sgx_pageinfo *pginfo, void *addr)
1562c273671SJarkko Sakkinen {
1572c273671SJarkko Sakkinen 	return __encls_2(EADD, pginfo, addr);
1582c273671SJarkko Sakkinen }
1592c273671SJarkko Sakkinen 
1604c3f7358SReinette Chatre /* Finalize enclave build, initialize enclave for user code execution. */
__einit(void * sigstruct,void * token,void * secs)1612c273671SJarkko Sakkinen static inline int __einit(void *sigstruct, void *token, void *secs)
1622c273671SJarkko Sakkinen {
1632c273671SJarkko Sakkinen 	return __encls_ret_3(EINIT, sigstruct, secs, token);
1642c273671SJarkko Sakkinen }
1652c273671SJarkko Sakkinen 
1664c3f7358SReinette Chatre /* Disassociate EPC page from its enclave and mark it as unused. */
__eremove(void * addr)1672c273671SJarkko Sakkinen static inline int __eremove(void *addr)
1682c273671SJarkko Sakkinen {
1692c273671SJarkko Sakkinen 	return __encls_ret_1(EREMOVE, addr);
1702c273671SJarkko Sakkinen }
1712c273671SJarkko Sakkinen 
1724c3f7358SReinette Chatre /* Copy data to an EPC page belonging to a debug enclave. */
__edbgwr(void * addr,unsigned long * data)1732c273671SJarkko Sakkinen static inline int __edbgwr(void *addr, unsigned long *data)
1742c273671SJarkko Sakkinen {
1752c273671SJarkko Sakkinen 	return __encls_2(EDGBWR, *data, addr);
1762c273671SJarkko Sakkinen }
1772c273671SJarkko Sakkinen 
1784c3f7358SReinette Chatre /* Copy data from an EPC page belonging to a debug enclave. */
__edbgrd(void * addr,unsigned long * data)1792c273671SJarkko Sakkinen static inline int __edbgrd(void *addr, unsigned long *data)
1802c273671SJarkko Sakkinen {
1812c273671SJarkko Sakkinen 	return __encls_1_1(EDGBRD, *data, addr);
1822c273671SJarkko Sakkinen }
1832c273671SJarkko Sakkinen 
1844c3f7358SReinette Chatre /* Track that software has completed the required TLB address clears. */
__etrack(void * addr)1852c273671SJarkko Sakkinen static inline int __etrack(void *addr)
1862c273671SJarkko Sakkinen {
1872c273671SJarkko Sakkinen 	return __encls_ret_1(ETRACK, addr);
1882c273671SJarkko Sakkinen }
1892c273671SJarkko Sakkinen 
1904c3f7358SReinette Chatre /* Load, verify, and unblock an EPC page. */
__eldu(struct sgx_pageinfo * pginfo,void * addr,void * va)1912c273671SJarkko Sakkinen static inline int __eldu(struct sgx_pageinfo *pginfo, void *addr,
1922c273671SJarkko Sakkinen 			 void *va)
1932c273671SJarkko Sakkinen {
1942c273671SJarkko Sakkinen 	return __encls_ret_3(ELDU, pginfo, addr, va);
1952c273671SJarkko Sakkinen }
1962c273671SJarkko Sakkinen 
1974c3f7358SReinette Chatre /* Make EPC page inaccessible to enclave, ready to be written to memory. */
__eblock(void * addr)1982c273671SJarkko Sakkinen static inline int __eblock(void *addr)
1992c273671SJarkko Sakkinen {
2002c273671SJarkko Sakkinen 	return __encls_ret_1(EBLOCK, addr);
2012c273671SJarkko Sakkinen }
2022c273671SJarkko Sakkinen 
2034c3f7358SReinette Chatre /* Initialize an EPC page into a Version Array (VA) page. */
__epa(void * addr)2042c273671SJarkko Sakkinen static inline int __epa(void *addr)
2052c273671SJarkko Sakkinen {
2062c273671SJarkko Sakkinen 	unsigned long rbx = SGX_PAGE_TYPE_VA;
2072c273671SJarkko Sakkinen 
2082c273671SJarkko Sakkinen 	return __encls_2(EPA, rbx, addr);
2092c273671SJarkko Sakkinen }
2102c273671SJarkko Sakkinen 
2114c3f7358SReinette Chatre /* Invalidate an EPC page and write it out to main memory. */
__ewb(struct sgx_pageinfo * pginfo,void * addr,void * va)2122c273671SJarkko Sakkinen static inline int __ewb(struct sgx_pageinfo *pginfo, void *addr,
2132c273671SJarkko Sakkinen 			void *va)
2142c273671SJarkko Sakkinen {
2152c273671SJarkko Sakkinen 	return __encls_ret_3(EWB, pginfo, addr, va);
2162c273671SJarkko Sakkinen }
2172c273671SJarkko Sakkinen 
2180fb2126dSReinette Chatre /* Restrict the EPCM permissions of an EPC page. */
__emodpr(struct sgx_secinfo * secinfo,void * addr)2190fb2126dSReinette Chatre static inline int __emodpr(struct sgx_secinfo *secinfo, void *addr)
2200fb2126dSReinette Chatre {
2210fb2126dSReinette Chatre 	return __encls_ret_2(EMODPR, secinfo, addr);
2220fb2126dSReinette Chatre }
2230fb2126dSReinette Chatre 
22409b38d0bSReinette Chatre /* Change the type of an EPC page. */
__emodt(struct sgx_secinfo * secinfo,void * addr)22509b38d0bSReinette Chatre static inline int __emodt(struct sgx_secinfo *secinfo, void *addr)
22609b38d0bSReinette Chatre {
22709b38d0bSReinette Chatre 	return __encls_ret_2(EMODT, secinfo, addr);
22809b38d0bSReinette Chatre }
22909b38d0bSReinette Chatre 
230*61416b29SReinette Chatre /* Zero a page of EPC memory and add it to an initialized enclave. */
__eaug(struct sgx_pageinfo * pginfo,void * addr)231*61416b29SReinette Chatre static inline int __eaug(struct sgx_pageinfo *pginfo, void *addr)
232*61416b29SReinette Chatre {
233*61416b29SReinette Chatre 	return __encls_2(EAUG, pginfo, addr);
234*61416b29SReinette Chatre }
235*61416b29SReinette Chatre 
2362c273671SJarkko Sakkinen #endif /* _X86_ENCLS_H */
237