xref: /freebsd/sys/amd64/sgx/sgx.c (revision faaa687646d50507f6e64bbedde38de167393f45)
12164af29SRuslan Bukin /*-
22164af29SRuslan Bukin  * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
32164af29SRuslan Bukin  * All rights reserved.
42164af29SRuslan Bukin  *
52164af29SRuslan Bukin  * This software was developed by BAE Systems, the University of Cambridge
62164af29SRuslan Bukin  * Computer Laboratory, and Memorial University under DARPA/AFRL contract
72164af29SRuslan Bukin  * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
82164af29SRuslan Bukin  * (TC) research program.
92164af29SRuslan Bukin  *
102164af29SRuslan Bukin  * Redistribution and use in source and binary forms, with or without
112164af29SRuslan Bukin  * modification, are permitted provided that the following conditions
122164af29SRuslan Bukin  * are met:
132164af29SRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
142164af29SRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
152164af29SRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
162164af29SRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
172164af29SRuslan Bukin  *    documentation and/or other materials provided with the distribution.
182164af29SRuslan Bukin  *
192164af29SRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
202164af29SRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
212164af29SRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
222164af29SRuslan Bukin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
232164af29SRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
242164af29SRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
252164af29SRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
262164af29SRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
272164af29SRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
282164af29SRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
292164af29SRuslan Bukin  * SUCH DAMAGE.
302164af29SRuslan Bukin  */
312164af29SRuslan Bukin 
322164af29SRuslan Bukin /*
332164af29SRuslan Bukin  * Design overview.
342164af29SRuslan Bukin  *
352164af29SRuslan Bukin  * The driver provides character device for mmap(2) and ioctl(2) system calls
362164af29SRuslan Bukin  * allowing user to manage isolated compartments ("enclaves") in user VA space.
372164af29SRuslan Bukin  *
382164af29SRuslan Bukin  * The driver duties is EPC pages management, enclave management, user data
392164af29SRuslan Bukin  * validation.
402164af29SRuslan Bukin  *
412164af29SRuslan Bukin  * This driver requires Intel SGX support from hardware.
422164af29SRuslan Bukin  *
432164af29SRuslan Bukin  * /dev/sgx:
442164af29SRuslan Bukin  *    .mmap:
452164af29SRuslan Bukin  *        sgx_mmap_single() allocates VM object with following pager
462164af29SRuslan Bukin  *        operations:
472164af29SRuslan Bukin  *              a) sgx_pg_ctor():
482164af29SRuslan Bukin  *                  VM object constructor does nothing
492164af29SRuslan Bukin  *              b) sgx_pg_dtor():
502164af29SRuslan Bukin  *                  VM object destructor destroys the SGX enclave associated
512164af29SRuslan Bukin  *                  with the object: it frees all the EPC pages allocated for
522164af29SRuslan Bukin  *                  enclave and removes the enclave.
532164af29SRuslan Bukin  *              c) sgx_pg_fault():
542164af29SRuslan Bukin  *                  VM object fault handler does nothing
552164af29SRuslan Bukin  *
562164af29SRuslan Bukin  *    .ioctl:
572164af29SRuslan Bukin  *        sgx_ioctl():
582164af29SRuslan Bukin  *               a) SGX_IOC_ENCLAVE_CREATE
592164af29SRuslan Bukin  *                   Adds Enclave SECS page: initial step of enclave creation.
602164af29SRuslan Bukin  *               b) SGX_IOC_ENCLAVE_ADD_PAGE
612164af29SRuslan Bukin  *                   Adds TCS, REG pages to the enclave.
622164af29SRuslan Bukin  *               c) SGX_IOC_ENCLAVE_INIT
632164af29SRuslan Bukin  *                   Finalizes enclave creation.
642164af29SRuslan Bukin  *
652164af29SRuslan Bukin  * Enclave lifecycle:
662164af29SRuslan Bukin  *          .-- ECREATE  -- Add SECS page
672164af29SRuslan Bukin  *   Kernel |   EADD     -- Add TCS, REG pages
682164af29SRuslan Bukin  *    space |   EEXTEND  -- Measure the page (take unique hash)
692164af29SRuslan Bukin  *    ENCLS |   EPA      -- Allocate version array page
702164af29SRuslan Bukin  *          '-- EINIT    -- Finalize enclave creation
712164af29SRuslan Bukin  *   User   .-- EENTER   -- Go to entry point of enclave
722164af29SRuslan Bukin  *    space |   EEXIT    -- Exit back to main application
732164af29SRuslan Bukin  *    ENCLU '-- ERESUME  -- Resume enclave execution (e.g. after exception)
742164af29SRuslan Bukin  *
752164af29SRuslan Bukin  * Enclave lifecycle from driver point of view:
762164af29SRuslan Bukin  *  1) User calls mmap() on /dev/sgx: we allocate a VM object
772164af29SRuslan Bukin  *  2) User calls ioctl SGX_IOC_ENCLAVE_CREATE: we look for the VM object
782164af29SRuslan Bukin  *     associated with user process created on step 1, create SECS physical
792164af29SRuslan Bukin  *     page and store it in enclave's VM object queue by special index
802164af29SRuslan Bukin  *     SGX_SECS_VM_OBJECT_INDEX.
812164af29SRuslan Bukin  *  3) User calls ioctl SGX_IOC_ENCLAVE_ADD_PAGE: we look for enclave created
822164af29SRuslan Bukin  *     on step 2, create TCS or REG physical page and map it to specified by
832164af29SRuslan Bukin  *     user address of enclave VM object.
842164af29SRuslan Bukin  *  4) User finalizes enclave creation with ioctl SGX_IOC_ENCLAVE_INIT call.
852164af29SRuslan Bukin  *  5) User can freely enter to and exit from enclave using ENCLU instructions
862164af29SRuslan Bukin  *     from userspace: the driver does nothing here.
872164af29SRuslan Bukin  *  6) User proceed munmap(2) system call (or the process with enclave dies):
882164af29SRuslan Bukin  *     we destroy the enclave associated with the object.
892164af29SRuslan Bukin  *
902164af29SRuslan Bukin  * EPC page types and their indexes in VM object queue:
912164af29SRuslan Bukin  *   - PT_SECS index is special and equals SGX_SECS_VM_OBJECT_INDEX (-1);
922164af29SRuslan Bukin  *   - PT_TCS and PT_REG indexes are specified by user in addr field of ioctl
932164af29SRuslan Bukin  *     request data and determined as follows:
942164af29SRuslan Bukin  *       pidx = OFF_TO_IDX(addp->addr - vmh->base);
952164af29SRuslan Bukin  *   - PT_VA index is special, created for PT_REG, PT_TCS and PT_SECS pages
962164af29SRuslan Bukin  *     and determined by formula:
972164af29SRuslan Bukin  *       va_page_idx = - SGX_VA_PAGES_OFFS - (page_idx / SGX_VA_PAGE_SLOTS);
982164af29SRuslan Bukin  *     PT_VA page can hold versions of up to 512 pages, and slot for each
992164af29SRuslan Bukin  *     page in PT_VA page is determined as follows:
1002164af29SRuslan Bukin  *       va_slot_idx = page_idx % SGX_VA_PAGE_SLOTS;
1012164af29SRuslan Bukin  *   - PT_TRIM is unused.
1022164af29SRuslan Bukin  *
1032164af29SRuslan Bukin  * Locking:
1042164af29SRuslan Bukin  *    SGX ENCLS set of instructions have limitations on concurrency:
1052164af29SRuslan Bukin  *    some instructions can't be executed same time on different CPUs.
1062164af29SRuslan Bukin  *    We use sc->mtx_encls lock around them to prevent concurrent execution.
1072164af29SRuslan Bukin  *    sc->mtx lock is used to manage list of created enclaves and the state of
1082164af29SRuslan Bukin  *    SGX driver.
1092164af29SRuslan Bukin  *
1102164af29SRuslan Bukin  * Eviction of EPC pages:
1112164af29SRuslan Bukin  *    Eviction support is not implemented in this driver, however the driver
1122164af29SRuslan Bukin  *    manages VA (version array) pages: it allocates a VA slot for each EPC
1132164af29SRuslan Bukin  *    page. This will be required for eviction support in future.
1142164af29SRuslan Bukin  *    VA pages and slots are currently unused.
1152164af29SRuslan Bukin  *
1162164af29SRuslan Bukin  * Intel® 64 and IA-32 Architectures Software Developer's Manual
1172164af29SRuslan Bukin  * https://software.intel.com/en-us/articles/intel-sdm
1182164af29SRuslan Bukin  */
1192164af29SRuslan Bukin 
1202164af29SRuslan Bukin #include <sys/param.h>
1212164af29SRuslan Bukin #include <sys/systm.h>
1222164af29SRuslan Bukin #include <sys/ioccom.h>
1232164af29SRuslan Bukin #include <sys/malloc.h>
1242164af29SRuslan Bukin #include <sys/kernel.h>
1252164af29SRuslan Bukin #include <sys/lock.h>
1262164af29SRuslan Bukin #include <sys/mutex.h>
1272164af29SRuslan Bukin #include <sys/rwlock.h>
1282164af29SRuslan Bukin #include <sys/conf.h>
1292164af29SRuslan Bukin #include <sys/module.h>
1302164af29SRuslan Bukin #include <sys/proc.h>
1312164af29SRuslan Bukin #include <sys/vmem.h>
1322164af29SRuslan Bukin #include <sys/vmmeter.h>
1332164af29SRuslan Bukin 
1342164af29SRuslan Bukin #include <vm/vm.h>
1352164af29SRuslan Bukin #include <vm/vm_param.h>
1362164af29SRuslan Bukin #include <vm/vm_extern.h>
1372164af29SRuslan Bukin #include <vm/vm_kern.h>
1382164af29SRuslan Bukin #include <vm/vm_page.h>
1392164af29SRuslan Bukin #include <vm/vm_map.h>
1402164af29SRuslan Bukin #include <vm/vm_object.h>
1412164af29SRuslan Bukin #include <vm/vm_pager.h>
1422164af29SRuslan Bukin #include <vm/vm_phys.h>
1432164af29SRuslan Bukin #include <vm/vm_radix.h>
1442164af29SRuslan Bukin #include <vm/pmap.h>
1452164af29SRuslan Bukin 
1462164af29SRuslan Bukin #include <machine/md_var.h>
1472164af29SRuslan Bukin #include <machine/specialreg.h>
1482164af29SRuslan Bukin #include <machine/cpufunc.h>
1492164af29SRuslan Bukin #include <machine/sgx.h>
1502164af29SRuslan Bukin #include <machine/sgxreg.h>
1512164af29SRuslan Bukin 
1522164af29SRuslan Bukin #include <amd64/sgx/sgxvar.h>
1532164af29SRuslan Bukin 
1547dea7660SRuslan Bukin #define	SGX_DEBUG
1557dea7660SRuslan Bukin #undef	SGX_DEBUG
1562164af29SRuslan Bukin 
1577dea7660SRuslan Bukin #ifdef	SGX_DEBUG
1582164af29SRuslan Bukin #define	dprintf(fmt, ...)	printf(fmt, ##__VA_ARGS__)
1592164af29SRuslan Bukin #else
1602164af29SRuslan Bukin #define	dprintf(fmt, ...)
1612164af29SRuslan Bukin #endif
1622164af29SRuslan Bukin 
1632164af29SRuslan Bukin static struct cdev_pager_ops sgx_pg_ops;
1642164af29SRuslan Bukin struct sgx_softc sgx_sc;
1652164af29SRuslan Bukin 
1662164af29SRuslan Bukin static int
sgx_get_epc_page(struct sgx_softc * sc,struct epc_page ** epc)1672164af29SRuslan Bukin sgx_get_epc_page(struct sgx_softc *sc, struct epc_page **epc)
1682164af29SRuslan Bukin {
1692164af29SRuslan Bukin 	vmem_addr_t addr;
1702164af29SRuslan Bukin 	int i;
1712164af29SRuslan Bukin 
1722164af29SRuslan Bukin 	if (vmem_alloc(sc->vmem_epc, PAGE_SIZE, M_FIRSTFIT | M_NOWAIT,
1732164af29SRuslan Bukin 	    &addr) == 0) {
1742164af29SRuslan Bukin 		i = (addr - sc->epc_base) / PAGE_SIZE;
1752164af29SRuslan Bukin 		*epc = &sc->epc_pages[i];
1762164af29SRuslan Bukin 		return (0);
1772164af29SRuslan Bukin 	}
1782164af29SRuslan Bukin 
1792164af29SRuslan Bukin 	return (ENOMEM);
1802164af29SRuslan Bukin }
1812164af29SRuslan Bukin 
1822164af29SRuslan Bukin static void
sgx_put_epc_page(struct sgx_softc * sc,struct epc_page * epc)1832164af29SRuslan Bukin sgx_put_epc_page(struct sgx_softc *sc, struct epc_page *epc)
1842164af29SRuslan Bukin {
1852164af29SRuslan Bukin 	vmem_addr_t addr;
1862164af29SRuslan Bukin 
1872164af29SRuslan Bukin 	if (epc == NULL)
1882164af29SRuslan Bukin 		return;
1892164af29SRuslan Bukin 
1902164af29SRuslan Bukin 	addr = (epc->index * PAGE_SIZE) + sc->epc_base;
1912164af29SRuslan Bukin 	vmem_free(sc->vmem_epc, addr, PAGE_SIZE);
1922164af29SRuslan Bukin }
1932164af29SRuslan Bukin 
1942164af29SRuslan Bukin static int
sgx_va_slot_init_by_index(struct sgx_softc * sc,vm_object_t object,uint64_t idx)1952164af29SRuslan Bukin sgx_va_slot_init_by_index(struct sgx_softc *sc, vm_object_t object,
1962164af29SRuslan Bukin     uint64_t idx)
1972164af29SRuslan Bukin {
1982164af29SRuslan Bukin 	struct epc_page *epc;
1992164af29SRuslan Bukin 	vm_page_t page;
2002164af29SRuslan Bukin 	vm_page_t p;
2012164af29SRuslan Bukin 	int ret;
2022164af29SRuslan Bukin 
2032164af29SRuslan Bukin 	VM_OBJECT_ASSERT_WLOCKED(object);
2042164af29SRuslan Bukin 
2052164af29SRuslan Bukin 	p = vm_page_lookup(object, idx);
2062164af29SRuslan Bukin 	if (p == NULL) {
2072164af29SRuslan Bukin 		ret = sgx_get_epc_page(sc, &epc);
2082164af29SRuslan Bukin 		if (ret) {
2092164af29SRuslan Bukin 			dprintf("%s: No free EPC pages available.\n",
2102164af29SRuslan Bukin 			    __func__);
2112164af29SRuslan Bukin 			return (ret);
2122164af29SRuslan Bukin 		}
2132164af29SRuslan Bukin 
2142164af29SRuslan Bukin 		mtx_lock(&sc->mtx_encls);
2152164af29SRuslan Bukin 		sgx_epa((void *)epc->base);
2162164af29SRuslan Bukin 		mtx_unlock(&sc->mtx_encls);
2172164af29SRuslan Bukin 
2182164af29SRuslan Bukin 		page = PHYS_TO_VM_PAGE(epc->phys);
2192164af29SRuslan Bukin 
2202164af29SRuslan Bukin 		page->valid = VM_PAGE_BITS_ALL;
2210012f373SJeff Roberson 		vm_page_insert(page, object, idx);
2222164af29SRuslan Bukin 	}
2232164af29SRuslan Bukin 
2242164af29SRuslan Bukin 	return (0);
2252164af29SRuslan Bukin }
2262164af29SRuslan Bukin 
2272164af29SRuslan Bukin static int
sgx_va_slot_init(struct sgx_softc * sc,struct sgx_enclave * enclave,uint64_t addr)2282164af29SRuslan Bukin sgx_va_slot_init(struct sgx_softc *sc,
2292164af29SRuslan Bukin     struct sgx_enclave *enclave,
2302164af29SRuslan Bukin     uint64_t addr)
2312164af29SRuslan Bukin {
2322164af29SRuslan Bukin 	vm_pindex_t pidx;
2332164af29SRuslan Bukin 	uint64_t va_page_idx;
2342164af29SRuslan Bukin 	uint64_t idx;
2352164af29SRuslan Bukin 	vm_object_t object;
2362164af29SRuslan Bukin 	int ret;
2372164af29SRuslan Bukin 
2382164af29SRuslan Bukin 	object = enclave->object;
2392164af29SRuslan Bukin 
2402164af29SRuslan Bukin 	VM_OBJECT_ASSERT_WLOCKED(object);
2412164af29SRuslan Bukin 
2422164af29SRuslan Bukin 	pidx = OFF_TO_IDX(addr);
2432164af29SRuslan Bukin 
2442164af29SRuslan Bukin 	va_page_idx = pidx / SGX_VA_PAGE_SLOTS;
2452164af29SRuslan Bukin 	idx = - SGX_VA_PAGES_OFFS - va_page_idx;
2462164af29SRuslan Bukin 
2472164af29SRuslan Bukin 	ret = sgx_va_slot_init_by_index(sc, object, idx);
2482164af29SRuslan Bukin 
2492164af29SRuslan Bukin 	return (ret);
2502164af29SRuslan Bukin }
2512164af29SRuslan Bukin 
2522164af29SRuslan Bukin static int
sgx_mem_find(struct sgx_softc * sc,uint64_t addr,vm_map_entry_t * entry0,vm_object_t * object0)2532164af29SRuslan Bukin sgx_mem_find(struct sgx_softc *sc, uint64_t addr,
2542164af29SRuslan Bukin     vm_map_entry_t *entry0, vm_object_t *object0)
2552164af29SRuslan Bukin {
2562164af29SRuslan Bukin 	vm_map_t map;
2572164af29SRuslan Bukin 	vm_map_entry_t entry;
2582164af29SRuslan Bukin 	vm_object_t object;
2592164af29SRuslan Bukin 
2602164af29SRuslan Bukin 	map = &curproc->p_vmspace->vm_map;
2612164af29SRuslan Bukin 
2622164af29SRuslan Bukin 	vm_map_lock_read(map);
2632164af29SRuslan Bukin 	if (!vm_map_lookup_entry(map, addr, &entry)) {
2642164af29SRuslan Bukin 		vm_map_unlock_read(map);
2652164af29SRuslan Bukin 		dprintf("%s: Can't find enclave.\n", __func__);
2662164af29SRuslan Bukin 		return (EINVAL);
2672164af29SRuslan Bukin 	}
2682164af29SRuslan Bukin 
2692164af29SRuslan Bukin 	object = entry->object.vm_object;
2702164af29SRuslan Bukin 	if (object == NULL || object->handle == NULL) {
2712164af29SRuslan Bukin 		vm_map_unlock_read(map);
2722164af29SRuslan Bukin 		return (EINVAL);
2732164af29SRuslan Bukin 	}
2742164af29SRuslan Bukin 
2752164af29SRuslan Bukin 	if (object->type != OBJT_MGTDEVICE ||
2762164af29SRuslan Bukin 	    object->un_pager.devp.ops != &sgx_pg_ops) {
2772164af29SRuslan Bukin 		vm_map_unlock_read(map);
2782164af29SRuslan Bukin 		return (EINVAL);
2792164af29SRuslan Bukin 	}
2802164af29SRuslan Bukin 
2812164af29SRuslan Bukin 	vm_object_reference(object);
2822164af29SRuslan Bukin 
2832164af29SRuslan Bukin 	*object0 = object;
2842164af29SRuslan Bukin 	*entry0 = entry;
2852164af29SRuslan Bukin 	vm_map_unlock_read(map);
2862164af29SRuslan Bukin 
2872164af29SRuslan Bukin 	return (0);
2882164af29SRuslan Bukin }
2892164af29SRuslan Bukin 
2902164af29SRuslan Bukin static int
sgx_enclave_find(struct sgx_softc * sc,uint64_t addr,struct sgx_enclave ** encl)2912164af29SRuslan Bukin sgx_enclave_find(struct sgx_softc *sc, uint64_t addr,
2922164af29SRuslan Bukin     struct sgx_enclave **encl)
2932164af29SRuslan Bukin {
2942164af29SRuslan Bukin 	struct sgx_vm_handle *vmh;
2952164af29SRuslan Bukin 	struct sgx_enclave *enclave;
2962164af29SRuslan Bukin 	vm_map_entry_t entry;
2972164af29SRuslan Bukin 	vm_object_t object;
2982164af29SRuslan Bukin 	int ret;
2992164af29SRuslan Bukin 
3002164af29SRuslan Bukin 	ret = sgx_mem_find(sc, addr, &entry, &object);
3012164af29SRuslan Bukin 	if (ret)
3022164af29SRuslan Bukin 		return (ret);
3032164af29SRuslan Bukin 
3042164af29SRuslan Bukin 	vmh = object->handle;
3052164af29SRuslan Bukin 	if (vmh == NULL) {
3062164af29SRuslan Bukin 		vm_object_deallocate(object);
3072164af29SRuslan Bukin 		return (EINVAL);
3082164af29SRuslan Bukin 	}
3092164af29SRuslan Bukin 
3102164af29SRuslan Bukin 	enclave = vmh->enclave;
3112164af29SRuslan Bukin 	if (enclave == NULL || enclave->object == NULL) {
3122164af29SRuslan Bukin 		vm_object_deallocate(object);
3132164af29SRuslan Bukin 		return (EINVAL);
3142164af29SRuslan Bukin 	}
3152164af29SRuslan Bukin 
3162164af29SRuslan Bukin 	*encl = enclave;
3172164af29SRuslan Bukin 
3182164af29SRuslan Bukin 	return (0);
3192164af29SRuslan Bukin }
3202164af29SRuslan Bukin 
3212164af29SRuslan Bukin static int
sgx_enclave_alloc(struct sgx_softc * sc,struct secs * secs,struct sgx_enclave ** enclave0)3222164af29SRuslan Bukin sgx_enclave_alloc(struct sgx_softc *sc, struct secs *secs,
3232164af29SRuslan Bukin     struct sgx_enclave **enclave0)
3242164af29SRuslan Bukin {
3252164af29SRuslan Bukin 	struct sgx_enclave *enclave;
3262164af29SRuslan Bukin 
3272164af29SRuslan Bukin 	enclave = malloc(sizeof(struct sgx_enclave),
3282164af29SRuslan Bukin 	    M_SGX, M_WAITOK | M_ZERO);
3292164af29SRuslan Bukin 
3302164af29SRuslan Bukin 	enclave->base = secs->base;
3312164af29SRuslan Bukin 	enclave->size = secs->size;
3322164af29SRuslan Bukin 
3332164af29SRuslan Bukin 	*enclave0 = enclave;
3342164af29SRuslan Bukin 
3352164af29SRuslan Bukin 	return (0);
3362164af29SRuslan Bukin }
3372164af29SRuslan Bukin 
3382164af29SRuslan Bukin static void
sgx_epc_page_remove(struct sgx_softc * sc,struct epc_page * epc)3392164af29SRuslan Bukin sgx_epc_page_remove(struct sgx_softc *sc,
3402164af29SRuslan Bukin     struct epc_page *epc)
3412164af29SRuslan Bukin {
3422164af29SRuslan Bukin 
3432164af29SRuslan Bukin 	mtx_lock(&sc->mtx_encls);
3442164af29SRuslan Bukin 	sgx_eremove((void *)epc->base);
3452164af29SRuslan Bukin 	mtx_unlock(&sc->mtx_encls);
3462164af29SRuslan Bukin }
3472164af29SRuslan Bukin 
3482164af29SRuslan Bukin static void
sgx_page_remove(struct sgx_softc * sc,vm_page_t p)3492164af29SRuslan Bukin sgx_page_remove(struct sgx_softc *sc, vm_page_t p)
3502164af29SRuslan Bukin {
3512164af29SRuslan Bukin 	struct epc_page *epc;
3522164af29SRuslan Bukin 	vm_paddr_t pa;
3532164af29SRuslan Bukin 	uint64_t offs;
3542164af29SRuslan Bukin 
3550fd977b3SMark Johnston 	(void)vm_page_remove(p);
3562164af29SRuslan Bukin 
3572164af29SRuslan Bukin 	dprintf("%s: p->pidx %ld\n", __func__, p->pindex);
3582164af29SRuslan Bukin 
3592164af29SRuslan Bukin 	pa = VM_PAGE_TO_PHYS(p);
3602164af29SRuslan Bukin 	epc = &sc->epc_pages[0];
3612164af29SRuslan Bukin 	offs = (pa - epc->phys) / PAGE_SIZE;
3622164af29SRuslan Bukin 	epc = &sc->epc_pages[offs];
3632164af29SRuslan Bukin 
3642164af29SRuslan Bukin 	sgx_epc_page_remove(sc, epc);
3652164af29SRuslan Bukin 	sgx_put_epc_page(sc, epc);
3662164af29SRuslan Bukin }
3672164af29SRuslan Bukin 
3682164af29SRuslan Bukin static void
sgx_enclave_remove(struct sgx_softc * sc,struct sgx_enclave * enclave)3692164af29SRuslan Bukin sgx_enclave_remove(struct sgx_softc *sc,
3702164af29SRuslan Bukin     struct sgx_enclave *enclave)
3712164af29SRuslan Bukin {
3722164af29SRuslan Bukin 	vm_object_t object;
3732164af29SRuslan Bukin 	vm_page_t p, p_secs, p_next;
3742164af29SRuslan Bukin 
3752164af29SRuslan Bukin 	mtx_lock(&sc->mtx);
3762164af29SRuslan Bukin 	TAILQ_REMOVE(&sc->enclaves, enclave, next);
3772164af29SRuslan Bukin 	mtx_unlock(&sc->mtx);
3782164af29SRuslan Bukin 
3792164af29SRuslan Bukin 	object = enclave->object;
3802164af29SRuslan Bukin 
3812164af29SRuslan Bukin 	VM_OBJECT_WLOCK(object);
3822164af29SRuslan Bukin 
3832164af29SRuslan Bukin 	/*
3842164af29SRuslan Bukin 	 * First remove all the pages except SECS,
3852164af29SRuslan Bukin 	 * then remove SECS page.
3862164af29SRuslan Bukin 	 */
3870f9e06e1SJeff Roberson restart:
3882164af29SRuslan Bukin 	TAILQ_FOREACH_SAFE(p, &object->memq, listq, p_next) {
3890f9e06e1SJeff Roberson 		if (p->pindex == SGX_SECS_VM_OBJECT_INDEX)
3902164af29SRuslan Bukin 			continue;
3910f9e06e1SJeff Roberson 		if (vm_page_busy_acquire(p, VM_ALLOC_WAITFAIL) == 0)
3920f9e06e1SJeff Roberson 			goto restart;
3932164af29SRuslan Bukin 		sgx_page_remove(sc, p);
3942164af29SRuslan Bukin 	}
3950f9e06e1SJeff Roberson 	p_secs = vm_page_grab(object, SGX_SECS_VM_OBJECT_INDEX,
3960f9e06e1SJeff Roberson 	    VM_ALLOC_NOCREAT);
3972164af29SRuslan Bukin 	/* Now remove SECS page */
3982164af29SRuslan Bukin 	if (p_secs != NULL)
3992164af29SRuslan Bukin 		sgx_page_remove(sc, p_secs);
4002164af29SRuslan Bukin 
4012164af29SRuslan Bukin 	KASSERT(TAILQ_EMPTY(&object->memq) == 1, ("not empty"));
4022164af29SRuslan Bukin 	KASSERT(object->resident_page_count == 0, ("count"));
4032164af29SRuslan Bukin 
4042164af29SRuslan Bukin 	VM_OBJECT_WUNLOCK(object);
4052164af29SRuslan Bukin }
4062164af29SRuslan Bukin 
4072164af29SRuslan Bukin static int
sgx_measure_page(struct sgx_softc * sc,struct epc_page * secs,struct epc_page * epc,uint16_t mrmask)4082164af29SRuslan Bukin sgx_measure_page(struct sgx_softc *sc, struct epc_page *secs,
4092164af29SRuslan Bukin     struct epc_page *epc, uint16_t mrmask)
4102164af29SRuslan Bukin {
4112164af29SRuslan Bukin 	int i, j;
4122164af29SRuslan Bukin 	int ret;
4132164af29SRuslan Bukin 
4142164af29SRuslan Bukin 	mtx_lock(&sc->mtx_encls);
4152164af29SRuslan Bukin 
4162164af29SRuslan Bukin 	for (i = 0, j = 1; i < PAGE_SIZE; i += 0x100, j <<= 1) {
4172164af29SRuslan Bukin 		if (!(j & mrmask))
4182164af29SRuslan Bukin 			continue;
4192164af29SRuslan Bukin 
4202164af29SRuslan Bukin 		ret = sgx_eextend((void *)secs->base,
4212164af29SRuslan Bukin 		    (void *)(epc->base + i));
4222164af29SRuslan Bukin 		if (ret == SGX_EFAULT) {
4232164af29SRuslan Bukin 			mtx_unlock(&sc->mtx_encls);
4242164af29SRuslan Bukin 			return (ret);
4252164af29SRuslan Bukin 		}
4262164af29SRuslan Bukin 	}
4272164af29SRuslan Bukin 
4282164af29SRuslan Bukin 	mtx_unlock(&sc->mtx_encls);
4292164af29SRuslan Bukin 
4302164af29SRuslan Bukin 	return (0);
4312164af29SRuslan Bukin }
4322164af29SRuslan Bukin 
4332164af29SRuslan Bukin static int
sgx_secs_validate(struct sgx_softc * sc,struct secs * secs)4342164af29SRuslan Bukin sgx_secs_validate(struct sgx_softc *sc, struct secs *secs)
4352164af29SRuslan Bukin {
4362164af29SRuslan Bukin 	struct secs_attr *attr;
4372164af29SRuslan Bukin 	int i;
4382164af29SRuslan Bukin 
4392164af29SRuslan Bukin 	if (secs->size == 0)
4402164af29SRuslan Bukin 		return (EINVAL);
4412164af29SRuslan Bukin 
4422164af29SRuslan Bukin 	/* BASEADDR must be naturally aligned on an SECS.SIZE boundary. */
4432164af29SRuslan Bukin 	if (secs->base & (secs->size - 1))
4442164af29SRuslan Bukin 		return (EINVAL);
4452164af29SRuslan Bukin 
4462164af29SRuslan Bukin 	/* SECS.SIZE must be at least 2 pages. */
4472164af29SRuslan Bukin 	if (secs->size < 2 * PAGE_SIZE)
4482164af29SRuslan Bukin 		return (EINVAL);
4492164af29SRuslan Bukin 
4502164af29SRuslan Bukin 	if ((secs->size & (secs->size - 1)) != 0)
4512164af29SRuslan Bukin 		return (EINVAL);
4522164af29SRuslan Bukin 
4532164af29SRuslan Bukin 	attr = &secs->attributes;
4542164af29SRuslan Bukin 
4552164af29SRuslan Bukin 	if (attr->reserved1 != 0 ||
4562164af29SRuslan Bukin 	    attr->reserved2 != 0 ||
4572164af29SRuslan Bukin 	    attr->reserved3 != 0)
4582164af29SRuslan Bukin 		return (EINVAL);
4592164af29SRuslan Bukin 
4602164af29SRuslan Bukin 	for (i = 0; i < SECS_ATTR_RSV4_SIZE; i++)
4612164af29SRuslan Bukin 		if (attr->reserved4[i])
4622164af29SRuslan Bukin 			return (EINVAL);
4632164af29SRuslan Bukin 
4642164af29SRuslan Bukin 	/*
4652164af29SRuslan Bukin 	 * Intel® Software Guard Extensions Programming Reference
4662164af29SRuslan Bukin 	 * 6.7.2 Relevant Fields in Various Data Structures
4672164af29SRuslan Bukin 	 * 6.7.2.1 SECS.ATTRIBUTES.XFRM
4682164af29SRuslan Bukin 	 * XFRM[1:0] must be set to 0x3.
4692164af29SRuslan Bukin 	 */
4702164af29SRuslan Bukin 	if ((attr->xfrm & 0x3) != 0x3)
4712164af29SRuslan Bukin 		return (EINVAL);
4722164af29SRuslan Bukin 
4732164af29SRuslan Bukin 	if (!attr->mode64bit)
4742164af29SRuslan Bukin 		return (EINVAL);
4752164af29SRuslan Bukin 
4762164af29SRuslan Bukin 	if (secs->size > sc->enclave_size_max)
4772164af29SRuslan Bukin 		return (EINVAL);
4782164af29SRuslan Bukin 
4792164af29SRuslan Bukin 	for (i = 0; i < SECS_RSV1_SIZE; i++)
4802164af29SRuslan Bukin 		if (secs->reserved1[i])
4812164af29SRuslan Bukin 			return (EINVAL);
4822164af29SRuslan Bukin 
4832164af29SRuslan Bukin 	for (i = 0; i < SECS_RSV2_SIZE; i++)
4842164af29SRuslan Bukin 		if (secs->reserved2[i])
4852164af29SRuslan Bukin 			return (EINVAL);
4862164af29SRuslan Bukin 
4872164af29SRuslan Bukin 	for (i = 0; i < SECS_RSV3_SIZE; i++)
4882164af29SRuslan Bukin 		if (secs->reserved3[i])
4892164af29SRuslan Bukin 			return (EINVAL);
4902164af29SRuslan Bukin 
4912164af29SRuslan Bukin 	for (i = 0; i < SECS_RSV4_SIZE; i++)
4922164af29SRuslan Bukin 		if (secs->reserved4[i])
4932164af29SRuslan Bukin 			return (EINVAL);
4942164af29SRuslan Bukin 
4952164af29SRuslan Bukin 	return (0);
4962164af29SRuslan Bukin }
4972164af29SRuslan Bukin 
4982164af29SRuslan Bukin static int
sgx_tcs_validate(struct tcs * tcs)4992164af29SRuslan Bukin sgx_tcs_validate(struct tcs *tcs)
5002164af29SRuslan Bukin {
5012164af29SRuslan Bukin 	int i;
5022164af29SRuslan Bukin 
5032164af29SRuslan Bukin 	if ((tcs->flags) ||
5042164af29SRuslan Bukin 	    (tcs->ossa & (PAGE_SIZE - 1)) ||
5052164af29SRuslan Bukin 	    (tcs->ofsbasgx & (PAGE_SIZE - 1)) ||
5062164af29SRuslan Bukin 	    (tcs->ogsbasgx & (PAGE_SIZE - 1)) ||
5072164af29SRuslan Bukin 	    ((tcs->fslimit & 0xfff) != 0xfff) ||
5082164af29SRuslan Bukin 	    ((tcs->gslimit & 0xfff) != 0xfff))
5092164af29SRuslan Bukin 		return (EINVAL);
5102164af29SRuslan Bukin 
5112164af29SRuslan Bukin 	for (i = 0; i < nitems(tcs->reserved3); i++)
5122164af29SRuslan Bukin 		if (tcs->reserved3[i])
5132164af29SRuslan Bukin 			return (EINVAL);
5142164af29SRuslan Bukin 
5152164af29SRuslan Bukin 	return (0);
5162164af29SRuslan Bukin }
5172164af29SRuslan Bukin 
5182164af29SRuslan Bukin static void
sgx_tcs_dump(struct sgx_softc * sc,struct tcs * t)5192164af29SRuslan Bukin sgx_tcs_dump(struct sgx_softc *sc, struct tcs *t)
5202164af29SRuslan Bukin {
5212164af29SRuslan Bukin 
5222164af29SRuslan Bukin 	dprintf("t->flags %lx\n", t->flags);
5232164af29SRuslan Bukin 	dprintf("t->ossa %lx\n", t->ossa);
5242164af29SRuslan Bukin 	dprintf("t->cssa %x\n", t->cssa);
5252164af29SRuslan Bukin 	dprintf("t->nssa %x\n", t->nssa);
5262164af29SRuslan Bukin 	dprintf("t->oentry %lx\n", t->oentry);
5272164af29SRuslan Bukin 	dprintf("t->ofsbasgx %lx\n", t->ofsbasgx);
5282164af29SRuslan Bukin 	dprintf("t->ogsbasgx %lx\n", t->ogsbasgx);
5292164af29SRuslan Bukin 	dprintf("t->fslimit %x\n", t->fslimit);
5302164af29SRuslan Bukin 	dprintf("t->gslimit %x\n", t->gslimit);
5312164af29SRuslan Bukin }
5322164af29SRuslan Bukin 
5332164af29SRuslan Bukin 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)5342164af29SRuslan Bukin sgx_pg_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
5352164af29SRuslan Bukin     vm_ooffset_t foff, struct ucred *cred, u_short *color)
5362164af29SRuslan Bukin {
5372164af29SRuslan Bukin 	struct sgx_vm_handle *vmh;
5382164af29SRuslan Bukin 
5392164af29SRuslan Bukin 	vmh = handle;
5402164af29SRuslan Bukin 	if (vmh == NULL) {
5412164af29SRuslan Bukin 		dprintf("%s: vmh not found.\n", __func__);
5422164af29SRuslan Bukin 		return (0);
5432164af29SRuslan Bukin 	}
5442164af29SRuslan Bukin 
5452164af29SRuslan Bukin 	dprintf("%s: vmh->base %lx foff 0x%lx size 0x%lx\n",
5462164af29SRuslan Bukin 	    __func__, vmh->base, foff, size);
5472164af29SRuslan Bukin 
5482164af29SRuslan Bukin 	return (0);
5492164af29SRuslan Bukin }
5502164af29SRuslan Bukin 
5512164af29SRuslan Bukin static void
sgx_pg_dtor(void * handle)5522164af29SRuslan Bukin sgx_pg_dtor(void *handle)
5532164af29SRuslan Bukin {
5542164af29SRuslan Bukin 	struct sgx_vm_handle *vmh;
5552164af29SRuslan Bukin 	struct sgx_softc *sc;
5562164af29SRuslan Bukin 
5572164af29SRuslan Bukin 	vmh = handle;
5582164af29SRuslan Bukin 	if (vmh == NULL) {
5592164af29SRuslan Bukin 		dprintf("%s: vmh not found.\n", __func__);
5602164af29SRuslan Bukin 		return;
5612164af29SRuslan Bukin 	}
5622164af29SRuslan Bukin 
5632164af29SRuslan Bukin 	sc = vmh->sc;
5642164af29SRuslan Bukin 	if (sc == NULL) {
5652164af29SRuslan Bukin 		dprintf("%s: sc is NULL\n", __func__);
5662164af29SRuslan Bukin 		return;
5672164af29SRuslan Bukin 	}
5682164af29SRuslan Bukin 
5692164af29SRuslan Bukin 	if (vmh->enclave == NULL) {
5702164af29SRuslan Bukin 		dprintf("%s: Enclave not found.\n", __func__);
5712164af29SRuslan Bukin 		return;
5722164af29SRuslan Bukin 	}
5732164af29SRuslan Bukin 
5742164af29SRuslan Bukin 	sgx_enclave_remove(sc, vmh->enclave);
5752164af29SRuslan Bukin 
5762164af29SRuslan Bukin 	free(vmh->enclave, M_SGX);
5772164af29SRuslan Bukin 	free(vmh, M_SGX);
5782164af29SRuslan Bukin }
5792164af29SRuslan Bukin 
5802164af29SRuslan Bukin static int
sgx_pg_fault(vm_object_t object,vm_ooffset_t offset,int prot,vm_page_t * mres)5812164af29SRuslan Bukin sgx_pg_fault(vm_object_t object, vm_ooffset_t offset,
5822164af29SRuslan Bukin     int prot, vm_page_t *mres)
5832164af29SRuslan Bukin {
5842164af29SRuslan Bukin 
5852164af29SRuslan Bukin 	/*
5862164af29SRuslan Bukin 	 * The purpose of this trivial handler is to handle the race
5872164af29SRuslan Bukin 	 * when user tries to access mmaped region before or during
5882164af29SRuslan Bukin 	 * enclave creation ioctl calls.
5892164af29SRuslan Bukin 	 */
5902164af29SRuslan Bukin 
5912164af29SRuslan Bukin 	dprintf("%s: offset 0x%lx\n", __func__, offset);
5922164af29SRuslan Bukin 
5932164af29SRuslan Bukin 	return (VM_PAGER_FAIL);
5942164af29SRuslan Bukin }
5952164af29SRuslan Bukin 
596*faaa6876SJohn Baldwin static void
sgx_pg_path(void * handle,char * path,size_t len)597*faaa6876SJohn Baldwin sgx_pg_path(void *handle, char *path, size_t len)
598*faaa6876SJohn Baldwin {
599*faaa6876SJohn Baldwin 	strlcpy(path, "sgx", len);
600*faaa6876SJohn Baldwin }
601*faaa6876SJohn Baldwin 
6022164af29SRuslan Bukin static struct cdev_pager_ops sgx_pg_ops = {
6032164af29SRuslan Bukin 	.cdev_pg_ctor = sgx_pg_ctor,
6042164af29SRuslan Bukin 	.cdev_pg_dtor = sgx_pg_dtor,
6052164af29SRuslan Bukin 	.cdev_pg_fault = sgx_pg_fault,
606*faaa6876SJohn Baldwin 	.cdev_pg_path = sgx_pg_path,
6072164af29SRuslan Bukin };
6082164af29SRuslan Bukin 
6092164af29SRuslan Bukin static void
sgx_insert_epc_page_by_index(vm_page_t page,vm_object_t object,vm_pindex_t pidx)6102164af29SRuslan Bukin sgx_insert_epc_page_by_index(vm_page_t page, vm_object_t object,
6112164af29SRuslan Bukin     vm_pindex_t pidx)
6122164af29SRuslan Bukin {
6132164af29SRuslan Bukin 
6142164af29SRuslan Bukin 	VM_OBJECT_ASSERT_WLOCKED(object);
6152164af29SRuslan Bukin 
6162164af29SRuslan Bukin 	page->valid = VM_PAGE_BITS_ALL;
6170012f373SJeff Roberson 	vm_page_insert(page, object, pidx);
6182164af29SRuslan Bukin }
6192164af29SRuslan Bukin 
6202164af29SRuslan Bukin static void
sgx_insert_epc_page(struct sgx_enclave * enclave,struct epc_page * epc,uint64_t addr)6212164af29SRuslan Bukin sgx_insert_epc_page(struct sgx_enclave *enclave,
6222164af29SRuslan Bukin     struct epc_page *epc, uint64_t addr)
6232164af29SRuslan Bukin {
6242164af29SRuslan Bukin 	vm_pindex_t pidx;
6252164af29SRuslan Bukin 	vm_page_t page;
6262164af29SRuslan Bukin 
6272164af29SRuslan Bukin 	VM_OBJECT_ASSERT_WLOCKED(enclave->object);
6282164af29SRuslan Bukin 
6292164af29SRuslan Bukin 	pidx = OFF_TO_IDX(addr);
6302164af29SRuslan Bukin 	page = PHYS_TO_VM_PAGE(epc->phys);
6312164af29SRuslan Bukin 
6322164af29SRuslan Bukin 	sgx_insert_epc_page_by_index(page, enclave->object, pidx);
6332164af29SRuslan Bukin }
6342164af29SRuslan Bukin 
6352164af29SRuslan Bukin static int
sgx_ioctl_create(struct sgx_softc * sc,struct sgx_enclave_create * param)6362164af29SRuslan Bukin sgx_ioctl_create(struct sgx_softc *sc, struct sgx_enclave_create *param)
6372164af29SRuslan Bukin {
6382164af29SRuslan Bukin 	struct sgx_vm_handle *vmh;
6392164af29SRuslan Bukin 	vm_map_entry_t entry;
6402164af29SRuslan Bukin 	vm_page_t p;
6412164af29SRuslan Bukin 	struct page_info pginfo;
6422164af29SRuslan Bukin 	struct secinfo secinfo;
6432164af29SRuslan Bukin 	struct sgx_enclave *enclave;
6442164af29SRuslan Bukin 	struct epc_page *epc;
6452164af29SRuslan Bukin 	struct secs *secs;
6462164af29SRuslan Bukin 	vm_object_t object;
6472164af29SRuslan Bukin 	vm_page_t page;
6482164af29SRuslan Bukin 	int ret;
6492164af29SRuslan Bukin 
6502164af29SRuslan Bukin 	epc = NULL;
6512164af29SRuslan Bukin 	secs = NULL;
6522164af29SRuslan Bukin 	enclave = NULL;
6532164af29SRuslan Bukin 	object = NULL;
6542164af29SRuslan Bukin 
6552164af29SRuslan Bukin 	/* SGX Enclave Control Structure (SECS) */
6562164af29SRuslan Bukin 	secs = malloc(PAGE_SIZE, M_SGX, M_WAITOK | M_ZERO);
6572164af29SRuslan Bukin 	ret = copyin((void *)param->src, secs, sizeof(struct secs));
6582164af29SRuslan Bukin 	if (ret) {
6592164af29SRuslan Bukin 		dprintf("%s: Can't copy SECS.\n", __func__);
6602164af29SRuslan Bukin 		goto error;
6612164af29SRuslan Bukin 	}
6622164af29SRuslan Bukin 
6632164af29SRuslan Bukin 	ret = sgx_secs_validate(sc, secs);
6642164af29SRuslan Bukin 	if (ret) {
6652164af29SRuslan Bukin 		dprintf("%s: SECS validation failed.\n", __func__);
6662164af29SRuslan Bukin 		goto error;
6672164af29SRuslan Bukin 	}
6682164af29SRuslan Bukin 
6692164af29SRuslan Bukin 	ret = sgx_mem_find(sc, secs->base, &entry, &object);
6702164af29SRuslan Bukin 	if (ret) {
6712164af29SRuslan Bukin 		dprintf("%s: Can't find vm_map.\n", __func__);
6722164af29SRuslan Bukin 		goto error;
6732164af29SRuslan Bukin 	}
6742164af29SRuslan Bukin 
6752164af29SRuslan Bukin 	vmh = object->handle;
6762164af29SRuslan Bukin 	if (!vmh) {
6772164af29SRuslan Bukin 		dprintf("%s: Can't find vmh.\n", __func__);
6782164af29SRuslan Bukin 		ret = ENXIO;
6792164af29SRuslan Bukin 		goto error;
6802164af29SRuslan Bukin 	}
6812164af29SRuslan Bukin 
6822164af29SRuslan Bukin 	dprintf("%s: entry start %lx offset %lx\n",
6832164af29SRuslan Bukin 	    __func__, entry->start, entry->offset);
6842164af29SRuslan Bukin 	vmh->base = (entry->start - entry->offset);
6852164af29SRuslan Bukin 
6862164af29SRuslan Bukin 	ret = sgx_enclave_alloc(sc, secs, &enclave);
6872164af29SRuslan Bukin 	if (ret) {
6882164af29SRuslan Bukin 		dprintf("%s: Can't alloc enclave.\n", __func__);
6892164af29SRuslan Bukin 		goto error;
6902164af29SRuslan Bukin 	}
6912164af29SRuslan Bukin 	enclave->object = object;
6922164af29SRuslan Bukin 	enclave->vmh = vmh;
6932164af29SRuslan Bukin 
6942164af29SRuslan Bukin 	memset(&secinfo, 0, sizeof(struct secinfo));
6952164af29SRuslan Bukin 	memset(&pginfo, 0, sizeof(struct page_info));
6962164af29SRuslan Bukin 	pginfo.linaddr = 0;
6972164af29SRuslan Bukin 	pginfo.srcpge = (uint64_t)secs;
6982164af29SRuslan Bukin 	pginfo.secinfo = &secinfo;
6992164af29SRuslan Bukin 	pginfo.secs = 0;
7002164af29SRuslan Bukin 
7012164af29SRuslan Bukin 	ret = sgx_get_epc_page(sc, &epc);
7022164af29SRuslan Bukin 	if (ret) {
7032164af29SRuslan Bukin 		dprintf("%s: Failed to get free epc page.\n", __func__);
7042164af29SRuslan Bukin 		goto error;
7052164af29SRuslan Bukin 	}
7062164af29SRuslan Bukin 	enclave->secs_epc_page = epc;
7072164af29SRuslan Bukin 
7082164af29SRuslan Bukin 	VM_OBJECT_WLOCK(object);
7092164af29SRuslan Bukin 	p = vm_page_lookup(object, SGX_SECS_VM_OBJECT_INDEX);
7102164af29SRuslan Bukin 	if (p) {
7112164af29SRuslan Bukin 		VM_OBJECT_WUNLOCK(object);
7122164af29SRuslan Bukin 		/* SECS page already added. */
7132164af29SRuslan Bukin 		ret = ENXIO;
7142164af29SRuslan Bukin 		goto error;
7152164af29SRuslan Bukin 	}
7162164af29SRuslan Bukin 
7172164af29SRuslan Bukin 	ret = sgx_va_slot_init_by_index(sc, object,
7182164af29SRuslan Bukin 	    - SGX_VA_PAGES_OFFS - SGX_SECS_VM_OBJECT_INDEX);
7192164af29SRuslan Bukin 	if (ret) {
7202164af29SRuslan Bukin 		VM_OBJECT_WUNLOCK(object);
7212164af29SRuslan Bukin 		dprintf("%s: Can't init va slot.\n", __func__);
7222164af29SRuslan Bukin 		goto error;
7232164af29SRuslan Bukin 	}
7242164af29SRuslan Bukin 
7252164af29SRuslan Bukin 	mtx_lock(&sc->mtx);
7262164af29SRuslan Bukin 	if ((sc->state & SGX_STATE_RUNNING) == 0) {
7272164af29SRuslan Bukin 		mtx_unlock(&sc->mtx);
7282164af29SRuslan Bukin 		/* Remove VA page that was just created for SECS page. */
7290f9e06e1SJeff Roberson 		p = vm_page_grab(enclave->object,
7300f9e06e1SJeff Roberson 		    - SGX_VA_PAGES_OFFS - SGX_SECS_VM_OBJECT_INDEX,
7310f9e06e1SJeff Roberson 		    VM_ALLOC_NOCREAT);
7322164af29SRuslan Bukin 		sgx_page_remove(sc, p);
7332164af29SRuslan Bukin 		VM_OBJECT_WUNLOCK(object);
7342164af29SRuslan Bukin 		goto error;
7352164af29SRuslan Bukin 	}
7362164af29SRuslan Bukin 	mtx_lock(&sc->mtx_encls);
7372164af29SRuslan Bukin 	ret = sgx_ecreate(&pginfo, (void *)epc->base);
7382164af29SRuslan Bukin 	mtx_unlock(&sc->mtx_encls);
7392164af29SRuslan Bukin 	if (ret == SGX_EFAULT) {
7402164af29SRuslan Bukin 		dprintf("%s: gp fault\n", __func__);
7412164af29SRuslan Bukin 		mtx_unlock(&sc->mtx);
7422164af29SRuslan Bukin 		/* Remove VA page that was just created for SECS page. */
7430f9e06e1SJeff Roberson 		p = vm_page_grab(enclave->object,
7440f9e06e1SJeff Roberson 		    - SGX_VA_PAGES_OFFS - SGX_SECS_VM_OBJECT_INDEX,
7450f9e06e1SJeff Roberson 		    VM_ALLOC_NOCREAT);
7462164af29SRuslan Bukin 		sgx_page_remove(sc, p);
7472164af29SRuslan Bukin 		VM_OBJECT_WUNLOCK(object);
7482164af29SRuslan Bukin 		goto error;
7492164af29SRuslan Bukin 	}
7502164af29SRuslan Bukin 
7512164af29SRuslan Bukin 	TAILQ_INSERT_TAIL(&sc->enclaves, enclave, next);
7522164af29SRuslan Bukin 	mtx_unlock(&sc->mtx);
7532164af29SRuslan Bukin 
7542164af29SRuslan Bukin 	vmh->enclave = enclave;
7552164af29SRuslan Bukin 
7562164af29SRuslan Bukin 	page = PHYS_TO_VM_PAGE(epc->phys);
7572164af29SRuslan Bukin 	sgx_insert_epc_page_by_index(page, enclave->object,
7582164af29SRuslan Bukin 	    SGX_SECS_VM_OBJECT_INDEX);
7592164af29SRuslan Bukin 
7602164af29SRuslan Bukin 	VM_OBJECT_WUNLOCK(object);
7612164af29SRuslan Bukin 
7622164af29SRuslan Bukin 	/* Release the reference. */
7632164af29SRuslan Bukin 	vm_object_deallocate(object);
7642164af29SRuslan Bukin 
7652164af29SRuslan Bukin 	free(secs, M_SGX);
7662164af29SRuslan Bukin 
7672164af29SRuslan Bukin 	return (0);
7682164af29SRuslan Bukin 
7692164af29SRuslan Bukin error:
7702164af29SRuslan Bukin 	free(secs, M_SGX);
7712164af29SRuslan Bukin 	sgx_put_epc_page(sc, epc);
7722164af29SRuslan Bukin 	free(enclave, M_SGX);
7732164af29SRuslan Bukin 	vm_object_deallocate(object);
7742164af29SRuslan Bukin 
7752164af29SRuslan Bukin 	return (ret);
7762164af29SRuslan Bukin }
7772164af29SRuslan Bukin 
7782164af29SRuslan Bukin static int
sgx_ioctl_add_page(struct sgx_softc * sc,struct sgx_enclave_add_page * addp)7792164af29SRuslan Bukin sgx_ioctl_add_page(struct sgx_softc *sc,
7802164af29SRuslan Bukin     struct sgx_enclave_add_page *addp)
7812164af29SRuslan Bukin {
7822164af29SRuslan Bukin 	struct epc_page *secs_epc_page;
7832164af29SRuslan Bukin 	struct sgx_enclave *enclave;
7842164af29SRuslan Bukin 	struct sgx_vm_handle *vmh;
7852164af29SRuslan Bukin 	struct epc_page *epc;
7862164af29SRuslan Bukin 	struct page_info pginfo;
7872164af29SRuslan Bukin 	struct secinfo secinfo;
7882164af29SRuslan Bukin 	vm_object_t object;
7892164af29SRuslan Bukin 	void *tmp_vaddr;
7902164af29SRuslan Bukin 	uint64_t page_type;
7912164af29SRuslan Bukin 	struct tcs *t;
7922164af29SRuslan Bukin 	uint64_t addr;
7932164af29SRuslan Bukin 	uint64_t pidx;
7942164af29SRuslan Bukin 	vm_page_t p;
7952164af29SRuslan Bukin 	int ret;
7962164af29SRuslan Bukin 
7972164af29SRuslan Bukin 	tmp_vaddr = NULL;
7982164af29SRuslan Bukin 	epc = NULL;
7992164af29SRuslan Bukin 	object = NULL;
8002164af29SRuslan Bukin 
8012164af29SRuslan Bukin 	/* Find and get reference to VM object. */
8022164af29SRuslan Bukin 	ret = sgx_enclave_find(sc, addp->addr, &enclave);
8032164af29SRuslan Bukin 	if (ret) {
8042164af29SRuslan Bukin 		dprintf("%s: Failed to find enclave.\n", __func__);
8052164af29SRuslan Bukin 		goto error;
8062164af29SRuslan Bukin 	}
8072164af29SRuslan Bukin 
8082164af29SRuslan Bukin 	object = enclave->object;
8092164af29SRuslan Bukin 	KASSERT(object != NULL, ("vm object is NULL\n"));
8102164af29SRuslan Bukin 	vmh = object->handle;
8112164af29SRuslan Bukin 
8122164af29SRuslan Bukin 	ret = sgx_get_epc_page(sc, &epc);
8132164af29SRuslan Bukin 	if (ret) {
8142164af29SRuslan Bukin 		dprintf("%s: Failed to get free epc page.\n", __func__);
8152164af29SRuslan Bukin 		goto error;
8162164af29SRuslan Bukin 	}
8172164af29SRuslan Bukin 
8182164af29SRuslan Bukin 	memset(&secinfo, 0, sizeof(struct secinfo));
8192164af29SRuslan Bukin 	ret = copyin((void *)addp->secinfo, &secinfo,
8202164af29SRuslan Bukin 	    sizeof(struct secinfo));
8212164af29SRuslan Bukin 	if (ret) {
8222164af29SRuslan Bukin 		dprintf("%s: Failed to copy secinfo.\n", __func__);
8232164af29SRuslan Bukin 		goto error;
8242164af29SRuslan Bukin 	}
8252164af29SRuslan Bukin 
8262164af29SRuslan Bukin 	tmp_vaddr = malloc(PAGE_SIZE, M_SGX, M_WAITOK | M_ZERO);
8272164af29SRuslan Bukin 	ret = copyin((void *)addp->src, tmp_vaddr, PAGE_SIZE);
8282164af29SRuslan Bukin 	if (ret) {
8292164af29SRuslan Bukin 		dprintf("%s: Failed to copy page.\n", __func__);
8302164af29SRuslan Bukin 		goto error;
8312164af29SRuslan Bukin 	}
8322164af29SRuslan Bukin 
8332164af29SRuslan Bukin 	page_type = (secinfo.flags & SECINFO_FLAGS_PT_M) >>
8342164af29SRuslan Bukin 	    SECINFO_FLAGS_PT_S;
8352164af29SRuslan Bukin 	if (page_type != SGX_PT_TCS && page_type != SGX_PT_REG) {
8362164af29SRuslan Bukin 		dprintf("%s: page can't be added.\n", __func__);
8372164af29SRuslan Bukin 		goto error;
8382164af29SRuslan Bukin 	}
8392164af29SRuslan Bukin 	if (page_type == SGX_PT_TCS) {
8402164af29SRuslan Bukin 		t = (struct tcs *)tmp_vaddr;
8412164af29SRuslan Bukin 		ret = sgx_tcs_validate(t);
8422164af29SRuslan Bukin 		if (ret) {
8432164af29SRuslan Bukin 			dprintf("%s: TCS page validation failed.\n",
8442164af29SRuslan Bukin 			    __func__);
8452164af29SRuslan Bukin 			goto error;
8462164af29SRuslan Bukin 		}
8472164af29SRuslan Bukin 		sgx_tcs_dump(sc, t);
8482164af29SRuslan Bukin 	}
8492164af29SRuslan Bukin 
8502164af29SRuslan Bukin 	addr = (addp->addr - vmh->base);
8512164af29SRuslan Bukin 	pidx = OFF_TO_IDX(addr);
8522164af29SRuslan Bukin 
8532164af29SRuslan Bukin 	VM_OBJECT_WLOCK(object);
8542164af29SRuslan Bukin 	p = vm_page_lookup(object, pidx);
8552164af29SRuslan Bukin 	if (p) {
8562164af29SRuslan Bukin 		VM_OBJECT_WUNLOCK(object);
8572164af29SRuslan Bukin 		/* Page already added. */
8582164af29SRuslan Bukin 		ret = ENXIO;
8592164af29SRuslan Bukin 		goto error;
8602164af29SRuslan Bukin 	}
8612164af29SRuslan Bukin 
8622164af29SRuslan Bukin 	ret = sgx_va_slot_init(sc, enclave, addr);
8632164af29SRuslan Bukin 	if (ret) {
8642164af29SRuslan Bukin 		VM_OBJECT_WUNLOCK(object);
8652164af29SRuslan Bukin 		dprintf("%s: Can't init va slot.\n", __func__);
8662164af29SRuslan Bukin 		goto error;
8672164af29SRuslan Bukin 	}
8682164af29SRuslan Bukin 
8692164af29SRuslan Bukin 	secs_epc_page = enclave->secs_epc_page;
8702164af29SRuslan Bukin 	memset(&pginfo, 0, sizeof(struct page_info));
8712164af29SRuslan Bukin 	pginfo.linaddr = (uint64_t)addp->addr;
8722164af29SRuslan Bukin 	pginfo.srcpge = (uint64_t)tmp_vaddr;
8732164af29SRuslan Bukin 	pginfo.secinfo = &secinfo;
8742164af29SRuslan Bukin 	pginfo.secs = (uint64_t)secs_epc_page->base;
8752164af29SRuslan Bukin 
8762164af29SRuslan Bukin 	mtx_lock(&sc->mtx_encls);
8772164af29SRuslan Bukin 	ret = sgx_eadd(&pginfo, (void *)epc->base);
8782164af29SRuslan Bukin 	if (ret == SGX_EFAULT) {
8792164af29SRuslan Bukin 		dprintf("%s: gp fault on eadd\n", __func__);
8802164af29SRuslan Bukin 		mtx_unlock(&sc->mtx_encls);
8812164af29SRuslan Bukin 		VM_OBJECT_WUNLOCK(object);
8822164af29SRuslan Bukin 		goto error;
8832164af29SRuslan Bukin 	}
8842164af29SRuslan Bukin 	mtx_unlock(&sc->mtx_encls);
8852164af29SRuslan Bukin 
8862164af29SRuslan Bukin 	ret = sgx_measure_page(sc, enclave->secs_epc_page, epc, addp->mrmask);
8872164af29SRuslan Bukin 	if (ret == SGX_EFAULT) {
8882164af29SRuslan Bukin 		dprintf("%s: gp fault on eextend\n", __func__);
8892164af29SRuslan Bukin 		sgx_epc_page_remove(sc, epc);
8902164af29SRuslan Bukin 		VM_OBJECT_WUNLOCK(object);
8912164af29SRuslan Bukin 		goto error;
8922164af29SRuslan Bukin 	}
8932164af29SRuslan Bukin 
8942164af29SRuslan Bukin 	sgx_insert_epc_page(enclave, epc, addr);
8952164af29SRuslan Bukin 
8962164af29SRuslan Bukin 	VM_OBJECT_WUNLOCK(object);
8972164af29SRuslan Bukin 
8982164af29SRuslan Bukin 	/* Release the reference. */
8992164af29SRuslan Bukin 	vm_object_deallocate(object);
9002164af29SRuslan Bukin 
9012164af29SRuslan Bukin 	free(tmp_vaddr, M_SGX);
9022164af29SRuslan Bukin 
9032164af29SRuslan Bukin 	return (0);
9042164af29SRuslan Bukin 
9052164af29SRuslan Bukin error:
9062164af29SRuslan Bukin 	free(tmp_vaddr, M_SGX);
9072164af29SRuslan Bukin 	sgx_put_epc_page(sc, epc);
9082164af29SRuslan Bukin 	vm_object_deallocate(object);
9092164af29SRuslan Bukin 
9102164af29SRuslan Bukin 	return (ret);
9112164af29SRuslan Bukin }
9122164af29SRuslan Bukin 
9132164af29SRuslan Bukin static int
sgx_ioctl_init(struct sgx_softc * sc,struct sgx_enclave_init * initp)9142164af29SRuslan Bukin sgx_ioctl_init(struct sgx_softc *sc, struct sgx_enclave_init *initp)
9152164af29SRuslan Bukin {
9162164af29SRuslan Bukin 	struct epc_page *secs_epc_page;
9172164af29SRuslan Bukin 	struct sgx_enclave *enclave;
9182164af29SRuslan Bukin 	struct thread *td;
9192164af29SRuslan Bukin 	void *tmp_vaddr;
9202164af29SRuslan Bukin 	void *einittoken;
9212164af29SRuslan Bukin 	void *sigstruct;
9222164af29SRuslan Bukin 	vm_object_t object;
9232164af29SRuslan Bukin 	int retry;
9242164af29SRuslan Bukin 	int ret;
9252164af29SRuslan Bukin 
9262164af29SRuslan Bukin 	td = curthread;
9272164af29SRuslan Bukin 	tmp_vaddr = NULL;
9282164af29SRuslan Bukin 	object = NULL;
9292164af29SRuslan Bukin 
9302164af29SRuslan Bukin 	dprintf("%s: addr %lx, sigstruct %lx, einittoken %lx\n",
9312164af29SRuslan Bukin 	    __func__, initp->addr, initp->sigstruct, initp->einittoken);
9322164af29SRuslan Bukin 
9332164af29SRuslan Bukin 	/* Find and get reference to VM object. */
9342164af29SRuslan Bukin 	ret = sgx_enclave_find(sc, initp->addr, &enclave);
9352164af29SRuslan Bukin 	if (ret) {
9362164af29SRuslan Bukin 		dprintf("%s: Failed to find enclave.\n", __func__);
9372164af29SRuslan Bukin 		goto error;
9382164af29SRuslan Bukin 	}
9392164af29SRuslan Bukin 
9402164af29SRuslan Bukin 	object = enclave->object;
9412164af29SRuslan Bukin 
9422164af29SRuslan Bukin 	tmp_vaddr = malloc(PAGE_SIZE, M_SGX, M_WAITOK | M_ZERO);
9432164af29SRuslan Bukin 	sigstruct = tmp_vaddr;
9442164af29SRuslan Bukin 	einittoken = (void *)((uint64_t)sigstruct + PAGE_SIZE / 2);
9452164af29SRuslan Bukin 
9462164af29SRuslan Bukin 	ret = copyin((void *)initp->sigstruct, sigstruct,
9472164af29SRuslan Bukin 	    SGX_SIGSTRUCT_SIZE);
9482164af29SRuslan Bukin 	if (ret) {
9492164af29SRuslan Bukin 		dprintf("%s: Failed to copy SIGSTRUCT page.\n", __func__);
9502164af29SRuslan Bukin 		goto error;
9512164af29SRuslan Bukin 	}
9522164af29SRuslan Bukin 
9532164af29SRuslan Bukin 	ret = copyin((void *)initp->einittoken, einittoken,
9542164af29SRuslan Bukin 	    SGX_EINITTOKEN_SIZE);
9552164af29SRuslan Bukin 	if (ret) {
9562164af29SRuslan Bukin 		dprintf("%s: Failed to copy EINITTOKEN page.\n", __func__);
9572164af29SRuslan Bukin 		goto error;
9582164af29SRuslan Bukin 	}
9592164af29SRuslan Bukin 
9602164af29SRuslan Bukin 	secs_epc_page = enclave->secs_epc_page;
9612164af29SRuslan Bukin 	retry = 16;
9622164af29SRuslan Bukin 	do {
9632164af29SRuslan Bukin 		mtx_lock(&sc->mtx_encls);
9642164af29SRuslan Bukin 		ret = sgx_einit(sigstruct, (void *)secs_epc_page->base,
9652164af29SRuslan Bukin 		    einittoken);
9662164af29SRuslan Bukin 		mtx_unlock(&sc->mtx_encls);
9672164af29SRuslan Bukin 		dprintf("%s: sgx_einit returned %d\n", __func__, ret);
9682164af29SRuslan Bukin 	} while (ret == SGX_UNMASKED_EVENT && retry--);
9692164af29SRuslan Bukin 
9702164af29SRuslan Bukin 	if (ret) {
9712164af29SRuslan Bukin 		dprintf("%s: Failed init enclave: %d\n", __func__, ret);
9722164af29SRuslan Bukin 		td->td_retval[0] = ret;
9732164af29SRuslan Bukin 		ret = 0;
9742164af29SRuslan Bukin 	}
9752164af29SRuslan Bukin 
9762164af29SRuslan Bukin error:
9772164af29SRuslan Bukin 	free(tmp_vaddr, M_SGX);
9782164af29SRuslan Bukin 
9792164af29SRuslan Bukin 	/* Release the reference. */
9802164af29SRuslan Bukin 	vm_object_deallocate(object);
9812164af29SRuslan Bukin 
9822164af29SRuslan Bukin 	return (ret);
9832164af29SRuslan Bukin }
9842164af29SRuslan Bukin 
9852164af29SRuslan Bukin static int
sgx_ioctl(struct cdev * dev,u_long cmd,caddr_t addr,int flags,struct thread * td)9862164af29SRuslan Bukin sgx_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
9872164af29SRuslan Bukin     struct thread *td)
9882164af29SRuslan Bukin {
9892164af29SRuslan Bukin 	struct sgx_enclave_add_page *addp;
9902164af29SRuslan Bukin 	struct sgx_enclave_create *param;
9912164af29SRuslan Bukin 	struct sgx_enclave_init *initp;
9922164af29SRuslan Bukin 	struct sgx_softc *sc;
9932164af29SRuslan Bukin 	int ret;
9942164af29SRuslan Bukin 	int len;
9952164af29SRuslan Bukin 
9962164af29SRuslan Bukin 	sc = &sgx_sc;
9972164af29SRuslan Bukin 
9982164af29SRuslan Bukin 	len = IOCPARM_LEN(cmd);
9992164af29SRuslan Bukin 
10002164af29SRuslan Bukin 	dprintf("%s: cmd %lx, addr %lx, len %d\n",
10012164af29SRuslan Bukin 	    __func__, cmd, (uint64_t)addr, len);
10022164af29SRuslan Bukin 
10032164af29SRuslan Bukin 	if (len > SGX_IOCTL_MAX_DATA_LEN)
10042164af29SRuslan Bukin 		return (EINVAL);
10052164af29SRuslan Bukin 
10062164af29SRuslan Bukin 	switch (cmd) {
10072164af29SRuslan Bukin 	case SGX_IOC_ENCLAVE_CREATE:
10082164af29SRuslan Bukin 		param = (struct sgx_enclave_create *)addr;
10092164af29SRuslan Bukin 		ret = sgx_ioctl_create(sc, param);
10102164af29SRuslan Bukin 		break;
10112164af29SRuslan Bukin 	case SGX_IOC_ENCLAVE_ADD_PAGE:
10122164af29SRuslan Bukin 		addp = (struct sgx_enclave_add_page *)addr;
10132164af29SRuslan Bukin 		ret = sgx_ioctl_add_page(sc, addp);
10142164af29SRuslan Bukin 		break;
10152164af29SRuslan Bukin 	case SGX_IOC_ENCLAVE_INIT:
10162164af29SRuslan Bukin 		initp = (struct sgx_enclave_init *)addr;
10172164af29SRuslan Bukin 		ret = sgx_ioctl_init(sc, initp);
10182164af29SRuslan Bukin 		break;
10192164af29SRuslan Bukin 	default:
10202164af29SRuslan Bukin 		return (EINVAL);
10212164af29SRuslan Bukin 	}
10222164af29SRuslan Bukin 
10232164af29SRuslan Bukin 	return (ret);
10242164af29SRuslan Bukin }
10252164af29SRuslan Bukin 
10262164af29SRuslan Bukin static int
sgx_mmap_single(struct cdev * cdev,vm_ooffset_t * offset,vm_size_t mapsize,struct vm_object ** objp,int nprot)10272164af29SRuslan Bukin sgx_mmap_single(struct cdev *cdev, vm_ooffset_t *offset,
10282164af29SRuslan Bukin     vm_size_t mapsize, struct vm_object **objp, int nprot)
10292164af29SRuslan Bukin {
10302164af29SRuslan Bukin 	struct sgx_vm_handle *vmh;
10312164af29SRuslan Bukin 	struct sgx_softc *sc;
10322164af29SRuslan Bukin 
10332164af29SRuslan Bukin 	sc = &sgx_sc;
10342164af29SRuslan Bukin 
10352164af29SRuslan Bukin 	dprintf("%s: mapsize 0x%lx, offset %lx\n",
10362164af29SRuslan Bukin 	    __func__, mapsize, *offset);
10372164af29SRuslan Bukin 
10382164af29SRuslan Bukin 	vmh = malloc(sizeof(struct sgx_vm_handle),
10392164af29SRuslan Bukin 	    M_SGX, M_WAITOK | M_ZERO);
10402164af29SRuslan Bukin 	vmh->sc = sc;
10412164af29SRuslan Bukin 	vmh->size = mapsize;
10422164af29SRuslan Bukin 	vmh->mem = cdev_pager_allocate(vmh, OBJT_MGTDEVICE, &sgx_pg_ops,
10432164af29SRuslan Bukin 	    mapsize, nprot, *offset, NULL);
10442164af29SRuslan Bukin 	if (vmh->mem == NULL) {
10452164af29SRuslan Bukin 		free(vmh, M_SGX);
10462164af29SRuslan Bukin 		return (ENOMEM);
10472164af29SRuslan Bukin 	}
10482164af29SRuslan Bukin 
10492164af29SRuslan Bukin 	VM_OBJECT_WLOCK(vmh->mem);
10502164af29SRuslan Bukin 	vm_object_set_flag(vmh->mem, OBJ_PG_DTOR);
10512164af29SRuslan Bukin 	VM_OBJECT_WUNLOCK(vmh->mem);
10522164af29SRuslan Bukin 
10532164af29SRuslan Bukin 	*objp = vmh->mem;
10542164af29SRuslan Bukin 
10552164af29SRuslan Bukin 	return (0);
10562164af29SRuslan Bukin }
10572164af29SRuslan Bukin 
10582164af29SRuslan Bukin static struct cdevsw sgx_cdevsw = {
10592164af29SRuslan Bukin 	.d_version =		D_VERSION,
10602164af29SRuslan Bukin 	.d_ioctl =		sgx_ioctl,
10612164af29SRuslan Bukin 	.d_mmap_single =	sgx_mmap_single,
10622164af29SRuslan Bukin 	.d_name =		"Intel SGX",
10632164af29SRuslan Bukin };
10642164af29SRuslan Bukin 
10652164af29SRuslan Bukin static int
sgx_get_epc_area(struct sgx_softc * sc)10662164af29SRuslan Bukin sgx_get_epc_area(struct sgx_softc *sc)
10672164af29SRuslan Bukin {
10682164af29SRuslan Bukin 	vm_offset_t epc_base_vaddr;
10692164af29SRuslan Bukin 	u_int cp[4];
10702164af29SRuslan Bukin 	int error;
10712164af29SRuslan Bukin 	int i;
10722164af29SRuslan Bukin 
10732164af29SRuslan Bukin 	cpuid_count(SGX_CPUID, 0x2, cp);
10742164af29SRuslan Bukin 
10752164af29SRuslan Bukin 	sc->epc_base = ((uint64_t)(cp[1] & 0xfffff) << 32) +
10762164af29SRuslan Bukin 	    (cp[0] & 0xfffff000);
10772164af29SRuslan Bukin 	sc->epc_size = ((uint64_t)(cp[3] & 0xfffff) << 32) +
10782164af29SRuslan Bukin 	    (cp[2] & 0xfffff000);
10792164af29SRuslan Bukin 	sc->npages = sc->epc_size / SGX_PAGE_SIZE;
10802164af29SRuslan Bukin 
10813caad0b8SMarcin Wojtas 	if (sc->epc_size == 0 || sc->epc_base == 0) {
10823caad0b8SMarcin Wojtas 		printf("%s: Incorrect EPC data: EPC base %lx, size %lu\n",
10833caad0b8SMarcin Wojtas 		    __func__, sc->epc_base, sc->epc_size);
10843caad0b8SMarcin Wojtas 		return (EINVAL);
10853caad0b8SMarcin Wojtas 	}
10863caad0b8SMarcin Wojtas 
10872164af29SRuslan Bukin 	if (cp[3] & 0xffff)
10882164af29SRuslan Bukin 		sc->enclave_size_max = (1 << ((cp[3] >> 8) & 0xff));
10892164af29SRuslan Bukin 	else
10902164af29SRuslan Bukin 		sc->enclave_size_max = SGX_ENCL_SIZE_MAX_DEF;
10912164af29SRuslan Bukin 
10922164af29SRuslan Bukin 	epc_base_vaddr = (vm_offset_t)pmap_mapdev_attr(sc->epc_base,
10932164af29SRuslan Bukin 	    sc->epc_size, VM_MEMATTR_DEFAULT);
10942164af29SRuslan Bukin 
10952164af29SRuslan Bukin 	sc->epc_pages = malloc(sizeof(struct epc_page) * sc->npages,
10962164af29SRuslan Bukin 	    M_DEVBUF, M_WAITOK | M_ZERO);
10972164af29SRuslan Bukin 
10982164af29SRuslan Bukin 	for (i = 0; i < sc->npages; i++) {
10992164af29SRuslan Bukin 		sc->epc_pages[i].base = epc_base_vaddr + SGX_PAGE_SIZE * i;
11002164af29SRuslan Bukin 		sc->epc_pages[i].phys = sc->epc_base + SGX_PAGE_SIZE * i;
11012164af29SRuslan Bukin 		sc->epc_pages[i].index = i;
11022164af29SRuslan Bukin 	}
11032164af29SRuslan Bukin 
11042164af29SRuslan Bukin 	sc->vmem_epc = vmem_create("SGX EPC", sc->epc_base, sc->epc_size,
11052164af29SRuslan Bukin 	    PAGE_SIZE, PAGE_SIZE, M_FIRSTFIT | M_WAITOK);
11062164af29SRuslan Bukin 	if (sc->vmem_epc == NULL) {
11072164af29SRuslan Bukin 		printf("%s: Can't create vmem arena.\n", __func__);
11082164af29SRuslan Bukin 		free(sc->epc_pages, M_SGX);
11092164af29SRuslan Bukin 		return (EINVAL);
11102164af29SRuslan Bukin 	}
11112164af29SRuslan Bukin 
11122164af29SRuslan Bukin 	error = vm_phys_fictitious_reg_range(sc->epc_base,
11132164af29SRuslan Bukin 	    sc->epc_base + sc->epc_size, VM_MEMATTR_DEFAULT);
11142164af29SRuslan Bukin 	if (error) {
11152164af29SRuslan Bukin 		printf("%s: Can't register fictitious space.\n", __func__);
11162164af29SRuslan Bukin 		free(sc->epc_pages, M_SGX);
11172164af29SRuslan Bukin 		return (EINVAL);
11182164af29SRuslan Bukin 	}
11192164af29SRuslan Bukin 
11202164af29SRuslan Bukin 	return (0);
11212164af29SRuslan Bukin }
11222164af29SRuslan Bukin 
11232164af29SRuslan Bukin static void
sgx_put_epc_area(struct sgx_softc * sc)11242164af29SRuslan Bukin sgx_put_epc_area(struct sgx_softc *sc)
11252164af29SRuslan Bukin {
11262164af29SRuslan Bukin 
11272164af29SRuslan Bukin 	vm_phys_fictitious_unreg_range(sc->epc_base,
11282164af29SRuslan Bukin 	    sc->epc_base + sc->epc_size);
11292164af29SRuslan Bukin 
11302164af29SRuslan Bukin 	free(sc->epc_pages, M_SGX);
11312164af29SRuslan Bukin }
11322164af29SRuslan Bukin 
11332164af29SRuslan Bukin static int
sgx_load(void)11342164af29SRuslan Bukin sgx_load(void)
11352164af29SRuslan Bukin {
11362164af29SRuslan Bukin 	struct sgx_softc *sc;
11372164af29SRuslan Bukin 	int error;
11382164af29SRuslan Bukin 
11392164af29SRuslan Bukin 	sc = &sgx_sc;
11402164af29SRuslan Bukin 
11412164af29SRuslan Bukin 	if ((cpu_stdext_feature & CPUID_STDEXT_SGX) == 0)
11422164af29SRuslan Bukin 		return (ENXIO);
11432164af29SRuslan Bukin 
11442164af29SRuslan Bukin 	error = sgx_get_epc_area(sc);
11452164af29SRuslan Bukin 	if (error) {
11462164af29SRuslan Bukin 		printf("%s: Failed to get Processor Reserved Memory area.\n",
11472164af29SRuslan Bukin 		    __func__);
11482164af29SRuslan Bukin 		return (ENXIO);
11492164af29SRuslan Bukin 	}
11502164af29SRuslan Bukin 
115156512942SRuslan Bukin 	mtx_init(&sc->mtx_encls, "SGX ENCLS", NULL, MTX_DEF);
115256512942SRuslan Bukin 	mtx_init(&sc->mtx, "SGX driver", NULL, MTX_DEF);
115356512942SRuslan Bukin 
11542164af29SRuslan Bukin 	TAILQ_INIT(&sc->enclaves);
11552164af29SRuslan Bukin 
11562164af29SRuslan Bukin 	sc->sgx_cdev = make_dev(&sgx_cdevsw, 0, UID_ROOT, GID_WHEEL,
11572164af29SRuslan Bukin 	    0600, "isgx");
11582164af29SRuslan Bukin 
11592164af29SRuslan Bukin 	sc->state |= SGX_STATE_RUNNING;
11602164af29SRuslan Bukin 
11612164af29SRuslan Bukin 	printf("SGX initialized: EPC base 0x%lx size %ld (%d pages)\n",
11622164af29SRuslan Bukin 	    sc->epc_base, sc->epc_size, sc->npages);
11632164af29SRuslan Bukin 
11642164af29SRuslan Bukin 	return (0);
11652164af29SRuslan Bukin }
11662164af29SRuslan Bukin 
11672164af29SRuslan Bukin static int
sgx_unload(void)11682164af29SRuslan Bukin sgx_unload(void)
11692164af29SRuslan Bukin {
11702164af29SRuslan Bukin 	struct sgx_softc *sc;
11712164af29SRuslan Bukin 
11722164af29SRuslan Bukin 	sc = &sgx_sc;
11732164af29SRuslan Bukin 
117456512942SRuslan Bukin 	if ((sc->state & SGX_STATE_RUNNING) == 0)
117556512942SRuslan Bukin 		return (0);
117656512942SRuslan Bukin 
11772164af29SRuslan Bukin 	mtx_lock(&sc->mtx);
11782164af29SRuslan Bukin 	if (!TAILQ_EMPTY(&sc->enclaves)) {
11792164af29SRuslan Bukin 		mtx_unlock(&sc->mtx);
11802164af29SRuslan Bukin 		return (EBUSY);
11812164af29SRuslan Bukin 	}
11822164af29SRuslan Bukin 	sc->state &= ~SGX_STATE_RUNNING;
11832164af29SRuslan Bukin 	mtx_unlock(&sc->mtx);
11842164af29SRuslan Bukin 
11852164af29SRuslan Bukin 	destroy_dev(sc->sgx_cdev);
11862164af29SRuslan Bukin 
11872164af29SRuslan Bukin 	vmem_destroy(sc->vmem_epc);
11882164af29SRuslan Bukin 	sgx_put_epc_area(sc);
11892164af29SRuslan Bukin 
11902164af29SRuslan Bukin 	mtx_destroy(&sc->mtx_encls);
11912164af29SRuslan Bukin 	mtx_destroy(&sc->mtx);
11922164af29SRuslan Bukin 
11932164af29SRuslan Bukin 	return (0);
11942164af29SRuslan Bukin }
11952164af29SRuslan Bukin 
11962164af29SRuslan Bukin static int
sgx_handler(module_t mod,int what,void * arg)11972164af29SRuslan Bukin sgx_handler(module_t mod, int what, void *arg)
11982164af29SRuslan Bukin {
11992164af29SRuslan Bukin 	int error;
12002164af29SRuslan Bukin 
12012164af29SRuslan Bukin 	switch (what) {
12022164af29SRuslan Bukin 	case MOD_LOAD:
12032164af29SRuslan Bukin 		error = sgx_load();
12042164af29SRuslan Bukin 		break;
12052164af29SRuslan Bukin 	case MOD_UNLOAD:
12062164af29SRuslan Bukin 		error = sgx_unload();
12072164af29SRuslan Bukin 		break;
12082164af29SRuslan Bukin 	default:
12092164af29SRuslan Bukin 		error = 0;
12102164af29SRuslan Bukin 		break;
12112164af29SRuslan Bukin 	}
12122164af29SRuslan Bukin 
12132164af29SRuslan Bukin 	return (error);
12142164af29SRuslan Bukin }
12152164af29SRuslan Bukin 
12162164af29SRuslan Bukin static moduledata_t sgx_kmod = {
12172164af29SRuslan Bukin 	"sgx",
12182164af29SRuslan Bukin 	sgx_handler,
12192164af29SRuslan Bukin 	NULL
12202164af29SRuslan Bukin };
12212164af29SRuslan Bukin 
12222164af29SRuslan Bukin DECLARE_MODULE(sgx, sgx_kmod, SI_SUB_LAST, SI_ORDER_ANY);
12232164af29SRuslan Bukin MODULE_VERSION(sgx, 1);
1224