0001
0002
0003
0004 #include <linux/acpi.h>
0005 #include <linux/miscdevice.h>
0006 #include <linux/mman.h>
0007 #include <linux/security.h>
0008 #include <linux/suspend.h>
0009 #include <asm/traps.h>
0010 #include "driver.h"
0011 #include "encl.h"
0012
0013 u64 sgx_attributes_reserved_mask;
0014 u64 sgx_xfrm_reserved_mask = ~0x3;
0015 u32 sgx_misc_reserved_mask;
0016
0017 static int sgx_open(struct inode *inode, struct file *file)
0018 {
0019 struct sgx_encl *encl;
0020 int ret;
0021
0022 encl = kzalloc(sizeof(*encl), GFP_KERNEL);
0023 if (!encl)
0024 return -ENOMEM;
0025
0026 kref_init(&encl->refcount);
0027 xa_init(&encl->page_array);
0028 mutex_init(&encl->lock);
0029 INIT_LIST_HEAD(&encl->va_pages);
0030 INIT_LIST_HEAD(&encl->mm_list);
0031 spin_lock_init(&encl->mm_lock);
0032
0033 ret = init_srcu_struct(&encl->srcu);
0034 if (ret) {
0035 kfree(encl);
0036 return ret;
0037 }
0038
0039 file->private_data = encl;
0040
0041 return 0;
0042 }
0043
0044 static int sgx_release(struct inode *inode, struct file *file)
0045 {
0046 struct sgx_encl *encl = file->private_data;
0047 struct sgx_encl_mm *encl_mm;
0048
0049
0050
0051
0052
0053
0054
0055 for ( ; ; ) {
0056 spin_lock(&encl->mm_lock);
0057
0058 if (list_empty(&encl->mm_list)) {
0059 encl_mm = NULL;
0060 } else {
0061 encl_mm = list_first_entry(&encl->mm_list,
0062 struct sgx_encl_mm, list);
0063 list_del_rcu(&encl_mm->list);
0064 }
0065
0066 spin_unlock(&encl->mm_lock);
0067
0068
0069 if (!encl_mm)
0070 break;
0071
0072 synchronize_srcu(&encl->srcu);
0073 mmu_notifier_unregister(&encl_mm->mmu_notifier, encl_mm->mm);
0074 kfree(encl_mm);
0075
0076
0077 kref_put(&encl->refcount, sgx_encl_release);
0078 }
0079
0080 kref_put(&encl->refcount, sgx_encl_release);
0081 return 0;
0082 }
0083
0084 static int sgx_mmap(struct file *file, struct vm_area_struct *vma)
0085 {
0086 struct sgx_encl *encl = file->private_data;
0087 int ret;
0088
0089 ret = sgx_encl_may_map(encl, vma->vm_start, vma->vm_end, vma->vm_flags);
0090 if (ret)
0091 return ret;
0092
0093 ret = sgx_encl_mm_add(encl, vma->vm_mm);
0094 if (ret)
0095 return ret;
0096
0097 vma->vm_ops = &sgx_vm_ops;
0098 vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
0099 vma->vm_private_data = encl;
0100
0101 return 0;
0102 }
0103
0104 static unsigned long sgx_get_unmapped_area(struct file *file,
0105 unsigned long addr,
0106 unsigned long len,
0107 unsigned long pgoff,
0108 unsigned long flags)
0109 {
0110 if ((flags & MAP_TYPE) == MAP_PRIVATE)
0111 return -EINVAL;
0112
0113 if (flags & MAP_FIXED)
0114 return addr;
0115
0116 return current->mm->get_unmapped_area(file, addr, len, pgoff, flags);
0117 }
0118
0119 #ifdef CONFIG_COMPAT
0120 static long sgx_compat_ioctl(struct file *filep, unsigned int cmd,
0121 unsigned long arg)
0122 {
0123 return sgx_ioctl(filep, cmd, arg);
0124 }
0125 #endif
0126
0127 static const struct file_operations sgx_encl_fops = {
0128 .owner = THIS_MODULE,
0129 .open = sgx_open,
0130 .release = sgx_release,
0131 .unlocked_ioctl = sgx_ioctl,
0132 #ifdef CONFIG_COMPAT
0133 .compat_ioctl = sgx_compat_ioctl,
0134 #endif
0135 .mmap = sgx_mmap,
0136 .get_unmapped_area = sgx_get_unmapped_area,
0137 };
0138
0139 static struct miscdevice sgx_dev_enclave = {
0140 .minor = MISC_DYNAMIC_MINOR,
0141 .name = "sgx_enclave",
0142 .nodename = "sgx_enclave",
0143 .fops = &sgx_encl_fops,
0144 };
0145
0146 int __init sgx_drv_init(void)
0147 {
0148 unsigned int eax, ebx, ecx, edx;
0149 u64 attr_mask;
0150 u64 xfrm_mask;
0151 int ret;
0152
0153 if (!cpu_feature_enabled(X86_FEATURE_SGX_LC))
0154 return -ENODEV;
0155
0156 cpuid_count(SGX_CPUID, 0, &eax, &ebx, &ecx, &edx);
0157
0158 if (!(eax & 1)) {
0159 pr_err("SGX disabled: SGX1 instruction support not available.\n");
0160 return -ENODEV;
0161 }
0162
0163 sgx_misc_reserved_mask = ~ebx | SGX_MISC_RESERVED_MASK;
0164
0165 cpuid_count(SGX_CPUID, 1, &eax, &ebx, &ecx, &edx);
0166
0167 attr_mask = (((u64)ebx) << 32) + (u64)eax;
0168 sgx_attributes_reserved_mask = ~attr_mask | SGX_ATTR_RESERVED_MASK;
0169
0170 if (cpu_feature_enabled(X86_FEATURE_OSXSAVE)) {
0171 xfrm_mask = (((u64)edx) << 32) + (u64)ecx;
0172 sgx_xfrm_reserved_mask = ~xfrm_mask;
0173 }
0174
0175 ret = misc_register(&sgx_dev_enclave);
0176 if (ret)
0177 return ret;
0178
0179 return 0;
0180 }