Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _X86_ENCLS_H
0003 #define _X86_ENCLS_H
0004 
0005 #include <linux/bitops.h>
0006 #include <linux/err.h>
0007 #include <linux/io.h>
0008 #include <linux/rwsem.h>
0009 #include <linux/types.h>
0010 #include <asm/asm.h>
0011 #include <asm/traps.h>
0012 #include "sgx.h"
0013 
0014 /* Retrieve the encoded trapnr from the specified return code. */
0015 #define ENCLS_TRAPNR(r) ((r) & ~SGX_ENCLS_FAULT_FLAG)
0016 
0017 /* Issue a WARN() about an ENCLS function. */
0018 #define ENCLS_WARN(r, name) {                         \
0019     do {                                  \
0020         int _r = (r);                         \
0021         WARN_ONCE(_r, "%s returned %d (0x%x)\n", (name), _r, _r); \
0022     } while (0);                              \
0023 }
0024 
0025 /*
0026  * encls_faulted() - Check if an ENCLS leaf faulted given an error code
0027  * @ret:    the return value of an ENCLS leaf function call
0028  *
0029  * Return:
0030  * - true:  ENCLS leaf faulted.
0031  * - false: Otherwise.
0032  */
0033 static inline bool encls_faulted(int ret)
0034 {
0035     return ret & SGX_ENCLS_FAULT_FLAG;
0036 }
0037 
0038 /**
0039  * encls_failed() - Check if an ENCLS function failed
0040  * @ret:    the return value of an ENCLS function call
0041  *
0042  * Check if an ENCLS function failed. This happens when the function causes a
0043  * fault that is not caused by an EPCM conflict or when the function returns a
0044  * non-zero value.
0045  */
0046 static inline bool encls_failed(int ret)
0047 {
0048     if (encls_faulted(ret))
0049         return ENCLS_TRAPNR(ret) != X86_TRAP_PF;
0050 
0051     return !!ret;
0052 }
0053 
0054 /**
0055  * __encls_ret_N - encode an ENCLS function that returns an error code in EAX
0056  * @rax:    function number
0057  * @inputs: asm inputs for the function
0058  *
0059  * Emit assembly for an ENCLS function that returns an error code, e.g. EREMOVE.
0060  * And because SGX isn't complex enough as it is, function that return an error
0061  * code also modify flags.
0062  *
0063  * Return:
0064  *  0 on success,
0065  *  SGX error code on failure
0066  */
0067 #define __encls_ret_N(rax, inputs...)               \
0068     ({                          \
0069     int ret;                        \
0070     asm volatile(                       \
0071     "1: .byte 0x0f, 0x01, 0xcf;\n\t"            \
0072     "2:\n"                          \
0073     _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FAULT_SGX)        \
0074     : "=a"(ret)                     \
0075     : "a"(rax), inputs                  \
0076     : "memory", "cc");                  \
0077     ret;                            \
0078     })
0079 
0080 #define __encls_ret_1(rax, rcx)     \
0081     ({              \
0082     __encls_ret_N(rax, "c"(rcx));   \
0083     })
0084 
0085 #define __encls_ret_2(rax, rbx, rcx)        \
0086     ({                  \
0087     __encls_ret_N(rax, "b"(rbx), "c"(rcx)); \
0088     })
0089 
0090 #define __encls_ret_3(rax, rbx, rcx, rdx)           \
0091     ({                          \
0092     __encls_ret_N(rax, "b"(rbx), "c"(rcx), "d"(rdx));   \
0093     })
0094 
0095 /**
0096  * __encls_N - encode an ENCLS function that doesn't return an error code
0097  * @rax:    function number
0098  * @rbx_out:    optional output variable
0099  * @inputs: asm inputs for the function
0100  *
0101  * Emit assembly for an ENCLS function that does not return an error code, e.g.
0102  * ECREATE.  Leaves without error codes either succeed or fault.  @rbx_out is an
0103  * optional parameter for use by EDGBRD, which returns the requested value in
0104  * RBX.
0105  *
0106  * Return:
0107  *   0 on success,
0108  *   trapnr with SGX_ENCLS_FAULT_FLAG set on fault
0109  */
0110 #define __encls_N(rax, rbx_out, inputs...)          \
0111     ({                          \
0112     int ret;                        \
0113     asm volatile(                       \
0114     "1: .byte 0x0f, 0x01, 0xcf;\n\t"            \
0115     "   xor %%eax,%%eax;\n"                 \
0116     "2:\n"                          \
0117     _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FAULT_SGX)        \
0118     : "=a"(ret), "=b"(rbx_out)              \
0119     : "a"(rax), inputs                  \
0120     : "memory");                        \
0121     ret;                            \
0122     })
0123 
0124 #define __encls_2(rax, rbx, rcx)                \
0125     ({                          \
0126     unsigned long ign_rbx_out;              \
0127     __encls_N(rax, ign_rbx_out, "b"(rbx), "c"(rcx));    \
0128     })
0129 
0130 #define __encls_1_1(rax, data, rcx)         \
0131     ({                      \
0132     unsigned long rbx_out;              \
0133     int ret = __encls_N(rax, rbx_out, "c"(rcx));    \
0134     if (!ret)                   \
0135         data = rbx_out;             \
0136     ret;                        \
0137     })
0138 
0139 /* Initialize an EPC page into an SGX Enclave Control Structure (SECS) page. */
0140 static inline int __ecreate(struct sgx_pageinfo *pginfo, void *secs)
0141 {
0142     return __encls_2(ECREATE, pginfo, secs);
0143 }
0144 
0145 /* Hash a 256 byte region of an enclave page to SECS:MRENCLAVE. */
0146 static inline int __eextend(void *secs, void *addr)
0147 {
0148     return __encls_2(EEXTEND, secs, addr);
0149 }
0150 
0151 /*
0152  * Associate an EPC page to an enclave either as a REG or TCS page
0153  * populated with the provided data.
0154  */
0155 static inline int __eadd(struct sgx_pageinfo *pginfo, void *addr)
0156 {
0157     return __encls_2(EADD, pginfo, addr);
0158 }
0159 
0160 /* Finalize enclave build, initialize enclave for user code execution. */
0161 static inline int __einit(void *sigstruct, void *token, void *secs)
0162 {
0163     return __encls_ret_3(EINIT, sigstruct, secs, token);
0164 }
0165 
0166 /* Disassociate EPC page from its enclave and mark it as unused. */
0167 static inline int __eremove(void *addr)
0168 {
0169     return __encls_ret_1(EREMOVE, addr);
0170 }
0171 
0172 /* Copy data to an EPC page belonging to a debug enclave. */
0173 static inline int __edbgwr(void *addr, unsigned long *data)
0174 {
0175     return __encls_2(EDGBWR, *data, addr);
0176 }
0177 
0178 /* Copy data from an EPC page belonging to a debug enclave. */
0179 static inline int __edbgrd(void *addr, unsigned long *data)
0180 {
0181     return __encls_1_1(EDGBRD, *data, addr);
0182 }
0183 
0184 /* Track that software has completed the required TLB address clears. */
0185 static inline int __etrack(void *addr)
0186 {
0187     return __encls_ret_1(ETRACK, addr);
0188 }
0189 
0190 /* Load, verify, and unblock an EPC page. */
0191 static inline int __eldu(struct sgx_pageinfo *pginfo, void *addr,
0192              void *va)
0193 {
0194     return __encls_ret_3(ELDU, pginfo, addr, va);
0195 }
0196 
0197 /* Make EPC page inaccessible to enclave, ready to be written to memory. */
0198 static inline int __eblock(void *addr)
0199 {
0200     return __encls_ret_1(EBLOCK, addr);
0201 }
0202 
0203 /* Initialize an EPC page into a Version Array (VA) page. */
0204 static inline int __epa(void *addr)
0205 {
0206     unsigned long rbx = SGX_PAGE_TYPE_VA;
0207 
0208     return __encls_2(EPA, rbx, addr);
0209 }
0210 
0211 /* Invalidate an EPC page and write it out to main memory. */
0212 static inline int __ewb(struct sgx_pageinfo *pginfo, void *addr,
0213             void *va)
0214 {
0215     return __encls_ret_3(EWB, pginfo, addr, va);
0216 }
0217 
0218 /* Restrict the EPCM permissions of an EPC page. */
0219 static inline int __emodpr(struct sgx_secinfo *secinfo, void *addr)
0220 {
0221     return __encls_ret_2(EMODPR, secinfo, addr);
0222 }
0223 
0224 /* Change the type of an EPC page. */
0225 static inline int __emodt(struct sgx_secinfo *secinfo, void *addr)
0226 {
0227     return __encls_ret_2(EMODT, secinfo, addr);
0228 }
0229 
0230 /* Zero a page of EPC memory and add it to an initialized enclave. */
0231 static inline int __eaug(struct sgx_pageinfo *pginfo, void *addr)
0232 {
0233     return __encls_2(EAUG, pginfo, addr);
0234 }
0235 
0236 #endif /* _X86_ENCLS_H */