diff options
author | Anton Vorontsov <avorontsov@ru.mvista.com> | 2009-09-22 19:49:27 -0400 |
---|---|---|
committer | Anton Vorontsov <avorontsov@ru.mvista.com> | 2009-09-22 19:49:27 -0400 |
commit | f056878332a91ed984a116bad4e7d49aefff9e6e (patch) | |
tree | 572f4757c8e7811d45e0be0c2ae529c78fb63441 /arch/x86/mm/fault.c | |
parent | 3961f7c3cf247eee5df7fabadc7a40f2deeb98f3 (diff) | |
parent | 7fa07729e439a6184bd824746d06a49cca553f15 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
drivers/power/wm97xx_battery.c
Diffstat (limited to 'arch/x86/mm/fault.c')
-rw-r--r-- | arch/x86/mm/fault.c | 70 |
1 files changed, 31 insertions, 39 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 78a5fff857be..82728f2c6d55 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_*(), ... */ |
@@ -285,26 +285,25 @@ check_v8086_mode(struct pt_regs *regs, unsigned long address, | |||
285 | tsk->thread.screen_bitmap |= 1 << bit; | 285 | tsk->thread.screen_bitmap |= 1 << bit; |
286 | } | 286 | } |
287 | 287 | ||
288 | static void dump_pagetable(unsigned long address) | 288 | static bool low_pfn(unsigned long pfn) |
289 | { | 289 | { |
290 | __typeof__(pte_val(__pte(0))) page; | 290 | return pfn < max_low_pfn; |
291 | } | ||
291 | 292 | ||
292 | page = read_cr3(); | 293 | static void dump_pagetable(unsigned long address) |
293 | page = ((__typeof__(page) *) __va(page))[address >> PGDIR_SHIFT]; | 294 | { |
295 | pgd_t *base = __va(read_cr3()); | ||
296 | pgd_t *pgd = &base[pgd_index(address)]; | ||
297 | pmd_t *pmd; | ||
298 | pte_t *pte; | ||
294 | 299 | ||
295 | #ifdef CONFIG_X86_PAE | 300 | #ifdef CONFIG_X86_PAE |
296 | printk("*pdpt = %016Lx ", page); | 301 | printk("*pdpt = %016Lx ", pgd_val(*pgd)); |
297 | if ((page >> PAGE_SHIFT) < max_low_pfn | 302 | if (!low_pfn(pgd_val(*pgd) >> PAGE_SHIFT) || !pgd_present(*pgd)) |
298 | && page & _PAGE_PRESENT) { | 303 | goto out; |
299 | page &= PAGE_MASK; | ||
300 | page = ((__typeof__(page) *) __va(page))[(address >> PMD_SHIFT) | ||
301 | & (PTRS_PER_PMD - 1)]; | ||
302 | printk(KERN_CONT "*pde = %016Lx ", page); | ||
303 | page &= ~_PAGE_NX; | ||
304 | } | ||
305 | #else | ||
306 | printk("*pde = %08lx ", page); | ||
307 | #endif | 304 | #endif |
305 | pmd = pmd_offset(pud_offset(pgd, address), address); | ||
306 | printk(KERN_CONT "*pde = %0*Lx ", sizeof(*pmd) * 2, (u64)pmd_val(*pmd)); | ||
308 | 307 | ||
309 | /* | 308 | /* |
310 | * We must not directly access the pte in the highpte | 309 | * We must not directly access the pte in the highpte |
@@ -312,16 +311,12 @@ static void dump_pagetable(unsigned long address) | |||
312 | * And let's rather not kmap-atomic the pte, just in case | 311 | * And let's rather not kmap-atomic the pte, just in case |
313 | * it's allocated already: | 312 | * it's allocated already: |
314 | */ | 313 | */ |
315 | if ((page >> PAGE_SHIFT) < max_low_pfn | 314 | if (!low_pfn(pmd_pfn(*pmd)) || !pmd_present(*pmd) || pmd_large(*pmd)) |
316 | && (page & _PAGE_PRESENT) | 315 | goto out; |
317 | && !(page & _PAGE_PSE)) { | ||
318 | |||
319 | page &= PAGE_MASK; | ||
320 | page = ((__typeof__(page) *) __va(page))[(address >> PAGE_SHIFT) | ||
321 | & (PTRS_PER_PTE - 1)]; | ||
322 | printk("*pte = %0*Lx ", sizeof(page)*2, (u64)page); | ||
323 | } | ||
324 | 316 | ||
317 | pte = pte_offset_kernel(pmd, address); | ||
318 | printk("*pte = %0*Lx ", sizeof(*pte) * 2, (u64)pte_val(*pte)); | ||
319 | out: | ||
325 | printk("\n"); | 320 | printk("\n"); |
326 | } | 321 | } |
327 | 322 | ||
@@ -426,10 +421,11 @@ static noinline int vmalloc_fault(unsigned long address) | |||
426 | } | 421 | } |
427 | 422 | ||
428 | static const char errata93_warning[] = | 423 | static const char errata93_warning[] = |
429 | KERN_ERR "******* Your BIOS seems to not contain a fix for K8 errata #93\n" | 424 | KERN_ERR |
430 | KERN_ERR "******* Working around it, but it may cause SEGVs or burn power.\n" | 425 | "******* Your BIOS seems to not contain a fix for K8 errata #93\n" |
431 | KERN_ERR "******* Please consider a BIOS update.\n" | 426 | "******* Working around it, but it may cause SEGVs or burn power.\n" |
432 | KERN_ERR "******* Disabling USB legacy in the BIOS may also help.\n"; | 427 | "******* Please consider a BIOS update.\n" |
428 | "******* Disabling USB legacy in the BIOS may also help.\n"; | ||
433 | 429 | ||
434 | /* | 430 | /* |
435 | * No vm86 mode in 64-bit mode: | 431 | * No vm86 mode in 64-bit mode: |
@@ -449,16 +445,12 @@ static int bad_address(void *p) | |||
449 | 445 | ||
450 | static void dump_pagetable(unsigned long address) | 446 | static void dump_pagetable(unsigned long address) |
451 | { | 447 | { |
452 | pgd_t *pgd; | 448 | pgd_t *base = __va(read_cr3() & PHYSICAL_PAGE_MASK); |
449 | pgd_t *pgd = base + pgd_index(address); | ||
453 | pud_t *pud; | 450 | pud_t *pud; |
454 | pmd_t *pmd; | 451 | pmd_t *pmd; |
455 | pte_t *pte; | 452 | pte_t *pte; |
456 | 453 | ||
457 | pgd = (pgd_t *)read_cr3(); | ||
458 | |||
459 | pgd = __va((unsigned long)pgd & PHYSICAL_PAGE_MASK); | ||
460 | |||
461 | pgd += pgd_index(address); | ||
462 | if (bad_address(pgd)) | 454 | if (bad_address(pgd)) |
463 | goto bad; | 455 | goto bad; |
464 | 456 | ||
@@ -696,7 +688,7 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code, | |||
696 | if (!printk_ratelimit()) | 688 | if (!printk_ratelimit()) |
697 | return; | 689 | return; |
698 | 690 | ||
699 | printk(KERN_CONT "%s%s[%d]: segfault at %lx ip %p sp %p error %lx", | 691 | printk("%s%s[%d]: segfault at %lx ip %p sp %p error %lx", |
700 | task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, | 692 | task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, |
701 | tsk->comm, task_pid_nr(tsk), address, | 693 | tsk->comm, task_pid_nr(tsk), address, |
702 | (void *)regs->ip, (void *)regs->sp, error_code); | 694 | (void *)regs->ip, (void *)regs->sp, error_code); |
@@ -1025,7 +1017,7 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code) | |||
1025 | if (unlikely(error_code & PF_RSVD)) | 1017 | if (unlikely(error_code & PF_RSVD)) |
1026 | pgtable_bad(regs, error_code, address); | 1018 | pgtable_bad(regs, error_code, address); |
1027 | 1019 | ||
1028 | perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); | 1020 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); |
1029 | 1021 | ||
1030 | /* | 1022 | /* |
1031 | * If we're in an interrupt, have no user context or are running | 1023 | * If we're in an interrupt, have no user context or are running |
@@ -1122,11 +1114,11 @@ good_area: | |||
1122 | 1114 | ||
1123 | if (fault & VM_FAULT_MAJOR) { | 1115 | if (fault & VM_FAULT_MAJOR) { |
1124 | tsk->maj_flt++; | 1116 | tsk->maj_flt++; |
1125 | perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, | 1117 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, |
1126 | regs, address); | 1118 | regs, address); |
1127 | } else { | 1119 | } else { |
1128 | tsk->min_flt++; | 1120 | tsk->min_flt++; |
1129 | perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, | 1121 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, |
1130 | regs, address); | 1122 | regs, address); |
1131 | } | 1123 | } |
1132 | 1124 | ||