aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2008-02-06 16:39:43 -0500
committerIngo Molnar <mingo@elte.hu>2008-02-06 16:39:43 -0500
commitd8b57bb700a73872fd06b891d7c9bc4cea1a6af4 (patch)
treea1667f46fd808cbd904eb5ccbabca4c35c48dde3 /arch/x86/mm
parent3aa4b37d3e899cfe7a9cbdcda2b277df4c1f210d (diff)
x86: make spurious fault handler aware of large mappings
In very rare cases, on certain CPUs, we could end up in the spurious fault handler and ignore a large pud/pmd mapping. The resulting pte pointer points into the mapped physical space and dereferencing it will fault recursively. Make the code aware of large mappings and do the permission check on the pmd/pud entry, when a large pud/pmd mapping is detected. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/mm')
-rw-r--r--arch/x86/mm/fault.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index ad8b9733d6b3..d8ed4006b3d2 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -428,6 +428,16 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
428} 428}
429#endif 429#endif
430 430
431static int spurious_fault_check(unsigned long error_code, pte_t *pte)
432{
433 if ((error_code & PF_WRITE) && !pte_write(*pte))
434 return 0;
435 if ((error_code & PF_INSTR) && !pte_exec(*pte))
436 return 0;
437
438 return 1;
439}
440
431/* 441/*
432 * Handle a spurious fault caused by a stale TLB entry. This allows 442 * Handle a spurious fault caused by a stale TLB entry. This allows
433 * us to lazily refresh the TLB when increasing the permissions of a 443 * us to lazily refresh the TLB when increasing the permissions of a
@@ -457,20 +467,21 @@ static int spurious_fault(unsigned long address,
457 if (!pud_present(*pud)) 467 if (!pud_present(*pud))
458 return 0; 468 return 0;
459 469
470 if (pud_large(*pud))
471 return spurious_fault_check(error_code, (pte_t *) pud);
472
460 pmd = pmd_offset(pud, address); 473 pmd = pmd_offset(pud, address);
461 if (!pmd_present(*pmd)) 474 if (!pmd_present(*pmd))
462 return 0; 475 return 0;
463 476
477 if (pmd_large(*pmd))
478 return spurious_fault_check(error_code, (pte_t *) pmd);
479
464 pte = pte_offset_kernel(pmd, address); 480 pte = pte_offset_kernel(pmd, address);
465 if (!pte_present(*pte)) 481 if (!pte_present(*pte))
466 return 0; 482 return 0;
467 483
468 if ((error_code & PF_WRITE) && !pte_write(*pte)) 484 return spurious_fault_check(error_code, pte);
469 return 0;
470 if ((error_code & PF_INSTR) && !pte_exec(*pte))
471 return 0;
472
473 return 1;
474} 485}
475 486
476/* 487/*