From: Sean Christopherson <sean.j.christopherson@xxxxxxxxx> The bare-metal kernel must intercept ECREATE to be able to impose policies on guests. When it does this, the bare-metal kernel runs ECREATE against the userspace mapping of the virtualized EPC. Provide wrappers around __ecreate() and __einit() to hide the ugliness of overloading the ENCLS return value to encode multiple error formats in a single int. KVM will trap-and-execute ECREATE and EINIT as part of SGX virtualization, and on an exception, KVM needs the trapnr so that it can inject the correct fault into the guest. Signed-off-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx> [Kai: Use sgx_update_lepubkeyhash() to update pubkey hash MSRs.] Signed-off-by: Kai Huang <kai.huang@xxxxxxxxx> --- v1->v2: - Refined commit msg based on Dave's comment. - Added comment to explain why to use __uaccess_xxx(). --- arch/x86/include/asm/sgx.h | 16 +++++++++ arch/x86/kernel/cpu/sgx/virt.c | 61 ++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 arch/x86/include/asm/sgx.h diff --git a/arch/x86/include/asm/sgx.h b/arch/x86/include/asm/sgx.h new file mode 100644 index 000000000000..0d643b985085 --- /dev/null +++ b/arch/x86/include/asm/sgx.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_SGX_H +#define _ASM_X86_SGX_H + +#include <linux/types.h> + +#ifdef CONFIG_X86_SGX_VIRTUALIZATION +struct sgx_pageinfo; + +int sgx_virt_ecreate(struct sgx_pageinfo *pageinfo, void __user *secs, + int *trapnr); +int sgx_virt_einit(void __user *sigstruct, void __user *token, + void __user *secs, u64 *lepubkeyhash, int *trapnr); +#endif + +#endif /* _ASM_X86_SGX_H */ diff --git a/arch/x86/kernel/cpu/sgx/virt.c b/arch/x86/kernel/cpu/sgx/virt.c index 1e8620f20651..97f02e5235ca 100644 --- a/arch/x86/kernel/cpu/sgx/virt.c +++ b/arch/x86/kernel/cpu/sgx/virt.c @@ -253,3 +253,64 @@ int __init sgx_virt_epc_init(void) return misc_register(&sgx_virt_epc_dev); } + +int sgx_virt_ecreate(struct sgx_pageinfo *pageinfo, void __user *secs, + int *trapnr) +{ + int ret; + + /* + * @secs is userspace address, and it's not guaranteed @secs points at + * an actual EPC page. It's also possible to generate a kernel mapping + * to physical EPC page by resolving PFN but using __uaccess_xx() is + * simpler. + */ + __uaccess_begin(); + ret = __ecreate(pageinfo, (void *)secs); + __uaccess_end(); + + if (encls_faulted(ret)) { + *trapnr = ENCLS_TRAPNR(ret); + return -EFAULT; + } + + /* ECREATE doesn't return an error code, it faults or succeeds. */ + WARN_ON_ONCE(ret); + return 0; +} +EXPORT_SYMBOL_GPL(sgx_virt_ecreate); + +static int __sgx_virt_einit(void __user *sigstruct, void __user *token, + void __user *secs) +{ + int ret; + + __uaccess_begin(); + ret = __einit((void *)sigstruct, (void *)token, (void *)secs); + __uaccess_end(); + return ret; +} + +int sgx_virt_einit(void __user *sigstruct, void __user *token, + void __user *secs, u64 *lepubkeyhash, int *trapnr) +{ + int ret; + + if (!boot_cpu_has(X86_FEATURE_SGX_LC)) { + ret = __sgx_virt_einit(sigstruct, token, secs); + } else { + preempt_disable(); + + sgx_update_lepubkeyhash(lepubkeyhash); + + ret = __sgx_virt_einit(sigstruct, token, secs); + preempt_enable(); + } + + if (encls_faulted(ret)) { + *trapnr = ENCLS_TRAPNR(ret); + return -EFAULT; + } + return ret; +} +EXPORT_SYMBOL_GPL(sgx_virt_einit); -- 2.29.2