linux/arch/arm/mm/abort-lv4t.S
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#include <linux/linkage.h>
   3#include <asm/assembler.h>
   4/*
   5 * Function: v4t_late_abort
   6 *
   7 * Params  : r2 = pt_regs
   8 *         : r4 = aborted context pc
   9 *         : r5 = aborted context psr
  10 *
  11 * Returns : r4-r5, r9-r11, r13 preserved
  12 *
  13 * Purpose : obtain information about current aborted instruction.
  14 * Note: we read user space.  This means we might cause a data
  15 * abort here if the I-TLB and D-TLB aren't seeing the same
  16 * picture.  Unfortunately, this does happen.  We live with it.
  17 */
  18ENTRY(v4t_late_abort)
  19        tst     r5, #PSR_T_BIT                  @ check for thumb mode
  20#ifdef CONFIG_CPU_CP15_MMU
  21        mrc     p15, 0, r1, c5, c0, 0           @ get FSR
  22        mrc     p15, 0, r0, c6, c0, 0           @ get FAR
  23        bic     r1, r1, #1 << 11 | 1 << 10      @ clear bits 11 and 10 of FSR
  24#else
  25        mov     r0, #0                          @ clear r0, r1 (no FSR/FAR)
  26        mov     r1, #0
  27#endif
  28        bne     .data_thumb_abort
  29        ldr     r8, [r4]                        @ read arm instruction
  30        uaccess_disable ip                      @ disable userspace access
  31        tst     r8, #1 << 20                    @ L = 1 -> write?
  32        orreq   r1, r1, #1 << 11                @ yes.
  33        and     r7, r8, #15 << 24
  34        add     pc, pc, r7, lsr #22             @ Now branch to the relevant processing routine
  35        nop
  36
  37/* 0 */ b       .data_arm_lateldrhpost          @ ldrh  rd, [rn], #m/rm
  38/* 1 */ b       .data_arm_lateldrhpre           @ ldrh  rd, [rn, #m/rm]
  39/* 2 */ b       .data_unknown
  40/* 3 */ b       .data_unknown
  41/* 4 */ b       .data_arm_lateldrpostconst      @ ldr   rd, [rn], #m
  42/* 5 */ b       .data_arm_lateldrpreconst       @ ldr   rd, [rn, #m] 
  43/* 6 */ b       .data_arm_lateldrpostreg        @ ldr   rd, [rn], rm
  44/* 7 */ b       .data_arm_lateldrprereg         @ ldr   rd, [rn, rm]
  45/* 8 */ b       .data_arm_ldmstm                @ ldm*a rn, <rlist>
  46/* 9 */ b       .data_arm_ldmstm                @ ldm*b rn, <rlist>
  47/* a */ b       .data_unknown
  48/* b */ b       .data_unknown
  49/* c */ b       do_DataAbort                    @ ldc   rd, [rn], #m    @ Same as ldr   rd, [rn], #m
  50/* d */ b       do_DataAbort                    @ ldc   rd, [rn, #m]
  51/* e */ b       .data_unknown
  52/* f */ b       .data_unknown
  53
  54.data_unknown_r9:
  55        ldr     r9, [sp], #4
  56.data_unknown:  @ Part of jumptable
  57        mov     r0, r4
  58        mov     r1, r8
  59        b       baddataabort
  60
  61.data_arm_ldmstm:
  62        tst     r8, #1 << 21                    @ check writeback bit
  63        beq     do_DataAbort                    @ no writeback -> no fixup
  64        str     r9, [sp, #-4]!
  65        mov     r7, #0x11
  66        orr     r7, r7, #0x1100
  67        and     r6, r8, r7
  68        and     r9, r8, r7, lsl #1
  69        add     r6, r6, r9, lsr #1
  70        and     r9, r8, r7, lsl #2
  71        add     r6, r6, r9, lsr #2
  72        and     r9, r8, r7, lsl #3
  73        add     r6, r6, r9, lsr #3
  74        add     r6, r6, r6, lsr #8
  75        add     r6, r6, r6, lsr #4
  76        and     r6, r6, #15                     @ r6 = no. of registers to transfer.
  77        and     r9, r8, #15 << 16               @ Extract 'n' from instruction
  78        ldr     r7, [r2, r9, lsr #14]           @ Get register 'Rn'
  79        tst     r8, #1 << 23                    @ Check U bit
  80        subne   r7, r7, r6, lsl #2              @ Undo increment
  81        addeq   r7, r7, r6, lsl #2              @ Undo decrement
  82        str     r7, [r2, r9, lsr #14]           @ Put register 'Rn'
  83        ldr     r9, [sp], #4
  84        b       do_DataAbort
  85
  86.data_arm_lateldrhpre:
  87        tst     r8, #1 << 21                    @ Check writeback bit
  88        beq     do_DataAbort                    @ No writeback -> no fixup
  89.data_arm_lateldrhpost:
  90        str     r9, [sp, #-4]!
  91        and     r9, r8, #0x00f                  @ get Rm / low nibble of immediate value
  92        tst     r8, #1 << 22                    @ if (immediate offset)
  93        andne   r6, r8, #0xf00                  @ { immediate high nibble
  94        orrne   r6, r9, r6, lsr #4              @   combine nibbles } else
  95        ldreq   r6, [r2, r9, lsl #2]            @ { load Rm value }
  96.data_arm_apply_r6_and_rn:
  97        and     r9, r8, #15 << 16               @ Extract 'n' from instruction
  98        ldr     r7, [r2, r9, lsr #14]           @ Get register 'Rn'
  99        tst     r8, #1 << 23                    @ Check U bit
 100        subne   r7, r7, r6                      @ Undo incrmenet
 101        addeq   r7, r7, r6                      @ Undo decrement
 102        str     r7, [r2, r9, lsr #14]           @ Put register 'Rn'
 103        ldr     r9, [sp], #4
 104        b       do_DataAbort
 105
 106.data_arm_lateldrpreconst:
 107        tst     r8, #1 << 21                    @ check writeback bit
 108        beq     do_DataAbort                    @ no writeback -> no fixup
 109.data_arm_lateldrpostconst:
 110        movs    r6, r8, lsl #20                 @ Get offset
 111        beq     do_DataAbort                    @ zero -> no fixup
 112        str     r9, [sp, #-4]!
 113        and     r9, r8, #15 << 16               @ Extract 'n' from instruction
 114        ldr     r7, [r2, r9, lsr #14]           @ Get register 'Rn'
 115        tst     r8, #1 << 23                    @ Check U bit
 116        subne   r7, r7, r6, lsr #20             @ Undo increment
 117        addeq   r7, r7, r6, lsr #20             @ Undo decrement
 118        str     r7, [r2, r9, lsr #14]           @ Put register 'Rn'
 119        ldr     r9, [sp], #4
 120        b       do_DataAbort
 121
 122.data_arm_lateldrprereg:
 123        tst     r8, #1 << 21                    @ check writeback bit
 124        beq     do_DataAbort                    @ no writeback -> no fixup
 125.data_arm_lateldrpostreg:
 126        and     r7, r8, #15                     @ Extract 'm' from instruction
 127        ldr     r6, [r2, r7, lsl #2]            @ Get register 'Rm'
 128        str     r9, [sp, #-4]!
 129        mov     r9, r8, lsr #7                  @ get shift count
 130        ands    r9, r9, #31
 131        and     r7, r8, #0x70                   @ get shift type
 132        orreq   r7, r7, #8                      @ shift count = 0
 133        add     pc, pc, r7
 134        nop
 135
 136        mov     r6, r6, lsl r9                  @ 0: LSL #!0
 137        b       .data_arm_apply_r6_and_rn
 138        b       .data_arm_apply_r6_and_rn       @ 1: LSL #0
 139        nop
 140        b       .data_unknown_r9                @ 2: MUL?
 141        nop
 142        b       .data_unknown_r9                @ 3: MUL?
 143        nop
 144        mov     r6, r6, lsr r9                  @ 4: LSR #!0
 145        b       .data_arm_apply_r6_and_rn
 146        mov     r6, r6, lsr #32                 @ 5: LSR #32
 147        b       .data_arm_apply_r6_and_rn
 148        b       .data_unknown_r9                @ 6: MUL?
 149        nop
 150        b       .data_unknown_r9                @ 7: MUL?
 151        nop
 152        mov     r6, r6, asr r9                  @ 8: ASR #!0
 153        b       .data_arm_apply_r6_and_rn
 154        mov     r6, r6, asr #32                 @ 9: ASR #32
 155        b       .data_arm_apply_r6_and_rn
 156        b       .data_unknown_r9                @ A: MUL?
 157        nop
 158        b       .data_unknown_r9                @ B: MUL?
 159        nop
 160        mov     r6, r6, ror r9                  @ C: ROR #!0
 161        b       .data_arm_apply_r6_and_rn
 162        mov     r6, r6, rrx                     @ D: RRX
 163        b       .data_arm_apply_r6_and_rn
 164        b       .data_unknown_r9                @ E: MUL?
 165        nop
 166        b       .data_unknown_r9                @ F: MUL?
 167
 168.data_thumb_abort:
 169        ldrh    r8, [r4]                        @ read instruction
 170        uaccess_disable ip                      @ disable userspace access
 171        tst     r8, #1 << 11                    @ L = 1 -> write?
 172        orreq   r1, r1, #1 << 8                 @ yes
 173        and     r7, r8, #15 << 12
 174        add     pc, pc, r7, lsr #10             @ lookup in table
 175        nop
 176
 177/* 0 */ b       .data_unknown
 178/* 1 */ b       .data_unknown
 179/* 2 */ b       .data_unknown
 180/* 3 */ b       .data_unknown
 181/* 4 */ b       .data_unknown
 182/* 5 */ b       .data_thumb_reg
 183/* 6 */ b       do_DataAbort
 184/* 7 */ b       do_DataAbort
 185/* 8 */ b       do_DataAbort
 186/* 9 */ b       do_DataAbort
 187/* A */ b       .data_unknown
 188/* B */ b       .data_thumb_pushpop
 189/* C */ b       .data_thumb_ldmstm
 190/* D */ b       .data_unknown
 191/* E */ b       .data_unknown
 192/* F */ b       .data_unknown
 193
 194.data_thumb_reg:
 195        tst     r8, #1 << 9
 196        beq     do_DataAbort
 197        tst     r8, #1 << 10                    @ If 'S' (signed) bit is set
 198        movne   r1, #0                          @ it must be a load instr
 199        b       do_DataAbort
 200
 201.data_thumb_pushpop:
 202        tst     r8, #1 << 10
 203        beq     .data_unknown
 204        str     r9, [sp, #-4]!
 205        and     r6, r8, #0x55                   @ hweight8(r8) + R bit
 206        and     r9, r8, #0xaa
 207        add     r6, r6, r9, lsr #1
 208        and     r9, r6, #0xcc
 209        and     r6, r6, #0x33
 210        add     r6, r6, r9, lsr #2
 211        movs    r7, r8, lsr #9                  @ C = r8 bit 8 (R bit)
 212        adc     r6, r6, r6, lsr #4              @ high + low nibble + R bit
 213        and     r6, r6, #15                     @ number of regs to transfer
 214        ldr     r7, [r2, #13 << 2]
 215        tst     r8, #1 << 11
 216        addeq   r7, r7, r6, lsl #2              @ increment SP if PUSH
 217        subne   r7, r7, r6, lsl #2              @ decrement SP if POP
 218        str     r7, [r2, #13 << 2]
 219        ldr     r9, [sp], #4
 220        b       do_DataAbort
 221
 222.data_thumb_ldmstm:
 223        str     r9, [sp, #-4]!
 224        and     r6, r8, #0x55                   @ hweight8(r8)
 225        and     r9, r8, #0xaa
 226        add     r6, r6, r9, lsr #1
 227        and     r9, r6, #0xcc
 228        and     r6, r6, #0x33
 229        add     r6, r6, r9, lsr #2
 230        add     r6, r6, r6, lsr #4
 231        and     r9, r8, #7 << 8
 232        ldr     r7, [r2, r9, lsr #6]
 233        and     r6, r6, #15                     @ number of regs to transfer
 234        sub     r7, r7, r6, lsl #2              @ always decrement
 235        str     r7, [r2, r9, lsr #6]
 236        ldr     r9, [sp], #4
 237        b       do_DataAbort
 238