root/arch/arm/mm/abort-lv4t.S

/* [<][>][^][v][top][bottom][index][help] */
   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  */
  18 ENTRY(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

/* [<][>][^][v][top][bottom][index][help] */