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 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 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 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 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 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 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 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 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 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 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 */ 387*0f9e06e1SJeff Roberson restart: 3882164af29SRuslan Bukin TAILQ_FOREACH_SAFE(p, &object->memq, listq, p_next) { 389*0f9e06e1SJeff Roberson if (p->pindex == SGX_SECS_VM_OBJECT_INDEX) 3902164af29SRuslan Bukin continue; 391*0f9e06e1SJeff Roberson if (vm_page_busy_acquire(p, VM_ALLOC_WAITFAIL) == 0) 392*0f9e06e1SJeff Roberson goto restart; 3932164af29SRuslan Bukin sgx_page_remove(sc, p); 3942164af29SRuslan Bukin } 395*0f9e06e1SJeff Roberson p_secs = vm_page_grab(object, SGX_SECS_VM_OBJECT_INDEX, 396*0f9e06e1SJeff 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 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 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 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 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 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 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 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 5962164af29SRuslan Bukin static struct cdev_pager_ops sgx_pg_ops = { 5972164af29SRuslan Bukin .cdev_pg_ctor = sgx_pg_ctor, 5982164af29SRuslan Bukin .cdev_pg_dtor = sgx_pg_dtor, 5992164af29SRuslan Bukin .cdev_pg_fault = sgx_pg_fault, 6002164af29SRuslan Bukin }; 6012164af29SRuslan Bukin 6022164af29SRuslan Bukin static void 6032164af29SRuslan Bukin sgx_insert_epc_page_by_index(vm_page_t page, vm_object_t object, 6042164af29SRuslan Bukin vm_pindex_t pidx) 6052164af29SRuslan Bukin { 6062164af29SRuslan Bukin 6072164af29SRuslan Bukin VM_OBJECT_ASSERT_WLOCKED(object); 6082164af29SRuslan Bukin 6092164af29SRuslan Bukin page->valid = VM_PAGE_BITS_ALL; 6100012f373SJeff Roberson vm_page_insert(page, object, pidx); 6112164af29SRuslan Bukin } 6122164af29SRuslan Bukin 6132164af29SRuslan Bukin static void 6142164af29SRuslan Bukin sgx_insert_epc_page(struct sgx_enclave *enclave, 6152164af29SRuslan Bukin struct epc_page *epc, uint64_t addr) 6162164af29SRuslan Bukin { 6172164af29SRuslan Bukin vm_pindex_t pidx; 6182164af29SRuslan Bukin vm_page_t page; 6192164af29SRuslan Bukin 6202164af29SRuslan Bukin VM_OBJECT_ASSERT_WLOCKED(enclave->object); 6212164af29SRuslan Bukin 6222164af29SRuslan Bukin pidx = OFF_TO_IDX(addr); 6232164af29SRuslan Bukin page = PHYS_TO_VM_PAGE(epc->phys); 6242164af29SRuslan Bukin 6252164af29SRuslan Bukin sgx_insert_epc_page_by_index(page, enclave->object, pidx); 6262164af29SRuslan Bukin } 6272164af29SRuslan Bukin 6282164af29SRuslan Bukin static int 6292164af29SRuslan Bukin sgx_ioctl_create(struct sgx_softc *sc, struct sgx_enclave_create *param) 6302164af29SRuslan Bukin { 6312164af29SRuslan Bukin struct sgx_vm_handle *vmh; 6322164af29SRuslan Bukin vm_map_entry_t entry; 6332164af29SRuslan Bukin vm_page_t p; 6342164af29SRuslan Bukin struct page_info pginfo; 6352164af29SRuslan Bukin struct secinfo secinfo; 6362164af29SRuslan Bukin struct sgx_enclave *enclave; 6372164af29SRuslan Bukin struct epc_page *epc; 6382164af29SRuslan Bukin struct secs *secs; 6392164af29SRuslan Bukin vm_object_t object; 6402164af29SRuslan Bukin vm_page_t page; 6412164af29SRuslan Bukin int ret; 6422164af29SRuslan Bukin 6432164af29SRuslan Bukin epc = NULL; 6442164af29SRuslan Bukin secs = NULL; 6452164af29SRuslan Bukin enclave = NULL; 6462164af29SRuslan Bukin object = NULL; 6472164af29SRuslan Bukin 6482164af29SRuslan Bukin /* SGX Enclave Control Structure (SECS) */ 6492164af29SRuslan Bukin secs = malloc(PAGE_SIZE, M_SGX, M_WAITOK | M_ZERO); 6502164af29SRuslan Bukin ret = copyin((void *)param->src, secs, sizeof(struct secs)); 6512164af29SRuslan Bukin if (ret) { 6522164af29SRuslan Bukin dprintf("%s: Can't copy SECS.\n", __func__); 6532164af29SRuslan Bukin goto error; 6542164af29SRuslan Bukin } 6552164af29SRuslan Bukin 6562164af29SRuslan Bukin ret = sgx_secs_validate(sc, secs); 6572164af29SRuslan Bukin if (ret) { 6582164af29SRuslan Bukin dprintf("%s: SECS validation failed.\n", __func__); 6592164af29SRuslan Bukin goto error; 6602164af29SRuslan Bukin } 6612164af29SRuslan Bukin 6622164af29SRuslan Bukin ret = sgx_mem_find(sc, secs->base, &entry, &object); 6632164af29SRuslan Bukin if (ret) { 6642164af29SRuslan Bukin dprintf("%s: Can't find vm_map.\n", __func__); 6652164af29SRuslan Bukin goto error; 6662164af29SRuslan Bukin } 6672164af29SRuslan Bukin 6682164af29SRuslan Bukin vmh = object->handle; 6692164af29SRuslan Bukin if (!vmh) { 6702164af29SRuslan Bukin dprintf("%s: Can't find vmh.\n", __func__); 6712164af29SRuslan Bukin ret = ENXIO; 6722164af29SRuslan Bukin goto error; 6732164af29SRuslan Bukin } 6742164af29SRuslan Bukin 6752164af29SRuslan Bukin dprintf("%s: entry start %lx offset %lx\n", 6762164af29SRuslan Bukin __func__, entry->start, entry->offset); 6772164af29SRuslan Bukin vmh->base = (entry->start - entry->offset); 6782164af29SRuslan Bukin 6792164af29SRuslan Bukin ret = sgx_enclave_alloc(sc, secs, &enclave); 6802164af29SRuslan Bukin if (ret) { 6812164af29SRuslan Bukin dprintf("%s: Can't alloc enclave.\n", __func__); 6822164af29SRuslan Bukin goto error; 6832164af29SRuslan Bukin } 6842164af29SRuslan Bukin enclave->object = object; 6852164af29SRuslan Bukin enclave->vmh = vmh; 6862164af29SRuslan Bukin 6872164af29SRuslan Bukin memset(&secinfo, 0, sizeof(struct secinfo)); 6882164af29SRuslan Bukin memset(&pginfo, 0, sizeof(struct page_info)); 6892164af29SRuslan Bukin pginfo.linaddr = 0; 6902164af29SRuslan Bukin pginfo.srcpge = (uint64_t)secs; 6912164af29SRuslan Bukin pginfo.secinfo = &secinfo; 6922164af29SRuslan Bukin pginfo.secs = 0; 6932164af29SRuslan Bukin 6942164af29SRuslan Bukin ret = sgx_get_epc_page(sc, &epc); 6952164af29SRuslan Bukin if (ret) { 6962164af29SRuslan Bukin dprintf("%s: Failed to get free epc page.\n", __func__); 6972164af29SRuslan Bukin goto error; 6982164af29SRuslan Bukin } 6992164af29SRuslan Bukin enclave->secs_epc_page = epc; 7002164af29SRuslan Bukin 7012164af29SRuslan Bukin VM_OBJECT_WLOCK(object); 7022164af29SRuslan Bukin p = vm_page_lookup(object, SGX_SECS_VM_OBJECT_INDEX); 7032164af29SRuslan Bukin if (p) { 7042164af29SRuslan Bukin VM_OBJECT_WUNLOCK(object); 7052164af29SRuslan Bukin /* SECS page already added. */ 7062164af29SRuslan Bukin ret = ENXIO; 7072164af29SRuslan Bukin goto error; 7082164af29SRuslan Bukin } 7092164af29SRuslan Bukin 7102164af29SRuslan Bukin ret = sgx_va_slot_init_by_index(sc, object, 7112164af29SRuslan Bukin - SGX_VA_PAGES_OFFS - SGX_SECS_VM_OBJECT_INDEX); 7122164af29SRuslan Bukin if (ret) { 7132164af29SRuslan Bukin VM_OBJECT_WUNLOCK(object); 7142164af29SRuslan Bukin dprintf("%s: Can't init va slot.\n", __func__); 7152164af29SRuslan Bukin goto error; 7162164af29SRuslan Bukin } 7172164af29SRuslan Bukin 7182164af29SRuslan Bukin mtx_lock(&sc->mtx); 7192164af29SRuslan Bukin if ((sc->state & SGX_STATE_RUNNING) == 0) { 7202164af29SRuslan Bukin mtx_unlock(&sc->mtx); 7212164af29SRuslan Bukin /* Remove VA page that was just created for SECS page. */ 722*0f9e06e1SJeff Roberson p = vm_page_grab(enclave->object, 723*0f9e06e1SJeff Roberson - SGX_VA_PAGES_OFFS - SGX_SECS_VM_OBJECT_INDEX, 724*0f9e06e1SJeff Roberson VM_ALLOC_NOCREAT); 7252164af29SRuslan Bukin sgx_page_remove(sc, p); 7262164af29SRuslan Bukin VM_OBJECT_WUNLOCK(object); 7272164af29SRuslan Bukin goto error; 7282164af29SRuslan Bukin } 7292164af29SRuslan Bukin mtx_lock(&sc->mtx_encls); 7302164af29SRuslan Bukin ret = sgx_ecreate(&pginfo, (void *)epc->base); 7312164af29SRuslan Bukin mtx_unlock(&sc->mtx_encls); 7322164af29SRuslan Bukin if (ret == SGX_EFAULT) { 7332164af29SRuslan Bukin dprintf("%s: gp fault\n", __func__); 7342164af29SRuslan Bukin mtx_unlock(&sc->mtx); 7352164af29SRuslan Bukin /* Remove VA page that was just created for SECS page. */ 736*0f9e06e1SJeff Roberson p = vm_page_grab(enclave->object, 737*0f9e06e1SJeff Roberson - SGX_VA_PAGES_OFFS - SGX_SECS_VM_OBJECT_INDEX, 738*0f9e06e1SJeff Roberson VM_ALLOC_NOCREAT); 7392164af29SRuslan Bukin sgx_page_remove(sc, p); 7402164af29SRuslan Bukin VM_OBJECT_WUNLOCK(object); 7412164af29SRuslan Bukin goto error; 7422164af29SRuslan Bukin } 7432164af29SRuslan Bukin 7442164af29SRuslan Bukin TAILQ_INSERT_TAIL(&sc->enclaves, enclave, next); 7452164af29SRuslan Bukin mtx_unlock(&sc->mtx); 7462164af29SRuslan Bukin 7472164af29SRuslan Bukin vmh->enclave = enclave; 7482164af29SRuslan Bukin 7492164af29SRuslan Bukin page = PHYS_TO_VM_PAGE(epc->phys); 7502164af29SRuslan Bukin sgx_insert_epc_page_by_index(page, enclave->object, 7512164af29SRuslan Bukin SGX_SECS_VM_OBJECT_INDEX); 7522164af29SRuslan Bukin 7532164af29SRuslan Bukin VM_OBJECT_WUNLOCK(object); 7542164af29SRuslan Bukin 7552164af29SRuslan Bukin /* Release the reference. */ 7562164af29SRuslan Bukin vm_object_deallocate(object); 7572164af29SRuslan Bukin 7582164af29SRuslan Bukin free(secs, M_SGX); 7592164af29SRuslan Bukin 7602164af29SRuslan Bukin return (0); 7612164af29SRuslan Bukin 7622164af29SRuslan Bukin error: 7632164af29SRuslan Bukin free(secs, M_SGX); 7642164af29SRuslan Bukin sgx_put_epc_page(sc, epc); 7652164af29SRuslan Bukin free(enclave, M_SGX); 7662164af29SRuslan Bukin vm_object_deallocate(object); 7672164af29SRuslan Bukin 7682164af29SRuslan Bukin return (ret); 7692164af29SRuslan Bukin } 7702164af29SRuslan Bukin 7712164af29SRuslan Bukin static int 7722164af29SRuslan Bukin sgx_ioctl_add_page(struct sgx_softc *sc, 7732164af29SRuslan Bukin struct sgx_enclave_add_page *addp) 7742164af29SRuslan Bukin { 7752164af29SRuslan Bukin struct epc_page *secs_epc_page; 7762164af29SRuslan Bukin struct sgx_enclave *enclave; 7772164af29SRuslan Bukin struct sgx_vm_handle *vmh; 7782164af29SRuslan Bukin struct epc_page *epc; 7792164af29SRuslan Bukin struct page_info pginfo; 7802164af29SRuslan Bukin struct secinfo secinfo; 7812164af29SRuslan Bukin vm_object_t object; 7822164af29SRuslan Bukin void *tmp_vaddr; 7832164af29SRuslan Bukin uint64_t page_type; 7842164af29SRuslan Bukin struct tcs *t; 7852164af29SRuslan Bukin uint64_t addr; 7862164af29SRuslan Bukin uint64_t pidx; 7872164af29SRuslan Bukin vm_page_t p; 7882164af29SRuslan Bukin int ret; 7892164af29SRuslan Bukin 7902164af29SRuslan Bukin tmp_vaddr = NULL; 7912164af29SRuslan Bukin epc = NULL; 7922164af29SRuslan Bukin object = NULL; 7932164af29SRuslan Bukin 7942164af29SRuslan Bukin /* Find and get reference to VM object. */ 7952164af29SRuslan Bukin ret = sgx_enclave_find(sc, addp->addr, &enclave); 7962164af29SRuslan Bukin if (ret) { 7972164af29SRuslan Bukin dprintf("%s: Failed to find enclave.\n", __func__); 7982164af29SRuslan Bukin goto error; 7992164af29SRuslan Bukin } 8002164af29SRuslan Bukin 8012164af29SRuslan Bukin object = enclave->object; 8022164af29SRuslan Bukin KASSERT(object != NULL, ("vm object is NULL\n")); 8032164af29SRuslan Bukin vmh = object->handle; 8042164af29SRuslan Bukin 8052164af29SRuslan Bukin ret = sgx_get_epc_page(sc, &epc); 8062164af29SRuslan Bukin if (ret) { 8072164af29SRuslan Bukin dprintf("%s: Failed to get free epc page.\n", __func__); 8082164af29SRuslan Bukin goto error; 8092164af29SRuslan Bukin } 8102164af29SRuslan Bukin 8112164af29SRuslan Bukin memset(&secinfo, 0, sizeof(struct secinfo)); 8122164af29SRuslan Bukin ret = copyin((void *)addp->secinfo, &secinfo, 8132164af29SRuslan Bukin sizeof(struct secinfo)); 8142164af29SRuslan Bukin if (ret) { 8152164af29SRuslan Bukin dprintf("%s: Failed to copy secinfo.\n", __func__); 8162164af29SRuslan Bukin goto error; 8172164af29SRuslan Bukin } 8182164af29SRuslan Bukin 8192164af29SRuslan Bukin tmp_vaddr = malloc(PAGE_SIZE, M_SGX, M_WAITOK | M_ZERO); 8202164af29SRuslan Bukin ret = copyin((void *)addp->src, tmp_vaddr, PAGE_SIZE); 8212164af29SRuslan Bukin if (ret) { 8222164af29SRuslan Bukin dprintf("%s: Failed to copy page.\n", __func__); 8232164af29SRuslan Bukin goto error; 8242164af29SRuslan Bukin } 8252164af29SRuslan Bukin 8262164af29SRuslan Bukin page_type = (secinfo.flags & SECINFO_FLAGS_PT_M) >> 8272164af29SRuslan Bukin SECINFO_FLAGS_PT_S; 8282164af29SRuslan Bukin if (page_type != SGX_PT_TCS && page_type != SGX_PT_REG) { 8292164af29SRuslan Bukin dprintf("%s: page can't be added.\n", __func__); 8302164af29SRuslan Bukin goto error; 8312164af29SRuslan Bukin } 8322164af29SRuslan Bukin if (page_type == SGX_PT_TCS) { 8332164af29SRuslan Bukin t = (struct tcs *)tmp_vaddr; 8342164af29SRuslan Bukin ret = sgx_tcs_validate(t); 8352164af29SRuslan Bukin if (ret) { 8362164af29SRuslan Bukin dprintf("%s: TCS page validation failed.\n", 8372164af29SRuslan Bukin __func__); 8382164af29SRuslan Bukin goto error; 8392164af29SRuslan Bukin } 8402164af29SRuslan Bukin sgx_tcs_dump(sc, t); 8412164af29SRuslan Bukin } 8422164af29SRuslan Bukin 8432164af29SRuslan Bukin addr = (addp->addr - vmh->base); 8442164af29SRuslan Bukin pidx = OFF_TO_IDX(addr); 8452164af29SRuslan Bukin 8462164af29SRuslan Bukin VM_OBJECT_WLOCK(object); 8472164af29SRuslan Bukin p = vm_page_lookup(object, pidx); 8482164af29SRuslan Bukin if (p) { 8492164af29SRuslan Bukin VM_OBJECT_WUNLOCK(object); 8502164af29SRuslan Bukin /* Page already added. */ 8512164af29SRuslan Bukin ret = ENXIO; 8522164af29SRuslan Bukin goto error; 8532164af29SRuslan Bukin } 8542164af29SRuslan Bukin 8552164af29SRuslan Bukin ret = sgx_va_slot_init(sc, enclave, addr); 8562164af29SRuslan Bukin if (ret) { 8572164af29SRuslan Bukin VM_OBJECT_WUNLOCK(object); 8582164af29SRuslan Bukin dprintf("%s: Can't init va slot.\n", __func__); 8592164af29SRuslan Bukin goto error; 8602164af29SRuslan Bukin } 8612164af29SRuslan Bukin 8622164af29SRuslan Bukin secs_epc_page = enclave->secs_epc_page; 8632164af29SRuslan Bukin memset(&pginfo, 0, sizeof(struct page_info)); 8642164af29SRuslan Bukin pginfo.linaddr = (uint64_t)addp->addr; 8652164af29SRuslan Bukin pginfo.srcpge = (uint64_t)tmp_vaddr; 8662164af29SRuslan Bukin pginfo.secinfo = &secinfo; 8672164af29SRuslan Bukin pginfo.secs = (uint64_t)secs_epc_page->base; 8682164af29SRuslan Bukin 8692164af29SRuslan Bukin mtx_lock(&sc->mtx_encls); 8702164af29SRuslan Bukin ret = sgx_eadd(&pginfo, (void *)epc->base); 8712164af29SRuslan Bukin if (ret == SGX_EFAULT) { 8722164af29SRuslan Bukin dprintf("%s: gp fault on eadd\n", __func__); 8732164af29SRuslan Bukin mtx_unlock(&sc->mtx_encls); 8742164af29SRuslan Bukin VM_OBJECT_WUNLOCK(object); 8752164af29SRuslan Bukin goto error; 8762164af29SRuslan Bukin } 8772164af29SRuslan Bukin mtx_unlock(&sc->mtx_encls); 8782164af29SRuslan Bukin 8792164af29SRuslan Bukin ret = sgx_measure_page(sc, enclave->secs_epc_page, epc, addp->mrmask); 8802164af29SRuslan Bukin if (ret == SGX_EFAULT) { 8812164af29SRuslan Bukin dprintf("%s: gp fault on eextend\n", __func__); 8822164af29SRuslan Bukin sgx_epc_page_remove(sc, epc); 8832164af29SRuslan Bukin VM_OBJECT_WUNLOCK(object); 8842164af29SRuslan Bukin goto error; 8852164af29SRuslan Bukin } 8862164af29SRuslan Bukin 8872164af29SRuslan Bukin sgx_insert_epc_page(enclave, epc, addr); 8882164af29SRuslan Bukin 8892164af29SRuslan Bukin VM_OBJECT_WUNLOCK(object); 8902164af29SRuslan Bukin 8912164af29SRuslan Bukin /* Release the reference. */ 8922164af29SRuslan Bukin vm_object_deallocate(object); 8932164af29SRuslan Bukin 8942164af29SRuslan Bukin free(tmp_vaddr, M_SGX); 8952164af29SRuslan Bukin 8962164af29SRuslan Bukin return (0); 8972164af29SRuslan Bukin 8982164af29SRuslan Bukin error: 8992164af29SRuslan Bukin free(tmp_vaddr, M_SGX); 9002164af29SRuslan Bukin sgx_put_epc_page(sc, epc); 9012164af29SRuslan Bukin vm_object_deallocate(object); 9022164af29SRuslan Bukin 9032164af29SRuslan Bukin return (ret); 9042164af29SRuslan Bukin } 9052164af29SRuslan Bukin 9062164af29SRuslan Bukin static int 9072164af29SRuslan Bukin sgx_ioctl_init(struct sgx_softc *sc, struct sgx_enclave_init *initp) 9082164af29SRuslan Bukin { 9092164af29SRuslan Bukin struct epc_page *secs_epc_page; 9102164af29SRuslan Bukin struct sgx_enclave *enclave; 9112164af29SRuslan Bukin struct thread *td; 9122164af29SRuslan Bukin void *tmp_vaddr; 9132164af29SRuslan Bukin void *einittoken; 9142164af29SRuslan Bukin void *sigstruct; 9152164af29SRuslan Bukin vm_object_t object; 9162164af29SRuslan Bukin int retry; 9172164af29SRuslan Bukin int ret; 9182164af29SRuslan Bukin 9192164af29SRuslan Bukin td = curthread; 9202164af29SRuslan Bukin tmp_vaddr = NULL; 9212164af29SRuslan Bukin object = NULL; 9222164af29SRuslan Bukin 9232164af29SRuslan Bukin dprintf("%s: addr %lx, sigstruct %lx, einittoken %lx\n", 9242164af29SRuslan Bukin __func__, initp->addr, initp->sigstruct, initp->einittoken); 9252164af29SRuslan Bukin 9262164af29SRuslan Bukin /* Find and get reference to VM object. */ 9272164af29SRuslan Bukin ret = sgx_enclave_find(sc, initp->addr, &enclave); 9282164af29SRuslan Bukin if (ret) { 9292164af29SRuslan Bukin dprintf("%s: Failed to find enclave.\n", __func__); 9302164af29SRuslan Bukin goto error; 9312164af29SRuslan Bukin } 9322164af29SRuslan Bukin 9332164af29SRuslan Bukin object = enclave->object; 9342164af29SRuslan Bukin 9352164af29SRuslan Bukin tmp_vaddr = malloc(PAGE_SIZE, M_SGX, M_WAITOK | M_ZERO); 9362164af29SRuslan Bukin sigstruct = tmp_vaddr; 9372164af29SRuslan Bukin einittoken = (void *)((uint64_t)sigstruct + PAGE_SIZE / 2); 9382164af29SRuslan Bukin 9392164af29SRuslan Bukin ret = copyin((void *)initp->sigstruct, sigstruct, 9402164af29SRuslan Bukin SGX_SIGSTRUCT_SIZE); 9412164af29SRuslan Bukin if (ret) { 9422164af29SRuslan Bukin dprintf("%s: Failed to copy SIGSTRUCT page.\n", __func__); 9432164af29SRuslan Bukin goto error; 9442164af29SRuslan Bukin } 9452164af29SRuslan Bukin 9462164af29SRuslan Bukin ret = copyin((void *)initp->einittoken, einittoken, 9472164af29SRuslan Bukin SGX_EINITTOKEN_SIZE); 9482164af29SRuslan Bukin if (ret) { 9492164af29SRuslan Bukin dprintf("%s: Failed to copy EINITTOKEN page.\n", __func__); 9502164af29SRuslan Bukin goto error; 9512164af29SRuslan Bukin } 9522164af29SRuslan Bukin 9532164af29SRuslan Bukin secs_epc_page = enclave->secs_epc_page; 9542164af29SRuslan Bukin retry = 16; 9552164af29SRuslan Bukin do { 9562164af29SRuslan Bukin mtx_lock(&sc->mtx_encls); 9572164af29SRuslan Bukin ret = sgx_einit(sigstruct, (void *)secs_epc_page->base, 9582164af29SRuslan Bukin einittoken); 9592164af29SRuslan Bukin mtx_unlock(&sc->mtx_encls); 9602164af29SRuslan Bukin dprintf("%s: sgx_einit returned %d\n", __func__, ret); 9612164af29SRuslan Bukin } while (ret == SGX_UNMASKED_EVENT && retry--); 9622164af29SRuslan Bukin 9632164af29SRuslan Bukin if (ret) { 9642164af29SRuslan Bukin dprintf("%s: Failed init enclave: %d\n", __func__, ret); 9652164af29SRuslan Bukin td->td_retval[0] = ret; 9662164af29SRuslan Bukin ret = 0; 9672164af29SRuslan Bukin } 9682164af29SRuslan Bukin 9692164af29SRuslan Bukin error: 9702164af29SRuslan Bukin free(tmp_vaddr, M_SGX); 9712164af29SRuslan Bukin 9722164af29SRuslan Bukin /* Release the reference. */ 9732164af29SRuslan Bukin vm_object_deallocate(object); 9742164af29SRuslan Bukin 9752164af29SRuslan Bukin return (ret); 9762164af29SRuslan Bukin } 9772164af29SRuslan Bukin 9782164af29SRuslan Bukin static int 9792164af29SRuslan Bukin sgx_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, 9802164af29SRuslan Bukin struct thread *td) 9812164af29SRuslan Bukin { 9822164af29SRuslan Bukin struct sgx_enclave_add_page *addp; 9832164af29SRuslan Bukin struct sgx_enclave_create *param; 9842164af29SRuslan Bukin struct sgx_enclave_init *initp; 9852164af29SRuslan Bukin struct sgx_softc *sc; 9862164af29SRuslan Bukin int ret; 9872164af29SRuslan Bukin int len; 9882164af29SRuslan Bukin 9892164af29SRuslan Bukin sc = &sgx_sc; 9902164af29SRuslan Bukin 9912164af29SRuslan Bukin len = IOCPARM_LEN(cmd); 9922164af29SRuslan Bukin 9932164af29SRuslan Bukin dprintf("%s: cmd %lx, addr %lx, len %d\n", 9942164af29SRuslan Bukin __func__, cmd, (uint64_t)addr, len); 9952164af29SRuslan Bukin 9962164af29SRuslan Bukin if (len > SGX_IOCTL_MAX_DATA_LEN) 9972164af29SRuslan Bukin return (EINVAL); 9982164af29SRuslan Bukin 9992164af29SRuslan Bukin switch (cmd) { 10002164af29SRuslan Bukin case SGX_IOC_ENCLAVE_CREATE: 10012164af29SRuslan Bukin param = (struct sgx_enclave_create *)addr; 10022164af29SRuslan Bukin ret = sgx_ioctl_create(sc, param); 10032164af29SRuslan Bukin break; 10042164af29SRuslan Bukin case SGX_IOC_ENCLAVE_ADD_PAGE: 10052164af29SRuslan Bukin addp = (struct sgx_enclave_add_page *)addr; 10062164af29SRuslan Bukin ret = sgx_ioctl_add_page(sc, addp); 10072164af29SRuslan Bukin break; 10082164af29SRuslan Bukin case SGX_IOC_ENCLAVE_INIT: 10092164af29SRuslan Bukin initp = (struct sgx_enclave_init *)addr; 10102164af29SRuslan Bukin ret = sgx_ioctl_init(sc, initp); 10112164af29SRuslan Bukin break; 10122164af29SRuslan Bukin default: 10132164af29SRuslan Bukin return (EINVAL); 10142164af29SRuslan Bukin } 10152164af29SRuslan Bukin 10162164af29SRuslan Bukin return (ret); 10172164af29SRuslan Bukin } 10182164af29SRuslan Bukin 10192164af29SRuslan Bukin static int 10202164af29SRuslan Bukin sgx_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, 10212164af29SRuslan Bukin vm_size_t mapsize, struct vm_object **objp, int nprot) 10222164af29SRuslan Bukin { 10232164af29SRuslan Bukin struct sgx_vm_handle *vmh; 10242164af29SRuslan Bukin struct sgx_softc *sc; 10252164af29SRuslan Bukin 10262164af29SRuslan Bukin sc = &sgx_sc; 10272164af29SRuslan Bukin 10282164af29SRuslan Bukin dprintf("%s: mapsize 0x%lx, offset %lx\n", 10292164af29SRuslan Bukin __func__, mapsize, *offset); 10302164af29SRuslan Bukin 10312164af29SRuslan Bukin vmh = malloc(sizeof(struct sgx_vm_handle), 10322164af29SRuslan Bukin M_SGX, M_WAITOK | M_ZERO); 10332164af29SRuslan Bukin vmh->sc = sc; 10342164af29SRuslan Bukin vmh->size = mapsize; 10352164af29SRuslan Bukin vmh->mem = cdev_pager_allocate(vmh, OBJT_MGTDEVICE, &sgx_pg_ops, 10362164af29SRuslan Bukin mapsize, nprot, *offset, NULL); 10372164af29SRuslan Bukin if (vmh->mem == NULL) { 10382164af29SRuslan Bukin free(vmh, M_SGX); 10392164af29SRuslan Bukin return (ENOMEM); 10402164af29SRuslan Bukin } 10412164af29SRuslan Bukin 10422164af29SRuslan Bukin VM_OBJECT_WLOCK(vmh->mem); 10432164af29SRuslan Bukin vm_object_set_flag(vmh->mem, OBJ_PG_DTOR); 10442164af29SRuslan Bukin VM_OBJECT_WUNLOCK(vmh->mem); 10452164af29SRuslan Bukin 10462164af29SRuslan Bukin *objp = vmh->mem; 10472164af29SRuslan Bukin 10482164af29SRuslan Bukin return (0); 10492164af29SRuslan Bukin } 10502164af29SRuslan Bukin 10512164af29SRuslan Bukin static struct cdevsw sgx_cdevsw = { 10522164af29SRuslan Bukin .d_version = D_VERSION, 10532164af29SRuslan Bukin .d_ioctl = sgx_ioctl, 10542164af29SRuslan Bukin .d_mmap_single = sgx_mmap_single, 10552164af29SRuslan Bukin .d_name = "Intel SGX", 10562164af29SRuslan Bukin }; 10572164af29SRuslan Bukin 10582164af29SRuslan Bukin static int 10592164af29SRuslan Bukin sgx_get_epc_area(struct sgx_softc *sc) 10602164af29SRuslan Bukin { 10612164af29SRuslan Bukin vm_offset_t epc_base_vaddr; 10622164af29SRuslan Bukin u_int cp[4]; 10632164af29SRuslan Bukin int error; 10642164af29SRuslan Bukin int i; 10652164af29SRuslan Bukin 10662164af29SRuslan Bukin cpuid_count(SGX_CPUID, 0x2, cp); 10672164af29SRuslan Bukin 10682164af29SRuslan Bukin sc->epc_base = ((uint64_t)(cp[1] & 0xfffff) << 32) + 10692164af29SRuslan Bukin (cp[0] & 0xfffff000); 10702164af29SRuslan Bukin sc->epc_size = ((uint64_t)(cp[3] & 0xfffff) << 32) + 10712164af29SRuslan Bukin (cp[2] & 0xfffff000); 10722164af29SRuslan Bukin sc->npages = sc->epc_size / SGX_PAGE_SIZE; 10732164af29SRuslan Bukin 10743caad0b8SMarcin Wojtas if (sc->epc_size == 0 || sc->epc_base == 0) { 10753caad0b8SMarcin Wojtas printf("%s: Incorrect EPC data: EPC base %lx, size %lu\n", 10763caad0b8SMarcin Wojtas __func__, sc->epc_base, sc->epc_size); 10773caad0b8SMarcin Wojtas return (EINVAL); 10783caad0b8SMarcin Wojtas } 10793caad0b8SMarcin Wojtas 10802164af29SRuslan Bukin if (cp[3] & 0xffff) 10812164af29SRuslan Bukin sc->enclave_size_max = (1 << ((cp[3] >> 8) & 0xff)); 10822164af29SRuslan Bukin else 10832164af29SRuslan Bukin sc->enclave_size_max = SGX_ENCL_SIZE_MAX_DEF; 10842164af29SRuslan Bukin 10852164af29SRuslan Bukin epc_base_vaddr = (vm_offset_t)pmap_mapdev_attr(sc->epc_base, 10862164af29SRuslan Bukin sc->epc_size, VM_MEMATTR_DEFAULT); 10872164af29SRuslan Bukin 10882164af29SRuslan Bukin sc->epc_pages = malloc(sizeof(struct epc_page) * sc->npages, 10892164af29SRuslan Bukin M_DEVBUF, M_WAITOK | M_ZERO); 10902164af29SRuslan Bukin 10912164af29SRuslan Bukin for (i = 0; i < sc->npages; i++) { 10922164af29SRuslan Bukin sc->epc_pages[i].base = epc_base_vaddr + SGX_PAGE_SIZE * i; 10932164af29SRuslan Bukin sc->epc_pages[i].phys = sc->epc_base + SGX_PAGE_SIZE * i; 10942164af29SRuslan Bukin sc->epc_pages[i].index = i; 10952164af29SRuslan Bukin } 10962164af29SRuslan Bukin 10972164af29SRuslan Bukin sc->vmem_epc = vmem_create("SGX EPC", sc->epc_base, sc->epc_size, 10982164af29SRuslan Bukin PAGE_SIZE, PAGE_SIZE, M_FIRSTFIT | M_WAITOK); 10992164af29SRuslan Bukin if (sc->vmem_epc == NULL) { 11002164af29SRuslan Bukin printf("%s: Can't create vmem arena.\n", __func__); 11012164af29SRuslan Bukin free(sc->epc_pages, M_SGX); 11022164af29SRuslan Bukin return (EINVAL); 11032164af29SRuslan Bukin } 11042164af29SRuslan Bukin 11052164af29SRuslan Bukin error = vm_phys_fictitious_reg_range(sc->epc_base, 11062164af29SRuslan Bukin sc->epc_base + sc->epc_size, VM_MEMATTR_DEFAULT); 11072164af29SRuslan Bukin if (error) { 11082164af29SRuslan Bukin printf("%s: Can't register fictitious space.\n", __func__); 11092164af29SRuslan Bukin free(sc->epc_pages, M_SGX); 11102164af29SRuslan Bukin return (EINVAL); 11112164af29SRuslan Bukin } 11122164af29SRuslan Bukin 11132164af29SRuslan Bukin return (0); 11142164af29SRuslan Bukin } 11152164af29SRuslan Bukin 11162164af29SRuslan Bukin static void 11172164af29SRuslan Bukin sgx_put_epc_area(struct sgx_softc *sc) 11182164af29SRuslan Bukin { 11192164af29SRuslan Bukin 11202164af29SRuslan Bukin vm_phys_fictitious_unreg_range(sc->epc_base, 11212164af29SRuslan Bukin sc->epc_base + sc->epc_size); 11222164af29SRuslan Bukin 11232164af29SRuslan Bukin free(sc->epc_pages, M_SGX); 11242164af29SRuslan Bukin } 11252164af29SRuslan Bukin 11262164af29SRuslan Bukin static int 11272164af29SRuslan Bukin sgx_load(void) 11282164af29SRuslan Bukin { 11292164af29SRuslan Bukin struct sgx_softc *sc; 11302164af29SRuslan Bukin int error; 11312164af29SRuslan Bukin 11322164af29SRuslan Bukin sc = &sgx_sc; 11332164af29SRuslan Bukin 11342164af29SRuslan Bukin if ((cpu_stdext_feature & CPUID_STDEXT_SGX) == 0) 11352164af29SRuslan Bukin return (ENXIO); 11362164af29SRuslan Bukin 11372164af29SRuslan Bukin error = sgx_get_epc_area(sc); 11382164af29SRuslan Bukin if (error) { 11392164af29SRuslan Bukin printf("%s: Failed to get Processor Reserved Memory area.\n", 11402164af29SRuslan Bukin __func__); 11412164af29SRuslan Bukin return (ENXIO); 11422164af29SRuslan Bukin } 11432164af29SRuslan Bukin 114456512942SRuslan Bukin mtx_init(&sc->mtx_encls, "SGX ENCLS", NULL, MTX_DEF); 114556512942SRuslan Bukin mtx_init(&sc->mtx, "SGX driver", NULL, MTX_DEF); 114656512942SRuslan Bukin 11472164af29SRuslan Bukin TAILQ_INIT(&sc->enclaves); 11482164af29SRuslan Bukin 11492164af29SRuslan Bukin sc->sgx_cdev = make_dev(&sgx_cdevsw, 0, UID_ROOT, GID_WHEEL, 11502164af29SRuslan Bukin 0600, "isgx"); 11512164af29SRuslan Bukin 11522164af29SRuslan Bukin sc->state |= SGX_STATE_RUNNING; 11532164af29SRuslan Bukin 11542164af29SRuslan Bukin printf("SGX initialized: EPC base 0x%lx size %ld (%d pages)\n", 11552164af29SRuslan Bukin sc->epc_base, sc->epc_size, sc->npages); 11562164af29SRuslan Bukin 11572164af29SRuslan Bukin return (0); 11582164af29SRuslan Bukin } 11592164af29SRuslan Bukin 11602164af29SRuslan Bukin static int 11612164af29SRuslan Bukin sgx_unload(void) 11622164af29SRuslan Bukin { 11632164af29SRuslan Bukin struct sgx_softc *sc; 11642164af29SRuslan Bukin 11652164af29SRuslan Bukin sc = &sgx_sc; 11662164af29SRuslan Bukin 116756512942SRuslan Bukin if ((sc->state & SGX_STATE_RUNNING) == 0) 116856512942SRuslan Bukin return (0); 116956512942SRuslan Bukin 11702164af29SRuslan Bukin mtx_lock(&sc->mtx); 11712164af29SRuslan Bukin if (!TAILQ_EMPTY(&sc->enclaves)) { 11722164af29SRuslan Bukin mtx_unlock(&sc->mtx); 11732164af29SRuslan Bukin return (EBUSY); 11742164af29SRuslan Bukin } 11752164af29SRuslan Bukin sc->state &= ~SGX_STATE_RUNNING; 11762164af29SRuslan Bukin mtx_unlock(&sc->mtx); 11772164af29SRuslan Bukin 11782164af29SRuslan Bukin destroy_dev(sc->sgx_cdev); 11792164af29SRuslan Bukin 11802164af29SRuslan Bukin vmem_destroy(sc->vmem_epc); 11812164af29SRuslan Bukin sgx_put_epc_area(sc); 11822164af29SRuslan Bukin 11832164af29SRuslan Bukin mtx_destroy(&sc->mtx_encls); 11842164af29SRuslan Bukin mtx_destroy(&sc->mtx); 11852164af29SRuslan Bukin 11862164af29SRuslan Bukin return (0); 11872164af29SRuslan Bukin } 11882164af29SRuslan Bukin 11892164af29SRuslan Bukin static int 11902164af29SRuslan Bukin sgx_handler(module_t mod, int what, void *arg) 11912164af29SRuslan Bukin { 11922164af29SRuslan Bukin int error; 11932164af29SRuslan Bukin 11942164af29SRuslan Bukin switch (what) { 11952164af29SRuslan Bukin case MOD_LOAD: 11962164af29SRuslan Bukin error = sgx_load(); 11972164af29SRuslan Bukin break; 11982164af29SRuslan Bukin case MOD_UNLOAD: 11992164af29SRuslan Bukin error = sgx_unload(); 12002164af29SRuslan Bukin break; 12012164af29SRuslan Bukin default: 12022164af29SRuslan Bukin error = 0; 12032164af29SRuslan Bukin break; 12042164af29SRuslan Bukin } 12052164af29SRuslan Bukin 12062164af29SRuslan Bukin return (error); 12072164af29SRuslan Bukin } 12082164af29SRuslan Bukin 12092164af29SRuslan Bukin static moduledata_t sgx_kmod = { 12102164af29SRuslan Bukin "sgx", 12112164af29SRuslan Bukin sgx_handler, 12122164af29SRuslan Bukin NULL 12132164af29SRuslan Bukin }; 12142164af29SRuslan Bukin 12152164af29SRuslan Bukin DECLARE_MODULE(sgx, sgx_kmod, SI_SUB_LAST, SI_ORDER_ANY); 12162164af29SRuslan Bukin MODULE_VERSION(sgx, 1); 1217