diff options
Diffstat (limited to 'arch/x86_64/mm')
-rw-r--r-- | arch/x86_64/mm/fault.c | 10 | ||||
-rw-r--r-- | arch/x86_64/mm/init.c | 7 | ||||
-rw-r--r-- | arch/x86_64/mm/pageattr.c | 58 |
3 files changed, 41 insertions, 34 deletions
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index 3751b4788e28..a65fc6f1dcaf 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c | |||
@@ -23,9 +23,9 @@ | |||
23 | #include <linux/compiler.h> | 23 | #include <linux/compiler.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/kprobes.h> | 25 | #include <linux/kprobes.h> |
26 | #include <linux/uaccess.h> | ||
26 | 27 | ||
27 | #include <asm/system.h> | 28 | #include <asm/system.h> |
28 | #include <asm/uaccess.h> | ||
29 | #include <asm/pgalloc.h> | 29 | #include <asm/pgalloc.h> |
30 | #include <asm/smp.h> | 30 | #include <asm/smp.h> |
31 | #include <asm/tlbflush.h> | 31 | #include <asm/tlbflush.h> |
@@ -96,7 +96,7 @@ void bust_spinlocks(int yes) | |||
96 | static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr, | 96 | static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr, |
97 | unsigned long error_code) | 97 | unsigned long error_code) |
98 | { | 98 | { |
99 | unsigned char __user *instr; | 99 | unsigned char *instr; |
100 | int scan_more = 1; | 100 | int scan_more = 1; |
101 | int prefetch = 0; | 101 | int prefetch = 0; |
102 | unsigned char *max_instr; | 102 | unsigned char *max_instr; |
@@ -116,7 +116,7 @@ static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr, | |||
116 | unsigned char instr_hi; | 116 | unsigned char instr_hi; |
117 | unsigned char instr_lo; | 117 | unsigned char instr_lo; |
118 | 118 | ||
119 | if (__get_user(opcode, (char __user *)instr)) | 119 | if (probe_kernel_address(instr, opcode)) |
120 | break; | 120 | break; |
121 | 121 | ||
122 | instr_hi = opcode & 0xf0; | 122 | instr_hi = opcode & 0xf0; |
@@ -154,7 +154,7 @@ static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr, | |||
154 | case 0x00: | 154 | case 0x00: |
155 | /* Prefetch instruction is 0x0F0D or 0x0F18 */ | 155 | /* Prefetch instruction is 0x0F0D or 0x0F18 */ |
156 | scan_more = 0; | 156 | scan_more = 0; |
157 | if (__get_user(opcode, (char __user *)instr)) | 157 | if (probe_kernel_address(instr, opcode)) |
158 | break; | 158 | break; |
159 | prefetch = (instr_lo == 0xF) && | 159 | prefetch = (instr_lo == 0xF) && |
160 | (opcode == 0x0D || opcode == 0x18); | 160 | (opcode == 0x0D || opcode == 0x18); |
@@ -170,7 +170,7 @@ static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr, | |||
170 | static int bad_address(void *p) | 170 | static int bad_address(void *p) |
171 | { | 171 | { |
172 | unsigned long dummy; | 172 | unsigned long dummy; |
173 | return __get_user(dummy, (unsigned long __user *)p); | 173 | return probe_kernel_address((unsigned long *)p, dummy); |
174 | } | 174 | } |
175 | 175 | ||
176 | void dump_pagetable(unsigned long address) | 176 | void dump_pagetable(unsigned long address) |
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index 4c0c00ef3ca7..2968b90ef8ad 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c | |||
@@ -730,14 +730,15 @@ static __init int x8664_sysctl_init(void) | |||
730 | __initcall(x8664_sysctl_init); | 730 | __initcall(x8664_sysctl_init); |
731 | #endif | 731 | #endif |
732 | 732 | ||
733 | /* A pseudo VMAs to allow ptrace access for the vsyscall page. This only | 733 | /* A pseudo VMA to allow ptrace access for the vsyscall page. This only |
734 | covers the 64bit vsyscall page now. 32bit has a real VMA now and does | 734 | covers the 64bit vsyscall page now. 32bit has a real VMA now and does |
735 | not need special handling anymore. */ | 735 | not need special handling anymore. */ |
736 | 736 | ||
737 | static struct vm_area_struct gate_vma = { | 737 | static struct vm_area_struct gate_vma = { |
738 | .vm_start = VSYSCALL_START, | 738 | .vm_start = VSYSCALL_START, |
739 | .vm_end = VSYSCALL_END, | 739 | .vm_end = VSYSCALL_START + (VSYSCALL_MAPPED_PAGES << PAGE_SHIFT), |
740 | .vm_page_prot = PAGE_READONLY | 740 | .vm_page_prot = PAGE_READONLY_EXEC, |
741 | .vm_flags = VM_READ | VM_EXEC | ||
741 | }; | 742 | }; |
742 | 743 | ||
743 | struct vm_area_struct *get_gate_vma(struct task_struct *tsk) | 744 | struct vm_area_struct *get_gate_vma(struct task_struct *tsk) |
diff --git a/arch/x86_64/mm/pageattr.c b/arch/x86_64/mm/pageattr.c index 3e231d762aaa..ccb91dd996a9 100644 --- a/arch/x86_64/mm/pageattr.c +++ b/arch/x86_64/mm/pageattr.c | |||
@@ -61,34 +61,40 @@ static struct page *split_large_page(unsigned long address, pgprot_t prot, | |||
61 | return base; | 61 | return base; |
62 | } | 62 | } |
63 | 63 | ||
64 | 64 | static void cache_flush_page(void *adr) | |
65 | static void flush_kernel_map(void *address) | ||
66 | { | 65 | { |
67 | if (0 && address && cpu_has_clflush) { | 66 | int i; |
68 | /* is this worth it? */ | 67 | for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size) |
69 | int i; | 68 | asm volatile("clflush (%0)" :: "r" (adr + i)); |
70 | for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size) | ||
71 | asm volatile("clflush (%0)" :: "r" (address + i)); | ||
72 | } else | ||
73 | asm volatile("wbinvd":::"memory"); | ||
74 | if (address) | ||
75 | __flush_tlb_one(address); | ||
76 | else | ||
77 | __flush_tlb_all(); | ||
78 | } | 69 | } |
79 | 70 | ||
71 | static void flush_kernel_map(void *arg) | ||
72 | { | ||
73 | struct list_head *l = (struct list_head *)arg; | ||
74 | struct page *pg; | ||
75 | |||
76 | /* When clflush is available always use it because it is | ||
77 | much cheaper than WBINVD */ | ||
78 | if (!cpu_has_clflush) | ||
79 | asm volatile("wbinvd" ::: "memory"); | ||
80 | list_for_each_entry(pg, l, lru) { | ||
81 | void *adr = page_address(pg); | ||
82 | if (cpu_has_clflush) | ||
83 | cache_flush_page(adr); | ||
84 | __flush_tlb_one(adr); | ||
85 | } | ||
86 | } | ||
80 | 87 | ||
81 | static inline void flush_map(unsigned long address) | 88 | static inline void flush_map(struct list_head *l) |
82 | { | 89 | { |
83 | on_each_cpu(flush_kernel_map, (void *)address, 1, 1); | 90 | on_each_cpu(flush_kernel_map, l, 1, 1); |
84 | } | 91 | } |
85 | 92 | ||
86 | static struct page *deferred_pages; /* protected by init_mm.mmap_sem */ | 93 | static LIST_HEAD(deferred_pages); /* protected by init_mm.mmap_sem */ |
87 | 94 | ||
88 | static inline void save_page(struct page *fpage) | 95 | static inline void save_page(struct page *fpage) |
89 | { | 96 | { |
90 | fpage->lru.next = (struct list_head *)deferred_pages; | 97 | list_add(&fpage->lru, &deferred_pages); |
91 | deferred_pages = fpage; | ||
92 | } | 98 | } |
93 | 99 | ||
94 | /* | 100 | /* |
@@ -207,18 +213,18 @@ int change_page_attr(struct page *page, int numpages, pgprot_t prot) | |||
207 | 213 | ||
208 | void global_flush_tlb(void) | 214 | void global_flush_tlb(void) |
209 | { | 215 | { |
210 | struct page *dpage; | 216 | struct page *pg, *next; |
217 | struct list_head l; | ||
211 | 218 | ||
212 | down_read(&init_mm.mmap_sem); | 219 | down_read(&init_mm.mmap_sem); |
213 | dpage = xchg(&deferred_pages, NULL); | 220 | list_replace_init(&deferred_pages, &l); |
214 | up_read(&init_mm.mmap_sem); | 221 | up_read(&init_mm.mmap_sem); |
215 | 222 | ||
216 | flush_map((dpage && !dpage->lru.next) ? (unsigned long)page_address(dpage) : 0); | 223 | flush_map(&l); |
217 | while (dpage) { | 224 | |
218 | struct page *tmp = dpage; | 225 | list_for_each_entry_safe(pg, next, &l, lru) { |
219 | dpage = (struct page *)dpage->lru.next; | 226 | ClearPagePrivate(pg); |
220 | ClearPagePrivate(tmp); | 227 | __free_page(pg); |
221 | __free_page(tmp); | ||
222 | } | 228 | } |
223 | } | 229 | } |
224 | 230 | ||