aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/fault.c
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-09-23 17:08:43 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2009-09-23 17:08:43 -0400
commitd7a4b414eed51f1653bb05ebe84122bf9a7ae18b (patch)
treebd6603a0c27de4c138a1767871897e9cd3e1a1d2 /arch/x86/mm/fault.c
parent1f0ab40976460bc4673fa204ce917a725185d8f2 (diff)
parenta724eada8c2a7b62463b73ccf73fd0bb6e928aeb (diff)
Merge commit 'linus/master' into tracing/kprobes
Conflicts: kernel/trace/Makefile kernel/trace/trace.h kernel/trace/trace_event_types.h kernel/trace/trace_export.c Merge reason: Sync with latest significant tracing core changes.
Diffstat (limited to 'arch/x86/mm/fault.c')
-rw-r--r--arch/x86/mm/fault.c59
1 files changed, 25 insertions, 34 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index c322e59f2d10..923ea3fb7037 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -10,7 +10,7 @@
10#include <linux/bootmem.h> /* max_low_pfn */ 10#include <linux/bootmem.h> /* max_low_pfn */
11#include <linux/kprobes.h> /* __kprobes, ... */ 11#include <linux/kprobes.h> /* __kprobes, ... */
12#include <linux/mmiotrace.h> /* kmmio_handler, ... */ 12#include <linux/mmiotrace.h> /* kmmio_handler, ... */
13#include <linux/perf_counter.h> /* perf_swcounter_event */ 13#include <linux/perf_event.h> /* perf_sw_event */
14 14
15#include <asm/traps.h> /* dotraplinkage, ... */ 15#include <asm/traps.h> /* dotraplinkage, ... */
16#include <asm/pgalloc.h> /* pgd_*(), ... */ 16#include <asm/pgalloc.h> /* pgd_*(), ... */
@@ -286,26 +286,25 @@ check_v8086_mode(struct pt_regs *regs, unsigned long address,
286 tsk->thread.screen_bitmap |= 1 << bit; 286 tsk->thread.screen_bitmap |= 1 << bit;
287} 287}
288 288
289static void dump_pagetable(unsigned long address) 289static bool low_pfn(unsigned long pfn)
290{ 290{
291 __typeof__(pte_val(__pte(0))) page; 291 return pfn < max_low_pfn;
292}
292 293
293 page = read_cr3(); 294static void dump_pagetable(unsigned long address)
294 page = ((__typeof__(page) *) __va(page))[address >> PGDIR_SHIFT]; 295{
296 pgd_t *base = __va(read_cr3());
297 pgd_t *pgd = &base[pgd_index(address)];
298 pmd_t *pmd;
299 pte_t *pte;
295 300
296#ifdef CONFIG_X86_PAE 301#ifdef CONFIG_X86_PAE
297 printk("*pdpt = %016Lx ", page); 302 printk("*pdpt = %016Lx ", pgd_val(*pgd));
298 if ((page >> PAGE_SHIFT) < max_low_pfn 303 if (!low_pfn(pgd_val(*pgd) >> PAGE_SHIFT) || !pgd_present(*pgd))
299 && page & _PAGE_PRESENT) { 304 goto out;
300 page &= PAGE_MASK;
301 page = ((__typeof__(page) *) __va(page))[(address >> PMD_SHIFT)
302 & (PTRS_PER_PMD - 1)];
303 printk(KERN_CONT "*pde = %016Lx ", page);
304 page &= ~_PAGE_NX;
305 }
306#else
307 printk("*pde = %08lx ", page);
308#endif 305#endif
306 pmd = pmd_offset(pud_offset(pgd, address), address);
307 printk(KERN_CONT "*pde = %0*Lx ", sizeof(*pmd) * 2, (u64)pmd_val(*pmd));
309 308
310 /* 309 /*
311 * We must not directly access the pte in the highpte 310 * We must not directly access the pte in the highpte
@@ -313,16 +312,12 @@ static void dump_pagetable(unsigned long address)
313 * And let's rather not kmap-atomic the pte, just in case 312 * And let's rather not kmap-atomic the pte, just in case
314 * it's allocated already: 313 * it's allocated already:
315 */ 314 */
316 if ((page >> PAGE_SHIFT) < max_low_pfn 315 if (!low_pfn(pmd_pfn(*pmd)) || !pmd_present(*pmd) || pmd_large(*pmd))
317 && (page & _PAGE_PRESENT) 316 goto out;
318 && !(page & _PAGE_PSE)) {
319
320 page &= PAGE_MASK;
321 page = ((__typeof__(page) *) __va(page))[(address >> PAGE_SHIFT)
322 & (PTRS_PER_PTE - 1)];
323 printk("*pte = %0*Lx ", sizeof(page)*2, (u64)page);
324 }
325 317
318 pte = pte_offset_kernel(pmd, address);
319 printk("*pte = %0*Lx ", sizeof(*pte) * 2, (u64)pte_val(*pte));
320out:
326 printk("\n"); 321 printk("\n");
327} 322}
328 323
@@ -451,16 +446,12 @@ static int bad_address(void *p)
451 446
452static void dump_pagetable(unsigned long address) 447static void dump_pagetable(unsigned long address)
453{ 448{
454 pgd_t *pgd; 449 pgd_t *base = __va(read_cr3() & PHYSICAL_PAGE_MASK);
450 pgd_t *pgd = base + pgd_index(address);
455 pud_t *pud; 451 pud_t *pud;
456 pmd_t *pmd; 452 pmd_t *pmd;
457 pte_t *pte; 453 pte_t *pte;
458 454
459 pgd = (pgd_t *)read_cr3();
460
461 pgd = __va((unsigned long)pgd & PHYSICAL_PAGE_MASK);
462
463 pgd += pgd_index(address);
464 if (bad_address(pgd)) 455 if (bad_address(pgd))
465 goto bad; 456 goto bad;
466 457
@@ -1027,7 +1018,7 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
1027 if (unlikely(error_code & PF_RSVD)) 1018 if (unlikely(error_code & PF_RSVD))
1028 pgtable_bad(regs, error_code, address); 1019 pgtable_bad(regs, error_code, address);
1029 1020
1030 perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); 1021 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
1031 1022
1032 /* 1023 /*
1033 * If we're in an interrupt, have no user context or are running 1024 * If we're in an interrupt, have no user context or are running
@@ -1124,11 +1115,11 @@ good_area:
1124 1115
1125 if (fault & VM_FAULT_MAJOR) { 1116 if (fault & VM_FAULT_MAJOR) {
1126 tsk->maj_flt++; 1117 tsk->maj_flt++;
1127 perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, 1118 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
1128 regs, address); 1119 regs, address);
1129 } else { 1120 } else {
1130 tsk->min_flt++; 1121 tsk->min_flt++;
1131 perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, 1122 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
1132 regs, address); 1123 regs, address);
1133 } 1124 }
1134 1125