]> git.hungrycats.org Git - linux/commitdiff
[ARM] page fault handling updates
authorRussell King <rmk@flint.arm.linux.org.uk>
Wed, 10 Jul 2002 13:01:38 +0000 (14:01 +0100)
committerRussell King <rmk@flint.arm.linux.org.uk>
Wed, 10 Jul 2002 13:01:38 +0000 (14:01 +0100)
- FSR "write" bit moved from bit 8 to bit 11.
- Handle bit 10 of FSR for xscale imprecise aborts.
- Allow Xscale CP0 and CP13 accesses.
- Move Xscale specific implementations to their own file.

12 files changed:
arch/arm/mm/Makefile
arch/arm/mm/abort-ev4.S
arch/arm/mm/abort-ev4t.S
arch/arm/mm/abort-ev5ej.S [deleted file]
arch/arm/mm/abort-ev5tej.S [new file with mode: 0644]
arch/arm/mm/abort-lv4t.S
arch/arm/mm/abort-xscale.S [new file with mode: 0644]
arch/arm/mm/copypage-v5te.S [deleted file]
arch/arm/mm/copypage-xscale.S [new file with mode: 0644]
arch/arm/mm/fault-armv.c
arch/arm/mm/proc-arm926.S
arch/arm/mm/proc-xscale.S

index a0f1a029dcc449c125376794dffc49339b58ee56..d516bc43fb0eecb04a0e311719718440fcd2d82b 100644 (file)
@@ -42,7 +42,7 @@ p-$(CONFIG_CPU_SA1100)        += proc-sa110.o   tlb-v4wb.o copypage-v4mc.o abort-ev4.o
 
 # ARMv5
 p-$(CONFIG_CPU_ARM926T)        += proc-arm926.o  tlb-v4wb.o copypage-v4wb.o abort-ev5ej.o
-p-$(CONFIG_CPU_XSCALE) += proc-xscale.o  tlb-v4wb.o copypage-v5te.o abort-ev4t.o  minicache.o
+p-$(CONFIG_CPU_XSCALE) += proc-xscale.o  tlb-v4wb.o copypage-xscale.o abort-xscale.o minicache.o
 
 obj-y          += $(sort $(p-y))
 
index 4eb0823da945a73a3967bd5ecc8d2859183fcf14..4f18f9e87bae9058700287a9fce5e529e8b90b31 100644 (file)
@@ -7,7 +7,7 @@
  *         : r3 = saved SPSR
  *
  * Returns : r0 = address of abort
- *        : r1 = FSR, bit 8 = write
+ *        : r1 = FSR, bit 11 = write
  *        : r2-r8 = corrupted
  *        : r9 = preserved
  *        : sp = pointer to registers
@@ -22,8 +22,9 @@ ENTRY(v4_early_abort)
        mrc     p15, 0, r1, c5, c0, 0           @ get FSR
        mrc     p15, 0, r0, c6, c0, 0           @ get FAR
        ldr     r3, [r2]                        @ read aborted ARM instruction
+       bic     r1, r1, #1 << 11 | 1 << 10      @ clear bits 11 and 10 of FSR
        tst     r3, #1 << 20                    @ L = 1 -> write?
-       orreq   r1, r1, #1 <<                 @ yes.
+       orreq   r1, r1, #1 << 11                @ yes.
        mov     pc, lr
 
 
index 31a38f1ed0c0c881ba9da812b7e507069761759e..831a4a21c216434d9acc2aa63e2139a47a1b829a 100644 (file)
@@ -7,7 +7,7 @@
  *         : r3 = saved SPSR
  *
  * Returns : r0 = address of abort
- *        : r1 = FSR, bit 8 = write
+ *        : r1 = FSR, bit 11 = write
  *        : r2-r8 = corrupted
  *        : r9 = preserved
  *        : sp = pointer to registers
@@ -24,8 +24,8 @@ ENTRY(v4t_early_abort)
        tst     r3, #PSR_T_BIT
        ldrneh  r3, [r2]                        @ read aborted thumb instruction
        ldreq   r3, [r2]                        @ read aborted ARM instruction
-       bic     r1, r1, #1 << 8
+       bic     r1, r1, #1 << 11 | 1 << 10      @ clear bits 11 and 10 of FSR
        movne   r3, r3, lsl #(21 - 12)          @ move thumb bit 11 to ARM bit 20
        tst     r3, #1 << 20                    @ check write
-       orreq   r1, r1, #1 << 8
+       orreq   r1, r1, #1 << 11
        mov     pc, lr
