0001
0002 #include <linux/linkage.h>
0003 #include <asm/assembler.h>
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
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 b .data_arm_lateldrhpost @ ldrh rd, [rn], #m/rm
0038 b .data_arm_lateldrhpre @ ldrh rd, [rn, #m/rm]
0039 b .data_unknown
0040 b .data_unknown
0041 b .data_arm_lateldrpostconst @ ldr rd, [rn], #m
0042 b .data_arm_lateldrpreconst @ ldr rd, [rn, #m]
0043 b .data_arm_lateldrpostreg @ ldr rd, [rn], rm
0044 b .data_arm_lateldrprereg @ ldr rd, [rn, rm]
0045 b .data_arm_ldmstm @ ldm*a rn, <rlist>
0046 b .data_arm_ldmstm @ ldm*b rn, <rlist>
0047 b .data_unknown
0048 b .data_unknown
0049 b do_DataAbort @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m
0050 b do_DataAbort @ ldc rd, [rn, #m]
0051 b .data_unknown
0052 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 b .data_unknown
0178 b .data_unknown
0179 b .data_unknown
0180 b .data_unknown
0181 b .data_unknown
0182 b .data_thumb_reg
0183 b do_DataAbort
0184 b do_DataAbort
0185 b do_DataAbort
0186 b do_DataAbort
0187 b .data_unknown
0188 b .data_thumb_pushpop
0189 b .data_thumb_ldmstm
0190 b .data_unknown
0191 b .data_unknown
0192 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