arch/x86/kvm/vmx/sgx.c

Source file repositories/reference/linux-study-clean/arch/x86/kvm/vmx/sgx.c

File Facts

System
Linux kernel
Corpus path
arch/x86/kvm/vmx/sgx.c
Extension
.c
Size
15435 bytes
Lines
512
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

guest_cpu_cap_has(vcpu, X86_FEATURE_SGX2)) {
		memset(&ex, 0, sizeof(ex));
		ex.vector = PF_VECTOR;
		ex.error_code = PFERR_PRESENT_MASK | PFERR_WRITE_MASK |
				PFERR_SGX_MASK;
		ex.address = gva;
		ex.error_code_valid = true;
		ex.nested_page_fault = false;
		kvm_inject_emulated_page_fault(vcpu, &ex);
	} else {
		kvm_inject_gp(vcpu, 0);
	}
	return 1;
}

static int __handle_encls_ecreate(struct kvm_vcpu *vcpu,
				  struct sgx_pageinfo *pageinfo,
				  unsigned long secs_hva,
				  gva_t secs_gva)
{
	struct sgx_secs *contents = (struct sgx_secs *)pageinfo->contents;
	struct kvm_cpuid_entry2 *sgx_12_0, *sgx_12_1;
	u64 attributes, xfrm, size;
	u32 miscselect;
	u8 max_size_log2;
	int trapnr, ret;

	sgx_12_0 = kvm_find_cpuid_entry_index(vcpu, 0x12, 0);
	sgx_12_1 = kvm_find_cpuid_entry_index(vcpu, 0x12, 1);
	if (!sgx_12_0 || !sgx_12_1) {
		kvm_prepare_emulation_failure_exit(vcpu);
		return 0;
	}

	miscselect = contents->miscselect;
	attributes = contents->attributes;
	xfrm = contents->xfrm;
	size = contents->size;

	/* Enforce restriction of access to the PROVISIONKEY. */
	if (!vcpu->kvm->arch.sgx_provisioning_allowed &&
	    (attributes & SGX_ATTR_PROVISIONKEY)) {
		if (sgx_12_1->eax & SGX_ATTR_PROVISIONKEY)
			pr_warn_once("SGX PROVISIONKEY advertised but not allowed\n");
		kvm_inject_gp(vcpu, 0);
		return 1;
	}

	/*
	 * Enforce CPUID restrictions on MISCSELECT, ATTRIBUTES and XFRM.  Note
	 * that the allowed XFRM (XFeature Request Mask) isn't strictly bound
	 * by the supported XCR0.  FP+SSE *must* be set in XFRM, even if XSAVE
	 * is unsupported, i.e. even if XCR0 itself is completely unsupported.
	 */
	if ((u32)miscselect & ~sgx_12_0->ebx ||
	    (u32)attributes & ~sgx_12_1->eax ||
	    (u32)(attributes >> 32) & ~sgx_12_1->ebx ||
	    (u32)xfrm & ~sgx_12_1->ecx ||
	    (u32)(xfrm >> 32) & ~sgx_12_1->edx ||
	    xfrm & ~(vcpu->arch.guest_supported_xcr0 | XFEATURE_MASK_FPSSE) ||
	    (xfrm & XFEATURE_MASK_FPSSE) != XFEATURE_MASK_FPSSE) {
		kvm_inject_gp(vcpu, 0);
		return 1;
	}

	/* Enforce CPUID restriction on max enclave size. */
	max_size_log2 = (attributes & SGX_ATTR_MODE64BIT) ? sgx_12_0->edx >> 8 :
							    sgx_12_0->edx;
	if (size >= BIT_ULL(max_size_log2)) {
		kvm_inject_gp(vcpu, 0);
		return 1;
	}

	/*
	 * sgx_virt_ecreate() returns:
	 *  1) 0:	ECREATE was successful
	 *  2) -EFAULT:	ECREATE was run but faulted, and trapnr was set to the
	 *		exception number.
	 *  3) -EINVAL:	access_ok() on @secs_hva failed. This should never
	 *		happen as KVM checks host addresses at memslot creation.
	 *		sgx_virt_ecreate() has already warned in this case.
	 */
	ret = sgx_virt_ecreate(pageinfo, (void __user *)secs_hva, &trapnr);
	if (!ret)
		return kvm_skip_emulated_instruction(vcpu);
	if (ret == -EFAULT)
		return sgx_inject_fault(vcpu, secs_gva, trapnr);

	return ret;
}

Annotation

Implementation Notes