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