driver.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright(c) 2016-20 Intel Corporation. */
  3. #include <linux/acpi.h>
  4. #include <linux/miscdevice.h>
  5. #include <linux/mman.h>
  6. #include <linux/security.h>
  7. #include <linux/suspend.h>
  8. #include <asm/traps.h>
  9. #include "driver.h"
  10. #include "encl.h"
  11. u64 sgx_attributes_reserved_mask;
  12. u64 sgx_xfrm_reserved_mask = ~0x3;
  13. u32 sgx_misc_reserved_mask;
  14. static int sgx_open(struct inode *inode, struct file *file)
  15. {
  16. struct sgx_encl *encl;
  17. int ret;
  18. encl = kzalloc(sizeof(*encl), GFP_KERNEL);
  19. if (!encl)
  20. return -ENOMEM;
  21. kref_init(&encl->refcount);
  22. xa_init(&encl->page_array);
  23. mutex_init(&encl->lock);
  24. INIT_LIST_HEAD(&encl->va_pages);
  25. INIT_LIST_HEAD(&encl->mm_list);
  26. spin_lock_init(&encl->mm_lock);
  27. ret = init_srcu_struct(&encl->srcu);
  28. if (ret) {
  29. kfree(encl);
  30. return ret;
  31. }
  32. file->private_data = encl;
  33. return 0;
  34. }
  35. static int sgx_release(struct inode *inode, struct file *file)
  36. {
  37. struct sgx_encl *encl = file->private_data;
  38. struct sgx_encl_mm *encl_mm;
  39. /*
  40. * Drain the remaining mm_list entries. At this point the list contains
  41. * entries for processes, which have closed the enclave file but have
  42. * not exited yet. The processes, which have exited, are gone from the
  43. * list by sgx_mmu_notifier_release().
  44. */
  45. for ( ; ; ) {
  46. spin_lock(&encl->mm_lock);
  47. if (list_empty(&encl->mm_list)) {
  48. encl_mm = NULL;
  49. } else {
  50. encl_mm = list_first_entry(&encl->mm_list,
  51. struct sgx_encl_mm, list);
  52. list_del_rcu(&encl_mm->list);
  53. }
  54. spin_unlock(&encl->mm_lock);
  55. /* The enclave is no longer mapped by any mm. */
  56. if (!encl_mm)
  57. break;
  58. synchronize_srcu(&encl->srcu);
  59. mmu_notifier_unregister(&encl_mm->mmu_notifier, encl_mm->mm);
  60. kfree(encl_mm);
  61. /* 'encl_mm' is gone, put encl_mm->encl reference: */
  62. kref_put(&encl->refcount, sgx_encl_release);
  63. }
  64. kref_put(&encl->refcount, sgx_encl_release);
  65. return 0;
  66. }
  67. static int sgx_mmap(struct file *file, struct vm_area_struct *vma)
  68. {
  69. struct sgx_encl *encl = file->private_data;
  70. int ret;
  71. ret = sgx_encl_may_map(encl, vma->vm_start, vma->vm_end, vma->vm_flags);
  72. if (ret)
  73. return ret;
  74. ret = sgx_encl_mm_add(encl, vma->vm_mm);
  75. if (ret)
  76. return ret;
  77. vma->vm_ops = &sgx_vm_ops;
  78. vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO);
  79. vma->vm_private_data = encl;
  80. return 0;
  81. }
  82. static unsigned long sgx_get_unmapped_area(struct file *file,
  83. unsigned long addr,
  84. unsigned long len,
  85. unsigned long pgoff,
  86. unsigned long flags)
  87. {
  88. if ((flags & MAP_TYPE) == MAP_PRIVATE)
  89. return -EINVAL;
  90. if (flags & MAP_FIXED)
  91. return addr;
  92. return current->mm->get_unmapped_area(file, addr, len, pgoff, flags);
  93. }
  94. #ifdef CONFIG_COMPAT
  95. static long sgx_compat_ioctl(struct file *filep, unsigned int cmd,
  96. unsigned long arg)
  97. {
  98. return sgx_ioctl(filep, cmd, arg);
  99. }
  100. #endif
  101. static const struct file_operations sgx_encl_fops = {
  102. .owner = THIS_MODULE,
  103. .open = sgx_open,
  104. .release = sgx_release,
  105. .unlocked_ioctl = sgx_ioctl,
  106. #ifdef CONFIG_COMPAT
  107. .compat_ioctl = sgx_compat_ioctl,
  108. #endif
  109. .mmap = sgx_mmap,
  110. .get_unmapped_area = sgx_get_unmapped_area,
  111. };
  112. static struct miscdevice sgx_dev_enclave = {
  113. .minor = MISC_DYNAMIC_MINOR,
  114. .name = "sgx_enclave",
  115. .nodename = "sgx_enclave",
  116. .fops = &sgx_encl_fops,
  117. };
  118. int __init sgx_drv_init(void)
  119. {
  120. unsigned int eax, ebx, ecx, edx;
  121. u64 attr_mask;
  122. u64 xfrm_mask;
  123. int ret;
  124. if (!cpu_feature_enabled(X86_FEATURE_SGX_LC))
  125. return -ENODEV;
  126. cpuid_count(SGX_CPUID, 0, &eax, &ebx, &ecx, &edx);
  127. if (!(eax & 1)) {
  128. pr_err("SGX disabled: SGX1 instruction support not available.\n");
  129. return -ENODEV;
  130. }
  131. sgx_misc_reserved_mask = ~ebx | SGX_MISC_RESERVED_MASK;
  132. cpuid_count(SGX_CPUID, 1, &eax, &ebx, &ecx, &edx);
  133. attr_mask = (((u64)ebx) << 32) + (u64)eax;
  134. sgx_attributes_reserved_mask = ~attr_mask | SGX_ATTR_RESERVED_MASK;
  135. if (cpu_feature_enabled(X86_FEATURE_OSXSAVE)) {
  136. xfrm_mask = (((u64)edx) << 32) + (u64)ecx;
  137. sgx_xfrm_reserved_mask = ~xfrm_mask;
  138. }
  139. ret = misc_register(&sgx_dev_enclave);
  140. if (ret)
  141. return ret;
  142. return 0;
  143. }