162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*  Copyright(c) 2021 Intel Corporation. */
362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <asm/sgx.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "cpuid.h"
862306a36Sopenharmony_ci#include "kvm_cache_regs.h"
962306a36Sopenharmony_ci#include "nested.h"
1062306a36Sopenharmony_ci#include "sgx.h"
1162306a36Sopenharmony_ci#include "vmx.h"
1262306a36Sopenharmony_ci#include "x86.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cibool __read_mostly enable_sgx = 1;
1562306a36Sopenharmony_cimodule_param_named(sgx, enable_sgx, bool, 0444);
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/* Initial value of guest's virtual SGX_LEPUBKEYHASHn MSRs */
1862306a36Sopenharmony_cistatic u64 sgx_pubkey_hash[4] __ro_after_init;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/*
2162306a36Sopenharmony_ci * ENCLS's memory operands use a fixed segment (DS) and a fixed
2262306a36Sopenharmony_ci * address size based on the mode.  Related prefixes are ignored.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_cistatic int sgx_get_encls_gva(struct kvm_vcpu *vcpu, unsigned long offset,
2562306a36Sopenharmony_ci			     int size, int alignment, gva_t *gva)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	struct kvm_segment s;
2862306a36Sopenharmony_ci	bool fault;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	/* Skip vmcs.GUEST_DS retrieval for 64-bit mode to avoid VMREADs. */
3162306a36Sopenharmony_ci	*gva = offset;
3262306a36Sopenharmony_ci	if (!is_64_bit_mode(vcpu)) {
3362306a36Sopenharmony_ci		vmx_get_segment(vcpu, &s, VCPU_SREG_DS);
3462306a36Sopenharmony_ci		*gva += s.base;
3562306a36Sopenharmony_ci	}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (!IS_ALIGNED(*gva, alignment)) {
3862306a36Sopenharmony_ci		fault = true;
3962306a36Sopenharmony_ci	} else if (likely(is_64_bit_mode(vcpu))) {
4062306a36Sopenharmony_ci		fault = is_noncanonical_address(*gva, vcpu);
4162306a36Sopenharmony_ci	} else {
4262306a36Sopenharmony_ci		*gva &= 0xffffffff;
4362306a36Sopenharmony_ci		fault = (s.unusable) ||
4462306a36Sopenharmony_ci			(s.type != 2 && s.type != 3) ||
4562306a36Sopenharmony_ci			(*gva > s.limit) ||
4662306a36Sopenharmony_ci			((s.base != 0 || s.limit != 0xffffffff) &&
4762306a36Sopenharmony_ci			(((u64)*gva + size - 1) > s.limit + 1));
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci	if (fault)
5062306a36Sopenharmony_ci		kvm_inject_gp(vcpu, 0);
5162306a36Sopenharmony_ci	return fault ? -EINVAL : 0;
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic void sgx_handle_emulation_failure(struct kvm_vcpu *vcpu, u64 addr,
5562306a36Sopenharmony_ci					 unsigned int size)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	uint64_t data[2] = { addr, size };
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	__kvm_prepare_emulation_failure_exit(vcpu, data, ARRAY_SIZE(data));
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic int sgx_read_hva(struct kvm_vcpu *vcpu, unsigned long hva, void *data,
6362306a36Sopenharmony_ci			unsigned int size)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	if (__copy_from_user(data, (void __user *)hva, size)) {
6662306a36Sopenharmony_ci		sgx_handle_emulation_failure(vcpu, hva, size);
6762306a36Sopenharmony_ci		return -EFAULT;
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	return 0;
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic int sgx_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t gva, bool write,
7462306a36Sopenharmony_ci			  gpa_t *gpa)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct x86_exception ex;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (write)
7962306a36Sopenharmony_ci		*gpa = kvm_mmu_gva_to_gpa_write(vcpu, gva, &ex);
8062306a36Sopenharmony_ci	else
8162306a36Sopenharmony_ci		*gpa = kvm_mmu_gva_to_gpa_read(vcpu, gva, &ex);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if (*gpa == INVALID_GPA) {
8462306a36Sopenharmony_ci		kvm_inject_emulated_page_fault(vcpu, &ex);
8562306a36Sopenharmony_ci		return -EFAULT;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return 0;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic int sgx_gpa_to_hva(struct kvm_vcpu *vcpu, gpa_t gpa, unsigned long *hva)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	*hva = kvm_vcpu_gfn_to_hva(vcpu, PFN_DOWN(gpa));
9462306a36Sopenharmony_ci	if (kvm_is_error_hva(*hva)) {
9562306a36Sopenharmony_ci		sgx_handle_emulation_failure(vcpu, gpa, 1);
9662306a36Sopenharmony_ci		return -EFAULT;
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	*hva |= gpa & ~PAGE_MASK;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	return 0;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic int sgx_inject_fault(struct kvm_vcpu *vcpu, gva_t gva, int trapnr)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	struct x86_exception ex;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/*
10962306a36Sopenharmony_ci	 * A non-EPCM #PF indicates a bad userspace HVA.  This *should* check
11062306a36Sopenharmony_ci	 * for PFEC.SGX and not assume any #PF on SGX2 originated in the EPC,
11162306a36Sopenharmony_ci	 * but the error code isn't (yet) plumbed through the ENCLS helpers.
11262306a36Sopenharmony_ci	 */
11362306a36Sopenharmony_ci	if (trapnr == PF_VECTOR && !boot_cpu_has(X86_FEATURE_SGX2)) {
11462306a36Sopenharmony_ci		kvm_prepare_emulation_failure_exit(vcpu);
11562306a36Sopenharmony_ci		return 0;
11662306a36Sopenharmony_ci	}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/*
11962306a36Sopenharmony_ci	 * If the guest thinks it's running on SGX2 hardware, inject an SGX
12062306a36Sopenharmony_ci	 * #PF if the fault matches an EPCM fault signature (#GP on SGX1,
12162306a36Sopenharmony_ci	 * #PF on SGX2).  The assumption is that EPCM faults are much more
12262306a36Sopenharmony_ci	 * likely than a bad userspace address.
12362306a36Sopenharmony_ci	 */
12462306a36Sopenharmony_ci	if ((trapnr == PF_VECTOR || !boot_cpu_has(X86_FEATURE_SGX2)) &&
12562306a36Sopenharmony_ci	    guest_cpuid_has(vcpu, X86_FEATURE_SGX2)) {
12662306a36Sopenharmony_ci		memset(&ex, 0, sizeof(ex));
12762306a36Sopenharmony_ci		ex.vector = PF_VECTOR;
12862306a36Sopenharmony_ci		ex.error_code = PFERR_PRESENT_MASK | PFERR_WRITE_MASK |
12962306a36Sopenharmony_ci				PFERR_SGX_MASK;
13062306a36Sopenharmony_ci		ex.address = gva;
13162306a36Sopenharmony_ci		ex.error_code_valid = true;
13262306a36Sopenharmony_ci		ex.nested_page_fault = false;
13362306a36Sopenharmony_ci		kvm_inject_emulated_page_fault(vcpu, &ex);
13462306a36Sopenharmony_ci	} else {
13562306a36Sopenharmony_ci		kvm_inject_gp(vcpu, 0);
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci	return 1;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic int __handle_encls_ecreate(struct kvm_vcpu *vcpu,
14162306a36Sopenharmony_ci				  struct sgx_pageinfo *pageinfo,
14262306a36Sopenharmony_ci				  unsigned long secs_hva,
14362306a36Sopenharmony_ci				  gva_t secs_gva)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	struct sgx_secs *contents = (struct sgx_secs *)pageinfo->contents;
14662306a36Sopenharmony_ci	struct kvm_cpuid_entry2 *sgx_12_0, *sgx_12_1;
14762306a36Sopenharmony_ci	u64 attributes, xfrm, size;
14862306a36Sopenharmony_ci	u32 miscselect;
14962306a36Sopenharmony_ci	u8 max_size_log2;
15062306a36Sopenharmony_ci	int trapnr, ret;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	sgx_12_0 = kvm_find_cpuid_entry_index(vcpu, 0x12, 0);
15362306a36Sopenharmony_ci	sgx_12_1 = kvm_find_cpuid_entry_index(vcpu, 0x12, 1);
15462306a36Sopenharmony_ci	if (!sgx_12_0 || !sgx_12_1) {
15562306a36Sopenharmony_ci		kvm_prepare_emulation_failure_exit(vcpu);
15662306a36Sopenharmony_ci		return 0;
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	miscselect = contents->miscselect;
16062306a36Sopenharmony_ci	attributes = contents->attributes;
16162306a36Sopenharmony_ci	xfrm = contents->xfrm;
16262306a36Sopenharmony_ci	size = contents->size;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	/* Enforce restriction of access to the PROVISIONKEY. */
16562306a36Sopenharmony_ci	if (!vcpu->kvm->arch.sgx_provisioning_allowed &&
16662306a36Sopenharmony_ci	    (attributes & SGX_ATTR_PROVISIONKEY)) {
16762306a36Sopenharmony_ci		if (sgx_12_1->eax & SGX_ATTR_PROVISIONKEY)
16862306a36Sopenharmony_ci			pr_warn_once("SGX PROVISIONKEY advertised but not allowed\n");
16962306a36Sopenharmony_ci		kvm_inject_gp(vcpu, 0);
17062306a36Sopenharmony_ci		return 1;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/*
17462306a36Sopenharmony_ci	 * Enforce CPUID restrictions on MISCSELECT, ATTRIBUTES and XFRM.  Note
17562306a36Sopenharmony_ci	 * that the allowed XFRM (XFeature Request Mask) isn't strictly bound
17662306a36Sopenharmony_ci	 * by the supported XCR0.  FP+SSE *must* be set in XFRM, even if XSAVE
17762306a36Sopenharmony_ci	 * is unsupported, i.e. even if XCR0 itself is completely unsupported.
17862306a36Sopenharmony_ci	 */
17962306a36Sopenharmony_ci	if ((u32)miscselect & ~sgx_12_0->ebx ||
18062306a36Sopenharmony_ci	    (u32)attributes & ~sgx_12_1->eax ||
18162306a36Sopenharmony_ci	    (u32)(attributes >> 32) & ~sgx_12_1->ebx ||
18262306a36Sopenharmony_ci	    (u32)xfrm & ~sgx_12_1->ecx ||
18362306a36Sopenharmony_ci	    (u32)(xfrm >> 32) & ~sgx_12_1->edx ||
18462306a36Sopenharmony_ci	    xfrm & ~(vcpu->arch.guest_supported_xcr0 | XFEATURE_MASK_FPSSE) ||
18562306a36Sopenharmony_ci	    (xfrm & XFEATURE_MASK_FPSSE) != XFEATURE_MASK_FPSSE) {
18662306a36Sopenharmony_ci		kvm_inject_gp(vcpu, 0);
18762306a36Sopenharmony_ci		return 1;
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	/* Enforce CPUID restriction on max enclave size. */
19162306a36Sopenharmony_ci	max_size_log2 = (attributes & SGX_ATTR_MODE64BIT) ? sgx_12_0->edx >> 8 :
19262306a36Sopenharmony_ci							    sgx_12_0->edx;
19362306a36Sopenharmony_ci	if (size >= BIT_ULL(max_size_log2)) {
19462306a36Sopenharmony_ci		kvm_inject_gp(vcpu, 0);
19562306a36Sopenharmony_ci		return 1;
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	/*
19962306a36Sopenharmony_ci	 * sgx_virt_ecreate() returns:
20062306a36Sopenharmony_ci	 *  1) 0:	ECREATE was successful
20162306a36Sopenharmony_ci	 *  2) -EFAULT:	ECREATE was run but faulted, and trapnr was set to the
20262306a36Sopenharmony_ci	 *		exception number.
20362306a36Sopenharmony_ci	 *  3) -EINVAL:	access_ok() on @secs_hva failed. This should never
20462306a36Sopenharmony_ci	 *		happen as KVM checks host addresses at memslot creation.
20562306a36Sopenharmony_ci	 *		sgx_virt_ecreate() has already warned in this case.
20662306a36Sopenharmony_ci	 */
20762306a36Sopenharmony_ci	ret = sgx_virt_ecreate(pageinfo, (void __user *)secs_hva, &trapnr);
20862306a36Sopenharmony_ci	if (!ret)
20962306a36Sopenharmony_ci		return kvm_skip_emulated_instruction(vcpu);
21062306a36Sopenharmony_ci	if (ret == -EFAULT)
21162306a36Sopenharmony_ci		return sgx_inject_fault(vcpu, secs_gva, trapnr);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return ret;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic int handle_encls_ecreate(struct kvm_vcpu *vcpu)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	gva_t pageinfo_gva, secs_gva;
21962306a36Sopenharmony_ci	gva_t metadata_gva, contents_gva;
22062306a36Sopenharmony_ci	gpa_t metadata_gpa, contents_gpa, secs_gpa;
22162306a36Sopenharmony_ci	unsigned long metadata_hva, contents_hva, secs_hva;
22262306a36Sopenharmony_ci	struct sgx_pageinfo pageinfo;
22362306a36Sopenharmony_ci	struct sgx_secs *contents;
22462306a36Sopenharmony_ci	struct x86_exception ex;
22562306a36Sopenharmony_ci	int r;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if (sgx_get_encls_gva(vcpu, kvm_rbx_read(vcpu), 32, 32, &pageinfo_gva) ||
22862306a36Sopenharmony_ci	    sgx_get_encls_gva(vcpu, kvm_rcx_read(vcpu), 4096, 4096, &secs_gva))
22962306a36Sopenharmony_ci		return 1;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	/*
23262306a36Sopenharmony_ci	 * Copy the PAGEINFO to local memory, its pointers need to be
23362306a36Sopenharmony_ci	 * translated, i.e. we need to do a deep copy/translate.
23462306a36Sopenharmony_ci	 */
23562306a36Sopenharmony_ci	r = kvm_read_guest_virt(vcpu, pageinfo_gva, &pageinfo,
23662306a36Sopenharmony_ci				sizeof(pageinfo), &ex);
23762306a36Sopenharmony_ci	if (r == X86EMUL_PROPAGATE_FAULT) {
23862306a36Sopenharmony_ci		kvm_inject_emulated_page_fault(vcpu, &ex);
23962306a36Sopenharmony_ci		return 1;
24062306a36Sopenharmony_ci	} else if (r != X86EMUL_CONTINUE) {
24162306a36Sopenharmony_ci		sgx_handle_emulation_failure(vcpu, pageinfo_gva,
24262306a36Sopenharmony_ci					     sizeof(pageinfo));
24362306a36Sopenharmony_ci		return 0;
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (sgx_get_encls_gva(vcpu, pageinfo.metadata, 64, 64, &metadata_gva) ||
24762306a36Sopenharmony_ci	    sgx_get_encls_gva(vcpu, pageinfo.contents, 4096, 4096,
24862306a36Sopenharmony_ci			      &contents_gva))
24962306a36Sopenharmony_ci		return 1;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/*
25262306a36Sopenharmony_ci	 * Translate the SECINFO, SOURCE and SECS pointers from GVA to GPA.
25362306a36Sopenharmony_ci	 * Resume the guest on failure to inject a #PF.
25462306a36Sopenharmony_ci	 */
25562306a36Sopenharmony_ci	if (sgx_gva_to_gpa(vcpu, metadata_gva, false, &metadata_gpa) ||
25662306a36Sopenharmony_ci	    sgx_gva_to_gpa(vcpu, contents_gva, false, &contents_gpa) ||
25762306a36Sopenharmony_ci	    sgx_gva_to_gpa(vcpu, secs_gva, true, &secs_gpa))
25862306a36Sopenharmony_ci		return 1;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/*
26162306a36Sopenharmony_ci	 * ...and then to HVA.  The order of accesses isn't architectural, i.e.
26262306a36Sopenharmony_ci	 * KVM doesn't have to fully process one address at a time.  Exit to
26362306a36Sopenharmony_ci	 * userspace if a GPA is invalid.
26462306a36Sopenharmony_ci	 */
26562306a36Sopenharmony_ci	if (sgx_gpa_to_hva(vcpu, metadata_gpa, &metadata_hva) ||
26662306a36Sopenharmony_ci	    sgx_gpa_to_hva(vcpu, contents_gpa, &contents_hva) ||
26762306a36Sopenharmony_ci	    sgx_gpa_to_hva(vcpu, secs_gpa, &secs_hva))
26862306a36Sopenharmony_ci		return 0;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	/*
27162306a36Sopenharmony_ci	 * Copy contents into kernel memory to prevent TOCTOU attack. E.g. the
27262306a36Sopenharmony_ci	 * guest could do ECREATE w/ SECS.SGX_ATTR_PROVISIONKEY=0, and
27362306a36Sopenharmony_ci	 * simultaneously set SGX_ATTR_PROVISIONKEY to bypass the check to
27462306a36Sopenharmony_ci	 * enforce restriction of access to the PROVISIONKEY.
27562306a36Sopenharmony_ci	 */
27662306a36Sopenharmony_ci	contents = (struct sgx_secs *)__get_free_page(GFP_KERNEL_ACCOUNT);
27762306a36Sopenharmony_ci	if (!contents)
27862306a36Sopenharmony_ci		return -ENOMEM;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* Exit to userspace if copying from a host userspace address fails. */
28162306a36Sopenharmony_ci	if (sgx_read_hva(vcpu, contents_hva, (void *)contents, PAGE_SIZE)) {
28262306a36Sopenharmony_ci		free_page((unsigned long)contents);
28362306a36Sopenharmony_ci		return 0;
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	pageinfo.metadata = metadata_hva;
28762306a36Sopenharmony_ci	pageinfo.contents = (u64)contents;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	r = __handle_encls_ecreate(vcpu, &pageinfo, secs_hva, secs_gva);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	free_page((unsigned long)contents);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return r;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic int handle_encls_einit(struct kvm_vcpu *vcpu)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	unsigned long sig_hva, secs_hva, token_hva, rflags;
29962306a36Sopenharmony_ci	struct vcpu_vmx *vmx = to_vmx(vcpu);
30062306a36Sopenharmony_ci	gva_t sig_gva, secs_gva, token_gva;
30162306a36Sopenharmony_ci	gpa_t sig_gpa, secs_gpa, token_gpa;
30262306a36Sopenharmony_ci	int ret, trapnr;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (sgx_get_encls_gva(vcpu, kvm_rbx_read(vcpu), 1808, 4096, &sig_gva) ||
30562306a36Sopenharmony_ci	    sgx_get_encls_gva(vcpu, kvm_rcx_read(vcpu), 4096, 4096, &secs_gva) ||
30662306a36Sopenharmony_ci	    sgx_get_encls_gva(vcpu, kvm_rdx_read(vcpu), 304, 512, &token_gva))
30762306a36Sopenharmony_ci		return 1;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	/*
31062306a36Sopenharmony_ci	 * Translate the SIGSTRUCT, SECS and TOKEN pointers from GVA to GPA.
31162306a36Sopenharmony_ci	 * Resume the guest on failure to inject a #PF.
31262306a36Sopenharmony_ci	 */
31362306a36Sopenharmony_ci	if (sgx_gva_to_gpa(vcpu, sig_gva, false, &sig_gpa) ||
31462306a36Sopenharmony_ci	    sgx_gva_to_gpa(vcpu, secs_gva, true, &secs_gpa) ||
31562306a36Sopenharmony_ci	    sgx_gva_to_gpa(vcpu, token_gva, false, &token_gpa))
31662306a36Sopenharmony_ci		return 1;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	/*
31962306a36Sopenharmony_ci	 * ...and then to HVA.  The order of accesses isn't architectural, i.e.
32062306a36Sopenharmony_ci	 * KVM doesn't have to fully process one address at a time.  Exit to
32162306a36Sopenharmony_ci	 * userspace if a GPA is invalid.  Note, all structures are aligned and
32262306a36Sopenharmony_ci	 * cannot split pages.
32362306a36Sopenharmony_ci	 */
32462306a36Sopenharmony_ci	if (sgx_gpa_to_hva(vcpu, sig_gpa, &sig_hva) ||
32562306a36Sopenharmony_ci	    sgx_gpa_to_hva(vcpu, secs_gpa, &secs_hva) ||
32662306a36Sopenharmony_ci	    sgx_gpa_to_hva(vcpu, token_gpa, &token_hva))
32762306a36Sopenharmony_ci		return 0;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	ret = sgx_virt_einit((void __user *)sig_hva, (void __user *)token_hva,
33062306a36Sopenharmony_ci			     (void __user *)secs_hva,
33162306a36Sopenharmony_ci			     vmx->msr_ia32_sgxlepubkeyhash, &trapnr);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (ret == -EFAULT)
33462306a36Sopenharmony_ci		return sgx_inject_fault(vcpu, secs_gva, trapnr);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	/*
33762306a36Sopenharmony_ci	 * sgx_virt_einit() returns -EINVAL when access_ok() fails on @sig_hva,
33862306a36Sopenharmony_ci	 * @token_hva or @secs_hva. This should never happen as KVM checks host
33962306a36Sopenharmony_ci	 * addresses at memslot creation. sgx_virt_einit() has already warned
34062306a36Sopenharmony_ci	 * in this case, so just return.
34162306a36Sopenharmony_ci	 */
34262306a36Sopenharmony_ci	if (ret < 0)
34362306a36Sopenharmony_ci		return ret;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	rflags = vmx_get_rflags(vcpu) & ~(X86_EFLAGS_CF | X86_EFLAGS_PF |
34662306a36Sopenharmony_ci					  X86_EFLAGS_AF | X86_EFLAGS_SF |
34762306a36Sopenharmony_ci					  X86_EFLAGS_OF);
34862306a36Sopenharmony_ci	if (ret)
34962306a36Sopenharmony_ci		rflags |= X86_EFLAGS_ZF;
35062306a36Sopenharmony_ci	else
35162306a36Sopenharmony_ci		rflags &= ~X86_EFLAGS_ZF;
35262306a36Sopenharmony_ci	vmx_set_rflags(vcpu, rflags);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	kvm_rax_write(vcpu, ret);
35562306a36Sopenharmony_ci	return kvm_skip_emulated_instruction(vcpu);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic inline bool encls_leaf_enabled_in_guest(struct kvm_vcpu *vcpu, u32 leaf)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	/*
36162306a36Sopenharmony_ci	 * ENCLS generates a #UD if SGX1 isn't supported, i.e. this point will
36262306a36Sopenharmony_ci	 * be reached if and only if the SGX1 leafs are enabled.
36362306a36Sopenharmony_ci	 */
36462306a36Sopenharmony_ci	if (leaf >= ECREATE && leaf <= ETRACK)
36562306a36Sopenharmony_ci		return true;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	if (leaf >= EAUG && leaf <= EMODT)
36862306a36Sopenharmony_ci		return guest_cpuid_has(vcpu, X86_FEATURE_SGX2);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	return false;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic inline bool sgx_enabled_in_guest_bios(struct kvm_vcpu *vcpu)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	const u64 bits = FEAT_CTL_SGX_ENABLED | FEAT_CTL_LOCKED;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return (to_vmx(vcpu)->msr_ia32_feature_control & bits) == bits;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ciint handle_encls(struct kvm_vcpu *vcpu)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	u32 leaf = (u32)kvm_rax_read(vcpu);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	if (!enable_sgx || !guest_cpuid_has(vcpu, X86_FEATURE_SGX) ||
38562306a36Sopenharmony_ci	    !guest_cpuid_has(vcpu, X86_FEATURE_SGX1)) {
38662306a36Sopenharmony_ci		kvm_queue_exception(vcpu, UD_VECTOR);
38762306a36Sopenharmony_ci	} else if (!encls_leaf_enabled_in_guest(vcpu, leaf) ||
38862306a36Sopenharmony_ci		   !sgx_enabled_in_guest_bios(vcpu) || !is_paging(vcpu)) {
38962306a36Sopenharmony_ci		kvm_inject_gp(vcpu, 0);
39062306a36Sopenharmony_ci	} else {
39162306a36Sopenharmony_ci		if (leaf == ECREATE)
39262306a36Sopenharmony_ci			return handle_encls_ecreate(vcpu);
39362306a36Sopenharmony_ci		if (leaf == EINIT)
39462306a36Sopenharmony_ci			return handle_encls_einit(vcpu);
39562306a36Sopenharmony_ci		WARN_ONCE(1, "unexpected exit on ENCLS[%u]", leaf);
39662306a36Sopenharmony_ci		vcpu->run->exit_reason = KVM_EXIT_UNKNOWN;
39762306a36Sopenharmony_ci		vcpu->run->hw.hardware_exit_reason = EXIT_REASON_ENCLS;
39862306a36Sopenharmony_ci		return 0;
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci	return 1;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_civoid setup_default_sgx_lepubkeyhash(void)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	/*
40662306a36Sopenharmony_ci	 * Use Intel's default value for Skylake hardware if Launch Control is
40762306a36Sopenharmony_ci	 * not supported, i.e. Intel's hash is hardcoded into silicon, or if
40862306a36Sopenharmony_ci	 * Launch Control is supported and enabled, i.e. mimic the reset value
40962306a36Sopenharmony_ci	 * and let the guest write the MSRs at will.  If Launch Control is
41062306a36Sopenharmony_ci	 * supported but disabled, then use the current MSR values as the hash
41162306a36Sopenharmony_ci	 * MSRs exist but are read-only (locked and not writable).
41262306a36Sopenharmony_ci	 */
41362306a36Sopenharmony_ci	if (!enable_sgx || boot_cpu_has(X86_FEATURE_SGX_LC) ||
41462306a36Sopenharmony_ci	    rdmsrl_safe(MSR_IA32_SGXLEPUBKEYHASH0, &sgx_pubkey_hash[0])) {
41562306a36Sopenharmony_ci		sgx_pubkey_hash[0] = 0xa6053e051270b7acULL;
41662306a36Sopenharmony_ci		sgx_pubkey_hash[1] = 0x6cfbe8ba8b3b413dULL;
41762306a36Sopenharmony_ci		sgx_pubkey_hash[2] = 0xc4916d99f2b3735dULL;
41862306a36Sopenharmony_ci		sgx_pubkey_hash[3] = 0xd4f8c05909f9bb3bULL;
41962306a36Sopenharmony_ci	} else {
42062306a36Sopenharmony_ci		/* MSR_IA32_SGXLEPUBKEYHASH0 is read above */
42162306a36Sopenharmony_ci		rdmsrl(MSR_IA32_SGXLEPUBKEYHASH1, sgx_pubkey_hash[1]);
42262306a36Sopenharmony_ci		rdmsrl(MSR_IA32_SGXLEPUBKEYHASH2, sgx_pubkey_hash[2]);
42362306a36Sopenharmony_ci		rdmsrl(MSR_IA32_SGXLEPUBKEYHASH3, sgx_pubkey_hash[3]);
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_civoid vcpu_setup_sgx_lepubkeyhash(struct kvm_vcpu *vcpu)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	struct vcpu_vmx *vmx = to_vmx(vcpu);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	memcpy(vmx->msr_ia32_sgxlepubkeyhash, sgx_pubkey_hash,
43262306a36Sopenharmony_ci	       sizeof(sgx_pubkey_hash));
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci/*
43662306a36Sopenharmony_ci * ECREATE must be intercepted to enforce MISCSELECT, ATTRIBUTES and XFRM
43762306a36Sopenharmony_ci * restrictions if the guest's allowed-1 settings diverge from hardware.
43862306a36Sopenharmony_ci */
43962306a36Sopenharmony_cistatic bool sgx_intercept_encls_ecreate(struct kvm_vcpu *vcpu)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	struct kvm_cpuid_entry2 *guest_cpuid;
44262306a36Sopenharmony_ci	u32 eax, ebx, ecx, edx;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (!vcpu->kvm->arch.sgx_provisioning_allowed)
44562306a36Sopenharmony_ci		return true;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	guest_cpuid = kvm_find_cpuid_entry_index(vcpu, 0x12, 0);
44862306a36Sopenharmony_ci	if (!guest_cpuid)
44962306a36Sopenharmony_ci		return true;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	cpuid_count(0x12, 0, &eax, &ebx, &ecx, &edx);
45262306a36Sopenharmony_ci	if (guest_cpuid->ebx != ebx || guest_cpuid->edx != edx)
45362306a36Sopenharmony_ci		return true;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	guest_cpuid = kvm_find_cpuid_entry_index(vcpu, 0x12, 1);
45662306a36Sopenharmony_ci	if (!guest_cpuid)
45762306a36Sopenharmony_ci		return true;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	cpuid_count(0x12, 1, &eax, &ebx, &ecx, &edx);
46062306a36Sopenharmony_ci	if (guest_cpuid->eax != eax || guest_cpuid->ebx != ebx ||
46162306a36Sopenharmony_ci	    guest_cpuid->ecx != ecx || guest_cpuid->edx != edx)
46262306a36Sopenharmony_ci		return true;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	return false;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_civoid vmx_write_encls_bitmap(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	/*
47062306a36Sopenharmony_ci	 * There is no software enable bit for SGX that is virtualized by
47162306a36Sopenharmony_ci	 * hardware, e.g. there's no CR4.SGXE, so when SGX is disabled in the
47262306a36Sopenharmony_ci	 * guest (either by the host or by the guest's BIOS) but enabled in the
47362306a36Sopenharmony_ci	 * host, trap all ENCLS leafs and inject #UD/#GP as needed to emulate
47462306a36Sopenharmony_ci	 * the expected system behavior for ENCLS.
47562306a36Sopenharmony_ci	 */
47662306a36Sopenharmony_ci	u64 bitmap = -1ull;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	/* Nothing to do if hardware doesn't support SGX */
47962306a36Sopenharmony_ci	if (!cpu_has_vmx_encls_vmexit())
48062306a36Sopenharmony_ci		return;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	if (guest_cpuid_has(vcpu, X86_FEATURE_SGX) &&
48362306a36Sopenharmony_ci	    sgx_enabled_in_guest_bios(vcpu)) {
48462306a36Sopenharmony_ci		if (guest_cpuid_has(vcpu, X86_FEATURE_SGX1)) {
48562306a36Sopenharmony_ci			bitmap &= ~GENMASK_ULL(ETRACK, ECREATE);
48662306a36Sopenharmony_ci			if (sgx_intercept_encls_ecreate(vcpu))
48762306a36Sopenharmony_ci				bitmap |= (1 << ECREATE);
48862306a36Sopenharmony_ci		}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci		if (guest_cpuid_has(vcpu, X86_FEATURE_SGX2))
49162306a36Sopenharmony_ci			bitmap &= ~GENMASK_ULL(EMODT, EAUG);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci		/*
49462306a36Sopenharmony_ci		 * Trap and execute EINIT if launch control is enabled in the
49562306a36Sopenharmony_ci		 * host using the guest's values for launch control MSRs, even
49662306a36Sopenharmony_ci		 * if the guest's values are fixed to hardware default values.
49762306a36Sopenharmony_ci		 * The MSRs are not loaded/saved on VM-Enter/VM-Exit as writing
49862306a36Sopenharmony_ci		 * the MSRs is extraordinarily expensive.
49962306a36Sopenharmony_ci		 */
50062306a36Sopenharmony_ci		if (boot_cpu_has(X86_FEATURE_SGX_LC))
50162306a36Sopenharmony_ci			bitmap |= (1 << EINIT);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci		if (!vmcs12 && is_guest_mode(vcpu))
50462306a36Sopenharmony_ci			vmcs12 = get_vmcs12(vcpu);
50562306a36Sopenharmony_ci		if (vmcs12 && nested_cpu_has_encls_exit(vmcs12))
50662306a36Sopenharmony_ci			bitmap |= vmcs12->encls_exiting_bitmap;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci	vmcs_write64(ENCLS_EXITING_BITMAP, bitmap);
50962306a36Sopenharmony_ci}
510