* [PATCH v3 1/2] ARM: Pass IFSR register to do_PrefetchAbort()
2009-09-21 11:05 [PATCH v3 1/2] ARM: Pass IFSR register to do_PrefetchAbort() Kirill A. Shutemov
@ 2009-09-21 9:37 ` Aaro Koskinen
2009-09-21 11:30 ` Kirill A. Shutemov
2009-09-21 11:05 ` [PATCH v3 2/2] ARM: Proper prefetch abort handling on ARMv7 Kirill A. Shutemov
1 sibling, 1 reply; 4+ messages in thread
From: Aaro Koskinen @ 2009-09-21 9:37 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
Kirill A. Shutemov wrote:
> It needed for proper prefetch abort handling on ARMv7.
>
> Instruction fault status register (IFSR) was introduced on ARMv7.
According to the ARMv7-AR reference manual it's available in ARMv6
(see chapter G.7).
> For older CPU we simulate IFSR with translation fault status. It
> allows to generalize code.
>
> Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
> ---
> arch/arm/include/asm/glue.h | 10 ++++++++--
> arch/arm/kernel/entry-armv.S | 14 ++++----------
> arch/arm/kernel/entry-common.S | 8 ++++++--
> arch/arm/mm/fault.c | 2 +-
> 4 files changed, 19 insertions(+), 15 deletions(-)
>
> diff --git a/arch/arm/include/asm/glue.h b/arch/arm/include/asm/glue.h
> index a0e39d5..5bfaf6f 100644
> --- a/arch/arm/include/asm/glue.h
> +++ b/arch/arm/include/asm/glue.h
> @@ -130,7 +130,10 @@
> # ifdef CPU_PABORT_HANDLER
> # define MULTI_PABORT 1
> # else
> -# define CPU_PABORT_HANDLER(reg, insn) mrc p15, 0, reg, cr6, cr0, 2
> +# define CPU_PABORT_HANDLER(addr, ifsr, insn) \
> + mrc p15, 0, addr, c6, c0, 2 ; \
> + mrc p15, 0, ifsr, c5, c0, 1
> +
> # endif
> #endif
>
> @@ -138,7 +141,10 @@
> # ifdef CPU_PABORT_HANDLER
> # define MULTI_PABORT 1
> # else
> -# define CPU_PABORT_HANDLER(reg, insn) mov reg, insn
> +#define __hash_5 #5
> +# define CPU_PABORT_HANDLER(addr, ifsr, insn) \
> + mov addr, insn ; \
> + mov ifsr, __hash_5
> # endif
> #endif
>
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index 3d727a8..335ae58 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -303,22 +303,16 @@ __pabt_svc:
> tst r3, #PSR_I_BIT
> biceq r9, r9, #PSR_I_BIT
>
> - @
> - @ set args, then call main handler
> - @
> - @ r0 - address of faulting instruction
> - @ r1 - pointer to registers on stack
> - @
> #ifdef MULTI_PABORT
> mov r0, r2 @ pass address of aborted instruction.
> ldr r4, .LCprocfns
> mov lr, pc
> ldr pc, [r4, #PROCESSOR_PABT_FUNC]
> #else
> - CPU_PABORT_HANDLER(r0, r2)
> + CPU_PABORT_HANDLER(r0, r1, r2)
> #endif
> msr cpsr_c, r9 @ Maybe enable interrupts
> - mov r1, sp @ regs
> + mov r2, sp @ regs
> bl do_PrefetchAbort @ call abort handler
>
> @
> @@ -697,10 +691,10 @@ __pabt_usr:
> mov lr, pc
> ldr pc, [r4, #PROCESSOR_PABT_FUNC]
> #else
> - CPU_PABORT_HANDLER(r0, r2)
> + CPU_PABORT_HANDLER(r0, r1, r2)
> #endif
> enable_irq @ Enable interrupts
> - mov r1, sp @ regs
> + mov r2, sp @ regs
> bl do_PrefetchAbort @ call abort handler
> UNWIND(.fnend )
> /* fall through */
> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index 807cfeb..931ab9a 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -426,10 +426,14 @@ sys_mmap2:
> ENDPROC(sys_mmap2)
>
> ENTRY(pabort_ifar)
> - mrc p15, 0, r0, cr6, cr0, 2
> -ENTRY(pabort_noifar)
> + mrc p15, 0, r0, c6, c0, 2 @ get IFAR
> + mrc p15, 0, r1, c5, c0, 1 @ get IFSR
> mov pc, lr
> ENDPROC(pabort_ifar)
> +ENTRY(pabort_noifar)
> + /* simulate IFSR with section translation fault status */
> + mov r1, #5
> + mov pc, lr
> ENDPROC(pabort_noifar)
>
> #ifdef CONFIG_OABI_COMPAT
> diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
> index cc8829d..5e27462 100644
> --- a/arch/arm/mm/fault.c
> +++ b/arch/arm/mm/fault.c
> @@ -506,7 +506,7 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
> }
>
> asmlinkage void __exception
> -do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
> +do_PrefetchAbort(unsigned long addr, int ifsr, struct pt_regs *regs)
> {
> do_translation_fault(addr, 0, regs);
> }
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v3 1/2] ARM: Pass IFSR register to do_PrefetchAbort()
@ 2009-09-21 11:05 Kirill A. Shutemov
2009-09-21 9:37 ` Aaro Koskinen
2009-09-21 11:05 ` [PATCH v3 2/2] ARM: Proper prefetch abort handling on ARMv7 Kirill A. Shutemov
0 siblings, 2 replies; 4+ messages in thread
From: Kirill A. Shutemov @ 2009-09-21 11:05 UTC (permalink / raw)
To: linux-arm-kernel
It needed for proper prefetch abort handling on ARMv7.
Instruction fault status register (IFSR) was introduced on ARMv7.
For older CPU we simulate IFSR with translation fault status. It
allows to generalize code.
Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
---
arch/arm/include/asm/glue.h | 10 ++++++++--
arch/arm/kernel/entry-armv.S | 14 ++++----------
arch/arm/kernel/entry-common.S | 8 ++++++--
arch/arm/mm/fault.c | 2 +-
4 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/arch/arm/include/asm/glue.h b/arch/arm/include/asm/glue.h
index a0e39d5..5bfaf6f 100644
--- a/arch/arm/include/asm/glue.h
+++ b/arch/arm/include/asm/glue.h
@@ -130,7 +130,10 @@
# ifdef CPU_PABORT_HANDLER
# define MULTI_PABORT 1
# else
-# define CPU_PABORT_HANDLER(reg, insn) mrc p15, 0, reg, cr6, cr0, 2
+# define CPU_PABORT_HANDLER(addr, ifsr, insn) \
+ mrc p15, 0, addr, c6, c0, 2 ; \
+ mrc p15, 0, ifsr, c5, c0, 1
+
# endif
#endif
@@ -138,7 +141,10 @@
# ifdef CPU_PABORT_HANDLER
# define MULTI_PABORT 1
# else
-# define CPU_PABORT_HANDLER(reg, insn) mov reg, insn
+#define __hash_5 #5
+# define CPU_PABORT_HANDLER(addr, ifsr, insn) \
+ mov addr, insn ; \
+ mov ifsr, __hash_5
# endif
#endif
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 3d727a8..335ae58 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -303,22 +303,16 @@ __pabt_svc:
tst r3, #PSR_I_BIT
biceq r9, r9, #PSR_I_BIT
- @
- @ set args, then call main handler
- @
- @ r0 - address of faulting instruction
- @ r1 - pointer to registers on stack
- @
#ifdef MULTI_PABORT
mov r0, r2 @ pass address of aborted instruction.
ldr r4, .LCprocfns
mov lr, pc
ldr pc, [r4, #PROCESSOR_PABT_FUNC]
#else
- CPU_PABORT_HANDLER(r0, r2)
+ CPU_PABORT_HANDLER(r0, r1, r2)
#endif
msr cpsr_c, r9 @ Maybe enable interrupts
- mov r1, sp @ regs
+ mov r2, sp @ regs
bl do_PrefetchAbort @ call abort handler
@
@@ -697,10 +691,10 @@ __pabt_usr:
mov lr, pc
ldr pc, [r4, #PROCESSOR_PABT_FUNC]
#else
- CPU_PABORT_HANDLER(r0, r2)
+ CPU_PABORT_HANDLER(r0, r1, r2)
#endif
enable_irq @ Enable interrupts
- mov r1, sp @ regs
+ mov r2, sp @ regs
bl do_PrefetchAbort @ call abort handler
UNWIND(.fnend )
/* fall through */
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 807cfeb..931ab9a 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -426,10 +426,14 @@ sys_mmap2:
ENDPROC(sys_mmap2)
ENTRY(pabort_ifar)
- mrc p15, 0, r0, cr6, cr0, 2
-ENTRY(pabort_noifar)
+ mrc p15, 0, r0, c6, c0, 2 @ get IFAR
+ mrc p15, 0, r1, c5, c0, 1 @ get IFSR
mov pc, lr
ENDPROC(pabort_ifar)
+ENTRY(pabort_noifar)
+ /* simulate IFSR with section translation fault status */
+ mov r1, #5
+ mov pc, lr
ENDPROC(pabort_noifar)
#ifdef CONFIG_OABI_COMPAT
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index cc8829d..5e27462 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -506,7 +506,7 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
}
asmlinkage void __exception
-do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
+do_PrefetchAbort(unsigned long addr, int ifsr, struct pt_regs *regs)
{
do_translation_fault(addr, 0, regs);
}
--
1.6.4.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v3 2/2] ARM: Proper prefetch abort handling on ARMv7
2009-09-21 11:05 [PATCH v3 1/2] ARM: Pass IFSR register to do_PrefetchAbort() Kirill A. Shutemov
2009-09-21 9:37 ` Aaro Koskinen
@ 2009-09-21 11:05 ` Kirill A. Shutemov
1 sibling, 0 replies; 4+ messages in thread
From: Kirill A. Shutemov @ 2009-09-21 11:05 UTC (permalink / raw)
To: linux-arm-kernel
Currently, on ARMv7, if an application tries to execute code
(or garbage) on non-executable page it hangs. It caused by incorrect
prefetch abort handling. Now every prefetch abort processes as
a translation fault.
To fix this we have to analize instruction fault status register
to figure out reason why we've got the abort and process it
accordingly.
To make IFSR different from DFSR we set bit 31 which is reserved in
both IFSR and DFSR.
Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
---
arch/arm/mm/fault.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 52 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 5e27462..be64139 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -203,6 +203,8 @@ __do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
good_area:
if (fsr & (1 << 11)) /* write? */
mask = VM_WRITE;
+ else if (fsr & (1 << 31))
+ mask = VM_EXEC;
else
mask = VM_READ|VM_EXEC|VM_WRITE;
@@ -505,9 +507,58 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
arm_notify_die("", regs, &info, fsr, 0);
}
+
+static struct fsr_info ifsr_info[] = {
+ { do_bad, SIGBUS, 0, "unknown 0" },
+ { do_bad, SIGBUS, 0, "unknown 1" },
+ { do_bad, SIGBUS, 0, "debug event" },
+ { do_bad, SIGSEGV, SEGV_ACCERR, "section access flag fault" },
+ { do_bad, SIGBUS, 0, "unknown 4" },
+ { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" },
+ { do_bad, SIGSEGV, SEGV_ACCERR, "page access flag fault" },
+ { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" },
+ { do_bad, SIGBUS, 0, "external abort on non-linefetch" },
+ { do_bad, SIGSEGV, SEGV_ACCERR, "section domain fault" },
+ { do_bad, SIGBUS, 0, "unknown 10" },
+ { do_bad, SIGSEGV, SEGV_ACCERR, "page domain fault" },
+ { do_bad, SIGBUS, 0, "external abort on translation" },
+ { do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" },
+ { do_bad, SIGBUS, 0, "external abort on translation" },
+ { do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" },
+ { do_bad, SIGBUS, 0, "unknown 16" },
+ { do_bad, SIGBUS, 0, "unknown 17" },
+ { do_bad, SIGBUS, 0, "unknown 18" },
+ { do_bad, SIGBUS, 0, "unknown 19" },
+ { do_bad, SIGBUS, 0, "unknown 20" },
+ { do_bad, SIGBUS, 0, "unknown 21" },
+ { do_bad, SIGBUS, 0, "unknown 22" },
+ { do_bad, SIGBUS, 0, "unknown 23" },
+ { do_bad, SIGBUS, 0, "unknown 24" },
+ { do_bad, SIGBUS, 0, "unknown 25" },
+ { do_bad, SIGBUS, 0, "unknown 26" },
+ { do_bad, SIGBUS, 0, "unknown 27" },
+ { do_bad, SIGBUS, 0, "unknown 28" },
+ { do_bad, SIGBUS, 0, "unknown 29" },
+ { do_bad, SIGBUS, 0, "unknown 30" },
+ { do_bad, SIGBUS, 0, "unknown 31" },
+};
+
asmlinkage void __exception
do_PrefetchAbort(unsigned long addr, int ifsr, struct pt_regs *regs)
{
- do_translation_fault(addr, 0, regs);
+ const struct fsr_info *inf = ifsr_info + (ifsr & 15) + ((ifsr & (1 << 10)) >> 6);
+ struct siginfo info;
+
+ if (!inf->fn(addr, ifsr | (1 << 31), regs))
+ return;
+
+ printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x)@0x%08lx\n",
+ inf->name, ifsr, addr);
+
+ info.si_signo = inf->sig;
+ info.si_errno = 0;
+ info.si_code = inf->code;
+ info.si_addr = (void __user *)addr;
+ arm_notify_die("", regs, &info, ifsr, 0);
}
--
1.6.4.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v3 1/2] ARM: Pass IFSR register to do_PrefetchAbort()
2009-09-21 9:37 ` Aaro Koskinen
@ 2009-09-21 11:30 ` Kirill A. Shutemov
0 siblings, 0 replies; 4+ messages in thread
From: Kirill A. Shutemov @ 2009-09-21 11:30 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Sep 21, 2009 at 12:37 PM, Aaro Koskinen <aaro.koskinen@nokia.com> wrote:
> Hi,
>
> Kirill A. Shutemov wrote:
>>
>> It needed for proper prefetch abort handling on ARMv7.
>>
>> Instruction fault status register (IFSR) was introduced on ARMv7.
>
> According to the ARMv7-AR reference manual it's available in ARMv6
> (see chapter G.7).
You are right. I'll fix my patch.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2009-09-21 11:30 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-09-21 11:05 [PATCH v3 1/2] ARM: Pass IFSR register to do_PrefetchAbort() Kirill A. Shutemov
2009-09-21 9:37 ` Aaro Koskinen
2009-09-21 11:30 ` Kirill A. Shutemov
2009-09-21 11:05 ` [PATCH v3 2/2] ARM: Proper prefetch abort handling on ARMv7 Kirill A. Shutemov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).