aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mm/fault.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-08-03 17:31:24 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-03 17:31:24 -0400
commitbe82ae0238b0453afcf4a76f0512b7dde34ba500 (patch)
treeaaa3f5f11fd51fd73365ee1a2164aad9a03de060 /arch/arm/mm/fault.c
parent4b4fd27c0b5ec638a1f06ced9226fd95229dbbf0 (diff)
parent7b70c4275f28702b76b273c8534c38f8313812e9 (diff)
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm: (291 commits) ARM: AMBA: Add pclk support to AMBA bus infrastructure ARM: 6278/2: fix regression in RealView after the introduction of pclk ARM: 6277/1: mach-shmobile: Allow users to select HZ, default to 128 ARM: 6276/1: mach-shmobile: remove duplicate NR_IRQS_LEGACY ARM: 6246/1: mmci: support larger MMCIDATALENGTH register ARM: 6245/1: mmci: enable hardware flow control on Ux500 variants ARM: 6244/1: mmci: add variant data and default MCICLOCK support ARM: 6243/1: mmci: pass power_mode to the translate_vdd callback ARM: 6274/1: add global control registers definition header file for nuc900 mx2_camera: fix type of dma buffer virtual address pointer mx2_camera: Add soc_camera support for i.MX25/i.MX27 arm/imx/gpio: add spinlock protection ARM: Add support for the LPC32XX arch ARM: LPC32XX: Arch config menu supoport and makefiles ARM: LPC32XX: Phytec 3250 platform support ARM: LPC32XX: Misc support functions ARM: LPC32XX: Serial support code ARM: LPC32XX: System suspend support ARM: LPC32XX: GPIO, timer, and IRQ drivers ARM: LPC32XX: Clock driver ...
Diffstat (limited to 'arch/arm/mm/fault.c')
-rw-r--r--arch/arm/mm/fault.c56
1 files changed, 42 insertions, 14 deletions
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index cbfb2edcf7d1..23b0b03af5ea 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -413,7 +413,16 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
413 pmd_k = pmd_offset(pgd_k, addr); 413 pmd_k = pmd_offset(pgd_k, addr);
414 pmd = pmd_offset(pgd, addr); 414 pmd = pmd_offset(pgd, addr);
415 415
416 if (pmd_none(*pmd_k)) 416 /*
417 * On ARM one Linux PGD entry contains two hardware entries (see page
418 * tables layout in pgtable.h). We normally guarantee that we always
419 * fill both L1 entries. But create_mapping() doesn't follow the rule.
420 * It can create inidividual L1 entries, so here we have to call
421 * pmd_none() check for the entry really corresponded to address, not
422 * for the first of pair.
423 */
424 index = (addr >> SECTION_SHIFT) & 1;
425 if (pmd_none(pmd_k[index]))
417 goto bad_area; 426 goto bad_area;
418 427
419 copy_pmd(pmd, pmd_k); 428 copy_pmd(pmd, pmd_k);
@@ -463,15 +472,10 @@ static struct fsr_info {
463 * defines these to be "precise" aborts. 472 * defines these to be "precise" aborts.
464 */ 473 */
465 { do_bad, SIGSEGV, 0, "vector exception" }, 474 { do_bad, SIGSEGV, 0, "vector exception" },
466 { do_bad, SIGILL, BUS_ADRALN, "alignment exception" }, 475 { do_bad, SIGBUS, BUS_ADRALN, "alignment exception" },
467 { do_bad, SIGKILL, 0, "terminal exception" }, 476 { do_bad, SIGKILL, 0, "terminal exception" },
468 { do_bad, SIGILL, BUS_ADRALN, "alignment exception" }, 477 { do_bad, SIGBUS, BUS_ADRALN, "alignment exception" },
469/* Do we need runtime check ? */
470#if __LINUX_ARM_ARCH__ < 6
471 { do_bad, SIGBUS, 0, "external abort on linefetch" }, 478 { do_bad, SIGBUS, 0, "external abort on linefetch" },
472#else
473 { do_translation_fault, SIGSEGV, SEGV_MAPERR, "I-cache maintenance fault" },
474#endif
475 { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" }, 479 { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" },
476 { do_bad, SIGBUS, 0, "external abort on linefetch" }, 480 { do_bad, SIGBUS, 0, "external abort on linefetch" },
477 { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" }, 481 { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" },
@@ -508,13 +512,15 @@ static struct fsr_info {
508 512
509void __init 513void __init
510hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), 514hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
511 int sig, const char *name) 515 int sig, int code, const char *name)
512{ 516{
513 if (nr >= 0 && nr < ARRAY_SIZE(fsr_info)) { 517 if (nr < 0 || nr >= ARRAY_SIZE(fsr_info))
514 fsr_info[nr].fn = fn; 518 BUG();
515 fsr_info[nr].sig = sig; 519
516 fsr_info[nr].name = name; 520 fsr_info[nr].fn = fn;
517 } 521 fsr_info[nr].sig = sig;
522 fsr_info[nr].code = code;
523 fsr_info[nr].name = name;
518} 524}
519 525
520/* 526/*
@@ -594,3 +600,25 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
594 arm_notify_die("", regs, &info, ifsr, 0); 600 arm_notify_die("", regs, &info, ifsr, 0);
595} 601}
596 602
603static int __init exceptions_init(void)
604{
605 if (cpu_architecture() >= CPU_ARCH_ARMv6) {
606 hook_fault_code(4, do_translation_fault, SIGSEGV, SEGV_MAPERR,
607 "I-cache maintenance fault");
608 }
609
610 if (cpu_architecture() >= CPU_ARCH_ARMv7) {
611 /*
612 * TODO: Access flag faults introduced in ARMv6K.
613 * Runtime check for 'K' extension is needed
614 */
615 hook_fault_code(3, do_bad, SIGSEGV, SEGV_MAPERR,
616 "section access flag fault");
617 hook_fault_code(6, do_bad, SIGSEGV, SEGV_MAPERR,
618 "section access flag fault");
619 }
620
621 return 0;
622}
623
624arch_initcall(exceptions_init);