diff --git a/arch/arm/mm/abort-ev5ej.S b/arch/arm/mm/abort-ev5ej.S
deleted file mode 100644 (file)
index 659fabb..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-/*
- * Function: v5ej_early_abort
- *
- * Params  : r2 = address of aborted instruction
- *         : r3 = saved SPSR
- *
- * Returns : r0 = address of abort
- *        : r1 = FSR, bit 8 = write
- *        : r2-r8 = corrupted
- *        : r9 = preserved
- *        : sp = pointer to registers
- *
- * Purpose : obtain information about current aborted instruction.
- * Note: we read user space.  This means we might cause a data
- * abort here if the I-TLB and D-TLB aren't seeing the same
- * picture.  Unfortunately, this does happen.  We live with it.
- */
-       .align  5
-ENTRY(v5ej_early_abort)
-       mrc     p15, 0, r1, c5, c0, 0           @ get FSR
-       mrc     p15, 0, r0, c6, c0, 0           @ get FAR
-       tst     r3, #PSR_J_BIT
-       orrne   r1, r1, #1 << 8                 @ always assume write
-       bne     1f
-       tst     r3, #PSR_T_BIT
-       ldrneh  r3, [r2]                        @ read aborted thumb instruction
-       ldreq   r3, [r2]                        @ read aborted ARM instruction
-       movne   r3, r3, lsl #(21 - 12)          @ move thumb bit 11 to ARM bit 20
-       tst     r3, #1 << 20                    @ L = 1 -> write
-       orreq   r1, r1, #1 << 8                 @ yes.
-1:     mov     pc, lr
-
-
diff --git a/arch/arm/mm/abort-ev5tej.S b/arch/arm/mm/abort-ev5tej.S
new file mode 100644 (file)
index 0000000..47591f8
--- /dev/null
@@ -0,0 +1,36 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+/*
+ * Function: v5tej_early_abort
+ *
+ * Params  : r2 = address of aborted instruction
+ *         : r3 = saved SPSR
+ *
+ * Returns : r0 = address of abort
+ *        : r1 = FSR, bit 11 = write
+ *        : r2-r8 = corrupted
+ *        : r9 = preserved
+ *        : sp = pointer to registers
+ *
+ * Purpose : obtain information about current aborted instruction.
+ * Note: we read user space.  This means we might cause a data
+ * abort here if the I-TLB and D-TLB aren't seeing the same
+ * picture.  Unfortunately, this does happen.  We live with it.
+ */
+       .align  5
+ENTRY(v5tej_early_abort)
+       mrc     p15, 0, r1, c5, c0, 0           @ get FSR
+       mrc     p15, 0, r0, c6, c0, 0           @ get FAR
+       bic     r1, r1, #1 << 11 | 1 << 10      @ clear bits 11 and 10 of FSR
+       tst     r3, #PSR_J_BIT
+       orrne   r1, r1, #1 << 11                @ always assume write
+       bne     1f
+       tst     r3, #PSR_T_BIT
+       ldrneh  r3, [r2]                        @ read aborted thumb instruction
+       ldreq   r3, [r2]                        @ read aborted ARM instruction
+       movne   r3, r3, lsl #(21 - 12)          @ move thumb bit 11 to ARM bit 20
+       tst     r3, #1 << 20                    @ L = 1 -> write
+       orreq   r1, r1, #1 << 11                @ yes.
+1:     mov     pc, lr
+
+
index 1742f586de85e95751c6604ecbb8da0af886dc57..e4b0ff054a513a482a3d5330d265deffed6e77dd 100644 (file)
@@ -7,7 +7,7 @@
  *         : r3 = saved SPSR
  *
  * Returns : r0 = address of abort
- *        : r1 = FSR, bit 8 = writing
+ *        : r1 = FSR, bit 11 = write
  *        : r2-r8 = corrupted
  *        : r9 = preserved
  *        : sp = pointer to registers
@@ -21,10 +21,11 @@ ENTRY(v4t_late_abort)
        tst     r3, #PSR_T_BIT                  @ check for thumb mode
        mrc     p15, 0, r1, c5, c0, 0           @ get FSR
        mrc     p15, 0, r0, c6, c0, 0           @ get FAR
+       bic     r1, r1, #1 << 11 | 1 << 10      @ clear bits 11 and 10 of FSR
        ldreq   r8, [r2]                        @ read arm instruction
        bne     .data_thumb_abort
        tst     r8, #1 << 20                    @ L = 1 -> write?
-       orreq   r1, r1, #1 <<                 @ yes.
+       orreq   r1, r1, #1 << 11                @ yes.
        and     r7, r8, #15 << 24
        add     pc, pc, r7, lsr #22             @ Now branch to the relevant processing routine
        nop
