Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Aug 2017 10:38:06 +0000 (UTC)
From:      Ruslan Bukin <br@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r322574 - in head/sys: amd64/include amd64/sgx modules modules/sgx modules/sgx_linux
Message-ID:  <201708161038.v7GAc6jQ077852@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: br
Date: Wed Aug 16 10:38:06 2017
New Revision: 322574
URL: https://svnweb.freebsd.org/changeset/base/322574

Log:
  Add support for Intel Software Guard Extensions (Intel SGX).
  
  Intel SGX allows to manage isolated compartments "Enclaves" in user VA
  space. Enclaves memory is part of processor reserved memory (PRM) and
  always encrypted. This allows to protect user application code and data
  from upper privilege levels including OS kernel.
  
  This includes SGX driver and optional linux ioctl compatibility layer.
  Intel SGX SDK for FreeBSD is also available.
  
  Note this requires support from hardware (available since late Intel
  Skylake CPUs).
  
  Many thanks to Robert Watson for support and Konstantin Belousov
  for code review.
  
  Project wiki: https://wiki.freebsd.org/Intel_SGX.
  
  Reviewed by:	kib
  Relnotes:	yes
  Sponsored by:	DARPA, AFRL
  Differential Revision:	https://reviews.freebsd.org/D11113

Added:
  head/sys/amd64/include/sgx.h   (contents, props changed)
  head/sys/amd64/include/sgxreg.h   (contents, props changed)
  head/sys/amd64/sgx/
  head/sys/amd64/sgx/sgx.c   (contents, props changed)
  head/sys/amd64/sgx/sgx_linux.c   (contents, props changed)
  head/sys/amd64/sgx/sgx_support.S   (contents, props changed)
  head/sys/amd64/sgx/sgxvar.h   (contents, props changed)
  head/sys/modules/sgx/
  head/sys/modules/sgx/Makefile   (contents, props changed)
  head/sys/modules/sgx_linux/
  head/sys/modules/sgx_linux/Makefile   (contents, props changed)
Modified:
  head/sys/amd64/include/cpufunc.h
  head/sys/modules/Makefile

Modified: head/sys/amd64/include/cpufunc.h
==============================================================================
--- head/sys/amd64/include/cpufunc.h	Wed Aug 16 10:30:23 2017	(r322573)
+++ head/sys/amd64/include/cpufunc.h	Wed Aug 16 10:38:06 2017	(r322574)
@@ -834,6 +834,85 @@ intr_restore(register_t rflags)
 	write_rflags(rflags);
 }
 
+enum {
+	SGX_ECREATE	= 0x0,
+	SGX_EADD	= 0x1,
+	SGX_EINIT	= 0x2,
+	SGX_EREMOVE	= 0x3,
+	SGX_EDGBRD	= 0x4,
+	SGX_EDGBWR	= 0x5,
+	SGX_EEXTEND	= 0x6,
+	SGX_ELDU	= 0x8,
+	SGX_EBLOCK	= 0x9,
+	SGX_EPA		= 0xA,
+	SGX_EWB		= 0xB,
+	SGX_ETRACK	= 0xC,
+};
+
+enum {
+	SGX_PT_SECS = 0x00,
+	SGX_PT_TCS  = 0x01,
+	SGX_PT_REG  = 0x02,
+	SGX_PT_VA   = 0x03,
+	SGX_PT_TRIM = 0x04,
+};
+
+int sgx_encls(uint32_t eax, uint64_t rbx, uint64_t rcx, uint64_t rdx);
+
+static __inline int
+sgx_ecreate(void *pginfo, void *secs)
+{
+
+	return (sgx_encls(SGX_ECREATE, (uint64_t)pginfo,
+	    (uint64_t)secs, 0));
+}
+
+static __inline int
+sgx_eadd(void *pginfo, void *epc)
+{
+
+	return (sgx_encls(SGX_EADD, (uint64_t)pginfo,
+	    (uint64_t)epc, 0));
+}
+
+static __inline int
+sgx_einit(void *sigstruct, void *secs, void *einittoken)
+{
+
+	return (sgx_encls(SGX_EINIT, (uint64_t)sigstruct,
+	    (uint64_t)secs, (uint64_t)einittoken));
+}
+
+static __inline int
+sgx_eextend(void *secs, void *epc)
+{
+
+	return (sgx_encls(SGX_EEXTEND, (uint64_t)secs,
+	    (uint64_t)epc, 0));
+}
+
+static __inline int
+sgx_epa(void *epc)
+{
+
+	return (sgx_encls(SGX_EPA, SGX_PT_VA, (uint64_t)epc, 0));
+}
+
+static __inline int
+sgx_eldu(uint64_t rbx, uint64_t rcx,
+    uint64_t rdx)
+{
+
+	return (sgx_encls(SGX_ELDU, rbx, rcx, rdx));
+}
+
+static __inline int
+sgx_eremove(void *epc)
+{
+
+	return (sgx_encls(SGX_EREMOVE, 0, (uint64_t)epc, 0));
+}
+
 #else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */
 
 int	breakpoint(void);

