Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #include <linux/linkage.h>
0003 #include <asm/assembler.h>
0004 /*
0005  * Function: v4t_late_abort
0006  *
0007  * Params  : r2 = pt_regs
0008  *     : r4 = aborted context pc
0009  *     : r5 = aborted context psr
0010  *
0011  * Returns : r4-r5, r9-r11, r13 preserved
0012  *
0013  * Purpose : obtain information about current aborted instruction.
0014  * Note: we read user space.  This means we might cause a data
0015  * abort here if the I-TLB and D-TLB aren't seeing the same
0016  * picture.  Unfortunately, this does happen.  We live with it.
0017  */
0018 ENTRY(v4t_late_abort)
0019     tst r5, #PSR_T_BIT          @ check for thumb mode
0020 #ifdef CONFIG_CPU_CP15_MMU
0021     mrc p15, 0, r1, c5, c0, 0       @ get FSR
0022     mrc p15, 0, r0, c6, c0, 0       @ get FAR
0023     bic r1, r1, #1 << 11 | 1 << 10  @ clear bits 11 and 10 of FSR
0024 #else
0025     mov r0, #0              @ clear r0, r1 (no FSR/FAR)
0026     mov r1, #0
0027 #endif
0028     bne .data_thumb_abort
0029     ldr r8, [r4]            @ read arm instruction
0030     uaccess_disable ip          @ disable userspace access
0031     tst r8, #1 << 20            @ L = 1 -> write?
0032     orreq   r1, r1, #1 << 11        @ yes.
0033     and r7, r8, #15 << 24
0034     add pc, pc, r7, lsr #22     @ Now branch to the relevant processing routine
0035     nop
0036 
0037 /* 0 */ b   .data_arm_lateldrhpost      @ ldrh  rd, [rn], #m/rm
0038 /* 1 */ b   .data_arm_lateldrhpre       @ ldrh  rd, [rn, #m/rm]
0039 /* 2 */ b   .data_unknown
0040 /* 3 */ b   .data_unknown
0041 /* 4 */ b   .data_arm_lateldrpostconst  @ ldr   rd, [rn], #m
0042 /* 5 */ b   .data_arm_lateldrpreconst   @ ldr   rd, [rn, #m] 
0043 /* 6 */ b   .data_arm_lateldrpostreg    @ ldr   rd, [rn], rm
0044 /* 7 */ b   .data_arm_lateldrprereg     @ ldr   rd, [rn, rm]
0045 /* 8 */ b   .data_arm_ldmstm        @ ldm*a rn, <rlist>
0046 /* 9 */ b   .data_arm_ldmstm        @ ldm*b rn, <rlist>
0047 /* a */ b   .data_unknown
0048 /* b */ b   .data_unknown
0049 /* c */ b   do_DataAbort            @ ldc   rd, [rn], #m    @ Same as ldr   rd, [rn], #m
0050 /* d */ b   do_DataAbort            @ ldc   rd, [rn, #m]
0051 /* e */ b   .data_unknown
0052 /* f */ b   .data_unknown
0053 
0054 .data_unknown_r9:
0055     ldr r9, [sp], #4
0056 .data_unknown:  @ Part of jumptable
0057     mov r0, r4
0058     mov r1, r8
0059     b   baddataabort
0060 
0061 .data_arm_ldmstm:
0062     tst r8, #1 << 21            @ check writeback bit
0063     beq do_DataAbort            @ no writeback -> no fixup
0064     str r9, [sp, #-4]!
0065     mov r7, #0x11
0066     orr r7, r7, #0x1100
0067     and r6, r8, r7
0068     and r9, r8, r7, lsl #1
0069     add r6, r6, r9, lsr #1
0070     and r9, r8, r7, lsl #2
0071     add r6, r6, r9, lsr #2
0072     and r9, r8, r7, lsl #3
0073     add r6, r6, r9, lsr #3
0074     add r6, r6, r6, lsr #8
0075     add r6, r6, r6, lsr #4
0076     and r6, r6, #15         @ r6 = no. of registers to transfer.
0077     and r9, r8, #15 << 16       @ Extract 'n' from instruction
0078     ldr r7, [r2, r9, lsr #14]       @ Get register 'Rn'
0079     tst r8, #1 << 23            @ Check U bit
0080     subne   r7, r7, r6, lsl #2      @ Undo increment
0081     addeq   r7, r7, r6, lsl #2      @ Undo decrement
0082     str r7, [r2, r9, lsr #14]       @ Put register 'Rn'
0083     ldr r9, [sp], #4
0084     b   do_DataAbort
0085 
0086 .data_arm_lateldrhpre:
0087     tst r8, #1 << 21            @ Check writeback bit
0088     beq do_DataAbort            @ No writeback -> no fixup
0089 .data_arm_lateldrhpost:
0090     str r9, [sp, #-4]!
0091     and r9, r8, #0x00f          @ get Rm / low nibble of immediate value
0092     tst r8, #1 << 22            @ if (immediate offset)
0093     andne   r6, r8, #0xf00          @ { immediate high nibble
0094     orrne   r6, r9, r6, lsr #4      @   combine nibbles } else
0095     ldreq   r6, [r2, r9, lsl #2]        @ { load Rm value }
0096 .data_arm_apply_r6_and_rn:
0097     and r9, r8, #15 << 16       @ Extract 'n' from instruction
0098     ldr r7, [r2, r9, lsr #14]       @ Get register 'Rn'
0099     tst r8, #1 << 23            @ Check U bit
0100     subne   r7, r7, r6          @ Undo incrmenet
0101     addeq   r7, r7, r6          @ Undo decrement
0102     str r7, [r2, r9, lsr #14]       @ Put register 'Rn'
0103     ldr r9, [sp], #4
0104     b   do_DataAbort
0105 
0106 .data_arm_lateldrpreconst:
0107     tst r8, #1 << 21            @ check writeback bit
0108     beq do_DataAbort            @ no writeback -> no fixup
0109 .data_arm_lateldrpostconst:
0110     movs    r6, r8, lsl #20         @ Get offset
0111     beq do_DataAbort            @ zero -> no fixup
0112     str r9, [sp, #-4]!
0113     and r9, r8, #15 << 16       @ Extract 'n' from instruction
0114     ldr r7, [r2, r9, lsr #14]       @ Get register 'Rn'
0115     tst r8, #1 << 23            @ Check U bit
0116     subne   r7, r7, r6, lsr #20     @ Undo increment
0117     addeq   r7, r7, r6, lsr #20     @ Undo decrement
0118     str r7, [r2, r9, lsr #14]       @ Put register 'Rn'
0119     ldr r9, [sp], #4
0120     b   do_DataAbort
0121 
0122 .data_arm_lateldrprereg:
0123     tst r8, #1 << 21            @ check writeback bit
0124     beq do_DataAbort            @ no writeback -> no fixup
0125 .data_arm_lateldrpostreg:
0126     and r7, r8, #15         @ Extract 'm' from instruction
0127     ldr r6, [r2, r7, lsl #2]        @ Get register 'Rm'
0128     str r9, [sp, #-4]!
0129     mov r9, r8, lsr #7          @ get shift count
0130     ands    r9, r9, #31
0131     and r7, r8, #0x70           @ get shift type
0132     orreq   r7, r7, #8          @ shift count = 0
0133     add pc, pc, r7
0134     nop
0135 
0136     mov r6, r6, lsl r9          @ 0: LSL #!0
0137     b   .data_arm_apply_r6_and_rn
0138     b   .data_arm_apply_r6_and_rn   @ 1: LSL #0
0139     nop
0140     b   .data_unknown_r9        @ 2: MUL?
0141     nop
0142     b   .data_unknown_r9        @ 3: MUL?
0143     nop
0144     mov r6, r6, lsr r9          @ 4: LSR #!0
0145     b   .data_arm_apply_r6_and_rn
0146     mov r6, r6, lsr #32         @ 5: LSR #32
0147     b   .data_arm_apply_r6_and_rn
0148     b   .data_unknown_r9        @ 6: MUL?
0149     nop
0150     b   .data_unknown_r9        @ 7: MUL?
0151     nop
0152     mov r6, r6, asr r9          @ 8: ASR #!0
0153     b   .data_arm_apply_r6_and_rn
0154     mov r6, r6, asr #32         @ 9: ASR #32
0155     b   .data_arm_apply_r6_and_rn
0156     b   .data_unknown_r9        @ A: MUL?
0157     nop
0158     b   .data_unknown_r9        @ B: MUL?
0159     nop
0160     mov r6, r6, ror r9          @ C: ROR #!0
0161     b   .data_arm_apply_r6_and_rn
0162     mov r6, r6, rrx         @ D: RRX
0163     b   .data_arm_apply_r6_and_rn
0164     b   .data_unknown_r9        @ E: MUL?
0165     nop
0166     b   .data_unknown_r9        @ F: MUL?
0167 
0168 .data_thumb_abort:
0169     ldrh    r8, [r4]            @ read instruction
0170     uaccess_disable ip          @ disable userspace access
0171     tst r8, #1 << 11            @ L = 1 -> write?
0172     orreq   r1, r1, #1 << 8         @ yes
0173     and r7, r8, #15 << 12
0174     add pc, pc, r7, lsr #10     @ lookup in table
0175     nop
0176 
0177 /* 0 */ b   .data_unknown
0178 /* 1 */ b   .data_unknown
0179 /* 2 */ b   .data_unknown
0180 /* 3 */ b   .data_unknown
0181 /* 4 */ b   .data_unknown
0182 /* 5 */ b   .data_thumb_reg
0183 /* 6 */ b   do_DataAbort
0184 /* 7 */ b   do_DataAbort
0185 /* 8 */ b   do_DataAbort
0186 /* 9 */ b   do_DataAbort
0187 /* A */ b   .data_unknown
0188 /* B */ b   .data_thumb_pushpop
0189 /* C */ b   .data_thumb_ldmstm
0190 /* D */ b   .data_unknown
0191 /* E */ b   .data_unknown
0192 /* F */ b   .data_unknown
0193 
0194 .data_thumb_reg:
0195     tst r8, #1 << 9
0196     beq do_DataAbort
0197     tst r8, #1 << 10            @ If 'S' (signed) bit is set
0198     movne   r1, #0              @ it must be a load instr
0199     b   do_DataAbort
0200 
0201 .data_thumb_pushpop:
0202     tst r8, #1 << 10
0203     beq .data_unknown
0204     str r9, [sp, #-4]!
0205     and r6, r8, #0x55           @ hweight8(r8) + R bit
0206     and r9, r8, #0xaa
0207     add r6, r6, r9, lsr #1
0208     and r9, r6, #0xcc
0209     and r6, r6, #0x33
0210     add r6, r6, r9, lsr #2
0211     movs    r7, r8, lsr #9          @ C = r8 bit 8 (R bit)
0212     adc r6, r6, r6, lsr #4      @ high + low nibble + R bit
0213     and r6, r6, #15         @ number of regs to transfer
0214     ldr r7, [r2, #13 << 2]
0215     tst r8, #1 << 11
0216     addeq   r7, r7, r6, lsl #2      @ increment SP if PUSH
0217     subne   r7, r7, r6, lsl #2      @ decrement SP if POP
0218     str r7, [r2, #13 << 2]
0219     ldr r9, [sp], #4
0220     b   do_DataAbort
0221 
0222 .data_thumb_ldmstm:
0223     str r9, [sp, #-4]!
0224     and r6, r8, #0x55           @ hweight8(r8)
0225     and r9, r8, #0xaa
0226     add r6, r6, r9, lsr #1
0227     and r9, r6, #0xcc
0228     and r6, r6, #0x33
0229     add r6, r6, r9, lsr #2
0230     add r6, r6, r6, lsr #4
0231     and r9, r8, #7 << 8
0232     ldr r7, [r2, r9, lsr #6]
0233     and r6, r6, #15         @ number of regs to transfer
0234     sub r7, r7, r6, lsl #2      @ always decrement
0235     str r7, [r2, r9, lsr #6]
0236     ldr r9, [sp], #4
0237     b   do_DataAbort