/* * (C) Copyright 2013 Intel Corporation * Author: Jarkko Sakkinen * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; version 2 * of the License. */ #include #include #include #include #include #include #include #include #include "gsgx.h" #if SDK_DRIVER_VERSION == KERNEL_VERSION(1, 6, 0) #include "isgx.h" #include "isgx_arch.h" #include "isgx_user.h" struct file *isgx_dev; static long enclave_create(struct file *filep, void * arg) { struct gsgx_enclave_create *createp = arg; struct isgx_create_param isgx_create; isgx_create.addr = createp->src; filep->private_data = (void *) createp->src; return KSYM(isgx_ioctl_enclave_create)(filep, ISGX_IOCTL_ENCLAVE_CREATE, (unsigned long) &isgx_create); } static long enclave_add_pages(struct file *filep, void * arg) { struct gsgx_enclave_add_pages *addp = arg; struct isgx_add_param isgx_add; uint64_t off; int ret = 0; if (!addp->addr || (addp->addr & (PAGE_SIZE - 1))) return -EINVAL; if (!addp->size || (addp->size & (PAGE_SIZE - 1))) return -EINVAL; if (!addp->secinfo) return -EINVAL; isgx_add.secinfo = (struct isgx_secinfo *) addp->secinfo; for (off = 0 ; off < addp->size ; off += PAGE_SIZE) { isgx_add.addr = addp->addr + off; isgx_add.user_addr = addp->flags & GSGX_ENCLAVE_ADD_PAGES_REPEAT_SRC ? addp->user_addr : addp->user_addr + off; isgx_add.flags = addp->flags & GSGX_ENCLAVE_ADD_PAGES_SKIP_EEXTEND ? ISGX_ADD_SKIP_EEXTEND : 0; ret = KSYM(isgx_ioctl_enclave_add_page)(filep, ISGX_IOCTL_ENCLAVE_ADD_PAGE, (unsigned long) &isgx_add); if (ret < 0) break; } return ret; } static long enclave_init(struct file *filep, void * arg) { struct gsgx_enclave_init *initp = arg; struct isgx_init_param isgx_init; isgx_init.addr = initp->addr; isgx_init.sigstruct = (void *) initp->sigstruct; isgx_init.einittoken = (struct isgx_einittoken *) initp->einittoken; return KSYM(isgx_ioctl_enclave_init)(filep, ISGX_IOCTL_ENCLAVE_INIT, (unsigned long) &isgx_init); } long gsgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { char data[256]; long (*handler) (struct file *filp, void *arg) = NULL; long ret; switch (cmd) { case GSGX_IOCTL_ENCLAVE_CREATE: handler = enclave_create; break; case GSGX_IOCTL_ENCLAVE_ADD_PAGES: handler = enclave_add_pages; break; case GSGX_IOCTL_ENCLAVE_INIT: handler = enclave_init; break; default: return -EINVAL; } if (copy_from_user(data, (void __user *) arg, _IOC_SIZE(cmd))) return -EFAULT; ret = handler(filep, (void *) data); if (!ret && (cmd & IOC_OUT)) { if (copy_to_user((void __user *) arg, data, _IOC_SIZE(cmd))) return -EFAULT; } return ret; } int gsgx_mmap(struct file *file, struct vm_area_struct *vma) { return KSYM(isgx_mmap)(file, vma); } unsigned long gsgx_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { if (file->private_data == (void *) GSGX_ENCLAVE_CREATE_NO_ADDR) { unsigned long unmapped_addr = KSYM(isgx_get_unmapped_area)(file, addr, len, pgoff, flags); file->private_data = (void *) unmapped_addr; return unmapped_addr; } else { unsigned long unmapped_addr = (unsigned long) file->private_data; struct mm_struct *mm = current->mm; struct vm_area_struct *vma = find_vma(mm, unmapped_addr); if (vma && vma->vm_start <= len) return -EINVAL; return unmapped_addr; } } IMPORT_KSYM_PROTO(isgx_ioctl_enclave_create, long, struct file *filep, unsigned int cmd, unsigned long arg); IMPORT_KSYM_PROTO(isgx_ioctl_enclave_init, long, struct file *filep, unsigned int cmd, unsigned long arg); IMPORT_KSYM_PROTO(isgx_ioctl_enclave_add_page, long, struct file *filep, unsigned int cmd, unsigned long arg); IMPORT_KSYM(isgx_enclave_release); IMPORT_KSYM_PROTO(isgx_mmap, int, struct file *, struct vm_area_struct *); IMPORT_KSYM_PROTO(isgx_get_unmapped_area, unsigned long, struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int gsgx_lookup_ksyms(void) { int ret; if ((ret = LOOKUP_KSYM(isgx_ioctl_enclave_create))) return ret; if ((ret = LOOKUP_KSYM(isgx_ioctl_enclave_init))) return ret; if ((ret = LOOKUP_KSYM(isgx_ioctl_enclave_add_page))) return ret; if ((ret = LOOKUP_KSYM(isgx_enclave_release))) return ret; if ((ret = LOOKUP_KSYM(isgx_mmap))) return ret; if ((ret = LOOKUP_KSYM(isgx_get_unmapped_area))) return ret; return 0; } #endif /* SGX_DRIVER_VERSION == 1.7 */