Added: head/sys/amd64/include/sgx.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/amd64/include/sgx.h	Wed Aug 16 10:38:06 2017	(r322574)
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/* User-visible header. */
+
+#ifndef _MACHINE_SGX_H_
+#define _MACHINE_SGX_H_
+
+#define	SGX_MAGIC	0xA4
+#define	SGX_IOC_ENCLAVE_CREATE \
+	_IOW(SGX_MAGIC, 0x00, struct sgx_enclave_create)
+#define	SGX_IOC_ENCLAVE_ADD_PAGE \
+	_IOW(SGX_MAGIC, 0x01, struct sgx_enclave_add_page)
+#define	SGX_IOC_ENCLAVE_INIT \
+	_IOW(SGX_MAGIC, 0x02, struct sgx_enclave_init)
+
+struct sgx_enclave_create {
+	uint64_t	src;
+} __packed;
+
+struct sgx_enclave_add_page {
+	uint64_t	addr;
+	uint64_t	src;
+	uint64_t	secinfo;
+	uint16_t	mrmask;
+} __packed;
+
+struct sgx_enclave_init {
+	uint64_t	addr;
+	uint64_t	sigstruct;
+	uint64_t	einittoken;
+} __packed;
+
+#endif /* !_MACHINE_SGX_H_ */

