[RFC PATCH 09/18] ARM: LPAE: Add fault handling support
Kirill A. Shutemov
kirill at shutemov.name
Mon Oct 25 06:17:11 EDT 2010
On Mon, Oct 25, 2010 at 10:00:24AM +0100, Catalin Marinas wrote:
> The DFSR and IFSR register format is different when LPAE is enabled. In
> addition, DFSR and IFSR have the similar definitions for the fault type.
> This modifies modifies the fault code to correctly handle the new
> format.
>
> Signed-off-by: Catalin Marinas <catalin.marinas at arm.com>
> ---
> arch/arm/mm/alignment.c | 8 ++++-
> arch/arm/mm/fault.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 87 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
> index 724ba3b..bc98a6e 100644
> --- a/arch/arm/mm/alignment.c
> +++ b/arch/arm/mm/alignment.c
> @@ -906,6 +906,12 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
> return 0;
> }
>
> +#ifdef CONFIG_ARM_LPAE
> +#define ALIGNMENT_FAULT 33
> +#else
> +#define ALIGNMENT_FAULT 1
> +#endif
> +
> /*
> * This needs to be done after sysctl_init, otherwise sys/ will be
> * overwritten. Actually, this shouldn't be in sys/ at all since
> @@ -939,7 +945,7 @@ static int __init alignment_init(void)
> ai_usermode = UM_FIXUP;
> }
>
> - hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN,
> + hook_fault_code(ALIGNMENT_FAULT, do_alignment, SIGBUS, BUS_ADRALN,
> "alignment exception");
>
> /*
> diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
> index 2966897..b662aea 100644
> --- a/arch/arm/mm/fault.c
> +++ b/arch/arm/mm/fault.c
> @@ -33,10 +33,15 @@
> #define FSR_WRITE (1 << 11)
> #define FSR_FS4 (1 << 10)
> #define FSR_FS3_0 (15)
> +#define FSR_FS5_0 (0x3f)
>
> static inline int fsr_fs(unsigned int fsr)
> {
> +#ifdef CONFIG_ARM_LPAE
> + return fsr & FSR_FS5_0;
> +#else
> return (fsr & FSR_FS3_0) | (fsr & FSR_FS4) >> 6;
> +#endif
> }
>
> #ifdef CONFIG_MMU
> @@ -108,7 +113,9 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
>
> pte = pte_offset_map(pmd, addr);
> printk(", *pte=%08lx", pte_val(*pte));
> +#ifndef CONFIG_ARM_LPAE
> printk(", *ppte=%08lx", pte_val(pte[-LINUX_PTE_OFFSET]));
> +#endif
> pte_unmap(pte);
> } while(0);
>
> @@ -467,6 +474,72 @@ static struct fsr_info {
> int code;
> const char *name;
> } fsr_info[] = {
> +#ifdef CONFIG_ARM_LPAE
> + { do_bad, SIGBUS, 0, "unknown 0" },
> + { do_bad, SIGBUS, 0, "unknown 1" },
> + { do_bad, SIGBUS, 0, "unknown 2" },
> + { do_bad, SIGBUS, 0, "unknown 3" },
> + { do_bad, SIGBUS, 0, "reserved translation fault" },
> + { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" },
> + { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
> + { do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
> + { do_bad, SIGBUS, 0, "reserved access flag fault" },
> + { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
> + { do_bad, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
> + { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
> + { do_bad, SIGBUS, 0, "reserved permission fault" },
> + { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
> + { do_sect_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
> + { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
> + { do_bad, SIGBUS, 0, "synchronous external abort" },
> + { do_bad, SIGBUS, 0, "asynchronous external abort" },
> + { do_bad, SIGBUS, 0, "unknown 18" },
> + { do_bad, SIGBUS, 0, "unknown 19" },
> + { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
> + { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
> + { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
> + { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
> + { do_bad, SIGBUS, 0, "synchronous parity error" },
> + { do_bad, SIGBUS, 0, "asynchronous parity error" },
> + { do_bad, SIGBUS, 0, "unknown 26" },
> + { do_bad, SIGBUS, 0, "unknown 27" },
> + { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
> + { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
> + { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
> + { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
> + { do_bad, SIGBUS, 0, "unknown 32" },
> + { do_bad, SIGILL, BUS_ADRALN, "alignment fault" },
s/SIGILL/SIGBUS/
> + { do_bad, SIGBUS, 0, "debug event" },
> + { do_bad, SIGBUS, 0, "unknown 35" },
> + { do_bad, SIGBUS, 0, "unknown 36" },
> + { do_bad, SIGBUS, 0, "unknown 37" },
> + { do_bad, SIGBUS, 0, "unknown 38" },
> + { do_bad, SIGBUS, 0, "unknown 39" },
> + { do_bad, SIGBUS, 0, "unknown 40" },
> + { do_bad, SIGBUS, 0, "unknown 41" },
> + { do_bad, SIGBUS, 0, "unknown 42" },
> + { do_bad, SIGBUS, 0, "unknown 43" },
> + { do_bad, SIGBUS, 0, "unknown 44" },
> + { do_bad, SIGBUS, 0, "unknown 45" },
> + { do_bad, SIGBUS, 0, "unknown 46" },
> + { do_bad, SIGBUS, 0, "unknown 47" },
> + { do_bad, SIGBUS, 0, "unknown 48" },
> + { do_bad, SIGBUS, 0, "unknown 49" },
> + { do_bad, SIGBUS, 0, "unknown 50" },
> + { do_bad, SIGBUS, 0, "unknown 51" },
> + { do_bad, SIGBUS, 0, "implementation fault (lockdown abort)" },
> + { do_bad, SIGBUS, 0, "unknown 53" },
> + { do_bad, SIGBUS, 0, "unknown 54" },
> + { do_bad, SIGBUS, 0, "unknown 55" },
> + { do_bad, SIGBUS, 0, "unknown 56" },
> + { do_bad, SIGBUS, 0, "unknown 57" },
> + { do_bad, SIGBUS, 0, "implementation fault (coprocessor abort)" },
> + { do_bad, SIGBUS, 0, "unknown 59" },
> + { do_bad, SIGBUS, 0, "unknown 60" },
> + { do_bad, SIGBUS, 0, "unknown 61" },
> + { do_bad, SIGBUS, 0, "unknown 62" },
> + { do_bad, SIGBUS, 0, "unknown 63" },
> +#else /* !CONFIG_ARM_LPAE */
> /*
> * The following are the standard ARMv3 and ARMv4 aborts. ARMv5
> * defines these to be "precise" aborts.
> @@ -508,6 +581,7 @@ static struct fsr_info {
> { do_bad, SIGBUS, 0, "unknown 29" },
> { do_bad, SIGBUS, 0, "unknown 30" },
> { do_bad, SIGBUS, 0, "unknown 31" }
> +#endif /* CONFIG_ARM_LPAE */
> };
>
> void __init
> @@ -546,6 +620,9 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
> }
>
>
> +#ifdef CONFIG_ARM_LPAE
> +#define ifsr_info fsr_info
> +#else /* !CONFIG_ARM_LPAE */
> static struct fsr_info ifsr_info[] = {
> { do_bad, SIGBUS, 0, "unknown 0" },
> { do_bad, SIGBUS, 0, "unknown 1" },
> @@ -580,6 +657,7 @@ static struct fsr_info ifsr_info[] = {
> { do_bad, SIGBUS, 0, "unknown 30" },
> { do_bad, SIGBUS, 0, "unknown 31" },
> };
> +#endif /* CONFIG_ARM_LPAE */
>
> asmlinkage void __exception
> do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
> @@ -602,6 +680,7 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
>
> static int __init exceptions_init(void)
> {
> +#ifndef CONFIG_ARM_LPAE
> if (cpu_architecture() >= CPU_ARCH_ARMv6) {
> hook_fault_code(4, do_translation_fault, SIGSEGV, SEGV_MAPERR,
> "I-cache maintenance fault");
> @@ -617,6 +696,7 @@ static int __init exceptions_init(void)
> hook_fault_code(6, do_bad, SIGSEGV, SEGV_MAPERR,
> "section access flag fault");
> }
> +#endif
>
> return 0;
> }
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
Kirill A. Shutemov
More information about the linux-arm-kernel
mailing list