diff --git a/arch/arm/mm/abort-xscale.S b/arch/arm/mm/abort-xscale.S
new file mode 100644 (file)
index 0000000..a5316d1
--- /dev/null
@@ -0,0 +1,34 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+/*
+ * Function: xscale_abort
+ *
+ * Params  : r2 = address of aborted instruction
+ *         : r3 = saved SPSR
+ *
+ * Returns : r0 = address of abort
+ *        : r1 = FSR, bit 11 = write
+ *        : r2-r8 = corrupted
+ *        : r9 = preserved
+ *        : sp = pointer to registers
+ *
+ * Purpose : obtain information about current aborted instruction.
+ * Note: we read user space.  This means we might cause a data
+ * abort here if the I-TLB and D-TLB aren't seeing the same
+ * picture.  Unfortunately, this does happen.  We live with it.
+ *
+ * Note: Xscale is contains non-standard architecture extensions.
+ * It requires its own early abort handler
+ */
+       .align  5
+ENTRY(xscale_abort)
+       mrc     p15, 0, r1, c5, c0, 0           @ get FSR
+       mrc     p15, 0, r0, c6, c0, 0           @ get FAR
+       tst     r3, #PSR_T_BIT
+       ldrneh  r3, [r2]                        @ read aborted thumb instruction
+       ldreq   r3, [r2]                        @ read aborted ARM instruction
+       bic     r1, r1, #1 << 11                @ clear bits 11 of FSR
+       movne   r3, r3, lsl #(21 - 12)          @ move thumb bit 11 to ARM bit 20
+       tst     r3, #1 << 20                    @ check write
+       orreq   r1, r1, #1 << 11
+       mov     pc, lr
diff --git a/arch/arm/mm/copypage-v5te.S b/arch/arm/mm/copypage-v5te.S
deleted file mode 100644 (file)
index 1685047..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- *  linux/arch/arm/lib/copypage-armv5te.S
- *
- *  Copyright (C) 2001 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/linkage.h>
-#include <asm/constants.h>
-
-/*
- * General note:
- *  We don't really want write-allocate cache behaviour for these functions
- *  since that will just eat through 8K of the cache.
- */
-
-       .text
-       .align  5
-/*
- * ARMv5TE optimised copy_user_page
- *  r0 = destination
- *  r1 = source
- *  r2 = virtual user address of ultimate destination page
- *
- * The source page may have some clean entries in the cache already, but we
- * can safely ignore them - break_cow() will flush them out of the cache
- * if we eventually end up using our copied page.
- *
- * What we could do is use the mini-cache to buffer reads from the source
- * page.  We rely on the mini-cache being smaller than one page, so we'll
- * cycle through the complete cache anyway.
- */
-ENTRY(v5te_mc_copy_user_page)
-       stmfd   sp!, {r4, r5, lr}
-       mov     r5, r0
-       mov     r0, r1
-       bl      map_page_minicache
-       mov     r1, r5
-       mov     lr, #PAGE_SZ/32
-
-1:     mov     ip, r1
-       ldrd    r2, [r0], #8
-       ldrd    r4, [r0], #8
-       strd    r2, [r1], #8
-       ldrd    r2, [r0], #8
-       strd    r4, [r1], #8
-       ldrd    r4, [r0], #8
-       strd    r2, [r1], #8
-       strd    r4, [r1], #8
-       mcr     p15, 0, ip, c7, c10, 1          @ clean D line
-       mcr     p15, 0, ip, c7, c6, 1           @ invalidate D line
-       subs    lr, lr, #1
-       bne     1b
-
-       ldmfd   sp!, {r4, r5, pc}
-
-       .align  5
-/*
- * ARMv5TE optimised clear_user_page
- *  r0 = destination
- *  r1 = virtual user address of ultimate destination page
- */
-ENTRY(v5te_mc_clear_user_page)
-       str     lr, [sp, #-4]!
-       mov     r1, #PAGE_SZ/32
-       mov     r2, #0
-       mov     r3, #0
-1:     mov     ip, r0
-       strd    r2, [r0], #8
-       strd    r2, [r0], #8
-       strd    r2, [r0], #8
-       strd    r2, [r0], #8
-       mcr     p15, 0, ip, c7, c10, 1          @ clean D line
-       mcr     p15, 0, ip, c7, c6, 1           @ invalidate D line
-       subs    r1, r1, #1
-       bne     1b
-       ldr     pc, [sp], #4
-
-       .section ".text.init", #alloc, #execinstr
-
-ENTRY(v5te_mc_user_fns)
-       .long   v5te_mc_clear_user_page
-       .long   v5te_mc_copy_user_page
diff --git a/arch/arm/mm/copypage-xscale.S b/arch/arm/mm/copypage-xscale.S
new file mode 100644 (file)
index 0000000..9b162f3
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ *  linux/arch/arm/lib/copypage-xscale.S
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/linkage.h>
+#include <asm/constants.h>
+
+/*
+ * General note:
+ *  We don't really want write-allocate cache behaviour for these functions
+ *  since that will just eat through 8K of the cache.
+ */
+
+       .text
+       .align  5
+/*
+ * XScale optimised copy_user_page
+ *  r0 = destination
+ *  r1 = source
+ *  r2 = virtual user address of ultimate destination page
+ *
+ * The source page may have some clean entries in the cache already, but we
+ * can safely ignore them - break_cow() will flush them out of the cache
+ * if we eventually end up using our copied page.
+ *
+ * What we could do is use the mini-cache to buffer reads from the source
+ * page.  We rely on the mini-cache being smaller than one page, so we'll
+ * cycle through the complete cache anyway.
+ */
+ENTRY(xscale_mc_copy_user_page)
+       stmfd   sp!, {r4, r5, lr}
+       mov     r5, r0
+       mov     r0, r1
+       bl      map_page_minicache
+       mov     r1, r5
+       mov     lr, #PAGE_SZ/32
+
+1:     mov     ip, r1
+       ldrd    r2, [r0], #8
+       ldrd    r4, [r0], #8
+       strd    r2, [r1], #8
+       ldrd    r2, [r0], #8
+       strd    r4, [r1], #8
+       ldrd    r4, [r0], #8
+       strd    r2, [r1], #8
+       strd    r4, [r1], #8
+       mcr     p15, 0, ip, c7, c10, 1          @ clean D line
+       mcr     p15, 0, ip, c7, c6, 1           @ invalidate D line
+       subs    lr, lr, #1
+       bne     1b
+
+       ldmfd   sp!, {r4, r5, pc}
+
+       .align  5
+/*
+ * XScale optimised clear_user_page
+ *  r0 = destination
+ *  r1 = virtual user address of ultimate destination page
+ */
+ENTRY(xscale_mc_clear_user_page)
+       str     lr, [sp, #-4]!
+       mov     r1, #PAGE_SZ/32
+       mov     r2, #0
+       mov     r3, #0
+1:     mov     ip, r0
+       strd    r2, [r0], #8
+       strd    r2, [r0], #8
+       strd    r2, [r0], #8
+       strd    r2, [r0], #8
+       mcr     p15, 0, ip, c7, c10, 1          @ clean D line
+       mcr     p15, 0, ip, c7, c6, 1           @ invalidate D line
+       subs    r1, r1, #1
+       bne     1b
+       ldr     pc, [sp], #4
+
+       .section ".text.init", #alloc, #execinstr
+
+ENTRY(xscale_mc_user_fns)
+       .long   xscale_mc_clear_user_page
+       .long   xscale_mc_copy_user_page
index aa6333a7a6592a01bf2cab0a47355e939edba86d..fb05656bdb6af9bfee6a4a14e52eae94a3d24612 100644 (file)
@@ -47,6 +47,10 @@ static struct fsr_info {
        int     sig;
        const char *name;
 } fsr_info[] = {
+       /*
+        * The following are the standard ARMv3 and ARMv4 aborts.  ARMv5
+        * defines these to be "precise" aborts.
+        */
        { do_bad,               SIGSEGV, "vector exception"                },
        { do_bad,               SIGILL,  "alignment exception"             },
        { do_bad,               SIGKILL, "terminal exception"              },
@@ -62,14 +66,35 @@ static struct fsr_info {
        { do_bad,               SIGBUS,  "external abort on translation"   },
        { do_sect_fault,        SIGSEGV, "section permission fault"        },
        { do_bad,               SIGBUS,  "external abort on translation"   },
-       { do_page_fault,        SIGSEGV, "page permission fault"           }
+       { do_page_fault,        SIGSEGV, "page permission fault"           },
+       /*
+        * The following are "imprecise" aborts, which are signalled by bit
+        * 10 of the FSR, and may not be recoverable.  These are only
+        * supported if the CPU abort handler supports bit 10.
+        */
+       { do_bad,               SIGBUS,  "unknown 16"                      },
+       { do_bad,               SIGBUS,  "unknown 17"                      },
+       { do_bad,               SIGBUS,  "unknown 18"                      },
+       { do_bad,               SIGBUS,  "unknown 19"                      },
+       { do_bad,               SIGBUS,  "lock abort"                      }, /* xscale */
+       { do_bad,               SIGBUS,  "unknown 21"                      },
+       { do_bad,               SIGBUS,  "imprecise external abort"        }, /* xscale */
+       { do_bad,               SIGBUS,  "unknown 23"                      },
+       { do_bad,               SIGBUS,  "dcache parity error"             }, /* xscale */
+       { do_bad,               SIGBUS,  "unknown 25"                      },
+       { do_bad,               SIGBUS,  "unknown 26"                      },
+       { do_bad,               SIGBUS,  "unknown 27"                      },
+       { do_bad,               SIGBUS,  "unknown 28"                      },
+       { do_bad,               SIGBUS,  "unknown 29"                      },
+       { do_bad,               SIGBUS,  "unknown 30"                      },
+       { do_bad,               SIGBUS,  "unknown 31"                      }
 };
 
 void __init
 hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
                int sig, const char *name)
 {
-       if (nr >= 0 && nr < 16) {
+       if (nr >= 0 && nr < ARRAY_SIZE(fsr_info)) {
                fsr_info[nr].fn   = fn;
                fsr_info[nr].sig  = sig;
                fsr_info[nr].name = name;
@@ -82,7 +107,7 @@ hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *)
 asmlinkage void
 do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
-       const struct fsr_info *inf = fsr_info + (fsr & 15);
+       const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6);
 
        if (!inf->fn(addr, fsr, regs))
                return;
index d4d1732cddf64b4f661af2652652b3b52b60648c..40c30d93571c9fbf859ee433462bb0fb35421346 100644 (file)
@@ -481,7 +481,7 @@ __arm926_setup:
  */
        .type   arm926_processor_functions, #object
 arm926_processor_functions:
-       .word   v5ej_early_abort
+       .word   v5tej_early_abort
        .word   cpu_arm926_check_bugs
        .word   cpu_arm926_proc_init
        .word   cpu_arm926_proc_fin
index 67cb6ae4df400134a44046a5273d5e0f107a81e3..d5fcb7a6fdb7ff72a3c94546014ac730e312e6f3 100644 (file)
@@ -602,8 +602,6 @@ ENTRY(cpu_xscale_set_pmd)
  */
        .align  5
 ENTRY(cpu_xscale_set_pte)
-       tst     r0, #2048
-       streq   r0, [r0, -r0]                   @ BUG_ON
        str     r1, [r0], #-2048                @ linux version
 
        bic     r2, r1, #0xff0
@@ -681,6 +679,9 @@ __xscale_setup:
        mcr     p15, 0, r4, c2, c0, 0           @ load page table pointer
        mov     r0, #0x1f                       @ Domains 0, 1 = client
        mcr     p15, 0, r0, c3, c0, 0           @ load domain access register
+       mov     r0, #1                          @ Allow access to CP0 and CP13
+       orr     r0, r0, #1 << 13                @ Its undefined whether this
+       mcr     p15, 0, r0, c15, c1, 0          @ affects USR or SVC modes
        mrc     p15, 0, r0, c1, c0, 0           @ get control register
        bic     r0, r0, #0x0200                 @ .... ..R. .... ....
        bic     r0, r0, #0x0082                 @ .... .... B... ..A.
@@ -697,7 +698,7 @@ __xscale_setup:
 
        .type   xscale_processor_functions, #object
 ENTRY(xscale_processor_functions)
-       .word   v4t_early_abort
+       .word   xscale_abort
        .word   cpu_xscale_check_bugs
        .word   cpu_xscale_proc_init
        .word   cpu_xscale_proc_fin
@@ -739,7 +740,7 @@ cpu_pxa250_info:
 
        .type   cpu_arch_name, #object
 cpu_arch_name:
-       .asciz  "armv5"
+       .asciz  "armv5te"
        .size   cpu_arch_name, . - cpu_arch_name
 
        .type   cpu_elf_name, #object
@@ -762,7 +763,7 @@ __80200_proc_info:
        .long   cpu_80200_info
        .long   xscale_processor_functions
        .long   v4wbi_tlb_fns
-       .long   v5te_mc_user_fns
+       .long   xscale_mc_user_fns
        .size   __80200_proc_info, . - __80200_proc_info
 
        .type   __pxa250_proc_info,#object
@@ -777,6 +778,6 @@ __pxa250_proc_info:
        .long   cpu_pxa250_info
        .long   xscale_processor_functions
        .long   v4wbi_tlb_fns
-       .long   v5te_mc_user_fns
+       .long   xscale_mc_user_fns
        .size   __pxa250_proc_info, . - __pxa250_proc_info