2005-04-16 15:20:36 -07:00
/ *
* linux/ a r c h / a r m / v f p / v f p h w . S
*
* Copyright ( C ) 2 0 0 4 A R M L i m i t e d .
* Written b y D e e p B l u e S o l u t i o n s L i m i t e d .
*
* This p r o g r a m i s f r e e s o f t w a r e ; you can redistribute it and/or modify
* it u n d e r t h e t e r m s o f t h e G N U G e n e r a l P u b l i c L i c e n s e v e r s i o n 2 a s
* published b y t h e F r e e S o f t w a r e F o u n d a t i o n .
*
* This c o d e i s c a l l e d f r o m t h e k e r n e l ' s u n d e f i n e d i n s t r u c t i o n t r a p .
* r9 h o l d s t h e r e t u r n a d d r e s s f o r s u c c e s s f u l h a n d l i n g .
* lr h o l d s t h e r e t u r n a d d r e s s f o r u n r e c o g n i s e d i n s t r u c t i o n s .
* r1 0 p o i n t s a t t h e s t a r t o f t h e p r i v a t e F P w o r k s p a c e i n t h e t h r e a d s t r u c t u r e
* sp p o i n t s t o a s t r u c t p t _ r e g s ( a s d e f i n e d i n i n c l u d e / a s m / p r o c / p t r a c e . h )
* /
# include < a s m / t h r e a d _ i n f o . h >
# include < a s m / v f p m a c r o s . h >
# include " . . / k e r n e l / e n t r y - h e a d e r . S "
.macro DBGSTR, s t r
# ifdef D E B U G
stmfd s p ! , { r0 - r3 , i p , l r }
add r0 , p c , #4
bl p r i n t k
b 1 f
.asciz " < 7 > VFP : \ str\ n "
.balign 4
1 : ldmfd s p ! , { r0 - r3 , i p , l r }
# endif
.endm
.macro DBGSTR1 , s t r , a r g
# ifdef D E B U G
stmfd s p ! , { r0 - r3 , i p , l r }
mov r1 , \ a r g
add r0 , p c , #4
bl p r i n t k
b 1 f
.asciz " < 7 > VFP : \ str\ n "
.balign 4
1 : ldmfd s p ! , { r0 - r3 , i p , l r }
# endif
.endm
.macro DBGSTR3 , s t r , a r g 1 , a r g 2 , a r g 3
# ifdef D E B U G
stmfd s p ! , { r0 - r3 , i p , l r }
mov r3 , \ a r g 3
mov r2 , \ a r g 2
mov r1 , \ a r g 1
add r0 , p c , #4
bl p r i n t k
b 1 f
.asciz " < 7 > VFP : \ str\ n "
.balign 4
1 : ldmfd s p ! , { r0 - r3 , i p , l r }
# endif
.endm
@ VFP hardware support entry point.
@
@ r0 = faulted instruction
@ r2 = faulted PC+4
@ r9 = successful return
@ r10 = vfp_state union
2007-01-24 18:47:08 +01:00
@ r11 = CPU number
2005-04-16 15:20:36 -07:00
@ lr = failure return
2008-08-28 11:22:32 +01:00
ENTRY( v f p _ s u p p o r t _ e n t r y )
2005-04-16 15:20:36 -07:00
DBGSTR3 " i n s t r % 0 8 x p c % 0 8 x s t a t e % p " , r0 , r2 , r10
VFPFMRX r1 , F P E X C @ Is the VFP enabled?
DBGSTR1 " f p e x c % 0 8 x " , r1
2007-07-18 09:37:10 +01:00
tst r1 , #F P E X C _ E N
2005-04-16 15:20:36 -07:00
bne l o o k _ f o r _ V F P _ e x c e p t i o n s @ VFP is already enabled
DBGSTR1 " e n a b l e % x " , r10
ldr r3 , l a s t _ V F P _ c o n t e x t _ a d d r e s s
2007-07-18 09:37:10 +01:00
orr r1 , r1 , #F P E X C _ E N @ u s e r F P E X C h a s t h e e n a b l e b i t s e t
2007-01-24 18:47:08 +01:00
ldr r4 , [ r3 , r11 , l s l #2 ] @ last_VFP_context pointer
2007-07-18 09:37:10 +01:00
bic r5 , r1 , #F P E X C _ E X @ m a k e s u r e e x c e p t i o n s a r e d i s a b l e d
2005-04-16 15:20:36 -07:00
cmp r4 , r10
beq c h e c k _ f o r _ e x c e p t i o n @ we are returning to the same
@ process, so the registers are
@ still there. In this case, we do
@ not want to drop a pending exception.
VFPFMXR F P E X C , r5 @ enable VFP, disable any pending
@ exceptions, so we can get at the
@ rest of it
2007-01-24 18:47:08 +01:00
# ifndef C O N F I G _ S M P
2005-04-16 15:20:36 -07:00
@ Save out the current registers to the old thread state
2007-01-24 18:47:08 +01:00
@ No need for SMP since this is not done lazily
2005-04-16 15:20:36 -07:00
DBGSTR1 " s a v e o l d s t a t e % p " , r4
cmp r4 , #0
beq n o _ o l d _ V F P _ p r o c e s s
2007-09-25 15:22:24 +01:00
VFPFSTMIA r4 , r5 @ save the working registers
2005-04-16 15:20:36 -07:00
VFPFMRX r5 , F P S C R @ current status
2007-11-22 18:32:01 +01:00
tst r1 , #F P E X C _ E X @ i s t h e r e a d d i t i o n a l s t a t e t o s a v e ?
2008-11-06 13:23:08 +00:00
beq 1 f
VFPFMRX r6 , F P I N S T @ FPINST (only if FPEXC.EX is set)
tst r1 , #F P E X C _ F P 2 V @ is there an FPINST2 to read?
beq 1 f
VFPFMRX r8 , F P I N S T 2 @ FPINST2 if needed (and present)
1 :
2005-04-16 15:20:36 -07:00
stmia r4 , { r1 , r5 , r6 , r8 } @ save FPEXC, FPSCR, FPINST, FPINST2
@ and point r4 at the word at the
@ start of the register dump
2007-01-24 18:47:08 +01:00
# endif
2005-04-16 15:20:36 -07:00
no_old_VFP_process :
DBGSTR1 " l o a d s t a t e % p " , r10
2007-01-24 18:47:08 +01:00
str r10 , [ r3 , r11 , l s l #2 ] @ update the last_VFP_context pointer
2005-04-16 15:20:36 -07:00
@ Load the saved state back into the VFP
2007-09-25 15:22:24 +01:00
VFPFLDMIA r10 , r5 @ reload the working registers while
2005-04-16 15:20:36 -07:00
@ FPEXC is in a safe state
2006-03-25 21:58:00 +00:00
ldmia r10 , { r1 , r5 , r6 , r8 } @ load FPEXC, FPSCR, FPINST, FPINST2
2007-11-22 18:32:01 +01:00
tst r1 , #F P E X C _ E X @ i s t h e r e a d d i t i o n a l s t a t e t o r e s t o r e ?
2008-11-06 13:23:08 +00:00
beq 1 f
VFPFMXR F P I N S T , r6 @ restore FPINST (only if FPEXC.EX is set)
tst r1 , #F P E X C _ F P 2 V @ is there an FPINST2 to write?
beq 1 f
VFPFMXR F P I N S T 2 , r8 @ FPINST2 if needed (and present)
1 :
2005-04-16 15:20:36 -07:00
VFPFMXR F P S C R , r5 @ restore status
check_for_exception :
2007-07-18 09:37:10 +01:00
tst r1 , #F P E X C _ E X
2005-04-16 15:20:36 -07:00
bne p r o c e s s _ e x c e p t i o n @ might as well handle the pending
@ exception before retrying branch
@ out before setting an FPEXC that
@ stops us reading stuff
VFPFMXR F P E X C , r1 @ restore FPEXC last
sub r2 , r2 , #4
str r2 , [ s p , #S _ P C ] @ r e t r y t h e i n s t r u c t i o n
2009-04-01 20:27:18 +01:00
# ifdef C O N F I G _ P R E E M P T
get_ t h r e a d _ i n f o r10
ldr r4 , [ r10 , #T I _ P R E E M P T ] @ g e t p r e e m p t c o u n t
sub r11 , r4 , #1 @ decrement it
str r11 , [ r10 , #T I _ P R E E M P T ]
# endif
2005-04-16 15:20:36 -07:00
mov p c , r9 @ we think we have handled things
look_for_VFP_exceptions :
2007-11-22 18:32:01 +01:00
@ Check for synchronous or asynchronous exception
tst r1 , #F P E X C _ E X | F P E X C _ D E X
2005-04-16 15:20:36 -07:00
bne p r o c e s s _ e x c e p t i o n
2007-11-22 18:32:01 +01:00
@ On some implementations of the VFP subarch 1, setting FPSCR.IXE
@ causes all the CDP instructions to be bounced synchronously without
@ setting the FPEXC.EX bit
2005-04-16 15:20:36 -07:00
VFPFMRX r5 , F P S C R
2007-11-22 18:32:01 +01:00
tst r5 , #F P S C R _ I X E
2005-04-16 15:20:36 -07:00
bne p r o c e s s _ e x c e p t i o n
@ Fall into hand on to next handler - appropriate coproc instr
@ not recognised by VFP
DBGSTR " n o t V F P "
2009-04-01 20:27:18 +01:00
# ifdef C O N F I G _ P R E E M P T
get_ t h r e a d _ i n f o r10
ldr r4 , [ r10 , #T I _ P R E E M P T ] @ g e t p r e e m p t c o u n t
sub r11 , r4 , #1 @ decrement it
str r11 , [ r10 , #T I _ P R E E M P T ]
# endif
2005-04-16 15:20:36 -07:00
mov p c , l r
process_exception :
DBGSTR " b o u n c e "
mov r2 , s p @ nothing stacked - regdump is at TOS
mov l r , r9 @ setup for a return to the user code.
@ Now call the C code to package up the bounce to the support code
@ r0 holds the trigger instruction
@ r1 holds the FPEXC value
@ r2 pointer to register dump
2007-11-22 18:32:01 +01:00
b V F P _ b o u n c e @ we have handled this - the support
2005-04-16 15:20:36 -07:00
@ code will raise an exception if
@ required. If not, the user code will
@ retry the faulted instruction
2008-08-28 11:22:32 +01:00
ENDPROC( v f p _ s u p p o r t _ e n t r y )
2005-04-16 15:20:36 -07:00
2008-08-28 11:22:32 +01:00
ENTRY( v f p _ s a v e _ s t a t e )
2007-01-24 18:47:08 +01:00
@ Save the current VFP state
@ r0 - save location
@ r1 - FPEXC
DBGSTR1 " s a v e V F P s t a t e % p " , r0
2007-09-25 15:22:24 +01:00
VFPFSTMIA r0 , r2 @ save the working registers
2007-01-24 18:47:08 +01:00
VFPFMRX r2 , F P S C R @ current status
2007-11-22 18:32:01 +01:00
tst r1 , #F P E X C _ E X @ i s t h e r e a d d i t i o n a l s t a t e t o s a v e ?
2008-11-06 13:23:08 +00:00
beq 1 f
VFPFMRX r3 , F P I N S T @ FPINST (only if FPEXC.EX is set)
tst r1 , #F P E X C _ F P 2 V @ is there an FPINST2 to read?
beq 1 f
VFPFMRX r12 , F P I N S T 2 @ FPINST2 if needed (and present)
1 :
2007-01-24 18:47:08 +01:00
stmia r0 , { r1 , r2 , r3 , r12 } @ save FPEXC, FPSCR, FPINST, FPINST2
mov p c , l r
2008-08-28 11:22:32 +01:00
ENDPROC( v f p _ s a v e _ s t a t e )
2007-01-24 18:47:08 +01:00
2005-04-16 15:20:36 -07:00
last_VFP_context_address :
.word last_VFP_context
2008-08-28 11:22:32 +01:00
ENTRY( v f p _ g e t _ f l o a t )
2005-04-16 15:20:36 -07:00
add p c , p c , r0 , l s l #3
mov r0 , r0
.irp dr,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,1 0 ,1 1 ,1 2 ,1 3 ,1 4 ,1 5
mrc p10 , 0 , r0 , c \ d r , c0 , 0 @ fmrs r0, s0
mov p c , l r
mrc p10 , 0 , r0 , c \ d r , c0 , 4 @ fmrs r0, s1
mov p c , l r
.endr
2008-08-28 11:22:32 +01:00
ENDPROC( v f p _ g e t _ f l o a t )
2005-04-16 15:20:36 -07:00
2008-08-28 11:22:32 +01:00
ENTRY( v f p _ p u t _ f l o a t )
2006-08-30 15:06:39 +01:00
add p c , p c , r1 , l s l #3
2005-04-16 15:20:36 -07:00
mov r0 , r0
.irp dr,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,1 0 ,1 1 ,1 2 ,1 3 ,1 4 ,1 5
2006-08-30 15:06:39 +01:00
mcr p10 , 0 , r0 , c \ d r , c0 , 0 @ fmsr r0, s0
2005-04-16 15:20:36 -07:00
mov p c , l r
2006-08-30 15:06:39 +01:00
mcr p10 , 0 , r0 , c \ d r , c0 , 4 @ fmsr r0, s1
2005-04-16 15:20:36 -07:00
mov p c , l r
.endr
2008-08-28 11:22:32 +01:00
ENDPROC( v f p _ p u t _ f l o a t )
2005-04-16 15:20:36 -07:00
2008-08-28 11:22:32 +01:00
ENTRY( v f p _ g e t _ d o u b l e )
2005-04-16 15:20:36 -07:00
add p c , p c , r0 , l s l #3
mov r0 , r0
.irp dr,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,1 0 ,1 1 ,1 2 ,1 3 ,1 4 ,1 5
2006-06-21 13:51:41 +01:00
fmrrd r0 , r1 , d \ d r
2005-04-16 15:20:36 -07:00
mov p c , l r
.endr
2007-09-25 15:22:24 +01:00
# ifdef C O N F I G _ V F P v3
@ d16 - d31 registers
.irp dr,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,1 0 ,1 1 ,1 2 ,1 3 ,1 4 ,1 5
mrrc p11 , 3 , r0 , r1 , c \ d r @ fmrrd r0, r1, d\dr
mov p c , l r
.endr
# endif
2005-04-16 15:20:36 -07:00
2007-09-25 15:22:24 +01:00
@ virtual register 16 (or 32 if VFPv3) for compare with zero
2005-04-16 15:20:36 -07:00
mov r0 , #0
mov r1 , #0
mov p c , l r
2008-08-28 11:22:32 +01:00
ENDPROC( v f p _ g e t _ d o u b l e )
2005-04-16 15:20:36 -07:00
2008-08-28 11:22:32 +01:00
ENTRY( v f p _ p u t _ d o u b l e )
2006-08-30 15:06:39 +01:00
add p c , p c , r2 , l s l #3
2005-04-16 15:20:36 -07:00
mov r0 , r0
.irp dr,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,1 0 ,1 1 ,1 2 ,1 3 ,1 4 ,1 5
2006-08-30 15:06:39 +01:00
fmdrr d \ d r , r0 , r1
2005-04-16 15:20:36 -07:00
mov p c , l r
.endr
2007-09-25 15:22:24 +01:00
# ifdef C O N F I G _ V F P v3
@ d16 - d31 registers
.irp dr,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,1 0 ,1 1 ,1 2 ,1 3 ,1 4 ,1 5
mcrr p11 , 3 , r1 , r2 , c \ d r @ fmdrr r1, r2, d\dr
mov p c , l r
.endr
# endif
2008-08-28 11:22:32 +01:00
ENDPROC( v f p _ p u t _ d o u b l e )