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