2005-04-17 02:20:36 +04:00
# include < l i n u x / l i n k a g e . h >
# include < a s m / a s s e m b l e r . h >
/ *
* Function : v4 t _ l a t e _ a b o r t
*
2011-06-26 19:01:26 +04:00
* Params : r2 = p t _ r e g s
* : r4 = a b o r t e d c o n t e x t p c
2011-06-26 17:35:07 +04:00
* : r5 = a b o r t e d c o n t e x t p s r
2005-04-17 02:20:36 +04:00
*
2011-06-27 15:27:47 +04:00
* Returns : r4 - r5 , r10 - r11 , r13 p r e s e r v e d
2005-04-17 02:20:36 +04:00
*
* Purpose : o b t a i n i n f o r m a t i o n a b o u t c u r r e n t a b o r t e d i n s t r u c t i o n .
* Note : we r e a d u s e r s p a c e . T h i s m e a n s w e m i g h t c a u s e a d a t a
* abort h e r e i f t h e I - T L B a n d D - T L B a r e n ' t s e e i n g t h e s a m e
* picture. U n f o r t u n a t e l y , t h i s d o e s h a p p e n . W e l i v e w i t h i t .
* /
ENTRY( v4 t _ l a t e _ a b o r t )
2011-06-26 17:35:07 +04:00
tst r5 , #P S R _ T _ B I T @ c h e c k f o r t h u m b m o d e
2006-09-28 16:46:16 +04:00
# ifdef C O N F I G _ C P U _ C P 1 5 _ M M U
2005-04-17 02:20:36 +04:00
mrc p15 , 0 , r1 , c5 , c0 , 0 @ get FSR
mrc p15 , 0 , r0 , c6 , c0 , 0 @ get FAR
2006-09-28 16:46:16 +04:00
bic r1 , r1 , #1 < < 1 1 | 1 < < 1 0 @ clear bits 11 and 10 of FSR
# else
mov r0 , #0 @ clear r0, r1 (no FSR/FAR)
mov r1 , #0
# endif
2005-04-17 02:20:36 +04:00
bne . d a t a _ t h u m b _ a b o r t
2011-06-26 17:35:07 +04:00
ldr r8 , [ r4 ] @ read arm instruction
2015-08-20 12:32:02 +03:00
uaccess_ d i s a b l e i p @ disable userspace access
2005-04-17 02:20:36 +04:00
tst r8 , #1 < < 2 0 @ L = 1 -> write?
orreq r1 , r1 , #1 < < 1 1 @ yes.
and r7 , r8 , #15 < < 2 4
add p c , p c , r7 , l s r #22 @ Now branch to the relevant processing routine
nop
/* 0 */ b . d a t a _ a r m _ l a t e l d r h p o s t @ ldrh rd, [rn], #m/rm
/* 1 */ b . d a t a _ a r m _ l a t e l d r h p r e @ ldrh rd, [rn, #m/rm]
/* 2 */ b . d a t a _ u n k n o w n
/* 3 */ b . d a t a _ u n k n o w n
/* 4 */ b . d a t a _ a r m _ l a t e l d r p o s t c o n s t @ ldr rd, [rn], #m
/* 5 */ b . d a t a _ a r m _ l a t e l d r p r e c o n s t @ ldr rd, [rn, #m]
/* 6 */ b . d a t a _ a r m _ l a t e l d r p o s t r e g @ ldr rd, [rn], rm
/* 7 */ b . d a t a _ a r m _ l a t e l d r p r e r e g @ ldr rd, [rn, rm]
/* 8 */ b . d a t a _ a r m _ l d m s t m @ ldm*a rn, <rlist>
/* 9 */ b . d a t a _ a r m _ l d m s t m @ ldm*b rn, <rlist>
/* a */ b . d a t a _ u n k n o w n
/* b */ b . d a t a _ u n k n o w n
2011-06-26 19:01:26 +04:00
/* c */ b d o _ D a t a A b o r t @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m
/* d */ b d o _ D a t a A b o r t @ ldc rd, [rn, #m]
2005-04-17 02:20:36 +04:00
/* e */ b . d a t a _ u n k n o w n
/* f */
.data_unknown : @ Part of jumptable
2011-06-26 17:35:07 +04:00
mov r0 , r4
2005-04-17 02:20:36 +04:00
mov r1 , r8
2011-06-26 19:01:26 +04:00
b b a d d a t a a b o r t
2005-04-17 02:20:36 +04:00
.data_arm_ldmstm :
tst r8 , #1 < < 2 1 @ check writeback bit
2011-06-26 19:01:26 +04:00
beq d o _ D a t a A b o r t @ no writeback -> no fixup
2005-04-17 02:20:36 +04:00
mov r7 , #0x11
orr r7 , r7 , #0x1100
and r6 , r8 , r7
2011-06-26 17:42:02 +04:00
and r9 , r8 , r7 , l s l #1
add r6 , r6 , r9 , l s r #1
and r9 , r8 , r7 , l s l #2
add r6 , r6 , r9 , l s r #2
and r9 , r8 , r7 , l s l #3
add r6 , r6 , r9 , l s r #3
2005-04-17 02:20:36 +04:00
add r6 , r6 , r6 , l s r #8
add r6 , r6 , r6 , l s r #4
and r6 , r6 , #15 @ r6 = no. of registers to transfer.
2011-06-27 15:27:47 +04:00
and r9 , r8 , #15 < < 1 6 @ Extract 'n' from instruction
ldr r7 , [ r2 , r9 , l s r #14 ] @ Get register 'Rn'
2005-04-17 02:20:36 +04:00
tst r8 , #1 < < 2 3 @ Check U bit
subne r7 , r7 , r6 , l s l #2 @ Undo increment
addeq r7 , r7 , r6 , l s l #2 @ Undo decrement
2011-06-27 15:27:47 +04:00
str r7 , [ r2 , r9 , l s r #14 ] @ Put register 'Rn'
2011-06-26 19:01:26 +04:00
b d o _ D a t a A b o r t
2005-04-17 02:20:36 +04:00
.data_arm_lateldrhpre :
tst r8 , #1 < < 2 1 @ Check writeback bit
2011-06-26 19:01:26 +04:00
beq d o _ D a t a A b o r t @ No writeback -> no fixup
2005-04-17 02:20:36 +04:00
.data_arm_lateldrhpost :
2011-06-27 15:27:47 +04:00
and r9 , r8 , #0x00f @ get Rm / low nibble of immediate value
2005-04-17 02:20:36 +04:00
tst r8 , #1 < < 2 2 @ if (immediate offset)
andne r6 , r8 , #0xf00 @ { immediate high nibble
2011-06-27 15:27:47 +04:00
orrne r6 , r9 , r6 , l s r #4 @ combine nibbles } else
ldreq r6 , [ r2 , r9 , l s l #2 ] @ { load Rm value }
2005-04-17 02:20:36 +04:00
.data_arm_apply_r6_and_rn :
2011-06-27 15:27:47 +04:00
and r9 , r8 , #15 < < 1 6 @ Extract 'n' from instruction
ldr r7 , [ r2 , r9 , l s r #14 ] @ Get register 'Rn'
2005-04-17 02:20:36 +04:00
tst r8 , #1 < < 2 3 @ Check U bit
subne r7 , r7 , r6 @ Undo incrmenet
addeq r7 , r7 , r6 @ Undo decrement
2011-06-27 15:27:47 +04:00
str r7 , [ r2 , r9 , l s r #14 ] @ Put register 'Rn'
2011-06-26 19:01:26 +04:00
b d o _ D a t a A b o r t
2005-04-17 02:20:36 +04:00
.data_arm_lateldrpreconst :
tst r8 , #1 < < 2 1 @ check writeback bit
2011-06-26 19:01:26 +04:00
beq d o _ D a t a A b o r t @ no writeback -> no fixup
2005-04-17 02:20:36 +04:00
.data_arm_lateldrpostconst :
2011-06-27 15:23:11 +04:00
movs r6 , r8 , l s l #20 @ Get offset
2011-06-26 19:01:26 +04:00
beq d o _ D a t a A b o r t @ zero -> no fixup
2011-06-27 15:27:47 +04:00
and r9 , r8 , #15 < < 1 6 @ Extract 'n' from instruction
ldr r7 , [ r2 , r9 , l s r #14 ] @ Get register 'Rn'
2005-04-17 02:20:36 +04:00
tst r8 , #1 < < 2 3 @ Check U bit
2011-06-27 15:23:11 +04:00
subne r7 , r7 , r6 , l s r #20 @ Undo increment
addeq r7 , r7 , r6 , l s r #20 @ Undo decrement
2011-06-27 15:27:47 +04:00
str r7 , [ r2 , r9 , l s r #14 ] @ Put register 'Rn'
2011-06-26 19:01:26 +04:00
b d o _ D a t a A b o r t
2005-04-17 02:20:36 +04:00
.data_arm_lateldrprereg :
tst r8 , #1 < < 2 1 @ check writeback bit
2011-06-26 19:01:26 +04:00
beq d o _ D a t a A b o r t @ no writeback -> no fixup
2005-04-17 02:20:36 +04:00
.data_arm_lateldrpostreg :
and r7 , r8 , #15 @ Extract 'm' from instruction
2011-06-27 12:52:54 +04:00
ldr r6 , [ r2 , r7 , l s l #2 ] @ Get register 'Rm'
2011-06-27 15:27:47 +04:00
mov r9 , r8 , l s r #7 @ get shift count
ands r9 , r9 , #31
2005-04-17 02:20:36 +04:00
and r7 , r8 , #0x70 @ get shift type
orreq r7 , r7 , #8 @ shift count = 0
add p c , p c , r7
nop
2011-06-27 15:27:47 +04:00
mov r6 , r6 , l s l r9 @ 0: LSL #!0
2005-04-17 02:20:36 +04:00
b . d a t a _ a r m _ a p p l y _ r6 _ a n d _ r n
b . d a t a _ a r m _ a p p l y _ r6 _ a n d _ r n @ 1: LSL #0
nop
b . d a t a _ u n k n o w n @ 2: MUL?
nop
b . d a t a _ u n k n o w n @ 3: MUL?
nop
2011-06-27 15:27:47 +04:00
mov r6 , r6 , l s r r9 @ 4: LSR #!0
2005-04-17 02:20:36 +04:00
b . d a t a _ a r m _ a p p l y _ r6 _ a n d _ r n
mov r6 , r6 , l s r #32 @ 5: LSR #32
b . d a t a _ a r m _ a p p l y _ r6 _ a n d _ r n
b . d a t a _ u n k n o w n @ 6: MUL?
nop
b . d a t a _ u n k n o w n @ 7: MUL?
nop
2011-06-27 15:27:47 +04:00
mov r6 , r6 , a s r r9 @ 8: ASR #!0
2005-04-17 02:20:36 +04:00
b . d a t a _ a r m _ a p p l y _ r6 _ a n d _ r n
mov r6 , r6 , a s r #32 @ 9: ASR #32
b . d a t a _ a r m _ a p p l y _ r6 _ a n d _ r n
b . d a t a _ u n k n o w n @ A: MUL?
nop
b . d a t a _ u n k n o w n @ B: MUL?
nop
2011-06-27 15:27:47 +04:00
mov r6 , r6 , r o r r9 @ C: ROR #!0
2005-04-17 02:20:36 +04:00
b . d a t a _ a r m _ a p p l y _ r6 _ a n d _ r n
mov r6 , r6 , r r x @ D: RRX
b . d a t a _ a r m _ a p p l y _ r6 _ a n d _ r n
b . d a t a _ u n k n o w n @ E: MUL?
nop
b . d a t a _ u n k n o w n @ F: MUL?
.data_thumb_abort :
2011-06-26 17:35:07 +04:00
ldrh r8 , [ r4 ] @ read instruction
2015-08-20 12:32:02 +03:00
uaccess_ d i s a b l e i p @ disable userspace access
2005-04-17 02:20:36 +04:00
tst r8 , #1 < < 1 1 @ L = 1 -> write?
orreq r1 , r1 , #1 < < 8 @ yes
and r7 , r8 , #15 < < 1 2
add p c , p c , r7 , l s r #10 @ lookup in table
nop
/* 0 */ b . d a t a _ u n k n o w n
/* 1 */ b . d a t a _ u n k n o w n
/* 2 */ b . d a t a _ u n k n o w n
/* 3 */ b . d a t a _ u n k n o w n
/* 4 */ b . d a t a _ u n k n o w n
/* 5 */ b . d a t a _ t h u m b _ r e g
2011-06-26 19:01:26 +04:00
/* 6 */ b d o _ D a t a A b o r t
/* 7 */ b d o _ D a t a A b o r t
/* 8 */ b d o _ D a t a A b o r t
/* 9 */ b d o _ D a t a A b o r t
2005-04-17 02:20:36 +04:00
/* A */ b . d a t a _ u n k n o w n
/* B */ b . d a t a _ t h u m b _ p u s h p o p
/* C */ b . d a t a _ t h u m b _ l d m s t m
/* D */ b . d a t a _ u n k n o w n
/* E */ b . d a t a _ u n k n o w n
/* F */ b . d a t a _ u n k n o w n
.data_thumb_reg :
tst r8 , #1 < < 9
2011-06-26 19:01:26 +04:00
beq d o _ D a t a A b o r t
2005-04-17 02:20:36 +04:00
tst r8 , #1 < < 1 0 @ If 'S' (signed) bit is set
movne r1 , #0 @ it must be a load instr
2011-06-26 19:01:26 +04:00
b d o _ D a t a A b o r t
2005-04-17 02:20:36 +04:00
.data_thumb_pushpop :
tst r8 , #1 < < 1 0
beq . d a t a _ u n k n o w n
and r6 , r8 , #0x55 @ hweight8(r8) + R bit
2011-06-26 17:42:02 +04:00
and r9 , r8 , #0xaa
add r6 , r6 , r9 , l s r #1
and r9 , r6 , #0xcc
2005-04-17 02:20:36 +04:00
and r6 , r6 , #0x33
2011-06-26 17:42:02 +04:00
add r6 , r6 , r9 , l s r #2
2005-04-17 02:20:36 +04:00
movs r7 , r8 , l s r #9 @ C = r8 bit 8 (R bit)
adc r6 , r6 , r6 , l s r #4 @ high + low nibble + R bit
and r6 , r6 , #15 @ number of regs to transfer
2011-06-27 12:52:54 +04:00
ldr r7 , [ r2 , #13 < < 2 ]
2005-04-17 02:20:36 +04:00
tst r8 , #1 < < 1 1
addeq r7 , r7 , r6 , l s l #2 @ increment SP if PUSH
subne r7 , r7 , r6 , l s l #2 @ decrement SP if POP
2011-06-27 12:52:54 +04:00
str r7 , [ r2 , #13 < < 2 ]
2011-06-26 19:01:26 +04:00
b d o _ D a t a A b o r t
2005-04-17 02:20:36 +04:00
.data_thumb_ldmstm :
and r6 , r8 , #0x55 @ hweight8(r8)
2011-06-26 17:42:02 +04:00
and r9 , r8 , #0xaa
add r6 , r6 , r9 , l s r #1
and r9 , r6 , #0xcc
2005-04-17 02:20:36 +04:00
and r6 , r6 , #0x33
2011-06-26 17:42:02 +04:00
add r6 , r6 , r9 , l s r #2
2005-04-17 02:20:36 +04:00
add r6 , r6 , r6 , l s r #4
2011-06-27 15:27:47 +04:00
and r9 , r8 , #7 < < 8
ldr r7 , [ r2 , r9 , l s r #6 ]
2005-04-17 02:20:36 +04:00
and r6 , r6 , #15 @ number of regs to transfer
sub r7 , r7 , r6 , l s l #2 @ always decrement
2011-06-27 15:27:47 +04:00
str r7 , [ r2 , r9 , l s r #6 ]
2011-06-26 19:01:26 +04:00
b d o _ D a t a A b o r t