1
2
3
4#include <linux/acpi.h>
5#include <linux/miscdevice.h>
6#include <linux/mman.h>
7#include <linux/security.h>
8#include <linux/suspend.h>
9#include <asm/traps.h>
10#include "driver.h"
11#include "encl.h"
12
13u64 sgx_attributes_reserved_mask;
14u64 sgx_xfrm_reserved_mask = ~0x3;
15u32 sgx_misc_reserved_mask;
16
17static int sgx_open(struct inode *inode, struct file *file)
18{
19 struct sgx_encl *encl;
20 int ret;
21 static bool warned = false;
22
23 encl = kzalloc(sizeof(*encl), GFP_KERNEL);
24 if (!encl)
25 return -ENOMEM;
26
27 kref_init(&encl->refcount);
28 xa_init(&encl->page_array);
29 mutex_init(&encl->lock);
30 INIT_LIST_HEAD(&encl->va_pages);
31 INIT_LIST_HEAD(&encl->mm_list);
32 spin_lock_init(&encl->mm_lock);
33
34 ret = init_srcu_struct(&encl->srcu);
35 if (ret) {
36 kfree(encl);
37 return ret;
38 }
39
40 if (!warned) {
41 mark_tech_preview("Intel Software Guard Extensions (SGX)", NULL);
42 warned = true;
43 }
44
45 file->private_data = encl;
46
47 return 0;
48}
49
50static int sgx_release(struct inode *inode, struct file *file)
51{
52 struct sgx_encl *encl = file->private_data;
53 struct sgx_encl_mm *encl_mm;
54
55
56
57
58
59
60
61 for ( ; ; ) {
62 spin_lock(&encl->mm_lock);
63
64 if (list_empty(&encl->mm_list)) {
65 encl_mm = NULL;
66 } else {
67 encl_mm = list_first_entry(&encl->mm_list,
68 struct sgx_encl_mm, list);
69 list_del_rcu(&encl_mm->list);
70 }
71
72 spin_unlock(&encl->mm_lock);
73
74
75 if (!encl_mm)
76 break;
77
78 synchronize_srcu(&encl->srcu);
79 mmu_notifier_unregister(&encl_mm->mmu_notifier, encl_mm->mm);
80 kfree(encl_mm);
81 }
82
83 kref_put(&encl->refcount, sgx_encl_release);
84 return 0;
85}
86
87static int sgx_mmap(struct file *file, struct vm_area_struct *vma)
88{
89 struct sgx_encl *encl = file->private_data;
90 int ret;
91
92 ret = sgx_encl_may_map(encl, vma->vm_start, vma->vm_end, vma->vm_flags);
93 if (ret)
94 return ret;
95
96 ret = sgx_encl_mm_add(encl, vma->vm_mm);
97 if (ret)
98 return ret;
99
100 vma->vm_ops = &sgx_vm_ops;
101 vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
102 vma->vm_private_data = encl;
103
104 return 0;
105}
106
107static unsigned long sgx_get_unmapped_area(struct file *file,
108 unsigned long addr,
109 unsigned long len,
110 unsigned long pgoff,
111 unsigned long flags)
112{
113 if ((flags & MAP_TYPE) == MAP_PRIVATE)
114 return -EINVAL;
115
116 if (flags & MAP_FIXED)
117 return addr;
118
119 return current->mm->get_unmapped_area(file, addr, len, pgoff, flags);
120}
121
122#ifdef CONFIG_COMPAT
123static long sgx_compat_ioctl(struct file *filep, unsigned int cmd,
124 unsigned long arg)
125{
126 return sgx_ioctl(filep, cmd, arg);
127}
128#endif
129
130static const struct file_operations sgx_encl_fops = {
131 .owner = THIS_MODULE,
132 .open = sgx_open,
133 .release = sgx_release,
134 .unlocked_ioctl = sgx_ioctl,
135#ifdef CONFIG_COMPAT
136 .compat_ioctl = sgx_compat_ioctl,
137#endif
138 .mmap = sgx_mmap,
139 .get_unmapped_area = sgx_get_unmapped_area,
140};
141
142const struct file_operations sgx_provision_fops = {
143 .owner = THIS_MODULE,
144};
145
146static struct miscdevice sgx_dev_enclave = {
147 .minor = MISC_DYNAMIC_MINOR,
148 .name = "sgx_enclave",
149 .nodename = "sgx_enclave",
150 .fops = &sgx_encl_fops,
151};
152
153static struct miscdevice sgx_dev_provision = {
154 .minor = MISC_DYNAMIC_MINOR,
155 .name = "sgx_provision",
156 .nodename = "sgx_provision",
157 .fops = &sgx_provision_fops,
158};
159
160int __init sgx_drv_init(void)
161{
162 unsigned int eax, ebx, ecx, edx;
163 u64 attr_mask;
164 u64 xfrm_mask;
165 int ret;
166
167 if (!cpu_feature_enabled(X86_FEATURE_SGX_LC))
168 return -ENODEV;
169
170 cpuid_count(SGX_CPUID, 0, &eax, &ebx, &ecx, &edx);
171
172 if (!(eax & 1)) {
173 pr_err("SGX disabled: SGX1 instruction support not available.\n");
174 return -ENODEV;
175 }
176
177 sgx_misc_reserved_mask = ~ebx | SGX_MISC_RESERVED_MASK;
178
179 cpuid_count(SGX_CPUID, 1, &eax, &ebx, &ecx, &edx);
180
181 attr_mask = (((u64)ebx) << 32) + (u64)eax;
182 sgx_attributes_reserved_mask = ~attr_mask | SGX_ATTR_RESERVED_MASK;
183
184 if (cpu_feature_enabled(X86_FEATURE_OSXSAVE)) {
185 xfrm_mask = (((u64)edx) << 32) + (u64)ecx;
186 sgx_xfrm_reserved_mask = ~xfrm_mask;
187 }
188
189 ret = misc_register(&sgx_dev_enclave);
190 if (ret)
191 return ret;
192
193 ret = misc_register(&sgx_dev_provision);
194 if (ret) {
195 misc_deregister(&sgx_dev_enclave);
196 return ret;
197 }
198
199 return 0;
200}
201