xref: /openbmc/linux/arch/x86/kernel/cpu/sgx/driver.c (revision 3fe0778e)
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 
13 static int sgx_open(struct inode *inode, struct file *file)
14 {
15 	struct sgx_encl *encl;
16 
17 	encl = kzalloc(sizeof(*encl), GFP_KERNEL);
18 	if (!encl)
19 		return -ENOMEM;
20 
21 	xa_init(&encl->page_array);
22 	mutex_init(&encl->lock);
23 
24 	file->private_data = encl;
25 
26 	return 0;
27 }
28 
29 static int sgx_release(struct inode *inode, struct file *file)
30 {
31 	struct sgx_encl *encl = file->private_data;
32 	struct sgx_encl_page *entry;
33 	unsigned long index;
34 
35 	xa_for_each(&encl->page_array, index, entry) {
36 		if (entry->epc_page) {
37 			sgx_free_epc_page(entry->epc_page);
38 			encl->secs_child_cnt--;
39 			entry->epc_page = NULL;
40 		}
41 
42 		kfree(entry);
43 	}
44 
45 	xa_destroy(&encl->page_array);
46 
47 	if (!encl->secs_child_cnt && encl->secs.epc_page) {
48 		sgx_free_epc_page(encl->secs.epc_page);
49 		encl->secs.epc_page = NULL;
50 	}
51 
52 	/* Detect EPC page leaks. */
53 	WARN_ON_ONCE(encl->secs_child_cnt);
54 	WARN_ON_ONCE(encl->secs.epc_page);
55 
56 	kfree(encl);
57 	return 0;
58 }
59 
60 static int sgx_mmap(struct file *file, struct vm_area_struct *vma)
61 {
62 	struct sgx_encl *encl = file->private_data;
63 	int ret;
64 
65 	ret = sgx_encl_may_map(encl, vma->vm_start, vma->vm_end, vma->vm_flags);
66 	if (ret)
67 		return ret;
68 
69 	vma->vm_ops = &sgx_vm_ops;
70 	vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
71 	vma->vm_private_data = encl;
72 
73 	return 0;
74 }
75 
76 static unsigned long sgx_get_unmapped_area(struct file *file,
77 					   unsigned long addr,
78 					   unsigned long len,
79 					   unsigned long pgoff,
80 					   unsigned long flags)
81 {
82 	if ((flags & MAP_TYPE) == MAP_PRIVATE)
83 		return -EINVAL;
84 
85 	if (flags & MAP_FIXED)
86 		return addr;
87 
88 	return current->mm->get_unmapped_area(file, addr, len, pgoff, flags);
89 }
90 
91 static const struct file_operations sgx_encl_fops = {
92 	.owner			= THIS_MODULE,
93 	.open			= sgx_open,
94 	.release		= sgx_release,
95 	.mmap			= sgx_mmap,
96 	.get_unmapped_area	= sgx_get_unmapped_area,
97 };
98 
99 static struct miscdevice sgx_dev_enclave = {
100 	.minor = MISC_DYNAMIC_MINOR,
101 	.name = "sgx_enclave",
102 	.nodename = "sgx_enclave",
103 	.fops = &sgx_encl_fops,
104 };
105 
106 int __init sgx_drv_init(void)
107 {
108 	if (!cpu_feature_enabled(X86_FEATURE_SGX_LC))
109 		return -ENODEV;
110 
111 	return misc_register(&sgx_dev_enclave);
112 }
113