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