diff options
| -rw-r--r-- | arch/x86/Kconfig | 4 | ||||
| -rw-r--r-- | arch/x86/include/asm/mpx.h | 36 | ||||
| -rw-r--r-- | arch/x86/mm/Makefile | 2 | ||||
| -rw-r--r-- | arch/x86/mm/mpx.c | 86 |
4 files changed, 128 insertions, 0 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ded8a6774ac9..967dfe0ba85e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -248,6 +248,10 @@ config HAVE_INTEL_TXT | |||
| 248 | def_bool y | 248 | def_bool y |
| 249 | depends on INTEL_IOMMU && ACPI | 249 | depends on INTEL_IOMMU && ACPI |
| 250 | 250 | ||
| 251 | config X86_INTEL_MPX | ||
| 252 | def_bool y | ||
| 253 | depends on CPU_SUP_INTEL | ||
| 254 | |||
| 251 | config X86_32_SMP | 255 | config X86_32_SMP |
| 252 | def_bool y | 256 | def_bool y |
| 253 | depends on X86_32 && SMP | 257 | depends on X86_32 && SMP |
diff --git a/arch/x86/include/asm/mpx.h b/arch/x86/include/asm/mpx.h new file mode 100644 index 000000000000..7d7c5f54cc5f --- /dev/null +++ b/arch/x86/include/asm/mpx.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #ifndef _ASM_X86_MPX_H | ||
| 2 | #define _ASM_X86_MPX_H | ||
| 3 | |||
| 4 | #include <linux/types.h> | ||
| 5 | #include <asm/ptrace.h> | ||
| 6 | |||
| 7 | #ifdef CONFIG_X86_64 | ||
| 8 | |||
| 9 | /* upper 28 bits [47:20] of the virtual address in 64-bit used to | ||
| 10 | * index into bounds directory (BD). | ||
| 11 | */ | ||
| 12 | #define MPX_BD_ENTRY_OFFSET 28 | ||
| 13 | #define MPX_BD_ENTRY_SHIFT 3 | ||
| 14 | /* bits [19:3] of the virtual address in 64-bit used to index into | ||
| 15 | * bounds table (BT). | ||
| 16 | */ | ||
| 17 | #define MPX_BT_ENTRY_OFFSET 17 | ||
| 18 | #define MPX_BT_ENTRY_SHIFT 5 | ||
| 19 | #define MPX_IGN_BITS 3 | ||
| 20 | |||
| 21 | #else | ||
| 22 | |||
| 23 | #define MPX_BD_ENTRY_OFFSET 20 | ||
| 24 | #define MPX_BD_ENTRY_SHIFT 2 | ||
| 25 | #define MPX_BT_ENTRY_OFFSET 10 | ||
| 26 | #define MPX_BT_ENTRY_SHIFT 4 | ||
| 27 | #define MPX_IGN_BITS 2 | ||
| 28 | |||
| 29 | #endif | ||
| 30 | |||
| 31 | #define MPX_BD_SIZE_BYTES (1UL<<(MPX_BD_ENTRY_OFFSET+MPX_BD_ENTRY_SHIFT)) | ||
| 32 | #define MPX_BT_SIZE_BYTES (1UL<<(MPX_BT_ENTRY_OFFSET+MPX_BT_ENTRY_SHIFT)) | ||
| 33 | |||
| 34 | #define MPX_BNDSTA_ERROR_CODE 0x3 | ||
| 35 | |||
| 36 | #endif /* _ASM_X86_MPX_H */ | ||
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 6a19ad9f370d..ecfdc46a024a 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile | |||
| @@ -30,3 +30,5 @@ obj-$(CONFIG_ACPI_NUMA) += srat.o | |||
| 30 | obj-$(CONFIG_NUMA_EMU) += numa_emulation.o | 30 | obj-$(CONFIG_NUMA_EMU) += numa_emulation.o |
| 31 | 31 | ||
| 32 | obj-$(CONFIG_MEMTEST) += memtest.o | 32 | obj-$(CONFIG_MEMTEST) += memtest.o |
| 33 | |||
| 34 | obj-$(CONFIG_X86_INTEL_MPX) += mpx.o | ||
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 | } | ||
