ARM: fix exceptions handling
cover ARM: fix exceptions handling
From: Kirill A. Shutemov <[email protected]>
Kirill A. Shutemov (5):
Use SIGBUS for unalinged access instead of SIGILL
Add 'code' parameter for hook_fault_code()
Check arch version and modify fsr_info[] depends on it at runtime ARMv6K and ARMv7 use fault statuses 3 and 6 as Access Flag fault Workaround infinity loop in handling of translation faults
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 | 16 +++++++++- arch/arm/mm/fault.c | 56 +++++++++++++++++++++++++++--------- arch/arm/plat-iop/pci.c | 2 +- 10 files changed, 69 insertions(+), 28 deletions(-)
PATCH 1/5 Use SIGBUS for unalinged access instead of SIGILL
From: Kirill A. Shutemov <[email protected]>
POSIX specify to use signal SIGBUS with code BUS_ADRALN for invalid address alignment.
--- arch/arm/mm/alignment.c | 4 ++-- arch/arm/mm/fault.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
arch/arm/mm/alignment.c +2 -2
@@ -924,8 +924,8 @@ static int __init alignment_init(void) ai_usermode =UM_FIXUP ; } -hook_fault_code (1 , do_alignment,SIGILL ,"alignment exception" ); -hook_fault_code (3 , do_alignment,SIGILL ,"alignment exception" ); +hook_fault_code (1 , do_alignment,SIGBUS ,"alignment exception" ); +hook_fault_code (3 , do_alignment,SIGBUS ,"alignment exception" );return 0 ; }
arch/arm/mm/fault.c +2 -2
@@ -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" },
Signature · 1 line
1.7.1.1
PATCH 2/5 Add 'code' parameter for hook_fault_code()
In reply to Kirill A. ShutsemovFrom: Kirill A. Shutemov <[email protected]>
Add one more parameter to hook_fault_code() to be able to set 'code' field of struct fsr_info.
--- 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(-)
arch/arm/include/asm/system.h +1 -1
@@ -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))))
arch/arm/mach-integrator/pci_v3.c +4 -4
@@ -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);
arch/arm/mach-iop13xx/pci.c +1 -1
@@ -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" ); }
arch/arm/mach-ixp2000/pci.c +1 -1
@@ -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" ); }
arch/arm/mach-ixp23xx/pci.c +1 -1
@@ -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 ;
arch/arm/mach-ixp4xx/common-pci.c +2 -1
@@ -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" );
arch/arm/mach-ks8695/pci.c +2 -2
@@ -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 )
arch/arm/mm/alignment.c +4 -2
@@ -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 ; }
arch/arm/mm/fault.c +8 -6
@@ -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; }/*
arch/arm/plat-iop/pci.c +1 -1
@@ -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 */
Signature · 1 line
1.7.1.1
PATCH 2/5 Add 'code' parameter for hook_fault_code()
arch/arm/mach-ixp2000/pci.c ixp2000_pci_preinit(void) · line 213
Quoted 11 lines · Kirill A. Shutsemov
arch/arm/mach-ixp2000/pci.c +1
-1@@ -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" );
This is broken - can you submit a fixed version please?
PATCH 2/5 Add 'code' parameter for hook_fault_code()
Quoted 9 lines · Russell King - ARM Linux
Quoted 8 lines · Kirill A. Shutsemov
arch/arm/mach-ixp2000/pci.c +0
-0@@ -209,7 +209,7 @@ ixp2000_pci_preinit(void) "the needed workaround has not been configured in");#endif
Quoted 5 lines
arch/arm/mach-ixp2000/pci.c ixp2000_pci_preinit(void) · line 213
Quoted 3 lines
arch/arm/mach-ixp2000/pci.c +1
-1-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" );This is broken - can you submit a fixed version please?
Done.
Signature · 1 line
Kirill A. Shutemov
PATCH 3/5 Check arch version and modify fsr_info[] depends on it at runtime
In reply to Kirill A. ShutsemovFrom: Kirill A. Shutemov <[email protected]>
--- arch/arm/mm/fault.c | 16 +++++++++++----- 1 files changed, 11 insertions(+), 5 deletions(-)
arch/arm/mm/fault.c +11 -5
@@ -466,12 +466,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" },
@@ -596,3 +591,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);
Signature · 1 line
1.7.1.1
PATCH 4/5 ARMv6K and ARMv7 use fault statuses 3 and 6 as Access Flag fault
In reply to Kirill A. ShutsemovFrom: Kirill A. Shutemov <[email protected]>
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.
--- arch/arm/mm/alignment.c | 14 ++++++++++++-- arch/arm/mm/fault.c | 11 +++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-)
arch/arm/mm/alignment.c +12 -2
@@ -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 ; }
arch/arm/mm/fault.c +11 -0
@@ -598,6 +598,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_MAPPERR , +"section access flag fault" ); +hook_fault_code (6 , do_bad,SIGSEGV ,SEGV_MAPPERR , +"section access flag fault" ); + } +return 0 ; }
Signature · 1 line
1.7.1.1
PATCH 4/5 ARMv6K and ARMv7 use fault statuses 3 and 6 as Access Flag fault
Hello.
Quoted 8 lines · Kirill A. Shutsemov
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 <[email protected]>
[...]
Quoted 12 lines
arch/arm/mm/alignment.c +2
-2@@ -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" ); + +/*
arch/arm/mm/alignment.c static int __init alignment_init(void) · line 940
Quoted 10 lines
arch/arm/mm/alignment.c +10
-0+* 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" ); + }
Curly braces not neeed here. I assume you haven't run your patch thruscripts/checkpatch.pl?
WBR, Sergei
PATCH 4/5 ARMv6K and ARMv7 use fault statuses 3 and 6 as Access Flag fault
Quoted 30 lines · Sergei Shtylyov
Hello.
Quoted 8 lines · Kirill A. Shutsemov
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 <[email protected]>[...]
Quoted 17 lines
arch/arm/mm/alignment.c +7
-2@@ -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.
Quoted 8 lines
arch/arm/mm/alignment.c static int __init alignment_init(void) · line 940
Quoted 5 lines
arch/arm/mm/alignment.c +5
-0+*/ +if (cpu_architecture () <= CPU_ARCH_ARMv6) { +hook_fault_code (3 , do_alignment,SIGBUS ,BUS_ADRALN , +"alignment exception" ); + }Curly braces not neeed here. I assume you haven't run your patch thru
scripts/checkpatch.pl?
total: 0 errors, 0 warnings, 37 lines checked
I'll remove it if you want. But I think it reasonable to leave braces in cases like:
if (condition) {
do_this(a, very_long, list, of, parameters,
second, part, of, the, list);
}What do you think?
Signature · 1 line
Kirill A. Shutemov
PATCH 4/5 ARMv6K and ARMv7 use fault statuses 3 and 6 as Access Flag fault
Quoted 37 lines · Kirill A. Shutemov
Quoted 28 lines
Hello.
Quoted 6 lines · Kirill A. Shutsemov
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 <[email protected]>[...]
Quoted 17 lines
arch/arm/mm/alignment.c +7
-2@@ -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. Quoted 8 lines
arch/arm/mm/alignment.c static int __init alignment_init(void) · line 940
Quoted 5 lines
arch/arm/mm/alignment.c +5
-0+*/ +if (cpu_architecture () <= CPU_ARCH_ARMv6) { +hook_fault_code (3 , do_alignment,SIGBUS ,BUS_ADRALN , +"alignment exception" ); + }Curly braces not neeed here. I assume you haven't run your patch thru
scripts/checkpatch.pl?
Quoted 1 line
total: 0 errors, 0 warnings, 37 lines checked
Strange, it used to warn about superfluous braces...
Quoted 9 lines
I'll remove it if you want. But I think it reasonable to leave braces in cases like:
if (condition) { do_this(a, very_long, list, of, parameters, second, part, of, the, list); }What do you think?
I wouldn't use braces in this case. But it's up to you after all, if
checkpatch.pl is indifferent about them...
WBR, Sergei
PATCH 5/5 Workaround infinity loop in handling of translation faults
In reply to Kirill A. ShutsemovFrom: Kirill A. Shutemov <[email protected]>
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.
--- arch/arm/mm/fault.c | 11 ++++++++++- 1 files changed, 10 insertions(+), 1 deletions(-)
arch/arm/mm/fault.c +10 -1
@@ -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);
Signature · 1 line
1.7.1.1