Merge tag 'mm-stable-2024-05-17-19-19' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-block.git] / arch / x86 / kernel / cpu / sgx / driver.c
CommitLineData
3fe0778e
JS
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright(c) 2016-20 Intel Corporation. */
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
9d0c151b
JS
13u64 sgx_attributes_reserved_mask;
14u64 sgx_xfrm_reserved_mask = ~0x3;
15u32 sgx_misc_reserved_mask;
16
3fe0778e
JS
17static int sgx_open(struct inode *inode, struct file *file)
18{
19 struct sgx_encl *encl;
1728ab54 20 int ret;
3fe0778e
JS
21
22 encl = kzalloc(sizeof(*encl), GFP_KERNEL);
23 if (!encl)
24 return -ENOMEM;
25
1728ab54 26 kref_init(&encl->refcount);
3fe0778e
JS
27 xa_init(&encl->page_array);
28 mutex_init(&encl->lock);
1728ab54
JS
29 INIT_LIST_HEAD(&encl->va_pages);
30 INIT_LIST_HEAD(&encl->mm_list);
31 spin_lock_init(&encl->mm_lock);
32
33 ret = init_srcu_struct(&encl->srcu);
34 if (ret) {
35 kfree(encl);
36 return ret;
37 }
3fe0778e
JS
38
39 file->private_data = encl;
40
41 return 0;
42}
43
44static int sgx_release(struct inode *inode, struct file *file)
45{
46 struct sgx_encl *encl = file->private_data;
1728ab54
JS
47 struct sgx_encl_mm *encl_mm;
48
49 /*
50 * Drain the remaining mm_list entries. At this point the list contains
51 * entries for processes, which have closed the enclave file but have
52 * not exited yet. The processes, which have exited, are gone from the
53 * list by sgx_mmu_notifier_release().
54 */
55 for ( ; ; ) {
56 spin_lock(&encl->mm_lock);
57
58 if (list_empty(&encl->mm_list)) {
59 encl_mm = NULL;
60 } else {
61 encl_mm = list_first_entry(&encl->mm_list,
62 struct sgx_encl_mm, list);
63 list_del_rcu(&encl_mm->list);
3fe0778e
JS
64 }
65
1728ab54 66 spin_unlock(&encl->mm_lock);
3fe0778e 67
1728ab54
JS
68 /* The enclave is no longer mapped by any mm. */
69 if (!encl_mm)
70 break;
3fe0778e 71
1728ab54
JS
72 synchronize_srcu(&encl->srcu);
73 mmu_notifier_unregister(&encl_mm->mmu_notifier, encl_mm->mm);
74 kfree(encl_mm);
2ade0d60
JS
75
76 /* 'encl_mm' is gone, put encl_mm->encl reference: */
77 kref_put(&encl->refcount, sgx_encl_release);
3fe0778e
JS
78 }
79
1728ab54 80 kref_put(&encl->refcount, sgx_encl_release);
3fe0778e
JS
81 return 0;
82}
83
84static int sgx_mmap(struct file *file, struct vm_area_struct *vma)
85{
86 struct sgx_encl *encl = file->private_data;
87 int ret;
88
89 ret = sgx_encl_may_map(encl, vma->vm_start, vma->vm_end, vma->vm_flags);
90 if (ret)
91 return ret;
92
1728ab54
JS
93 ret = sgx_encl_mm_add(encl, vma->vm_mm);
94 if (ret)
95 return ret;
96
3fe0778e 97 vma->vm_ops = &sgx_vm_ops;
1c71222e 98 vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO);
3fe0778e
JS
99 vma->vm_private_data = encl;
100
101 return 0;
102}
103
104static unsigned long sgx_get_unmapped_area(struct file *file,
105 unsigned long addr,
106 unsigned long len,
107 unsigned long pgoff,
108 unsigned long flags)
109{
110 if ((flags & MAP_TYPE) == MAP_PRIVATE)
111 return -EINVAL;
112
113 if (flags & MAP_FIXED)
114 return addr;
115
529ce23a 116 return mm_get_unmapped_area(current->mm, file, addr, len, pgoff, flags);
3fe0778e
JS
117}
118
888d2491
JS
119#ifdef CONFIG_COMPAT
120static long sgx_compat_ioctl(struct file *filep, unsigned int cmd,
121 unsigned long arg)
122{
123 return sgx_ioctl(filep, cmd, arg);
124}
125#endif
126
3fe0778e
JS
127static const struct file_operations sgx_encl_fops = {
128 .owner = THIS_MODULE,
129 .open = sgx_open,
130 .release = sgx_release,
888d2491
JS
131 .unlocked_ioctl = sgx_ioctl,
132#ifdef CONFIG_COMPAT
133 .compat_ioctl = sgx_compat_ioctl,
134#endif
3fe0778e
JS
135 .mmap = sgx_mmap,
136 .get_unmapped_area = sgx_get_unmapped_area,
137};
138
139static struct miscdevice sgx_dev_enclave = {
140 .minor = MISC_DYNAMIC_MINOR,
141 .name = "sgx_enclave",
142 .nodename = "sgx_enclave",
143 .fops = &sgx_encl_fops,
144};
145
146int __init sgx_drv_init(void)
147{
9d0c151b
JS
148 unsigned int eax, ebx, ecx, edx;
149 u64 attr_mask;
150 u64 xfrm_mask;
c82c6186 151 int ret;
9d0c151b 152
3fe0778e
JS
153 if (!cpu_feature_enabled(X86_FEATURE_SGX_LC))
154 return -ENODEV;
155
9d0c151b
JS
156 cpuid_count(SGX_CPUID, 0, &eax, &ebx, &ecx, &edx);
157
158 if (!(eax & 1)) {
159 pr_err("SGX disabled: SGX1 instruction support not available.\n");
160 return -ENODEV;
161 }
162
163 sgx_misc_reserved_mask = ~ebx | SGX_MISC_RESERVED_MASK;
164
165 cpuid_count(SGX_CPUID, 1, &eax, &ebx, &ecx, &edx);
166
167 attr_mask = (((u64)ebx) << 32) + (u64)eax;
168 sgx_attributes_reserved_mask = ~attr_mask | SGX_ATTR_RESERVED_MASK;
169
170 if (cpu_feature_enabled(X86_FEATURE_OSXSAVE)) {
171 xfrm_mask = (((u64)edx) << 32) + (u64)ecx;
172 sgx_xfrm_reserved_mask = ~xfrm_mask;
173 }
174
c82c6186
JS
175 ret = misc_register(&sgx_dev_enclave);
176 if (ret)
177 return ret;
178
c82c6186 179 return 0;
3fe0778e 180}