File Index
Files and directories
Sign in
FILE

driver.c

File preview with syntax highlighting.

linux-6.19.14/arch/x86/kernel/cpu/sgx/driver.c C
  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
 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
 22	encl = kzalloc(sizeof(*encl), GFP_KERNEL);
 23	if (!encl)
 24		return -ENOMEM;
 25
 26	kref_init(&encl->refcount);
 27	xa_init(&encl->page_array);
 28	mutex_init(&encl->lock);
 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	}
 38
 39	file->private_data = encl;
 40
 41	return 0;
 42}
 43
 44static int sgx_open(struct inode *inode, struct file *file)
 45{
 46	int ret;
 47
 48	ret = sgx_inc_usage_count();
 49	if (ret)
 50		return ret;
 51
 52	ret = __sgx_open(inode, file);
 53	if (ret) {
 54		sgx_dec_usage_count();
 55		return ret;
 56	}
 57
 58	return 0;
 59}
 60
 61static int sgx_release(struct inode *inode, struct file *file)
 62{
 63	struct sgx_encl *encl = file->private_data;
 64	struct sgx_encl_mm *encl_mm;
 65
 66	/*
 67	 * Drain the remaining mm_list entries. At this point the list contains
 68	 * entries for processes, which have closed the enclave file but have
 69	 * not exited yet. The processes, which have exited, are gone from the
 70	 * list by sgx_mmu_notifier_release().
 71	 */
 72	for ( ; ; )  {
 73		spin_lock(&encl->mm_lock);
 74
 75		if (list_empty(&encl->mm_list)) {
 76			encl_mm = NULL;
 77		} else {
 78			encl_mm = list_first_entry(&encl->mm_list,
 79						   struct sgx_encl_mm, list);
 80			list_del_rcu(&encl_mm->list);
 81		}
 82
 83		spin_unlock(&encl->mm_lock);
 84
 85		/* The enclave is no longer mapped by any mm. */
 86		if (!encl_mm)
 87			break;
 88
 89		synchronize_srcu(&encl->srcu);
 90		mmu_notifier_unregister(&encl_mm->mmu_notifier, encl_mm->mm);
 91		kfree(encl_mm);
 92
 93		/* 'encl_mm' is gone, put encl_mm->encl reference: */
 94		kref_put(&encl->refcount, sgx_encl_release);
 95	}
 96
 97	kref_put(&encl->refcount, sgx_encl_release);
 98	return 0;
 99}
100
101static int sgx_mmap(struct file *file, struct vm_area_struct *vma)
102{
103	struct sgx_encl *encl = file->private_data;
104	int ret;
105
106	ret = sgx_encl_may_map(encl, vma->vm_start, vma->vm_end, vma->vm_flags);
107	if (ret)
108		return ret;
109
110	ret = sgx_encl_mm_add(encl, vma->vm_mm);
111	if (ret)
112		return ret;
113
114	vma->vm_ops = &sgx_vm_ops;
115	vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO);
116	vma->vm_private_data = encl;
117
118	return 0;
119}
120
121static unsigned long sgx_get_unmapped_area(struct file *file,
122					   unsigned long addr,
123					   unsigned long len,
124					   unsigned long pgoff,
125					   unsigned long flags)
126{
127	if ((flags & MAP_TYPE) == MAP_PRIVATE)
128		return -EINVAL;
129
130	if (flags & MAP_FIXED)
131		return addr;
132
133	return mm_get_unmapped_area(file, addr, len, pgoff, flags);
134}
135
136#ifdef CONFIG_COMPAT
137static long sgx_compat_ioctl(struct file *filep, unsigned int cmd,
138			      unsigned long arg)
139{
140	return sgx_ioctl(filep, cmd, arg);
141}
142#endif
143
144static const struct file_operations sgx_encl_fops = {
145	.owner			= THIS_MODULE,
146	.open			= sgx_open,
147	.release		= sgx_release,
148	.unlocked_ioctl		= sgx_ioctl,
149#ifdef CONFIG_COMPAT
150	.compat_ioctl		= sgx_compat_ioctl,
151#endif
152	.mmap			= sgx_mmap,
153	.get_unmapped_area	= sgx_get_unmapped_area,
154};
155
156static struct miscdevice sgx_dev_enclave = {
157	.minor = MISC_DYNAMIC_MINOR,
158	.name = "sgx_enclave",
159	.nodename = "sgx_enclave",
160	.fops = &sgx_encl_fops,
161};
162
163int __init sgx_drv_init(void)
164{
165	unsigned int eax, ebx, ecx, edx;
166	u64 attr_mask;
167	u64 xfrm_mask;
168	int ret;
169
170	if (!cpu_feature_enabled(X86_FEATURE_SGX_LC)) {
171		pr_info("SGX disabled: SGX launch control CPU feature is not available, /dev/sgx_enclave disabled.\n");
172		return -ENODEV;
173	}
174
175	cpuid_count(SGX_CPUID, 0, &eax, &ebx, &ecx, &edx);
176
177	if (!(eax & 1))  {
178		pr_info("SGX disabled: SGX1 instruction support not available, /dev/sgx_enclave disabled.\n");
179		return -ENODEV;
180	}
181
182	sgx_misc_reserved_mask = ~ebx | SGX_MISC_RESERVED_MASK;
183
184	cpuid_count(SGX_CPUID, 1, &eax, &ebx, &ecx, &edx);
185
186	attr_mask = (((u64)ebx) << 32) + (u64)eax;
187	sgx_attributes_reserved_mask = ~attr_mask | SGX_ATTR_RESERVED_MASK;
188
189	if (cpu_feature_enabled(X86_FEATURE_OSXSAVE)) {
190		xfrm_mask = (((u64)edx) << 32) + (u64)ecx;
191		sgx_xfrm_reserved_mask = ~xfrm_mask;
192	}
193
194	ret = misc_register(&sgx_dev_enclave);
195	if (ret) {
196		pr_info("SGX disabled: Unable to register the /dev/sgx_enclave driver (%d).\n", ret);
197		return ret;
198	}
199
200	return 0;
201}
~/ Read-only file preview.