diff options
Diffstat (limited to 'arch/x86/mm')
-rw-r--r-- | arch/x86/mm/Makefile | 3 | ||||
-rw-r--r-- | arch/x86/mm/fault.c | 19 | ||||
-rw-r--r-- | arch/x86/mm/init.c | 63 | ||||
-rw-r--r-- | arch/x86/mm/pageattr.c | 1 | ||||
-rw-r--r-- | arch/x86/mm/pat.c | 7 | ||||
-rw-r--r-- | arch/x86/mm/setup_nx.c | 69 | ||||
-rw-r--r-- | arch/x86/mm/tlb.c | 15 |
7 files changed, 100 insertions, 77 deletions
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 9b5a9f59a478..06630d26e56d 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile | |||
@@ -1,9 +1,10 @@ | |||
1 | obj-y := init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \ | 1 | obj-y := init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \ |
2 | pat.o pgtable.o physaddr.o gup.o | 2 | pat.o pgtable.o physaddr.o gup.o setup_nx.o |
3 | 3 | ||
4 | # Make sure __phys_addr has no stackprotector | 4 | # Make sure __phys_addr has no stackprotector |
5 | nostackp := $(call cc-option, -fno-stack-protector) | 5 | nostackp := $(call cc-option, -fno-stack-protector) |
6 | CFLAGS_physaddr.o := $(nostackp) | 6 | CFLAGS_physaddr.o := $(nostackp) |
7 | CFLAGS_setup_nx.o := $(nostackp) | ||
7 | 8 | ||
8 | obj-$(CONFIG_SMP) += tlb.o | 9 | obj-$(CONFIG_SMP) += tlb.o |
9 | 10 | ||
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 923ea3fb7037..8f4e2ac93928 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -168,6 +168,7 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long address, | |||
168 | info.si_errno = 0; | 168 | info.si_errno = 0; |
169 | info.si_code = si_code; | 169 | info.si_code = si_code; |
170 | info.si_addr = (void __user *)address; | 170 | info.si_addr = (void __user *)address; |
171 | info.si_addr_lsb = si_code == BUS_MCEERR_AR ? PAGE_SHIFT : 0; | ||
171 | 172 | ||
172 | force_sig_info(si_signo, &info, tsk); | 173 | force_sig_info(si_signo, &info, tsk); |
173 | } | 174 | } |
@@ -791,10 +792,12 @@ out_of_memory(struct pt_regs *regs, unsigned long error_code, | |||
791 | } | 792 | } |
792 | 793 | ||
793 | static void | 794 | static void |
794 | do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address) | 795 | do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, |
796 | unsigned int fault) | ||
795 | { | 797 | { |
796 | struct task_struct *tsk = current; | 798 | struct task_struct *tsk = current; |
797 | struct mm_struct *mm = tsk->mm; | 799 | struct mm_struct *mm = tsk->mm; |
800 | int code = BUS_ADRERR; | ||
798 | 801 | ||
799 | up_read(&mm->mmap_sem); | 802 | up_read(&mm->mmap_sem); |
800 | 803 | ||
@@ -810,7 +813,15 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address) | |||
810 | tsk->thread.error_code = error_code; | 813 | tsk->thread.error_code = error_code; |
811 | tsk->thread.trap_no = 14; | 814 | tsk->thread.trap_no = 14; |
812 | 815 | ||
813 | force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk); | 816 | #ifdef CONFIG_MEMORY_FAILURE |
817 | if (fault & VM_FAULT_HWPOISON) { | ||
818 | printk(KERN_ERR | ||
819 | "MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n", | ||
820 | tsk->comm, tsk->pid, address); | ||
821 | code = BUS_MCEERR_AR; | ||
822 | } | ||
823 | #endif | ||
824 | force_sig_info_fault(SIGBUS, code, address, tsk); | ||
814 | } | 825 | } |
815 | 826 | ||
816 | static noinline void | 827 | static noinline void |
@@ -820,8 +831,8 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code, | |||
820 | if (fault & VM_FAULT_OOM) { | 831 | if (fault & VM_FAULT_OOM) { |
821 | out_of_memory(regs, error_code, address); | 832 | out_of_memory(regs, error_code, address); |
822 | } else { | 833 | } else { |
823 | if (fault & VM_FAULT_SIGBUS) | 834 | if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON)) |
824 | do_sigbus(regs, error_code, address); | 835 | do_sigbus(regs, error_code, address, fault); |
825 | else | 836 | else |
826 | BUG(); | 837 | BUG(); |
827 | } | 838 | } |
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 0607119cef94..73ffd5536f62 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c | |||
@@ -28,69 +28,6 @@ int direct_gbpages | |||
28 | #endif | 28 | #endif |
29 | ; | 29 | ; |
30 | 30 | ||
31 | int nx_enabled; | ||
32 | |||
33 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) | ||
34 | static int disable_nx __cpuinitdata; | ||
35 | |||
36 | /* | ||
37 | * noexec = on|off | ||
38 | * | ||
39 | * Control non-executable mappings for processes. | ||
40 | * | ||
41 | * on Enable | ||
42 | * off Disable | ||
43 | */ | ||
44 | static int __init noexec_setup(char *str) | ||
45 | { | ||
46 | if (!str) | ||
47 | return -EINVAL; | ||
48 | if (!strncmp(str, "on", 2)) { | ||
49 | __supported_pte_mask |= _PAGE_NX; | ||
50 | disable_nx = 0; | ||
51 | } else if (!strncmp(str, "off", 3)) { | ||
52 | disable_nx = 1; | ||
53 | __supported_pte_mask &= ~_PAGE_NX; | ||
54 | } | ||
55 | return 0; | ||
56 | } | ||
57 | early_param("noexec", noexec_setup); | ||
58 | #endif | ||
59 | |||
60 | #ifdef CONFIG_X86_PAE | ||
61 | static void __init set_nx(void) | ||
62 | { | ||
63 | unsigned int v[4], l, h; | ||
64 | |||
65 | if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) { | ||
66 | cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]); | ||
67 | |||
68 | if ((v[3] & (1 << 20)) && !disable_nx) { | ||
69 | rdmsr(MSR_EFER, l, h); | ||
70 | l |= EFER_NX; | ||
71 | wrmsr(MSR_EFER, l, h); | ||
72 | nx_enabled = 1; | ||
73 | __supported_pte_mask |= _PAGE_NX; | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | #else | ||
78 | static inline void set_nx(void) | ||
79 | { | ||
80 | } | ||
81 | #endif | ||
82 | |||
83 | #ifdef CONFIG_X86_64 | ||
84 | void __cpuinit check_efer(void) | ||
85 | { | ||
86 | unsigned long efer; | ||
87 | |||
88 | rdmsrl(MSR_EFER, efer); | ||
89 | if (!(efer & EFER_NX) || disable_nx) | ||
90 | __supported_pte_mask &= ~_PAGE_NX; | ||
91 | } | ||
92 | #endif | ||
93 | |||
94 | static void __init find_early_table_space(unsigned long end, int use_pse, | 31 | static void __init find_early_table_space(unsigned long end, int use_pse, |
95 | int use_gbpages) | 32 | int use_gbpages) |
96 | { | 33 | { |
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 24952fdc7e40..dd38bfbefd1f 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -144,6 +144,7 @@ void clflush_cache_range(void *vaddr, unsigned int size) | |||
144 | 144 | ||
145 | mb(); | 145 | mb(); |
146 | } | 146 | } |
147 | EXPORT_SYMBOL_GPL(clflush_cache_range); | ||
147 | 148 | ||
148 | static void __cpa_flush_all(void *arg) | 149 | static void __cpa_flush_all(void *arg) |
149 | { | 150 | { |
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 7257cf3decf9..e78cd0ec2bcf 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c | |||
@@ -81,6 +81,7 @@ enum { | |||
81 | void pat_init(void) | 81 | void pat_init(void) |
82 | { | 82 | { |
83 | u64 pat; | 83 | u64 pat; |
84 | bool boot_cpu = !boot_pat_state; | ||
84 | 85 | ||
85 | if (!pat_enabled) | 86 | if (!pat_enabled) |
86 | return; | 87 | return; |
@@ -122,8 +123,10 @@ void pat_init(void) | |||
122 | rdmsrl(MSR_IA32_CR_PAT, boot_pat_state); | 123 | rdmsrl(MSR_IA32_CR_PAT, boot_pat_state); |
123 | 124 | ||
124 | wrmsrl(MSR_IA32_CR_PAT, pat); | 125 | wrmsrl(MSR_IA32_CR_PAT, pat); |
125 | printk(KERN_INFO "x86 PAT enabled: cpu %d, old 0x%Lx, new 0x%Lx\n", | 126 | |
126 | smp_processor_id(), boot_pat_state, pat); | 127 | if (boot_cpu) |
128 | printk(KERN_INFO "x86 PAT enabled: cpu %d, old 0x%Lx, new 0x%Lx\n", | ||
129 | smp_processor_id(), boot_pat_state, pat); | ||
127 | } | 130 | } |
128 | 131 | ||
129 | #undef PAT | 132 | #undef PAT |
diff --git a/arch/x86/mm/setup_nx.c b/arch/x86/mm/setup_nx.c new file mode 100644 index 000000000000..513d8ed5d2ec --- /dev/null +++ b/arch/x86/mm/setup_nx.c | |||
@@ -0,0 +1,69 @@ | |||
1 | #include <linux/spinlock.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <linux/init.h> | ||
4 | |||
5 | #include <asm/pgtable.h> | ||
6 | |||
7 | int nx_enabled; | ||
8 | |||
9 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) | ||
10 | static int disable_nx __cpuinitdata; | ||
11 | |||
12 | /* | ||
13 | * noexec = on|off | ||
14 | * | ||
15 | * Control non-executable mappings for processes. | ||
16 | * | ||
17 | * on Enable | ||
18 | * off Disable | ||
19 | */ | ||
20 | static int __init noexec_setup(char *str) | ||
21 | { | ||
22 | if (!str) | ||
23 | return -EINVAL; | ||
24 | if (!strncmp(str, "on", 2)) { | ||
25 | __supported_pte_mask |= _PAGE_NX; | ||
26 | disable_nx = 0; | ||
27 | } else if (!strncmp(str, "off", 3)) { | ||
28 | disable_nx = 1; | ||
29 | __supported_pte_mask &= ~_PAGE_NX; | ||
30 | } | ||
31 | return 0; | ||
32 | } | ||
33 | early_param("noexec", noexec_setup); | ||
34 | #endif | ||
35 | |||
36 | #ifdef CONFIG_X86_PAE | ||
37 | void __init set_nx(void) | ||
38 | { | ||
39 | unsigned int v[4], l, h; | ||
40 | |||
41 | if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) { | ||
42 | cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]); | ||
43 | |||
44 | if ((v[3] & (1 << 20)) && !disable_nx) { | ||
45 | rdmsr(MSR_EFER, l, h); | ||
46 | l |= EFER_NX; | ||
47 | wrmsr(MSR_EFER, l, h); | ||
48 | nx_enabled = 1; | ||
49 | __supported_pte_mask |= _PAGE_NX; | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | #else | ||
54 | void set_nx(void) | ||
55 | { | ||
56 | } | ||
57 | #endif | ||
58 | |||
59 | #ifdef CONFIG_X86_64 | ||
60 | void __cpuinit check_efer(void) | ||
61 | { | ||
62 | unsigned long efer; | ||
63 | |||
64 | rdmsrl(MSR_EFER, efer); | ||
65 | if (!(efer & EFER_NX) || disable_nx) | ||
66 | __supported_pte_mask &= ~_PAGE_NX; | ||
67 | } | ||
68 | #endif | ||
69 | |||
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index c814e144a3f0..36fe08eeb5c3 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c | |||
@@ -59,7 +59,8 @@ void leave_mm(int cpu) | |||
59 | { | 59 | { |
60 | if (percpu_read(cpu_tlbstate.state) == TLBSTATE_OK) | 60 | if (percpu_read(cpu_tlbstate.state) == TLBSTATE_OK) |
61 | BUG(); | 61 | BUG(); |
62 | cpu_clear(cpu, percpu_read(cpu_tlbstate.active_mm)->cpu_vm_mask); | 62 | cpumask_clear_cpu(cpu, |
63 | mm_cpumask(percpu_read(cpu_tlbstate.active_mm))); | ||
63 | load_cr3(swapper_pg_dir); | 64 | load_cr3(swapper_pg_dir); |
64 | } | 65 | } |
65 | EXPORT_SYMBOL_GPL(leave_mm); | 66 | EXPORT_SYMBOL_GPL(leave_mm); |
@@ -234,8 +235,8 @@ void flush_tlb_current_task(void) | |||
234 | preempt_disable(); | 235 | preempt_disable(); |
235 | 236 | ||
236 | local_flush_tlb(); | 237 | local_flush_tlb(); |
237 | if (cpumask_any_but(&mm->cpu_vm_mask, smp_processor_id()) < nr_cpu_ids) | 238 | if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) |
238 | flush_tlb_others(&mm->cpu_vm_mask, mm, TLB_FLUSH_ALL); | 239 | flush_tlb_others(mm_cpumask(mm), mm, TLB_FLUSH_ALL); |
239 | preempt_enable(); | 240 | preempt_enable(); |
240 | } | 241 | } |
241 | 242 | ||
@@ -249,8 +250,8 @@ void flush_tlb_mm(struct mm_struct *mm) | |||
249 | else | 250 | else |
250 | leave_mm(smp_processor_id()); | 251 | leave_mm(smp_processor_id()); |
251 | } | 252 | } |
252 | if (cpumask_any_but(&mm->cpu_vm_mask, smp_processor_id()) < nr_cpu_ids) | 253 | if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) |
253 | flush_tlb_others(&mm->cpu_vm_mask, mm, TLB_FLUSH_ALL); | 254 | flush_tlb_others(mm_cpumask(mm), mm, TLB_FLUSH_ALL); |
254 | 255 | ||
255 | preempt_enable(); | 256 | preempt_enable(); |
256 | } | 257 | } |
@@ -268,8 +269,8 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long va) | |||
268 | leave_mm(smp_processor_id()); | 269 | leave_mm(smp_processor_id()); |
269 | } | 270 | } |
270 | 271 | ||
271 | if (cpumask_any_but(&mm->cpu_vm_mask, smp_processor_id()) < nr_cpu_ids) | 272 | if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) |
272 | flush_tlb_others(&mm->cpu_vm_mask, mm, va); | 273 | flush_tlb_others(mm_cpumask(mm), mm, va); |
273 | 274 | ||
274 | preempt_enable(); | 275 | preempt_enable(); |
275 | } | 276 | } |