Added: head/sys/amd64/include/sgxreg.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/amd64/include/sgxreg.h	Wed Aug 16 10:38:06 2017	(r322574)
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/* Machine-defined variables. */
+
+#ifndef _MACHINE_SGXREG_H_
+#define _MACHINE_SGXREG_H_
+
+/* Error codes. */
+#define	SGX_SUCCESS			0
+#define	SGX_INVALID_SIG_STRUCT		1	/* EINIT */
+#define	SGX_INVALID_ATTRIBUTE		2	/* EINIT, EGETKEY */
+#define	SGX_BLSTATE			3	/* EBLOCK */
+#define	SGX_INVALID_MEASUREMENT		4	/* EINIT */
+#define	SGX_NOTBLOCKABLE		5	/* EBLOCK */
+#define	SGX_PG_INVLD			6	/* EBLOCK */
+#define	SGX_LOCKFAIL			7	/* EBLOCK, EMODPR, EMODT */
+#define	SGX_INVALID_SIGNATURE		8	/* EINIT */
+#define	SGX_MAC_COMPARE_FAIL		9	/* ELDB, ELDU */
+#define	SGX_PAGE_NOT_BLOCKED		10	/* EWB */
+#define	SGX_NOT_TRACKED			11	/* EWB, EACCEPT */
+#define	SGX_VA_SLOT_OCCUPIED		12	/* EWB */
+#define	SGX_CHILD_PRESENT		13	/* EWB, EREMOVE */
+#define	SGX_ENCLAVE_ACT			14	/* EREMOVE */
+#define	SGX_ENTRYEPOCH_LOCKED		15	/* EBLOCK */
+#define	SGX_INVALID_EINIT_TOKEN		16	/* EINIT */
+#define	SGX_PREV_TRK_INCMPL		17	/* ETRACK */
+#define	SGX_PG_IS_SECS			18	/* EBLOCK */
+#define	SGX_PAGE_ATTRIBUTES_MISMATCH	19	/* EACCEPT, EACCEPTCOPY */
+#define	SGX_PAGE_NOT_MODIFIABLE		20	/* EMODPR, EMODT */
+#define	SGX_INVALID_CPUSVN		32	/* EINIT, EGETKEY */
+#define	SGX_INVALID_ISVSVN		64	/* EGETKEY */
+#define	SGX_UNMASKED_EVENT		128	/* EINIT */
+#define	SGX_INVALID_KEYNAME		256	/* EGETKEY */
+
+/*
+ * 2.10 Page Information (PAGEINFO)
+ * PAGEINFO is an architectural data structure that is used as a parameter
+ * to the EPC-management instructions. It requires 32-Byte alignment.
+ */
+struct page_info {
+	uint64_t linaddr;
+	uint64_t srcpge;
+	union {
+		struct secinfo *secinfo;
+		uint64_t pcmd;
+	};
+	uint64_t secs;
+} __aligned(32);
+
+/*
+ * 2.11 Security Information (SECINFO)
+ * The SECINFO data structure holds meta-data about an enclave page.
+ */
+struct secinfo {
+	uint64_t flags;
+#define	SECINFO_FLAGS_PT_S	8	/* Page type shift */
+#define	SECINFO_FLAGS_PT_M	(0xff << SECINFO_FLAGS_PT_S)
+	uint64_t reserved[7];
+} __aligned(64);
+
+/*
+ * 2.7.1 ATTRIBUTES
+ * The ATTRIBUTES data structure is comprised of bit-granular fields that
+ * are used in the SECS, CPUID enumeration, the REPORT and the KEYREQUEST
+ * structures.
+ */
+struct secs_attr {
+	uint8_t		reserved1: 1;
+	uint8_t		debug: 1;
+	uint8_t		mode64bit: 1;
+	uint8_t		reserved2: 1;
+	uint8_t		provisionkey: 1;
+	uint8_t		einittokenkey: 1;
+	uint8_t		reserved3: 2;
+#define	SECS_ATTR_RSV4_SIZE	7
+	uint8_t		reserved4[SECS_ATTR_RSV4_SIZE];
+	uint64_t	xfrm;			/* X-Feature Request Mask */
+};
+
+/*
+ * 2.7 SGX Enclave Control Structure (SECS)
+ * The SECS data structure requires 4K-Bytes alignment.
+ */
+struct secs {
+	uint64_t	size;
+	uint64_t	base;
+	uint32_t	ssa_frame_size;
+	uint32_t	misc_select;
+#define	SECS_RSV1_SIZE	24
+	uint8_t		reserved1[SECS_RSV1_SIZE];
+	struct secs_attr attributes;
+	uint8_t		mr_enclave[32];
+#define	SECS_RSV2_SIZE	32
+	uint8_t		reserved2[SECS_RSV2_SIZE];
+	uint8_t		mr_signer[32];
+#define	SECS_RSV3_SIZE	96
+	uint8_t		reserved3[SECS_RSV3_SIZE];
+	uint16_t	isv_prod_id;
+	uint16_t	isv_svn;
+#define	SECS_RSV4_SIZE	3836
+	uint8_t		reserved4[SECS_RSV4_SIZE];
+};
+
+/*
+ * 2.8 Thread Control Structure (TCS)
+ * Each executing thread in the enclave is associated with a
+ * Thread Control Structure. It requires 4K-Bytes alignment.
+ */
+struct tcs {
+	uint64_t	reserved1;
+	uint64_t	flags;
+	uint64_t	ossa;
+	uint32_t	cssa;
+	uint32_t	nssa;
+	uint64_t	oentry;
+	uint64_t	reserved2;
+	uint64_t	ofsbasgx;
+	uint64_t	ogsbasgx;
+	uint32_t	fslimit;
+	uint32_t	gslimit;
+	uint64_t	reserved3[503];
+};
+
+#endif /* !_MACHINE_SGXREG_H_ */

