From 3dc91aff9c3ef54b15cdaf32f61f973489fe69eb Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Thu, 22 Jul 2010 13:16:49 +0100 Subject: ARM: 6252/1: Use SIGBUS for unaligned access instead of SIGILL POSIX specify to use signal SIGBUS with code BUS_ADRALN for invalid address alignment. Signed-off-by: Kirill A. Shutemov Signed-off-by: Russell King --- arch/arm/mm/fault.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm/mm/fault.c') diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index cbfb2edcf7d..ce6f3a422c8 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -463,9 +463,9 @@ static struct fsr_info { * defines these to be "precise" aborts. */ { do_bad, SIGSEGV, 0, "vector exception" }, - { do_bad, SIGILL, BUS_ADRALN, "alignment exception" }, + { do_bad, SIGBUS, BUS_ADRALN, "alignment exception" }, { do_bad, SIGKILL, 0, "terminal exception" }, - { do_bad, SIGILL, BUS_ADRALN, "alignment exception" }, + { do_bad, SIGBUS, BUS_ADRALN, "alignment exception" }, /* Do we need runtime check ? */ #if __LINUX_ARM_ARCH__ < 6 { do_bad, SIGBUS, 0, "external abort on linefetch" }, -- cgit v1.2.3-70-g09d2 From 6338a6aa7c082f11d55712251e14178c68bf5869 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Thu, 22 Jul 2010 13:18:19 +0100 Subject: ARM: 6269/1: Add 'code' parameter for hook_fault_code() Add one more parameter to hook_fault_code() to be able to set 'code' field of struct fsr_info. Signed-off-by: Kirill A. Shutemov Signed-off-by: Russell King --- arch/arm/include/asm/system.h | 2 +- arch/arm/mach-integrator/pci_v3.c | 8 ++++---- arch/arm/mach-iop13xx/pci.c | 2 +- arch/arm/mach-ixp2000/pci.c | 2 +- arch/arm/mach-ixp23xx/pci.c | 2 +- arch/arm/mach-ixp4xx/common-pci.c | 3 ++- arch/arm/mach-ks8695/pci.c | 4 ++-- arch/arm/mm/alignment.c | 6 ++++-- arch/arm/mm/fault.c | 14 ++++++++------ arch/arm/plat-iop/pci.c | 2 +- 10 files changed, 25 insertions(+), 20 deletions(-) (limited to 'arch/arm/mm/fault.c') diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 5f4f4800273..8ba1ccf82a0 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -83,7 +83,7 @@ void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info, void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), - int sig, const char *name); + int sig, int code, const char *name); #define xchg(ptr,x) \ ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c index 9cef0590d5a..6467d99fa2e 100644 --- a/arch/arm/mach-integrator/pci_v3.c +++ b/arch/arm/mach-integrator/pci_v3.c @@ -505,10 +505,10 @@ void __init pci_v3_preinit(void) /* * Hook in our fault handler for PCI errors */ - hook_fault_code(4, v3_pci_fault, SIGBUS, "external abort on linefetch"); - hook_fault_code(6, v3_pci_fault, SIGBUS, "external abort on linefetch"); - hook_fault_code(8, v3_pci_fault, SIGBUS, "external abort on non-linefetch"); - hook_fault_code(10, v3_pci_fault, SIGBUS, "external abort on non-linefetch"); + hook_fault_code(4, v3_pci_fault, SIGBUS, 0, "external abort on linefetch"); + hook_fault_code(6, v3_pci_fault, SIGBUS, 0, "external abort on linefetch"); + hook_fault_code(8, v3_pci_fault, SIGBUS, 0, "external abort on non-linefetch"); + hook_fault_code(10, v3_pci_fault, SIGBUS, 0, "external abort on non-linefetch"); spin_lock_irqsave(&v3_lock, flags); diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c index 6d5a90813d3..773ea0c95b9 100644 --- a/arch/arm/mach-iop13xx/pci.c +++ b/arch/arm/mach-iop13xx/pci.c @@ -987,7 +987,7 @@ void __init iop13xx_pci_init(void) iop13xx_atux_setup(); } - hook_fault_code(16+6, iop13xx_pci_abort, SIGBUS, + hook_fault_code(16+6, iop13xx_pci_abort, SIGBUS, 0, "imprecise external abort"); } diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c index 90771cad06f..f797c5f538b 100644 --- a/arch/arm/mach-ixp2000/pci.c +++ b/arch/arm/mach-ixp2000/pci.c @@ -209,7 +209,7 @@ ixp2000_pci_preinit(void) "the needed workaround has not been configured in"); #endif - hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS, + hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS, 0, "PCI config cycle to non-existent device"); } diff --git a/arch/arm/mach-ixp23xx/pci.c b/arch/arm/mach-ixp23xx/pci.c index 4b0e598a91c..563819a8329 100644 --- a/arch/arm/mach-ixp23xx/pci.c +++ b/arch/arm/mach-ixp23xx/pci.c @@ -229,7 +229,7 @@ void __init ixp23xx_pci_preinit(void) { ixp23xx_pci_common_init(); - hook_fault_code(16+6, ixp23xx_pci_abort_handler, SIGBUS, + hook_fault_code(16+6, ixp23xx_pci_abort_handler, SIGBUS, 0, "PCI config cycle to non-existent device"); *IXP23XX_PCI_ADDR_EXT = 0x0000e000; diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c index e3181534c7f..f4fbb5ec645 100644 --- a/arch/arm/mach-ixp4xx/common-pci.c +++ b/arch/arm/mach-ixp4xx/common-pci.c @@ -382,7 +382,8 @@ void __init ixp4xx_pci_preinit(void) /* hook in our fault handler for PCI errors */ - hook_fault_code(16+6, abort_handler, SIGBUS, "imprecise external abort"); + hook_fault_code(16+6, abort_handler, SIGBUS, 0, + "imprecise external abort"); pr_debug("setup PCI-AHB(inbound) and AHB-PCI(outbound) address mappings\n"); diff --git a/arch/arm/mach-ks8695/pci.c b/arch/arm/mach-ks8695/pci.c index 78499667eb7..5fcd082a17f 100644 --- a/arch/arm/mach-ks8695/pci.c +++ b/arch/arm/mach-ks8695/pci.c @@ -268,8 +268,8 @@ static void __init ks8695_pci_preinit(void) __raw_writel(0, KS8695_PCI_VA + KS8695_PIOBAC); /* hook in fault handlers */ - hook_fault_code(8, ks8695_pci_fault, SIGBUS, "external abort on non-linefetch"); - hook_fault_code(10, ks8695_pci_fault, SIGBUS, "external abort on non-linefetch"); + hook_fault_code(8, ks8695_pci_fault, SIGBUS, 0, "external abort on non-linefetch"); + hook_fault_code(10, ks8695_pci_fault, SIGBUS, 0, "external abort on non-linefetch"); } static void ks8695_show_pciregs(void) diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 53a609680c1..77cfdbed950 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -924,8 +924,10 @@ static int __init alignment_init(void) ai_usermode = UM_FIXUP; } - hook_fault_code(1, do_alignment, SIGBUS, "alignment exception"); - hook_fault_code(3, do_alignment, SIGBUS, "alignment exception"); + hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN, + "alignment exception"); + hook_fault_code(3, do_alignment, SIGBUS, BUS_ADRALN, + "alignment exception"); return 0; } diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index ce6f3a422c8..84131c83243 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -508,13 +508,15 @@ static struct fsr_info { void __init hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), - int sig, const char *name) + int sig, int code, const char *name) { - if (nr >= 0 && nr < ARRAY_SIZE(fsr_info)) { - fsr_info[nr].fn = fn; - fsr_info[nr].sig = sig; - fsr_info[nr].name = name; - } + if (nr < 0 || nr >= ARRAY_SIZE(fsr_info)) + BUG(); + + fsr_info[nr].fn = fn; + fsr_info[nr].sig = sig; + fsr_info[nr].code = code; + fsr_info[nr].name = name; } /* diff --git a/arch/arm/plat-iop/pci.c b/arch/arm/plat-iop/pci.c index ce31f316ac7..43f2b158237 100644 --- a/arch/arm/plat-iop/pci.c +++ b/arch/arm/plat-iop/pci.c @@ -359,7 +359,7 @@ static void __init iop3xx_atu_debug(void) DBG("ATU: IOP3XX_ATUCMD=0x%04x\n", *IOP3XX_ATUCMD); DBG("ATU: IOP3XX_ATUCR=0x%08x\n", *IOP3XX_ATUCR); - hook_fault_code(16+6, iop3xx_pci_abort, SIGBUS, "imprecise external abort"); + hook_fault_code(16+6, iop3xx_pci_abort, SIGBUS, 0, "imprecise external abort"); } /* for platforms that might be host-bus-adapters */ -- cgit v1.2.3-70-g09d2 From 33a9c41bf5d8adae9d882513e617c4c645195e71 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Thu, 22 Jul 2010 13:20:22 +0100 Subject: ARM: 6255/1: Workaround infinity loop in handling of translation faults On ARM one Linux PGD entry contains two hardware entries (see page tables layout in pgtable.h). We normally guarantee that we always fill both L1 entries. But create_mapping() doesn't follow the rule. It can create inidividual L1 entries, so here we have to call pmd_none() check in do_translation_fault() for the entry really corresponded to address, not for the first of pair. Signed-off-by: Kirill A. Shutemov Signed-off-by: Russell King --- arch/arm/mm/fault.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'arch/arm/mm/fault.c') diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 84131c83243..564b1c4829e 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, pmd_k = pmd_offset(pgd_k, addr); pmd = pmd_offset(pgd, addr); - if (pmd_none(*pmd_k)) + /* + * On ARM one Linux PGD entry contains two hardware entries (see page + * tables layout in pgtable.h). We normally guarantee that we always + * fill both L1 entries. But create_mapping() doesn't follow the rule. + * It can create inidividual L1 entries, so here we have to call + * pmd_none() check for the entry really corresponded to address, not + * for the first of pair. + */ + index = (addr >> SECTION_SHIFT) & 1; + if (pmd_none(pmd_k[index])) goto bad_area; copy_pmd(pmd, pmd_k); -- cgit v1.2.3-70-g09d2 From 993bf4ec8c2a2b7979389ab196bf2fe217117158 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Thu, 22 Jul 2010 13:23:25 +0100 Subject: ARM: 6256/1: Check arch version and modify fsr_info[] depends on it at runtime Signed-off-by: Kirill A. Shutemov Signed-off-by: Russell King --- arch/arm/mm/fault.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'arch/arm/mm/fault.c') diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 564b1c4829e..5835e63454f 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -475,12 +475,7 @@ static struct fsr_info { { do_bad, SIGBUS, BUS_ADRALN, "alignment exception" }, { do_bad, SIGKILL, 0, "terminal exception" }, { do_bad, SIGBUS, BUS_ADRALN, "alignment exception" }, -/* Do we need runtime check ? */ -#if __LINUX_ARM_ARCH__ < 6 { do_bad, SIGBUS, 0, "external abort on linefetch" }, -#else - { do_translation_fault, SIGSEGV, SEGV_MAPERR, "I-cache maintenance fault" }, -#endif { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" }, { do_bad, SIGBUS, 0, "external abort on linefetch" }, { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" }, @@ -605,3 +600,14 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs) arm_notify_die("", regs, &info, ifsr, 0); } +static int __init exceptions_init(void) +{ + if (cpu_architecture() >= CPU_ARCH_ARMv6) { + hook_fault_code(4, do_translation_fault, SIGSEGV, SEGV_MAPERR, + "I-cache maintenance fault"); + } + + return 0; +} + +arch_initcall(exceptions_init); -- cgit v1.2.3-70-g09d2 From b8ab5397bcbd92e3fd4a9770e0bf59315fa38dab Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Mon, 26 Jul 2010 11:20:41 +0100 Subject: ARM: 6268/1: ARMv6K and ARMv7 use fault statuses 3 and 6 as Access Flag fault Statuses 3 (0b00011) and 6 (0x00110) of DFSR are Access Flags faults on ARMv6K and ARMv7. Let's patch fsr_info[] at runtime if we are on ARMv7 or later. Unfortunately, we don't have runtime check for 'K' extension, so we can't check for it. Signed-off-by: Kirill A. Shutemov Signed-off-by: Russell King --- arch/arm/mm/alignment.c | 14 ++++++++++++-- arch/arm/mm/fault.c | 11 +++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) (limited to 'arch/arm/mm/fault.c') diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 77cfdbed950..d073b64ae87 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -926,8 +926,18 @@ static int __init alignment_init(void) hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN, "alignment exception"); - hook_fault_code(3, do_alignment, SIGBUS, BUS_ADRALN, - "alignment exception"); + + /* + * ARMv6K and ARMv7 use fault status 3 (0b00011) as Access Flag section + * fault, not as alignment error. + * + * TODO: handle ARMv6K properly. Runtime check for 'K' extension is + * needed. + */ + if (cpu_architecture() <= CPU_ARCH_ARMv6) { + hook_fault_code(3, do_alignment, SIGBUS, BUS_ADRALN, + "alignment exception"); + } return 0; } diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 5835e63454f..23b0b03af5e 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -607,6 +607,17 @@ static int __init exceptions_init(void) "I-cache maintenance fault"); } + if (cpu_architecture() >= CPU_ARCH_ARMv7) { + /* + * TODO: Access flag faults introduced in ARMv6K. + * Runtime check for 'K' extension is needed + */ + hook_fault_code(3, do_bad, SIGSEGV, SEGV_MAPERR, + "section access flag fault"); + hook_fault_code(6, do_bad, SIGSEGV, SEGV_MAPERR, + "section access flag fault"); + } + return 0; } -- cgit v1.2.3-70-g09d2