diff options
Diffstat (limited to 'arch/x86/mm/mpx.c')
-rw-r--r-- | arch/x86/mm/mpx.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c new file mode 100644 index 000000000000..72d13b0779a2 --- /dev/null +++ b/arch/x86/mm/mpx.c | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * mpx.c - Memory Protection eXtensions | ||
3 | * | ||
4 | * Copyright (c) 2014, Intel Corporation. | ||
5 | * Qiaowei Ren <qiaowei.ren@intel.com> | ||
6 | * Dave Hansen <dave.hansen@intel.com> | ||
7 | */ | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/syscalls.h> | ||
10 | #include <linux/sched/sysctl.h> | ||
11 | |||
12 | #include <asm/mman.h> | ||
13 | #include <asm/mpx.h> | ||
14 | |||
15 | static const char *mpx_mapping_name(struct vm_area_struct *vma) | ||
16 | { | ||
17 | return "[mpx]"; | ||
18 | } | ||
19 | |||
20 | static struct vm_operations_struct mpx_vma_ops = { | ||
21 | .name = mpx_mapping_name, | ||
22 | }; | ||
23 | |||
24 | /* | ||
25 | * This is really a simplified "vm_mmap". it only handles MPX | ||
26 | * bounds tables (the bounds directory is user-allocated). | ||
27 | * | ||
28 | * Later on, we use the vma->vm_ops to uniquely identify these | ||
29 | * VMAs. | ||
30 | */ | ||
31 | static unsigned long mpx_mmap(unsigned long len) | ||
32 | { | ||
33 | unsigned long ret; | ||
34 | unsigned long addr, pgoff; | ||
35 | struct mm_struct *mm = current->mm; | ||
36 | vm_flags_t vm_flags; | ||
37 | struct vm_area_struct *vma; | ||
38 | |||
39 | /* Only bounds table and bounds directory can be allocated here */ | ||
40 | if (len != MPX_BD_SIZE_BYTES && len != MPX_BT_SIZE_BYTES) | ||
41 | return -EINVAL; | ||
42 | |||
43 | down_write(&mm->mmap_sem); | ||
44 | |||
45 | /* Too many mappings? */ | ||
46 | if (mm->map_count > sysctl_max_map_count) { | ||
47 | ret = -ENOMEM; | ||
48 | goto out; | ||
49 | } | ||
50 | |||
51 | /* Obtain the address to map to. we verify (or select) it and ensure | ||
52 | * that it represents a valid section of the address space. | ||
53 | */ | ||
54 | addr = get_unmapped_area(NULL, 0, len, 0, MAP_ANONYMOUS | MAP_PRIVATE); | ||
55 | if (addr & ~PAGE_MASK) { | ||
56 | ret = addr; | ||
57 | goto out; | ||
58 | } | ||
59 | |||
60 | vm_flags = VM_READ | VM_WRITE | VM_MPX | | ||
61 | mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; | ||
62 | |||
63 | /* Set pgoff according to addr for anon_vma */ | ||
64 | pgoff = addr >> PAGE_SHIFT; | ||
65 | |||
66 | ret = mmap_region(NULL, addr, len, vm_flags, pgoff); | ||
67 | if (IS_ERR_VALUE(ret)) | ||
68 | goto out; | ||
69 | |||
70 | vma = find_vma(mm, ret); | ||
71 | if (!vma) { | ||
72 | ret = -ENOMEM; | ||
73 | goto out; | ||
74 | } | ||
75 | vma->vm_ops = &mpx_vma_ops; | ||
76 | |||
77 | if (vm_flags & VM_LOCKED) { | ||
78 | up_write(&mm->mmap_sem); | ||
79 | mm_populate(ret, len); | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | out: | ||
84 | up_write(&mm->mmap_sem); | ||
85 | return ret; | ||
86 | } | ||