Added: head/sys/amd64/sgx/sgx.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/amd64/sgx/sgx.c	Wed Aug 16 10:38:06 2017	(r322574)
@@ -0,0 +1,1211 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Design overview.
+ *
+ * The driver provides character device for mmap(2) and ioctl(2) system calls
+ * allowing user to manage isolated compartments ("enclaves") in user VA space.
+ *
+ * The driver duties is EPC pages management, enclave management, user data
+ * validation.
+ *
+ * This driver requires Intel SGX support from hardware.
+ *
+ * /dev/sgx:
+ *    .mmap:
+ *        sgx_mmap_single() allocates VM object with following pager
+ *        operations:
+ *              a) sgx_pg_ctor():
+ *                  VM object constructor does nothing
+ *              b) sgx_pg_dtor():
+ *                  VM object destructor destroys the SGX enclave associated
+ *                  with the object: it frees all the EPC pages allocated for
+ *                  enclave and removes the enclave.
+ *              c) sgx_pg_fault():
+ *                  VM object fault handler does nothing
+ *
+ *    .ioctl:
+ *        sgx_ioctl():
+ *               a) SGX_IOC_ENCLAVE_CREATE
+ *                   Adds Enclave SECS page: initial step of enclave creation.
+ *               b) SGX_IOC_ENCLAVE_ADD_PAGE
+ *                   Adds TCS, REG pages to the enclave.
+ *               c) SGX_IOC_ENCLAVE_INIT
+ *                   Finalizes enclave creation.
+ *
+ * Enclave lifecycle:
+ *          .-- ECREATE  -- Add SECS page
+ *   Kernel |   EADD     -- Add TCS, REG pages
+ *    space |   EEXTEND  -- Measure the page (take unique hash)
+ *    ENCLS |   EPA      -- Allocate version array page
+ *          '-- EINIT    -- Finalize enclave creation
+ *   User   .-- EENTER   -- Go to entry point of enclave
+ *    space |   EEXIT    -- Exit back to main application
+ *    ENCLU '-- ERESUME  -- Resume enclave execution (e.g. after exception)
+ *  
+ * Enclave lifecycle from driver point of view:
+ *  1) User calls mmap() on /dev/sgx: we allocate a VM object
+ *  2) User calls ioctl SGX_IOC_ENCLAVE_CREATE: we look for the VM object
+ *     associated with user process created on step 1, create SECS physical
+ *     page and store it in enclave's VM object queue by special index
+ *     SGX_SECS_VM_OBJECT_INDEX.
+ *  3) User calls ioctl SGX_IOC_ENCLAVE_ADD_PAGE: we look for enclave created
+ *     on step 2, create TCS or REG physical page and map it to specified by
+ *     user address of enclave VM object.
+ *  4) User finalizes enclave creation with ioctl SGX_IOC_ENCLAVE_INIT call.
+ *  5) User can freely enter to and exit from enclave using ENCLU instructions
+ *     from userspace: the driver does nothing here.
+ *  6) User proceed munmap(2) system call (or the process with enclave dies):
+ *     we destroy the enclave associated with the object.
+ *
+ * EPC page types and their indexes in VM object queue:
+ *   - PT_SECS index is special and equals SGX_SECS_VM_OBJECT_INDEX (-1);
+ *   - PT_TCS and PT_REG indexes are specified by user in addr field of ioctl
+ *     request data and determined as follows:
+ *       pidx = OFF_TO_IDX(addp->addr - vmh->base);
+ *   - PT_VA index is special, created for PT_REG, PT_TCS and PT_SECS pages
+ *     and determined by formula:
+ *       va_page_idx = - SGX_VA_PAGES_OFFS - (page_idx / SGX_VA_PAGE_SLOTS);
+ *     PT_VA page can hold versions of up to 512 pages, and slot for each
+ *     page in PT_VA page is determined as follows:
+ *       va_slot_idx = page_idx % SGX_VA_PAGE_SLOTS;
+ *   - PT_TRIM is unused.
+ *
+ * Locking:
+ *    SGX ENCLS set of instructions have limitations on concurrency:
+ *    some instructions can't be executed same time on different CPUs.
+ *    We use sc->mtx_encls lock around them to prevent concurrent execution.
+ *    sc->mtx lock is used to manage list of created enclaves and the state of
+ *    SGX driver.
+ *
+ * Eviction of EPC pages:
+ *    Eviction support is not implemented in this driver, however the driver
+ *    manages VA (version array) pages: it allocates a VA slot for each EPC
+ *    page. This will be required for eviction support in future.
+ *    VA pages and slots are currently unused.
+ *
+ * IntelĀ® 64 and IA-32 Architectures Software Developer's Manual
+ * https://software.intel.com/en-us/articles/intel-sdm
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ioccom.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/conf.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/vmem.h>
+#include <sys/vmmeter.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_phys.h>
+#include <vm/vm_radix.h>
+#include <vm/pmap.h>
+
+#include <machine/md_var.h>
+#include <machine/specialreg.h>
+#include <machine/cpufunc.h>
+#include <machine/sgx.h>
+#include <machine/sgxreg.h>
+
+#include <amd64/sgx/sgxvar.h>
+
+#define	DEBUG
+#undef	DEBUG
+
+#ifdef	DEBUG
+#define	dprintf(fmt, ...)	printf(fmt, ##__VA_ARGS__)
+#else
+#define	dprintf(fmt, ...)
+#endif
+
+static struct cdev_pager_ops sgx_pg_ops;
+struct sgx_softc sgx_sc;
+
+static int
+sgx_get_epc_page(struct sgx_softc *sc, struct epc_page **epc)
+{
+	vmem_addr_t addr;
+	int i;
+
+	if (vmem_alloc(sc->vmem_epc, PAGE_SIZE, M_FIRSTFIT | M_NOWAIT,
+	    &addr) == 0) {
+		i = (addr - sc->epc_base) / PAGE_SIZE;
+		*epc = &sc->epc_pages[i];
+		return (0);
+	}
+
+	return (ENOMEM);
+}
+
+static void
+sgx_put_epc_page(struct sgx_softc *sc, struct epc_page *epc)
+{
+	vmem_addr_t addr;
+
+	if (epc == NULL)
+		return;
+
+	addr = (epc->index * PAGE_SIZE) + sc->epc_base;
+	vmem_free(sc->vmem_epc, addr, PAGE_SIZE);
+}
+
+static int
+sgx_va_slot_init_by_index(struct sgx_softc *sc, vm_object_t object,
+    uint64_t idx)
+{
+	struct epc_page *epc;
+	vm_page_t page;
+	vm_page_t p;
+	int ret;
+
+	VM_OBJECT_ASSERT_WLOCKED(object);
+
+	p = vm_page_lookup(object, idx);
+	if (p == NULL) {
+		ret = sgx_get_epc_page(sc, &epc);
+		if (ret) {
+			dprintf("%s: No free EPC pages available.\n",
+			    __func__);
+			return (ret);
+		}
+
+		mtx_lock(&sc->mtx_encls);
+		sgx_epa((void *)epc->base);
+		mtx_unlock(&sc->mtx_encls);
+
+		page = PHYS_TO_VM_PAGE(epc->phys);
+
+		vm_page_insert(page, object, idx);
+		page->valid = VM_PAGE_BITS_ALL;
+	}
+
+	return (0);
+}
+
+static int
+sgx_va_slot_init(struct sgx_softc *sc,
+    struct sgx_enclave *enclave,
+    uint64_t addr)
+{
+	vm_pindex_t pidx;
+	uint64_t va_page_idx;
+	uint64_t idx;
+	vm_object_t object;
+	int va_slot;
+	int ret;
+
+	object = enclave->object;
+
+	VM_OBJECT_ASSERT_WLOCKED(object);
+
+	pidx = OFF_TO_IDX(addr);
+
+	va_slot = pidx % SGX_VA_PAGE_SLOTS;
+	va_page_idx = pidx / SGX_VA_PAGE_SLOTS;
+	idx = - SGX_VA_PAGES_OFFS - va_page_idx;
+
+	ret = sgx_va_slot_init_by_index(sc, object, idx);
+
+	return (ret);
+}
+
+static int
+sgx_mem_find(struct sgx_softc *sc, uint64_t addr,
+    vm_map_entry_t *entry0, vm_object_t *object0)
+{
+	vm_map_t map;
+	vm_map_entry_t entry;
+	vm_object_t object;
+
+	map = &curproc->p_vmspace->vm_map;
+
+	vm_map_lock_read(map);
+	if (!vm_map_lookup_entry(map, addr, &entry)) {
+		vm_map_unlock_read(map);
+		dprintf("%s: Can't find enclave.\n", __func__);
+		return (EINVAL);
+	}
+
+	object = entry->object.vm_object;
+	if (object == NULL || object->handle == NULL) {
+		vm_map_unlock_read(map);
+		return (EINVAL);
+	}
+
+	if (object->type != OBJT_MGTDEVICE ||
+	    object->un_pager.devp.ops != &sgx_pg_ops) {
+		vm_map_unlock_read(map);
+		return (EINVAL);
+	}
+
+	vm_object_reference(object);
+
+	*object0 = object;
+	*entry0 = entry;
+	vm_map_unlock_read(map);
+
+	return (0);
+}
+
+static int
+sgx_enclave_find(struct sgx_softc *sc, uint64_t addr,
+    struct sgx_enclave **encl)
+{
+	struct sgx_vm_handle *vmh;
+	struct sgx_enclave *enclave;
+	vm_map_entry_t entry;
+	vm_object_t object;
+	int ret;
+
+	ret = sgx_mem_find(sc, addr, &entry, &object);
+	if (ret)
+		return (ret);
+
+	vmh = object->handle;
+	if (vmh == NULL) {
+		vm_object_deallocate(object);
+		return (EINVAL);
+	}
+
+	enclave = vmh->enclave;
+	if (enclave == NULL || enclave->object == NULL) {
+		vm_object_deallocate(object);
+		return (EINVAL);
+	}
+
+	*encl = enclave;
+
+	return (0);
+}
+
+static int
+sgx_enclave_alloc(struct sgx_softc *sc, struct secs *secs,
+    struct sgx_enclave **enclave0)
+{
+	struct sgx_enclave *enclave;
+
+	enclave = malloc(sizeof(struct sgx_enclave),
+	    M_SGX, M_WAITOK | M_ZERO);
+
+	enclave->base = secs->base;
+	enclave->size = secs->size;
+
+	*enclave0 = enclave;
+
+	return (0);
+}
+
+static void
+sgx_epc_page_remove(struct sgx_softc *sc,
+    struct epc_page *epc)
+{
+
+	mtx_lock(&sc->mtx_encls);
+	sgx_eremove((void *)epc->base);
+	mtx_unlock(&sc->mtx_encls);
+}
+
+static void
+sgx_page_remove(struct sgx_softc *sc, vm_page_t p)
+{
+	struct epc_page *epc;
+	vm_paddr_t pa;
+	uint64_t offs;
+
+	vm_page_lock(p);
+	vm_page_remove(p);
+	vm_page_unlock(p);
+
+	dprintf("%s: p->pidx %ld\n", __func__, p->pindex);
+
+	pa = VM_PAGE_TO_PHYS(p);
+	epc = &sc->epc_pages[0];
+	offs = (pa - epc->phys) / PAGE_SIZE;
+	epc = &sc->epc_pages[offs];
+
+	sgx_epc_page_remove(sc, epc);
+	sgx_put_epc_page(sc, epc);
+}
+
+static void
+sgx_enclave_remove(struct sgx_softc *sc,
+    struct sgx_enclave *enclave)
+{
+	vm_object_t object;
+	vm_page_t p, p_secs, p_next;
+
+	mtx_lock(&sc->mtx);
+	TAILQ_REMOVE(&sc->enclaves, enclave, next);
+	mtx_unlock(&sc->mtx);
+
+	object = enclave->object;
+
+	VM_OBJECT_WLOCK(object);
+
+	/*
+	 * First remove all the pages except SECS,
+	 * then remove SECS page.
+	 */
+	p_secs = NULL;
+	TAILQ_FOREACH_SAFE(p, &object->memq, listq, p_next) {
+		if (p->pindex == SGX_SECS_VM_OBJECT_INDEX) {
+			p_secs = p;
+			continue;
+		}
+		sgx_page_remove(sc, p);
+	}
+	/* Now remove SECS page */
+	if (p_secs != NULL)
+		sgx_page_remove(sc, p_secs);
+
+	KASSERT(TAILQ_EMPTY(&object->memq) == 1, ("not empty"));
+	KASSERT(object->resident_page_count == 0, ("count"));
+
+	VM_OBJECT_WUNLOCK(object);
+}
+
+static int
+sgx_measure_page(struct sgx_softc *sc, struct epc_page *secs,
+    struct epc_page *epc, uint16_t mrmask)
+{
+	int i, j;
+	int ret;
+
+	mtx_lock(&sc->mtx_encls);
+
+	for (i = 0, j = 1; i < PAGE_SIZE; i += 0x100, j <<= 1) {
+		if (!(j & mrmask))
+			continue;
+
+		ret = sgx_eextend((void *)secs->base,
+		    (void *)(epc->base + i));
+		if (ret == SGX_EFAULT) {
+			mtx_unlock(&sc->mtx_encls);
+			return (ret);
+		}
+	}
+
+	mtx_unlock(&sc->mtx_encls);
+
+	return (0);
+}
+
+static int
+sgx_secs_validate(struct sgx_softc *sc, struct secs *secs)
+{
+	struct secs_attr *attr;
+	int i;
+
+	if (secs->size == 0)
+		return (EINVAL);
+
+	/* BASEADDR must be naturally aligned on an SECS.SIZE boundary. */
+	if (secs->base & (secs->size - 1))
+		return (EINVAL);
+
+	/* SECS.SIZE must be at least 2 pages. */
+	if (secs->size < 2 * PAGE_SIZE)
+		return (EINVAL);
+
+	if ((secs->size & (secs->size - 1)) != 0)
+		return (EINVAL);
+
+	attr = &secs->attributes;
+
+	if (attr->reserved1 != 0 ||
+	    attr->reserved2 != 0 ||
+	    attr->reserved3 != 0)
+		return (EINVAL);
+
+	for (i = 0; i < SECS_ATTR_RSV4_SIZE; i++)
+		if (attr->reserved4[i])
+			return (EINVAL);
+
+	/*
+	 * IntelĀ® Software Guard Extensions Programming Reference
+	 * 6.7.2 Relevant Fields in Various Data Structures
+	 * 6.7.2.1 SECS.ATTRIBUTES.XFRM
+	 * XFRM[1:0] must be set to 0x3.
+	 */
+	if ((attr->xfrm & 0x3) != 0x3)
+		return (EINVAL);
+
+	if (!attr->mode64bit)
+		return (EINVAL);
+
+	if (secs->size > sc->enclave_size_max)
+		return (EINVAL);
+
+	for (i = 0; i < SECS_RSV1_SIZE; i++)
+		if (secs->reserved1[i])
+			return (EINVAL);
+
+	for (i = 0; i < SECS_RSV2_SIZE; i++)
+		if (secs->reserved2[i])
+			return (EINVAL);
+
+	for (i = 0; i < SECS_RSV3_SIZE; i++)
+		if (secs->reserved3[i])
+			return (EINVAL);
+
+	for (i = 0; i < SECS_RSV4_SIZE; i++)
+		if (secs->reserved4[i])
+			return (EINVAL);
+
+	return (0);
+}
+
+static int
+sgx_tcs_validate(struct tcs *tcs)
+{
+	int i;
+
+	if ((tcs->flags) ||
+	    (tcs->ossa & (PAGE_SIZE - 1)) ||
+	    (tcs->ofsbasgx & (PAGE_SIZE - 1)) ||
+	    (tcs->ogsbasgx & (PAGE_SIZE - 1)) ||
+	    ((tcs->fslimit & 0xfff) != 0xfff) ||
+	    ((tcs->gslimit & 0xfff) != 0xfff))
+		return (EINVAL);
+
+	for (i = 0; i < nitems(tcs->reserved3); i++)
+		if (tcs->reserved3[i])
+			return (EINVAL);
+
+	return (0);
+}
+
+static void
+sgx_tcs_dump(struct sgx_softc *sc, struct tcs *t)
+{
+
+	dprintf("t->flags %lx\n", t->flags);
+	dprintf("t->ossa %lx\n", t->ossa);
+	dprintf("t->cssa %x\n", t->cssa);
+	dprintf("t->nssa %x\n", t->nssa);
+	dprintf("t->oentry %lx\n", t->oentry);
+	dprintf("t->ofsbasgx %lx\n", t->ofsbasgx);
+	dprintf("t->ogsbasgx %lx\n", t->ogsbasgx);
+	dprintf("t->fslimit %x\n", t->fslimit);
+	dprintf("t->gslimit %x\n", t->gslimit);
+}
+
+static int
+sgx_pg_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
+    vm_ooffset_t foff, struct ucred *cred, u_short *color)
+{
+	struct sgx_vm_handle *vmh;
+
+	vmh = handle;
+	if (vmh == NULL) {
+		dprintf("%s: vmh not found.\n", __func__);
+		return (0);
+	}
+
+	dprintf("%s: vmh->base %lx foff 0x%lx size 0x%lx\n",
+	    __func__, vmh->base, foff, size);
+
+	return (0);
+}
+
+static void
+sgx_pg_dtor(void *handle)
+{
+	struct sgx_vm_handle *vmh;
+	struct sgx_softc *sc;
+
+	vmh = handle;
+	if (vmh == NULL) {
+		dprintf("%s: vmh not found.\n", __func__);
+		return;
+	}
+
+	sc = vmh->sc;
+	if (sc == NULL) {
+		dprintf("%s: sc is NULL\n", __func__);
+		return;
+	}
+
+	if (vmh->enclave == NULL) {
+		dprintf("%s: Enclave not found.\n", __func__);
+		return;
+	}
+
+	sgx_enclave_remove(sc, vmh->enclave);
+
+	free(vmh->enclave, M_SGX);
+	free(vmh, M_SGX);
+}
+
+static int
+sgx_pg_fault(vm_object_t object, vm_ooffset_t offset,
+    int prot, vm_page_t *mres)
+{
+
+	/*
+	 * The purpose of this trivial handler is to handle the race
+	 * when user tries to access mmaped region before or during
+	 * enclave creation ioctl calls.
+	 */
+
+	dprintf("%s: offset 0x%lx\n", __func__, offset);
+
+	return (VM_PAGER_FAIL);
+}
+
+static struct cdev_pager_ops sgx_pg_ops = {
+	.cdev_pg_ctor = sgx_pg_ctor,
+	.cdev_pg_dtor = sgx_pg_dtor,
+	.cdev_pg_fault = sgx_pg_fault,
+};
+
+
+static void
+sgx_insert_epc_page_by_index(vm_page_t page, vm_object_t object,
+    vm_pindex_t pidx)
+{
+
+	VM_OBJECT_ASSERT_WLOCKED(object);
+
+	vm_page_insert(page, object, pidx);
+	page->valid = VM_PAGE_BITS_ALL;
+}
+
+static void
+sgx_insert_epc_page(struct sgx_enclave *enclave,
+    struct epc_page *epc, uint64_t addr)
+{
+	vm_pindex_t pidx;
+	vm_page_t page;
+
+	VM_OBJECT_ASSERT_WLOCKED(enclave->object);
+
+	pidx = OFF_TO_IDX(addr);
+	page = PHYS_TO_VM_PAGE(epc->phys);
+
+	sgx_insert_epc_page_by_index(page, enclave->object, pidx);
+}
+
+static int
+sgx_ioctl_create(struct sgx_softc *sc, struct sgx_enclave_create *param)
+{
+	struct sgx_vm_handle *vmh;
+	vm_map_entry_t entry;
+	vm_page_t p;
+	struct page_info pginfo;
+	struct secinfo secinfo;
+	struct sgx_enclave *enclave;
+	struct epc_page *epc;
+	struct secs *secs;
+	vm_object_t object;
+	vm_page_t page;
+	int ret;
+
+	epc = NULL;
+	secs = NULL;
+	enclave = NULL;
+	object = NULL;
+
+	/* SGX Enclave Control Structure (SECS) */
+	secs = malloc(PAGE_SIZE, M_SGX, M_WAITOK | M_ZERO);
+	ret = copyin((void *)param->src, secs, sizeof(struct secs));
+	if (ret) {
+		dprintf("%s: Can't copy SECS.\n", __func__);
+		goto error;
+	}
+
+	ret = sgx_secs_validate(sc, secs);
+	if (ret) {
+		dprintf("%s: SECS validation failed.\n", __func__);
+		goto error;
+	}
+
+	ret = sgx_mem_find(sc, secs->base, &entry, &object);
+	if (ret) {
+		dprintf("%s: Can't find vm_map.\n", __func__);
+		goto error;
+	}
+
+	vmh = object->handle;
+	if (!vmh) {
+		dprintf("%s: Can't find vmh.\n", __func__);
+		ret = ENXIO;
+		goto error;
+	}
+
+	dprintf("%s: entry start %lx offset %lx\n",
+	    __func__, entry->start, entry->offset);
+	vmh->base = (entry->start - entry->offset);
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201708161038.v7GAc6jQ077852>