2005-04-17 02:20:36 +04:00
/ *
* linux/ a r c h / a r m / k e r n e l / e n t r y - a r m v . S
*
* Copyright ( C ) 1 9 9 6 ,1 9 9 7 ,1 9 9 8 R u s s e l l K i n g .
* ARM7 0 0 f i x b y M a t t h e w G o d b o l t ( l i n u x - u s e r @willothewisp.demon.co.uk)
2006-01-14 00:05:25 +03:00
* nommu s u p p o r t b y H y o k S . C h o i ( h y o k . c h o i @samsung.com)
2005-04-17 02:20:36 +04:00
*
* 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 .
*
* Low- l e v e l v e c t o r i n t e r f a c e r o u t i n e s
*
2007-12-04 16:33:33 +03:00
* Note : there i s a S t r o n g A R M b u g i n t h e S T M I A r n , { r e g s } ^ i n s t r u c t i o n
* that c a u s e s i t t o s a v e w r o n g v a l u e s . . . B e a w a r e !
2005-04-17 02:20:36 +04:00
* /
2005-10-30 00:44:55 +04:00
# include < a s m / m e m o r y . h >
2005-04-17 02:20:36 +04:00
# include < a s m / g l u e . h >
# include < a s m / v f p m a c r o s . h >
2008-08-05 19:14:15 +04:00
# include < m a c h / e n t r y - m a c r o . S >
2006-06-21 16:31:52 +04:00
# include < a s m / t h r e a d _ n o t i f y . h >
2009-02-16 13:42:09 +03:00
# include < a s m / u n w i n d . h >
2009-11-10 02:53:29 +03:00
# include < a s m / u n i s t d . h >
2010-07-05 17:53:10 +04:00
# include < a s m / t l s . h >
2005-04-17 02:20:36 +04:00
# include " e n t r y - h e a d e r . S "
2005-05-21 21:14:44 +04:00
/ *
* Interrupt h a n d l i n g . P r e s e r v e s r7 , r8 , r9
* /
.macro irq_handler
2007-02-17 00:16:32 +03:00
get_ i r q n r _ p r e a m b l e r5 , l r
2005-05-21 21:14:44 +04:00
1 : get_ i r q n r _ a n d _ b a s e r0 , r6 , r5 , l r
movne r1 , s p
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
2009-07-24 15:32:54 +04:00
adrne l r , B S Y M ( 1 b )
2005-05-21 21:14:44 +04:00
bne a s m _ d o _ I R Q
2005-05-21 21:16:44 +04:00
# ifdef C O N F I G _ S M P
/ *
* XXX
*
* this m a c r o a s s u m e s t h a t i r q s t a t ( r6 ) a n d b a s e ( r5 ) a r e
* preserved f r o m g e t _ i r q n r _ a n d _ b a s e a b o v e
* /
2010-09-04 13:47:48 +04:00
ALT_ S M P ( t e s t _ f o r _ i p i r0 , r6 , r5 , l r )
ALT_ U P _ B ( 9 9 9 7 f )
2005-05-21 21:16:44 +04:00
movne r0 , s p
2009-07-24 15:32:54 +04:00
adrne l r , B S Y M ( 1 b )
2005-05-21 21:16:44 +04:00
bne d o _ I P I
2005-11-08 22:08:05 +03:00
# ifdef C O N F I G _ L O C A L _ T I M E R S
test_ f o r _ l t i r q r0 , r6 , r5 , l r
movne r0 , s p
2009-07-24 15:32:54 +04:00
adrne l r , B S Y M ( 1 b )
2005-11-08 22:08:05 +03:00
bne d o _ l o c a l _ t i m e r
# endif
2010-09-04 13:47:48 +04:00
9997 :
2005-05-21 21:16:44 +04:00
# endif
2005-05-21 21:14:44 +04:00
.endm
2007-12-03 23:27:56 +03:00
# ifdef C O N F I G _ K P R O B E S
.section .kprobes .text , " ax" ,% p r o g b i t s
# else
.text
# endif
2005-04-17 02:20:36 +04:00
/ *
* Invalid m o d e h a n d l e r s
* /
2005-06-01 01:22:32 +04:00
.macro inv_ e n t r y , r e a s o n
sub s p , s p , #S _ F R A M E _ S I Z E
2009-07-24 15:32:54 +04:00
ARM( s t m i b s p , { r1 - l r } )
THUMB( s t m i a s p , { r0 - r12 } )
THUMB( s t r s p , [ s p , #S _ S P ] )
THUMB( s t r l r , [ s p , #S _ L R ] )
2005-04-17 02:20:36 +04:00
mov r1 , #\ r e a s o n
.endm
__pabt_invalid :
2005-06-01 01:22:32 +04:00
inv_ e n t r y B A D _ P R E F E T C H
b c o m m o n _ i n v a l i d
2008-08-28 14:22:32 +04:00
ENDPROC( _ _ p a b t _ i n v a l i d )
2005-04-17 02:20:36 +04:00
__dabt_invalid :
2005-06-01 01:22:32 +04:00
inv_ e n t r y B A D _ D A T A
b c o m m o n _ i n v a l i d
2008-08-28 14:22:32 +04:00
ENDPROC( _ _ d a b t _ i n v a l i d )
2005-04-17 02:20:36 +04:00
__irq_invalid :
2005-06-01 01:22:32 +04:00
inv_ e n t r y B A D _ I R Q
b c o m m o n _ i n v a l i d
2008-08-28 14:22:32 +04:00
ENDPROC( _ _ i r q _ i n v a l i d )
2005-04-17 02:20:36 +04:00
__und_invalid :
2005-06-01 01:22:32 +04:00
inv_ e n t r y B A D _ U N D E F I N S T R
@
@ XXX fall through to common_invalid
@
@
@ common_invalid - generic code for failed exception (re-entrant version of handlers)
@
common_invalid :
zero_ f p
ldmia r0 , { r4 - r6 }
add r0 , s p , #S _ P C @ h e r e f o r i n t e r l o c k a v o i d a n c e
mov r7 , #- 1 @ "" "" "" ""
str r4 , [ s p ] @ save preserved r0
stmia r0 , { r5 - r7 } @ lr_<exception>,
@ cpsr_<exception>, "old_r0"
2005-04-17 02:20:36 +04:00
mov r0 , s p
b b a d _ m o d e
2008-08-28 14:22:32 +04:00
ENDPROC( _ _ u n d _ i n v a l i d )
2005-04-17 02:20:36 +04:00
/ *
* SVC m o d e h a n d l e r s
* /
2006-01-14 19:18:08 +03:00
# if d e f i n e d ( C O N F I G _ A E A B I ) & & ( _ _ L I N U X _ A R M _ A R C H _ _ > = 5 )
# define S P F I X ( c o d e . . . ) c o d e
# else
# define S P F I X ( c o d e . . . )
# endif
2007-12-14 23:56:01 +03:00
.macro svc_ e n t r y , s t a c k _ h o l e =0
2009-02-16 13:42:09 +03:00
UNWIND( . f n s t a r t )
UNWIND( . s a v e { r0 - p c } )
2009-07-24 15:32:54 +04:00
sub s p , s p , #( S _ F R A M E _ S I Z E + \ s t a c k _ h o l e - 4 )
# ifdef C O N F I G _ T H U M B 2 _ K E R N E L
SPFIX( s t r r0 , [ s p ] ) @ temporarily saved
SPFIX( m o v r0 , s p )
SPFIX( t s t r0 , #4 ) @ test original stack alignment
SPFIX( l d r r0 , [ s p ] ) @ restored
# else
2006-01-14 19:18:08 +03:00
SPFIX( t s t s p , #4 )
2009-07-24 15:32:54 +04:00
# endif
SPFIX( s u b e q s p , s p , #4 )
stmia s p , { r1 - r12 }
2005-06-01 01:22:32 +04:00
ldmia r0 , { r1 - r3 }
2009-07-24 15:32:54 +04:00
add r5 , s p , #S _ S P - 4 @ here for interlock avoidance
2005-06-01 01:22:32 +04:00
mov r4 , #- 1 @ "" "" "" ""
2009-07-24 15:32:54 +04:00
add r0 , s p , #( S _ F R A M E _ S I Z E + \ s t a c k _ h o l e - 4 )
SPFIX( a d d e q r0 , r0 , #4 )
str r1 , [ s p , #- 4 ] ! @ save the "real" r0 copied
2005-06-01 01:22:32 +04:00
@ from the exception stack
2005-04-17 02:20:36 +04:00
mov r1 , l r
@
@ We are now ready to fill in the remaining blanks on the stack:
@
@ r0 - sp_svc
@ r1 - lr_svc
@ r2 - lr_<exception>, already fixed up for correct return/restart
@ r3 - spsr_<exception>
@ r4 - orig_r0 (see pt_regs definition in ptrace.h)
@
stmia r5 , { r0 - r4 }
.endm
.align 5
__dabt_svc :
2005-06-01 01:22:32 +04:00
svc_ e n t r y
2005-04-17 02:20:36 +04:00
@
@ get ready to re-enable interrupts if appropriate
@
mrs r9 , c p s r
tst r3 , #P S R _ I _ B I T
biceq r9 , r9 , #P S R _ I _ B I T
@
@ Call the processor-specific abort handler:
@
@ r2 - aborted context pc
@ r3 - aborted context cpsr
@
@ The abort handler must return the aborted address in r0, and
@ the fault status register in r1. r9 must be preserved.
@
2008-04-19 01:43:07 +04:00
# ifdef M U L T I _ D A B O R T
2005-04-17 02:20:36 +04:00
ldr r4 , . L C p r o c f n s
mov l r , p c
2008-04-19 01:43:07 +04:00
ldr p c , [ r4 , #P R O C E S S O R _ D A B T _ F U N C ]
2005-04-17 02:20:36 +04:00
# else
2008-04-19 01:43:07 +04:00
bl C P U _ D A B O R T _ H A N D L E R
2005-04-17 02:20:36 +04:00
# endif
@
@ set desired IRQ state, then call main handler
@
msr c p s r _ c , r9
mov r2 , s p
bl d o _ D a t a A b o r t
@
@ IRQs off again before pulling preserved data off the stack
@
2010-07-10 13:10:18 +04:00
disable_ i r q _ n o t r a c e
2005-04-17 02:20:36 +04:00
@
@ restore SPSR and restart the instruction
@
2009-07-24 15:32:54 +04:00
ldr r2 , [ s p , #S _ P S R ]
svc_ e x i t r2 @ return from exception
2009-02-16 13:42:09 +03:00
UNWIND( . f n e n d )
2008-08-28 14:22:32 +04:00
ENDPROC( _ _ d a b t _ s v c )
2005-04-17 02:20:36 +04:00
.align 5
__irq_svc :
2005-06-01 01:22:32 +04:00
svc_ e n t r y
2010-07-10 13:10:18 +04:00
# ifdef C O N F I G _ T R A C E _ I R Q F L A G S
bl t r a c e _ h a r d i r q s _ o f f
# endif
2005-04-17 02:20:36 +04:00
# ifdef C O N F I G _ P R E E M P T
2005-05-21 21:15:45 +04:00
get_ t h r e a d _ i n f o t s k
ldr r8 , [ t s k , #T I _ P R E E M P T ] @ g e t p r e e m p t c o u n t
add r7 , r8 , #1 @ increment it
str r7 , [ t s k , #T I _ P R E E M P T ]
2005-04-17 02:20:36 +04:00
# endif
2005-06-01 01:22:32 +04:00
2005-05-21 21:14:44 +04:00
irq_ h a n d l e r
2005-04-17 02:20:36 +04:00
# ifdef C O N F I G _ P R E E M P T
2008-04-13 20:47:35 +04:00
str r8 , [ t s k , #T I _ P R E E M P T ] @ r e s t o r e p r e e m p t c o u n t
2005-05-21 21:15:45 +04:00
ldr r0 , [ t s k , #T I _ F L A G S ] @ g e t f l a g s
2008-04-13 20:47:35 +04:00
teq r8 , #0 @ if preempt count != 0
movne r0 , #0 @ force flags to 0
2005-04-17 02:20:36 +04:00
tst r0 , #_ T I F _ N E E D _ R E S C H E D
blne s v c _ p r e e m p t
# endif
2009-07-24 15:32:54 +04:00
ldr r4 , [ s p , #S _ P S R ] @ i r q s a r e a l r e a d y d i s a b l e d
2006-08-27 15:07:02 +04:00
# ifdef C O N F I G _ T R A C E _ I R Q F L A G S
2009-07-24 15:32:54 +04:00
tst r4 , #P S R _ I _ B I T
2006-08-27 15:07:02 +04:00
bleq t r a c e _ h a r d i r q s _ o n
# endif
2009-07-24 15:32:54 +04:00
svc_ e x i t r4 @ return from exception
2009-02-16 13:42:09 +03:00
UNWIND( . f n e n d )
2008-08-28 14:22:32 +04:00
ENDPROC( _ _ i r q _ s v c )
2005-04-17 02:20:36 +04:00
.ltorg
# ifdef C O N F I G _ P R E E M P T
svc_preempt :
2008-04-13 20:47:35 +04:00
mov r8 , l r
2005-04-17 02:20:36 +04:00
1 : bl p r e e m p t _ s c h e d u l e _ i r q @ irq en/disable is done inside
2005-05-21 21:15:45 +04:00
ldr r0 , [ t s k , #T I _ F L A G S ] @ g e t n e w t a s k s T I _ F L A G S
2005-04-17 02:20:36 +04:00
tst r0 , #_ T I F _ N E E D _ R E S C H E D
2008-04-13 20:47:35 +04:00
moveq p c , r8 @ go again
2005-04-17 02:20:36 +04:00
b 1 b
# endif
.align 5
__und_svc :
2007-12-14 23:56:01 +03:00
# ifdef C O N F I G _ K P R O B E S
@ If a kprobe is about to simulate a "stmdb sp..." instruction,
@ it obviously needs free stack space which then will belong to
@ the saved context.
svc_ e n t r y 6 4
# else
2005-06-01 01:22:32 +04:00
svc_ e n t r y
2007-12-14 23:56:01 +03:00
# endif
2005-04-17 02:20:36 +04:00
@
@ call emulation code, which returns using r9 if it has emulated
@ the instruction, or the more conventional lr if we are to treat
@ this as a real undefined instruction
@
@ r0 - instruction
@
2009-09-19 02:27:07 +04:00
# ifndef C O N F I G _ T H U M B 2 _ K E R N E L
2005-04-17 02:20:36 +04:00
ldr r0 , [ r2 , #- 4 ]
2009-09-19 02:27:07 +04:00
# else
ldrh r0 , [ r2 , #- 2 ] @ Thumb instruction at LR - 2
and r9 , r0 , #0xf800
cmp r9 , #0xe800 @ 32-bit instruction if xx >= 0
ldrhhs r9 , [ r2 ] @ bottom 16 bits
orrhs r0 , r9 , r0 , l s l #16
# endif
2009-07-24 15:32:54 +04:00
adr r9 , B S Y M ( 1 f )
2005-04-17 02:20:36 +04:00
bl c a l l _ f p e
mov r0 , s p @ struct pt_regs *regs
bl d o _ u n d e f i n s t r
@
@ IRQs off again before pulling preserved data off the stack
@
2010-07-10 13:10:18 +04:00
1 : disable_ i r q _ n o t r a c e
2005-04-17 02:20:36 +04:00
@
@ restore SPSR and restart the instruction
@
2009-07-24 15:32:54 +04:00
ldr r2 , [ s p , #S _ P S R ] @ G e t S V C c p s r
svc_ e x i t r2 @ return from exception
2009-02-16 13:42:09 +03:00
UNWIND( . f n e n d )
2008-08-28 14:22:32 +04:00
ENDPROC( _ _ u n d _ s v c )
2005-04-17 02:20:36 +04:00
.align 5
__pabt_svc :
2005-06-01 01:22:32 +04:00
svc_ e n t r y
2005-04-17 02:20:36 +04:00
@
@ re-enable interrupts if appropriate
@
mrs r9 , c p s r
tst r3 , #P S R _ I _ B I T
biceq r9 , r9 , #P S R _ I _ B I T
2008-04-19 01:43:07 +04:00
mov r0 , r2 @ pass address of aborted instruction.
2009-09-25 16:39:47 +04:00
# ifdef M U L T I _ P A B O R T
2008-04-19 01:43:07 +04:00
ldr r4 , . L C p r o c f n s
mov l r , p c
ldr p c , [ r4 , #P R O C E S S O R _ P A B T _ F U N C ]
# else
2009-09-25 16:39:47 +04:00
bl C P U _ P A B O R T _ H A N D L E R
2008-04-19 01:43:07 +04:00
# endif
msr c p s r _ c , r9 @ Maybe enable interrupts
2009-09-25 16:39:47 +04:00
mov r2 , s p @ regs
2005-04-17 02:20:36 +04:00
bl d o _ P r e f e t c h A b o r t @ call abort handler
@
@ IRQs off again before pulling preserved data off the stack
@
2010-07-10 13:10:18 +04:00
disable_ i r q _ n o t r a c e
2005-04-17 02:20:36 +04:00
@
@ restore SPSR and restart the instruction
@
2009-07-24 15:32:54 +04:00
ldr r2 , [ s p , #S _ P S R ]
svc_ e x i t r2 @ return from exception
2009-02-16 13:42:09 +03:00
UNWIND( . f n e n d )
2008-08-28 14:22:32 +04:00
ENDPROC( _ _ p a b t _ s v c )
2005-04-17 02:20:36 +04:00
.align 5
2005-05-31 21:02:00 +04:00
.LCcralign :
.word cr_alignment
2008-04-19 01:43:07 +04:00
# ifdef M U L T I _ D A B O R T
2005-04-17 02:20:36 +04:00
.LCprocfns :
.word processor
# endif
.LCfp :
.word fp_enter
/ *
* User m o d e h a n d l e r s
2006-01-14 19:18:08 +03:00
*
* EABI n o t e : s p _ s v c i s a l w a y s 6 4 - b i t a l i g n e d h e r e , s o s h o u l d S _ F R A M E _ S I Z E
2005-04-17 02:20:36 +04:00
* /
2006-01-14 19:18:08 +03:00
# if d e f i n e d ( C O N F I G _ A E A B I ) & & ( _ _ L I N U X _ A R M _ A R C H _ _ > = 5 ) & & ( S _ F R A M E _ S I Z E & 7 )
# error " s i z e o f ( s t r u c t p t _ r e g s ) m u s t b e a m u l t i p l e o f 8 "
# endif
2005-06-01 01:22:32 +04:00
.macro usr_entry
2009-02-16 13:42:09 +03:00
UNWIND( . f n s t a r t )
UNWIND( . c a n t u n w i n d ) @ don't unwind the user space
2005-06-01 01:22:32 +04:00
sub s p , s p , #S _ F R A M E _ S I Z E
2009-07-24 15:32:54 +04:00
ARM( s t m i b s p , { r1 - r12 } )
THUMB( s t m i a s p , { r0 - r12 } )
2005-06-01 01:22:32 +04:00
ldmia r0 , { r1 - r3 }
add r0 , s p , #S _ P C @ h e r e f o r i n t e r l o c k a v o i d a n c e
mov r4 , #- 1 @ "" "" "" ""
str r1 , [ s p ] @ save the "real" r0 copied
@ from the exception stack
2005-04-17 02:20:36 +04:00
@
@ We are now ready to fill in the remaining blanks on the stack:
@
@ r2 - lr_<exception>, already fixed up for correct return/restart
@ r3 - spsr_<exception>
@ r4 - orig_r0 (see pt_regs definition in ptrace.h)
@
@ Also, separately save sp_usr and lr_usr
@
2005-06-01 01:22:32 +04:00
stmia r0 , { r2 - r4 }
2009-07-24 15:32:54 +04:00
ARM( s t m d b r0 , { s p , l r } ^ )
THUMB( s t o r e _ u s e r _ s p _ l r r0 , r1 , S _ S P - S _ P C )
2005-04-17 02:20:36 +04:00
@
@ Enable the alignment trap while in kernel mode
@
2005-05-31 21:02:00 +04:00
alignment_ t r a p r0
2005-04-17 02:20:36 +04:00
@
@ Clear FP to mark the first stack frame
@
zero_ f p
.endm
[ARM] 4659/1: remove possibilities for spurious false negative with __kuser_cmpxchg
The ARM __kuser_cmpxchg routine is meant to implement an atomic cmpxchg
in user space. It however can produce spurious false negative if a
processor exception occurs in the middle of the operation. Normally
this is not a problem since cmpxchg is typically called in a loop until
it succeeds to implement an atomic increment for example.
Some use cases which don't involve a loop require that the operation be
100% reliable though. This patch changes the implementation so to
reattempt the operation after an exception has occurred in the critical
section rather than abort it.
Here's a simple program to test the fix (don't use CONFIG_NO_HZ in your
kernel as this depends on a sufficiently high interrupt rate):
#include <stdio.h>
typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
int main()
{
int i, x = 0;
for (i = 0; i < 100000000; i++) {
int v = x;
if (__kernel_cmpxchg(v, v+1, &x))
printf("failed at %d: %d vs %d\n", i, v, x);
}
printf("done with %d vs %d\n", i, x);
return 0;
}
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2007-11-20 19:20:29 +03:00
.macro kuser_cmpxchg_check
# if _ _ L I N U X _ A R M _ A R C H _ _ < 6 & & ! d e f i n e d ( C O N F I G _ N E E D S _ S Y S C A L L _ F O R _ C M P X C H G )
# ifndef C O N F I G _ M M U
# warning " N P T L o n n o n M M U n e e d s f i x i n g "
# else
@ Make sure our user space atomic helper is restarted
@ if it was interrupted in a critical region. Here we
@ perform a quick test inline since it should be false
@ 99.9999% of the time. The rest is done out of line.
cmp r2 , #T A S K _ S I Z E
blhs k u s e r _ c m p x c h g _ f i x u p
# endif
# endif
.endm
2005-04-17 02:20:36 +04:00
.align 5
__dabt_usr :
2005-06-01 01:22:32 +04:00
usr_ e n t r y
[ARM] 4659/1: remove possibilities for spurious false negative with __kuser_cmpxchg
The ARM __kuser_cmpxchg routine is meant to implement an atomic cmpxchg
in user space. It however can produce spurious false negative if a
processor exception occurs in the middle of the operation. Normally
this is not a problem since cmpxchg is typically called in a loop until
it succeeds to implement an atomic increment for example.
Some use cases which don't involve a loop require that the operation be
100% reliable though. This patch changes the implementation so to
reattempt the operation after an exception has occurred in the critical
section rather than abort it.
Here's a simple program to test the fix (don't use CONFIG_NO_HZ in your
kernel as this depends on a sufficiently high interrupt rate):
#include <stdio.h>
typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
int main()
{
int i, x = 0;
for (i = 0; i < 100000000; i++) {
int v = x;
if (__kernel_cmpxchg(v, v+1, &x))
printf("failed at %d: %d vs %d\n", i, v, x);
}
printf("done with %d vs %d\n", i, x);
return 0;
}
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2007-11-20 19:20:29 +03:00
kuser_ c m p x c h g _ c h e c k
2005-04-17 02:20:36 +04:00
@
@ Call the processor-specific abort handler:
@
@ r2 - aborted context pc
@ r3 - aborted context cpsr
@
@ The abort handler must return the aborted address in r0, and
@ the fault status register in r1.
@
2008-04-19 01:43:07 +04:00
# ifdef M U L T I _ D A B O R T
2005-04-17 02:20:36 +04:00
ldr r4 , . L C p r o c f n s
mov l r , p c
2008-04-19 01:43:07 +04:00
ldr p c , [ r4 , #P R O C E S S O R _ D A B T _ F U N C ]
2005-04-17 02:20:36 +04:00
# else
2008-04-19 01:43:07 +04:00
bl C P U _ D A B O R T _ H A N D L E R
2005-04-17 02:20:36 +04:00
# endif
@
@ IRQs on, then call the main handler
@
2005-04-26 18:18:26 +04:00
enable_ i r q
2005-04-17 02:20:36 +04:00
mov r2 , s p
2009-07-24 15:32:54 +04:00
adr l r , B S Y M ( r e t _ f r o m _ e x c e p t i o n )
2005-04-17 02:20:36 +04:00
b d o _ D a t a A b o r t
2009-02-16 13:42:09 +03:00
UNWIND( . f n e n d )
2008-08-28 14:22:32 +04:00
ENDPROC( _ _ d a b t _ u s r )
2005-04-17 02:20:36 +04:00
.align 5
__irq_usr :
2005-06-01 01:22:32 +04:00
usr_ e n t r y
[ARM] 4659/1: remove possibilities for spurious false negative with __kuser_cmpxchg
The ARM __kuser_cmpxchg routine is meant to implement an atomic cmpxchg
in user space. It however can produce spurious false negative if a
processor exception occurs in the middle of the operation. Normally
this is not a problem since cmpxchg is typically called in a loop until
it succeeds to implement an atomic increment for example.
Some use cases which don't involve a loop require that the operation be
100% reliable though. This patch changes the implementation so to
reattempt the operation after an exception has occurred in the critical
section rather than abort it.
Here's a simple program to test the fix (don't use CONFIG_NO_HZ in your
kernel as this depends on a sufficiently high interrupt rate):
#include <stdio.h>
typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
int main()
{
int i, x = 0;
for (i = 0; i < 100000000; i++) {
int v = x;
if (__kernel_cmpxchg(v, v+1, &x))
printf("failed at %d: %d vs %d\n", i, v, x);
}
printf("done with %d vs %d\n", i, x);
return 0;
}
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2007-11-20 19:20:29 +03:00
kuser_ c m p x c h g _ c h e c k
2005-04-17 02:20:36 +04:00
2005-05-21 21:15:45 +04:00
get_ t h r e a d _ i n f o t s k
2005-04-17 02:20:36 +04:00
# ifdef C O N F I G _ P R E E M P T
2005-05-21 21:15:45 +04:00
ldr r8 , [ t s k , #T I _ P R E E M P T ] @ g e t p r e e m p t c o u n t
add r7 , r8 , #1 @ increment it
str r7 , [ t s k , #T I _ P R E E M P T ]
2005-04-17 02:20:36 +04:00
# endif
2005-06-01 01:22:32 +04:00
2005-05-21 21:14:44 +04:00
irq_ h a n d l e r
2005-04-17 02:20:36 +04:00
# ifdef C O N F I G _ P R E E M P T
2005-05-21 21:15:45 +04:00
ldr r0 , [ t s k , #T I _ P R E E M P T ]
str r8 , [ t s k , #T I _ P R E E M P T ]
2005-04-17 02:20:36 +04:00
teq r0 , r7
2009-07-24 15:32:54 +04:00
ARM( s t r n e r0 , [ r0 , - r0 ] )
THUMB( m o v n e r0 , #0 )
THUMB( s t r n e r0 , [ r0 ] )
2005-04-17 02:20:36 +04:00
# endif
2005-06-01 01:22:32 +04:00
2005-04-17 02:20:36 +04:00
mov w h y , #0
b r e t _ t o _ u s e r
2009-02-16 13:42:09 +03:00
UNWIND( . f n e n d )
2008-08-28 14:22:32 +04:00
ENDPROC( _ _ i r q _ u s r )
2005-04-17 02:20:36 +04:00
.ltorg
.align 5
__und_usr :
2005-06-01 01:22:32 +04:00
usr_ e n t r y
2005-04-17 02:20:36 +04:00
@
@ fall through to the emulation code, which returns using r9 if
@ it has emulated the instruction, or the more conventional lr
@ if we are to treat this as a real undefined instruction
@
@ r0 - instruction
@
2009-07-24 15:32:54 +04:00
adr r9 , B S Y M ( r e t _ f r o m _ e x c e p t i o n )
adr l r , B S Y M ( _ _ u n d _ u s r _ u n k n o w n )
2008-04-19 01:43:08 +04:00
tst r3 , #P S R _ T _ B I T @ T h u m b m o d e ?
2009-07-24 15:32:54 +04:00
itet e q @ explicit IT needed for the 1f label
2008-04-19 01:43:08 +04:00
subeq r4 , r2 , #4 @ ARM instr at LR - 4
subne r4 , r2 , #2 @ Thumb instr at LR - 2
1 : ldreqt r0 , [ r4 ]
2009-05-30 17:00:18 +04:00
# ifdef C O N F I G _ C P U _ E N D I A N _ B E 8
reveq r0 , r0 @ little endian instruction
# endif
2008-04-19 01:43:08 +04:00
beq c a l l _ f p e
@ Thumb instruction
# if _ _ L I N U X _ A R M _ A R C H _ _ > = 7
2009-07-24 15:32:54 +04:00
2 :
ARM( l d r h t r5 , [ r4 ] , #2 )
THUMB( l d r h t r5 , [ r4 ] )
THUMB( a d d r4 , r4 , #2 )
2008-04-19 01:43:08 +04:00
and r0 , r5 , #0xf800 @ mask bits 111x x... .... ....
cmp r0 , #0xe800 @ 32bit instruction if xx != 0
blo _ _ u n d _ u s r _ u n k n o w n
3 : ldrht r0 , [ r4 ]
add r2 , r2 , #2 @ r2 is PC + 2, make it PC + 4
orr r0 , r0 , r5 , l s l #16
# else
b _ _ u n d _ u s r _ u n k n o w n
# endif
2009-02-16 13:42:09 +03:00
UNWIND( . f n e n d )
2008-08-28 14:22:32 +04:00
ENDPROC( _ _ u n d _ u s r )
2008-04-19 01:43:08 +04:00
2005-04-17 02:20:36 +04:00
@
@ fallthrough to call_fpe
@
/ *
* The o u t o f l i n e f i x u p f o r t h e l d r t a b o v e .
* /
2010-04-19 13:15:03 +04:00
.pushsection .fixup , " ax"
2008-04-19 01:43:08 +04:00
4 : mov p c , r9
2010-04-19 13:15:03 +04:00
.popsection
.pushsection _ _ ex_ t a b l e ," a "
2008-04-19 01:43:08 +04:00
.long 1 b, 4 b
# if _ _ L I N U X _ A R M _ A R C H _ _ > = 7
.long 2 b, 4 b
.long 3 b, 4 b
# endif
2010-04-19 13:15:03 +04:00
.popsection
2005-04-17 02:20:36 +04:00
/ *
* Check w h e t h e r t h e i n s t r u c t i o n i s a c o - p r o c e s s o r i n s t r u c t i o n .
* If y e s , w e n e e d t o c a l l t h e r e l e v a n t c o - p r o c e s s o r h a n d l e r .
*
* Note t h a t w e d o n ' t d o a f u l l c h e c k h e r e f o r t h e c o - p r o c e s s o r
* instructions; all instructions with bit 27 set are well
* defined. T h e o n l y i n s t r u c t i o n s t h a t s h o u l d f a u l t a r e t h e
* co- p r o c e s s o r i n s t r u c t i o n s . H o w e v e r , w e h a v e t o w a t c h o u t
* for t h e A R M 6 / A R M 7 S W I b u g .
*
2008-01-10 21:16:17 +03:00
* NEON i s a s p e c i a l c a s e t h a t h a s t o b e h a n d l e d h e r e . N o t a l l
* NEON i n s t r u c t i o n s a r e c o - p r o c e s s o r i n s t r u c t i o n s , s o w e h a v e
* to m a k e a s p e c i a l c a s e o f c h e c k i n g f o r t h e m . P l u s , t h e r e ' s
* five g r o u p s o f t h e m , s o w e h a v e a t a b l e o f m a s k / o p c o d e p a i r s
* to c h e c k a g a i n s t , a n d i f a n y m a t c h t h e n w e b r a n c h o f f i n t o t h e
* NEON h a n d l e r c o d e .
*
2005-04-17 02:20:36 +04:00
* Emulators m a y w i s h t o m a k e u s e o f t h e f o l l o w i n g r e g i s t e r s :
* r0 = i n s t r u c t i o n o p c o d e .
* r2 = P C + 4
2007-01-07 01:53:48 +03:00
* r9 = n o r m a l " s u c c e s s f u l " r e t u r n a d d r e s s
2005-04-17 02:20:36 +04:00
* r1 0 = t h i s t h r e a d s t h r e a d _ i n f o s t r u c t u r e .
2007-01-07 01:53:48 +03:00
* lr = u n r e c o g n i s e d i n s t r u c t i o n r e t u r n a d d r e s s
2005-04-17 02:20:36 +04:00
* /
2008-04-19 01:43:08 +04:00
@
@ Fall-through from Thumb-2 __und_usr
@
# ifdef C O N F I G _ N E O N
adr r6 , . L C n e o n _ t h u m b _ o p c o d e s
b 2 f
# endif
2005-04-17 02:20:36 +04:00
call_fpe :
2008-01-10 21:16:17 +03:00
# ifdef C O N F I G _ N E O N
2008-04-19 01:43:08 +04:00
adr r6 , . L C n e o n _ a r m _ o p c o d e s
2008-01-10 21:16:17 +03:00
2 :
ldr r7 , [ r6 ] , #4 @ mask value
cmp r7 , #0 @ end mask?
beq 1 f
and r8 , r0 , r7
ldr r7 , [ r6 ] , #4 @ opcode bits matching in mask
cmp r8 , r7 @ NEON instruction?
bne 2 b
get_ t h r e a d _ i n f o r10
mov r7 , #1
strb r7 , [ r10 , #T I _ U S E D _ C P + 10 ] @ mark CP#10 as used
strb r7 , [ r10 , #T I _ U S E D _ C P + 11 ] @ mark CP#11 as used
b d o _ v f p @ let VFP handler handle this
1 :
# endif
2005-04-17 02:20:36 +04:00
tst r0 , #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27
2008-04-19 01:43:08 +04:00
tstne r0 , #0x04000000 @ bit 26 set on both ARM and Thumb-2
2005-04-17 02:20:36 +04:00
# if d e f i n e d ( C O N F I G _ C P U _ A R M 6 1 0 ) | | d e f i n e d ( C O N F I G _ C P U _ A R M 7 1 0 )
and r8 , r0 , #0x0f000000 @ mask out op-code bits
teqne r8 , #0x0f000000 @ SWI (ARM6/7 bug)?
# endif
moveq p c , l r
get_ t h r e a d _ i n f o r10 @ get current thread
and r8 , r0 , #0x00000f00 @ mask out CP number
2009-07-24 15:32:54 +04:00
THUMB( l s r r8 , r8 , #8 )
2005-04-17 02:20:36 +04:00
mov r7 , #1
add r6 , r10 , #T I _ U S E D _ C P
2009-07-24 15:32:54 +04:00
ARM( s t r b r7 , [ r6 , r8 , l s r #8 ] ) @ set appropriate used_cp[]
THUMB( s t r b r7 , [ r6 , r8 ] ) @ set appropriate used_cp[]
2005-04-17 02:20:36 +04:00
# ifdef C O N F I G _ I W M M X T
@ Test if we need to give access to iWMMXt coprocessors
ldr r5 , [ r10 , #T I _ F L A G S ]
rsbs r7 , r8 , #( 1 < < 8 ) @ CP 0 or 1 only
movcss r7 , r5 , l s r #( T I F _ U S I N G _ I W M M X T + 1 )
bcs i w m m x t _ t a s k _ e n a b l e
# endif
2009-07-24 15:32:54 +04:00
ARM( a d d p c , p c , r8 , l s r #6 )
THUMB( l s l r8 , r8 , #2 )
THUMB( a d d p c , r8 )
nop
2009-10-12 20:31:20 +04:00
movw_ p c l r @ CP#0
2009-07-24 15:32:54 +04:00
W( b ) d o _ f p e @ CP#1 (FPE)
W( b ) d o _ f p e @ CP#2 (FPE)
2009-10-12 20:31:20 +04:00
movw_ p c l r @ CP#3
2006-06-28 02:03:03 +04:00
# ifdef C O N F I G _ C R U N C H
b c r u n c h _ t a s k _ e n a b l e @ CP#4 (MaverickCrunch)
b c r u n c h _ t a s k _ e n a b l e @ CP#5 (MaverickCrunch)
b c r u n c h _ t a s k _ e n a b l e @ CP#6 (MaverickCrunch)
# else
2009-10-12 20:31:20 +04:00
movw_ p c l r @ CP#4
movw_ p c l r @ CP#5
movw_ p c l r @ CP#6
2006-06-28 02:03:03 +04:00
# endif
2009-10-12 20:31:20 +04:00
movw_ p c l r @ CP#7
movw_ p c l r @ CP#8
movw_ p c l r @ CP#9
2005-04-17 02:20:36 +04:00
# ifdef C O N F I G _ V F P
2009-07-24 15:32:54 +04:00
W( b ) d o _ v f p @ CP#10 (VFP)
W( b ) d o _ v f p @ CP#11 (VFP)
2005-04-17 02:20:36 +04:00
# else
2009-10-12 20:31:20 +04:00
movw_ p c l r @ CP#10 (VFP)
movw_ p c l r @ CP#11 (VFP)
2005-04-17 02:20:36 +04:00
# endif
2009-10-12 20:31:20 +04:00
movw_ p c l r @ CP#12
movw_ p c l r @ CP#13
movw_ p c l r @ CP#14 (Debug)
movw_ p c l r @ CP#15 (Control)
2005-04-17 02:20:36 +04:00
2008-01-10 21:16:17 +03:00
# ifdef C O N F I G _ N E O N
.align 6
2008-04-19 01:43:08 +04:00
.LCneon_arm_opcodes :
2008-01-10 21:16:17 +03:00
.word 0xfe000000 @ mask
.word 0xf2000000 @ opcode
.word 0xff100000 @ mask
.word 0xf4000000 @ opcode
2008-04-19 01:43:08 +04:00
.word 0x00000000 @ mask
.word 0x00000000 @ opcode
.LCneon_thumb_opcodes :
.word 0xef000000 @ mask
.word 0xef000000 @ opcode
.word 0xff100000 @ mask
.word 0xf9000000 @ opcode
2008-01-10 21:16:17 +03:00
.word 0x00000000 @ mask
.word 0x00000000 @ opcode
# endif
2005-04-17 02:20:36 +04:00
do_fpe :
2006-03-15 15:33:43 +03:00
enable_ i r q
2005-04-17 02:20:36 +04:00
ldr r4 , . L C f p
add r10 , r10 , #T I _ F P S T A T E @ r 10 = w o r k s p a c e
ldr p c , [ r4 ] @ Call FP module USR entry point
/ *
* The F P m o d u l e i s c a l l e d w i t h t h e s e r e g i s t e r s s e t :
* r0 = i n s t r u c t i o n
* r2 = P C + 4
* r9 = n o r m a l " s u c c e s s f u l " r e t u r n a d d r e s s
* r1 0 = F P w o r k s p a c e
* lr = u n r e c o g n i s e d F P i n s t r u c t i o n r e t u r n a d d r e s s
* /
2010-04-30 13:45:46 +04:00
.pushsection .data
2005-04-17 02:20:36 +04:00
ENTRY( f p _ e n t e r )
2007-01-07 01:53:48 +03:00
.word no_fp
2010-04-30 13:45:46 +04:00
.popsection
2005-04-17 02:20:36 +04:00
2009-09-19 02:27:07 +04:00
ENTRY( n o _ f p )
mov p c , l r
ENDPROC( n o _ f p )
2007-01-07 01:53:48 +03:00
__und_usr_unknown :
2009-01-28 02:20:00 +03:00
enable_ i r q
2005-04-17 02:20:36 +04:00
mov r0 , s p
2009-07-24 15:32:54 +04:00
adr l r , B S Y M ( r e t _ f r o m _ e x c e p t i o n )
2005-04-17 02:20:36 +04:00
b d o _ u n d e f i n s t r
2008-08-28 14:22:32 +04:00
ENDPROC( _ _ u n d _ u s r _ u n k n o w n )
2005-04-17 02:20:36 +04:00
.align 5
__pabt_usr :
2005-06-01 01:22:32 +04:00
usr_ e n t r y
2005-04-17 02:20:36 +04:00
2008-04-19 01:43:07 +04:00
mov r0 , r2 @ pass address of aborted instruction.
2009-09-25 16:39:47 +04:00
# ifdef M U L T I _ P A B O R T
2008-04-19 01:43:07 +04:00
ldr r4 , . L C p r o c f n s
mov l r , p c
ldr p c , [ r4 , #P R O C E S S O R _ P A B T _ F U N C ]
# else
2009-09-25 16:39:47 +04:00
bl C P U _ P A B O R T _ H A N D L E R
2008-04-19 01:43:07 +04:00
# endif
2005-04-26 18:18:26 +04:00
enable_ i r q @ Enable interrupts
2009-09-25 16:39:47 +04:00
mov r2 , s p @ regs
2005-04-17 02:20:36 +04:00
bl d o _ P r e f e t c h A b o r t @ call abort handler
2009-02-16 13:42:09 +03:00
UNWIND( . f n e n d )
2005-04-17 02:20:36 +04:00
/* fall through */
/ *
* This i s t h e r e t u r n c o d e t o u s e r m o d e f o r a b o r t h a n d l e r s
* /
ENTRY( r e t _ f r o m _ e x c e p t i o n )
2009-02-16 13:42:09 +03:00
UNWIND( . f n s t a r t )
UNWIND( . c a n t u n w i n d )
2005-04-17 02:20:36 +04:00
get_ t h r e a d _ i n f o t s k
mov w h y , #0
b r e t _ t o _ u s e r
2009-02-16 13:42:09 +03:00
UNWIND( . f n e n d )
2008-08-28 14:22:32 +04:00
ENDPROC( _ _ p a b t _ u s r )
ENDPROC( r e t _ f r o m _ e x c e p t i o n )
2005-04-17 02:20:36 +04:00
/ *
* Register s w i t c h f o r A R M v3 a n d A R M v4 p r o c e s s o r s
* r0 = p r e v i o u s t a s k _ s t r u c t , r1 = p r e v i o u s t h r e a d _ i n f o , r2 = n e x t t h r e a d _ i n f o
* previous a n d n e x t a r e g u a r a n t e e d n o t t o b e t h e s a m e .
* /
ENTRY( _ _ s w i t c h _ t o )
2009-02-16 13:42:09 +03:00
UNWIND( . f n s t a r t )
UNWIND( . c a n t u n w i n d )
2005-04-17 02:20:36 +04:00
add i p , r1 , #T I _ C P U _ S A V E
ldr r3 , [ r2 , #T I _ T P _ V A L U E ]
2009-07-24 15:32:54 +04:00
ARM( s t m i a i p ! , { r4 - s l , f p , s p , l r } ) @ Store most regs on stack
THUMB( s t m i a i p ! , { r4 - s l , f p } ) @ Store most regs on stack
THUMB( s t r s p , [ i p ] , #4 )
THUMB( s t r l r , [ i p ] , #4 )
2006-06-21 16:31:52 +04:00
# ifdef C O N F I G _ M M U
ldr r6 , [ r2 , #T I _ C P U _ D O M A I N ]
2006-01-14 00:05:25 +03:00
# endif
2010-07-05 17:53:10 +04:00
set_ t l s r3 , r4 , r5
2010-06-08 05:50:33 +04:00
# if d e f i n e d ( C O N F I G _ C C _ S T A C K P R O T E C T O R ) & & ! d e f i n e d ( C O N F I G _ S M P )
ldr r7 , [ r2 , #T I _ T A S K ]
ldr r8 , =__stack_chk_guard
ldr r7 , [ r7 , #T S K _ S T A C K _ C A N A R Y ]
# endif
2006-01-14 00:05:25 +03:00
# ifdef C O N F I G _ M M U
2005-04-17 02:20:36 +04:00
mcr p15 , 0 , r6 , c3 , c0 , 0 @ Set domain register
# endif
2006-06-21 16:31:52 +04:00
mov r5 , r0
add r4 , r2 , #T I _ C P U _ S A V E
ldr r0 , =thread_notify_head
mov r1 , #T H R E A D _ N O T I F Y _ S W I T C H
bl a t o m i c _ n o t i f i e r _ c a l l _ c h a i n
2010-06-08 05:50:33 +04:00
# if d e f i n e d ( C O N F I G _ C C _ S T A C K P R O T E C T O R ) & & ! d e f i n e d ( C O N F I G _ S M P )
str r7 , [ r8 ]
# endif
2009-07-24 15:32:54 +04:00
THUMB( m o v i p , r4 )
2006-06-21 16:31:52 +04:00
mov r0 , r5
2009-07-24 15:32:54 +04:00
ARM( l d m i a r4 , { r4 - s l , f p , s p , p c } ) @ Load all regs saved previously
THUMB( l d m i a i p ! , { r4 - s l , f p } ) @ Load all regs saved previously
THUMB( l d r s p , [ i p ] , #4 )
THUMB( l d r p c , [ i p ] )
2009-02-16 13:42:09 +03:00
UNWIND( . f n e n d )
2008-08-28 14:22:32 +04:00
ENDPROC( _ _ s w i t c h _ t o )
2005-04-17 02:20:36 +04:00
_ _ INIT
2005-04-30 01:08:33 +04:00
/ *
* User h e l p e r s .
*
* These a r e s e g m e n t o f k e r n e l p r o v i d e d u s e r c o d e r e a c h a b l e f r o m u s e r s p a c e
* at a f i x e d a d d r e s s i n k e r n e l m e m o r y . T h i s i s u s e d t o p r o v i d e u s e r s p a c e
* with s o m e o p e r a t i o n s w h i c h r e q u i r e k e r n e l h e l p b e c a u s e o f u n i m p l e m e n t e d
* native f e a t u r e a n d / o r i n s t r u c t i o n s i n m a n y A R M C P U s . T h e i d e a i s f o r
* this c o d e t o b e e x e c u t e d d i r e c t l y i n u s e r m o d e f o r b e s t e f f i c i e n c y b u t
* which i s t o o i n t i m a t e w i t h t h e k e r n e l c o u n t e r p a r t t o b e l e f t t o u s e r
* libraries. I n f a c t t h i s c o d e m i g h t e v e n d i f f e r f r o m o n e C P U t o a n o t h e r
* depending o n t h e a v a i l a b l e i n s t r u c t i o n s e t a n d r e s t r i c t i o n s l i k e o n
* SMP s y s t e m s . I n o t h e r w o r d s , t h e k e r n e l r e s e r v e s t h e r i g h t t o c h a n g e
* this c o d e a s n e e d e d w i t h o u t w a r n i n g . O n l y t h e e n t r y p o i n t s a n d t h e i r
* results a r e g u a r a n t e e d t o b e s t a b l e .
*
* Each s e g m e n t i s 3 2 - b y t e a l i g n e d a n d w i l l b e m o v e d t o t h e t o p o f t h e h i g h
* vector p a g e . N e w s e g m e n t s ( i f e v e r n e e d e d ) m u s t b e a d d e d i n f r o n t o f
* existing o n e s . T h i s m e c h a n i s m s h o u l d b e u s e d o n l y f o r t h i n g s t h a t a r e
* really s m a l l a n d j u s t i f i e d , a n d n o t b e a b u s e d f r e e l y .
*
* User s p a c e i s e x p e c t e d t o i m p l e m e n t t h o s e t h i n g s i n l i n e w h e n o p t i m i z i n g
* for a p r o c e s s o r t h a t h a s t h e n e c e s s a r y n a t i v e s u p p o r t , b u t o n l y i f s u c h
* resulting b i n a r i e s a r e a l r e a d y t o b e i n c o m p a t i b l e w i t h e a r l i e r A R M
* processors d u e t o t h e u s e o f u n s u p p o r t e d i n s t r u c t i o n s o t h e r t h a n w h a t
* is p r o v i d e d h e r e . I n o t h e r w o r d s d o n ' t m a k e b i n a r i e s u n a b l e t o r u n o n
* earlier p r o c e s s o r s j u s t f o r t h e s a k e o f n o t u s i n g t h e s e k e r n e l h e l p e r s
* if y o u r c o m p i l e d c o d e i s n o t g o i n g t o u s e t h e n e w i n s t r u c t i o n s f o r o t h e r
* purpose.
* /
2009-07-24 15:32:54 +04:00
THUMB( . a r m )
2005-04-30 01:08:33 +04:00
2006-08-18 20:20:15 +04:00
.macro usr_ r e t , r e g
# ifdef C O N F I G _ A R M _ T H U M B
bx \ r e g
# else
mov p c , \ r e g
# endif
.endm
2005-04-30 01:08:33 +04:00
.align 5
.globl __kuser_helper_start
__kuser_helper_start :
2005-12-20 01:20:51 +03:00
/ *
* Reference p r o t o t y p e :
*
* void _ _ k e r n e l _ m e m o r y _ b a r r i e r ( v o i d )
*
* Input :
*
* lr = r e t u r n a d d r e s s
*
* Output :
*
* none
*
* Clobbered :
*
[ARM] 4659/1: remove possibilities for spurious false negative with __kuser_cmpxchg
The ARM __kuser_cmpxchg routine is meant to implement an atomic cmpxchg
in user space. It however can produce spurious false negative if a
processor exception occurs in the middle of the operation. Normally
this is not a problem since cmpxchg is typically called in a loop until
it succeeds to implement an atomic increment for example.
Some use cases which don't involve a loop require that the operation be
100% reliable though. This patch changes the implementation so to
reattempt the operation after an exception has occurred in the critical
section rather than abort it.
Here's a simple program to test the fix (don't use CONFIG_NO_HZ in your
kernel as this depends on a sufficiently high interrupt rate):
#include <stdio.h>
typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
int main()
{
int i, x = 0;
for (i = 0; i < 100000000; i++) {
int v = x;
if (__kernel_cmpxchg(v, v+1, &x))
printf("failed at %d: %d vs %d\n", i, v, x);
}
printf("done with %d vs %d\n", i, x);
return 0;
}
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2007-11-20 19:20:29 +03:00
* none
2005-12-20 01:20:51 +03:00
*
* Definition a n d u s e r s p a c e u s a g e e x a m p l e :
*
* typedef v o i d ( _ _ k e r n e l _ d m b _ t ) ( v o i d ) ;
* # define _ _ k e r n e l _ d m b ( * ( _ _ k e r n e l _ d m b _ t * ) 0 x f f f f0 f a0 )
*
* Apply a n y n e e d e d m e m o r y b a r r i e r t o p r e s e r v e c o n s i s t e n c y w i t h d a t a m o d i f i e d
* manually a n d _ _ k u s e r _ c m p x c h g u s a g e .
*
* This c o u l d b e u s e d a s f o l l o w s :
*
* # define _ _ k e r n e l _ d m b ( ) \
* asm v o l a t i l e ( " m o v r0 , #0xffff0fff ; mov lr, pc; sub pc, r0, #95" \
2006-03-29 01:19:29 +04:00
* : : : " r0 " , " l r " ," c c " )
2005-12-20 01:20:51 +03:00
* /
__kuser_memory_barrier : @ 0xffff0fa0
2009-05-25 23:58:00 +04:00
smp_ d m b
2006-08-18 20:20:15 +04:00
usr_ r e t l r
2005-12-20 01:20:51 +03:00
.align 5
2005-04-30 01:08:33 +04:00
/ *
* Reference p r o t o t y p e :
*
* int _ _ k e r n e l _ c m p x c h g ( i n t o l d v a l , i n t n e w v a l , i n t * p t r )
*
* Input :
*
* r0 = o l d v a l
* r1 = n e w v a l
* r2 = p t r
* lr = r e t u r n a d d r e s s
*
* Output :
*
* r0 = r e t u r n e d v a l u e ( z e r o o r n o n - z e r o )
* C f l a g = s e t i f r0 = = 0 , c l e a r i f r0 ! = 0
*
* Clobbered :
*
* r3 , i p , f l a g s
*
* Definition a n d u s e r s p a c e u s a g e e x a m p l e :
*
* typedef i n t ( _ _ k e r n e l _ c m p x c h g _ t ) ( i n t o l d v a l , i n t n e w v a l , i n t * p t r ) ;
* # define _ _ k e r n e l _ c m p x c h g ( * ( _ _ k e r n e l _ c m p x c h g _ t * ) 0 x f f f f0 f c0 )
*
* Atomically s t o r e n e w v a l i n * p t r i f * p t r i s e q u a l t o o l d v a l f o r u s e r s p a c e .
* Return z e r o i f * p t r w a s c h a n g e d o r n o n - z e r o i f n o e x c h a n g e h a p p e n e d .
* The C f l a g i s a l s o s e t i f * p t r w a s c h a n g e d t o a l l o w f o r a s s e m b l y
* optimization i n t h e c a l l i n g c o d e .
*
2006-02-09 00:19:37 +03:00
* Notes :
*
* - This r o u t i n e a l r e a d y i n c l u d e s m e m o r y b a r r i e r s a s n e e d e d .
*
2005-04-30 01:08:33 +04:00
* For e x a m p l e , a u s e r s p a c e a t o m i c _ a d d i m p l e m e n t a t i o n c o u l d l o o k l i k e t h i s :
*
* # define a t o m i c _ a d d ( p t r , v a l ) \
* ( { register u n s i g n e d i n t * _ _ p t r a s m ( " r2 " ) = ( p t r ) ; \
* register u n s i g n e d i n t _ _ r e s u l t a s m ( " r1 " ) ; \
* asm v o l a t i l e ( \
* " 1 : @ atomic_add\n\t" \
* " ldr r0 , [ r2 ] \ n \ t " \
* " mov r3 , #0xffff0fff \ n \ t " \
* " add l r , p c , #4 \ n \ t " \
* " add r1 , r0 , % 2 \ n \ t " \
* " add p c , r3 , #( 0xffff0fc0 - 0 x f f f f0 f f f ) \ n \ t " \
* " bcc 1 b " \
* : " = & r" ( _ _ r e s u l t ) \
* : " r" ( _ _ p t r ) , " r I L " ( v a l ) \
* : " r0 " ," r3 " ," i p " ," l r " ," c c " ," m e m o r y " ) ; \
* _ _ result; })
* /
__kuser_cmpxchg : @ 0xffff0fc0
2005-06-08 22:00:47 +04:00
# if d e f i n e d ( C O N F I G _ N E E D S _ S Y S C A L L _ F O R _ C M P X C H G )
2005-04-30 01:08:33 +04:00
2005-06-08 22:00:47 +04:00
/ *
* Poor y o u . N o f a s t s o l u t i o n p o s s i b l e . . .
* The k e r n e l i t s e l f m u s t p e r f o r m t h e o p e r a t i o n .
* A s p e c i a l g h o s t s y s c a l l i s u s e d f o r t h a t ( s e e t r a p s . c ) .
* /
2006-01-19 01:38:49 +03:00
stmfd s p ! , { r7 , l r }
2010-12-01 20:12:43 +03:00
ldr r7 , 1 f @ it's 20 bits
2009-11-10 02:53:29 +03:00
swi _ _ A R M _ N R _ c m p x c h g
2006-01-19 01:38:49 +03:00
ldmfd s p ! , { r7 , p c }
2009-11-10 02:53:29 +03:00
1 : .word _ _ A R M _ N R _ c m p x c h g
2005-06-08 22:00:47 +04:00
# elif _ _ L I N U X _ A R M _ A R C H _ _ < 6
2005-04-30 01:08:33 +04:00
[ARM] 4659/1: remove possibilities for spurious false negative with __kuser_cmpxchg
The ARM __kuser_cmpxchg routine is meant to implement an atomic cmpxchg
in user space. It however can produce spurious false negative if a
processor exception occurs in the middle of the operation. Normally
this is not a problem since cmpxchg is typically called in a loop until
it succeeds to implement an atomic increment for example.
Some use cases which don't involve a loop require that the operation be
100% reliable though. This patch changes the implementation so to
reattempt the operation after an exception has occurred in the critical
section rather than abort it.
Here's a simple program to test the fix (don't use CONFIG_NO_HZ in your
kernel as this depends on a sufficiently high interrupt rate):
#include <stdio.h>
typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
int main()
{
int i, x = 0;
for (i = 0; i < 100000000; i++) {
int v = x;
if (__kernel_cmpxchg(v, v+1, &x))
printf("failed at %d: %d vs %d\n", i, v, x);
}
printf("done with %d vs %d\n", i, x);
return 0;
}
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2007-11-20 19:20:29 +03:00
# ifdef C O N F I G _ M M U
2005-04-30 01:08:33 +04:00
/ *
[ARM] 4659/1: remove possibilities for spurious false negative with __kuser_cmpxchg
The ARM __kuser_cmpxchg routine is meant to implement an atomic cmpxchg
in user space. It however can produce spurious false negative if a
processor exception occurs in the middle of the operation. Normally
this is not a problem since cmpxchg is typically called in a loop until
it succeeds to implement an atomic increment for example.
Some use cases which don't involve a loop require that the operation be
100% reliable though. This patch changes the implementation so to
reattempt the operation after an exception has occurred in the critical
section rather than abort it.
Here's a simple program to test the fix (don't use CONFIG_NO_HZ in your
kernel as this depends on a sufficiently high interrupt rate):
#include <stdio.h>
typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
int main()
{
int i, x = 0;
for (i = 0; i < 100000000; i++) {
int v = x;
if (__kernel_cmpxchg(v, v+1, &x))
printf("failed at %d: %d vs %d\n", i, v, x);
}
printf("done with %d vs %d\n", i, x);
return 0;
}
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2007-11-20 19:20:29 +03:00
* The o n l y t h i n g t h a t c a n b r e a k a t o m i c i t y i n t h i s c m p x c h g
* implementation i s e i t h e r a n I R Q o r a d a t a a b o r t e x c e p t i o n
* causing a n o t h e r p r o c e s s / t h r e a d t o b e s c h e d u l e d i n t h e m i d d l e
* of t h e c r i t i c a l s e q u e n c e . T o p r e v e n t t h i s , c o d e i s a d d e d t o
* the I R Q a n d d a t a a b o r t e x c e p t i o n h a n d l e r s t o s e t t h e p c b a c k
* to t h e b e g i n n i n g o f t h e c r i t i c a l s e c t i o n i f i t i s f o u n d t o b e
* within t h a t c r i t i c a l s e c t i o n ( s e e k u s e r _ c m p x c h g _ f i x u p ) .
2005-04-30 01:08:33 +04:00
* /
[ARM] 4659/1: remove possibilities for spurious false negative with __kuser_cmpxchg
The ARM __kuser_cmpxchg routine is meant to implement an atomic cmpxchg
in user space. It however can produce spurious false negative if a
processor exception occurs in the middle of the operation. Normally
this is not a problem since cmpxchg is typically called in a loop until
it succeeds to implement an atomic increment for example.
Some use cases which don't involve a loop require that the operation be
100% reliable though. This patch changes the implementation so to
reattempt the operation after an exception has occurred in the critical
section rather than abort it.
Here's a simple program to test the fix (don't use CONFIG_NO_HZ in your
kernel as this depends on a sufficiently high interrupt rate):
#include <stdio.h>
typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
int main()
{
int i, x = 0;
for (i = 0; i < 100000000; i++) {
int v = x;
if (__kernel_cmpxchg(v, v+1, &x))
printf("failed at %d: %d vs %d\n", i, v, x);
}
printf("done with %d vs %d\n", i, x);
return 0;
}
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2007-11-20 19:20:29 +03:00
1 : ldr r3 , [ r2 ] @ load current val
subs r3 , r3 , r0 @ compare with oldval
2 : streq r1 , [ r2 ] @ store newval if eq
rsbs r0 , r3 , #0 @ set return val and C flag
usr_ r e t l r
.text
kuser_cmpxchg_fixup :
@ Called from kuser_cmpxchg_check macro.
@ r2 = address of interrupted insn (must be preserved).
@ sp = saved regs. r7 and r8 are clobbered.
@ 1b = first critical insn, 2b = last critical insn.
@ If r2 >= 1b and r2 <= 2b then saved pc_usr is set to 1b.
mov r7 , #0xffff0fff
sub r7 , r7 , #( 0xffff0fff - ( 0 x f f f f0 f c0 + ( 1 b - _ _ k u s e r _ c m p x c h g ) ) )
subs r8 , r2 , r7
rsbcss r8 , r8 , #( 2 b - 1 b )
strcs r7 , [ s p , #S _ P C ]
mov p c , l r
.previous
2006-02-09 00:19:37 +03:00
# else
# warning " N P T L o n n o n M M U n e e d s f i x i n g "
mov r0 , #- 1
adds r0 , r0 , #0
2006-08-18 20:20:15 +04:00
usr_ r e t l r
[ARM] 4659/1: remove possibilities for spurious false negative with __kuser_cmpxchg
The ARM __kuser_cmpxchg routine is meant to implement an atomic cmpxchg
in user space. It however can produce spurious false negative if a
processor exception occurs in the middle of the operation. Normally
this is not a problem since cmpxchg is typically called in a loop until
it succeeds to implement an atomic increment for example.
Some use cases which don't involve a loop require that the operation be
100% reliable though. This patch changes the implementation so to
reattempt the operation after an exception has occurred in the critical
section rather than abort it.
Here's a simple program to test the fix (don't use CONFIG_NO_HZ in your
kernel as this depends on a sufficiently high interrupt rate):
#include <stdio.h>
typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
int main()
{
int i, x = 0;
for (i = 0; i < 100000000; i++) {
int v = x;
if (__kernel_cmpxchg(v, v+1, &x))
printf("failed at %d: %d vs %d\n", i, v, x);
}
printf("done with %d vs %d\n", i, x);
return 0;
}
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2007-11-20 19:20:29 +03:00
# endif
2005-04-30 01:08:33 +04:00
# else
2010-01-12 21:59:16 +03:00
smp_ d m b
[ARM] 4659/1: remove possibilities for spurious false negative with __kuser_cmpxchg
The ARM __kuser_cmpxchg routine is meant to implement an atomic cmpxchg
in user space. It however can produce spurious false negative if a
processor exception occurs in the middle of the operation. Normally
this is not a problem since cmpxchg is typically called in a loop until
it succeeds to implement an atomic increment for example.
Some use cases which don't involve a loop require that the operation be
100% reliable though. This patch changes the implementation so to
reattempt the operation after an exception has occurred in the critical
section rather than abort it.
Here's a simple program to test the fix (don't use CONFIG_NO_HZ in your
kernel as this depends on a sufficiently high interrupt rate):
#include <stdio.h>
typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
int main()
{
int i, x = 0;
for (i = 0; i < 100000000; i++) {
int v = x;
if (__kernel_cmpxchg(v, v+1, &x))
printf("failed at %d: %d vs %d\n", i, v, x);
}
printf("done with %d vs %d\n", i, x);
return 0;
}
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2007-11-20 19:20:29 +03:00
1 : ldrex r3 , [ r2 ]
2005-04-30 01:08:33 +04:00
subs r3 , r3 , r0
strexeq r3 , r1 , [ r2 ]
[ARM] 4659/1: remove possibilities for spurious false negative with __kuser_cmpxchg
The ARM __kuser_cmpxchg routine is meant to implement an atomic cmpxchg
in user space. It however can produce spurious false negative if a
processor exception occurs in the middle of the operation. Normally
this is not a problem since cmpxchg is typically called in a loop until
it succeeds to implement an atomic increment for example.
Some use cases which don't involve a loop require that the operation be
100% reliable though. This patch changes the implementation so to
reattempt the operation after an exception has occurred in the critical
section rather than abort it.
Here's a simple program to test the fix (don't use CONFIG_NO_HZ in your
kernel as this depends on a sufficiently high interrupt rate):
#include <stdio.h>
typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
int main()
{
int i, x = 0;
for (i = 0; i < 100000000; i++) {
int v = x;
if (__kernel_cmpxchg(v, v+1, &x))
printf("failed at %d: %d vs %d\n", i, v, x);
}
printf("done with %d vs %d\n", i, x);
return 0;
}
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2007-11-20 19:20:29 +03:00
teqeq r3 , #1
beq 1 b
2005-04-30 01:08:33 +04:00
rsbs r0 , r3 , #0
[ARM] 4659/1: remove possibilities for spurious false negative with __kuser_cmpxchg
The ARM __kuser_cmpxchg routine is meant to implement an atomic cmpxchg
in user space. It however can produce spurious false negative if a
processor exception occurs in the middle of the operation. Normally
this is not a problem since cmpxchg is typically called in a loop until
it succeeds to implement an atomic increment for example.
Some use cases which don't involve a loop require that the operation be
100% reliable though. This patch changes the implementation so to
reattempt the operation after an exception has occurred in the critical
section rather than abort it.
Here's a simple program to test the fix (don't use CONFIG_NO_HZ in your
kernel as this depends on a sufficiently high interrupt rate):
#include <stdio.h>
typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
int main()
{
int i, x = 0;
for (i = 0; i < 100000000; i++) {
int v = x;
if (__kernel_cmpxchg(v, v+1, &x))
printf("failed at %d: %d vs %d\n", i, v, x);
}
printf("done with %d vs %d\n", i, x);
return 0;
}
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2007-11-20 19:20:29 +03:00
/* beware -- each __kuser slot must be 8 instructions max */
2010-09-04 13:47:48 +04:00
ALT_ S M P ( b _ _ k u s e r _ m e m o r y _ b a r r i e r )
ALT_ U P ( u s r _ r e t l r )
2005-04-30 01:08:33 +04:00
# endif
.align 5
/ *
* Reference p r o t o t y p e :
*
* int _ _ k e r n e l _ g e t _ t l s ( v o i d )
*
* Input :
*
* lr = r e t u r n a d d r e s s
*
* Output :
*
* r0 = T L S v a l u e
*
* Clobbered :
*
[ARM] 4659/1: remove possibilities for spurious false negative with __kuser_cmpxchg
The ARM __kuser_cmpxchg routine is meant to implement an atomic cmpxchg
in user space. It however can produce spurious false negative if a
processor exception occurs in the middle of the operation. Normally
this is not a problem since cmpxchg is typically called in a loop until
it succeeds to implement an atomic increment for example.
Some use cases which don't involve a loop require that the operation be
100% reliable though. This patch changes the implementation so to
reattempt the operation after an exception has occurred in the critical
section rather than abort it.
Here's a simple program to test the fix (don't use CONFIG_NO_HZ in your
kernel as this depends on a sufficiently high interrupt rate):
#include <stdio.h>
typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
int main()
{
int i, x = 0;
for (i = 0; i < 100000000; i++) {
int v = x;
if (__kernel_cmpxchg(v, v+1, &x))
printf("failed at %d: %d vs %d\n", i, v, x);
}
printf("done with %d vs %d\n", i, x);
return 0;
}
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2007-11-20 19:20:29 +03:00
* none
2005-04-30 01:08:33 +04:00
*
* Definition a n d u s e r s p a c e u s a g e e x a m p l e :
*
* typedef i n t ( _ _ k e r n e l _ g e t _ t l s _ t ) ( v o i d ) ;
* # define _ _ k e r n e l _ g e t _ t l s ( * ( _ _ k e r n e l _ g e t _ t l s _ t * ) 0 x f f f f0 f e 0 )
*
* Get t h e T L S v a l u e a s p r e v i o u s l y s e t v i a t h e _ _ A R M _ N R _ s e t _ t l s s y s c a l l .
*
* This c o u l d b e u s e d a s f o l l o w s :
*
* # define _ _ k e r n e l _ g e t _ t l s ( ) \
* ( { register u n s i g n e d i n t _ _ v a l a s m ( " r0 " ) ; \
* asm( " m o v r0 , #0xffff0fff ; mov lr, pc; sub pc, r0, #31" \
* : " = r" ( _ _ v a l ) : : " l r " ," c c " ) ; \
* _ _ val; })
* /
__kuser_get_tls : @ 0xffff0fe0
2010-07-05 17:53:10 +04:00
ldr r0 , [ p c , #( 16 - 8 ) ] @ read TLS, set in kuser_get_tls_init
2006-08-18 20:20:15 +04:00
usr_ r e t l r
2010-07-05 17:53:10 +04:00
mrc p15 , 0 , r0 , c13 , c0 , 3 @ 0xffff0fe8 hardware TLS code
.rep 4
.word 0 @ 0xffff0ff0 software TLS value, then
.endr @ pad up to __kuser_helper_version
2005-04-30 01:08:33 +04:00
/ *
* Reference d e c l a r a t i o n :
*
* extern u n s i g n e d i n t _ _ k e r n e l _ h e l p e r _ v e r s i o n ;
*
* Definition a n d u s e r s p a c e u s a g e e x a m p l e :
*
* # define _ _ k e r n e l _ h e l p e r _ v e r s i o n ( * ( u n s i g n e d i n t * ) 0 x f f f f0 f f c )
*
* User s p a c e m a y r e a d t h i s t o d e t e r m i n e t h e c u r e n t n u m b e r o f h e l p e r s
* available.
* /
__kuser_helper_version : @ 0xffff0ffc
.word ( ( _ _ kuser_ h e l p e r _ e n d - _ _ k u s e r _ h e l p e r _ s t a r t ) > > 5 )
.globl __kuser_helper_end
__kuser_helper_end :
2009-07-24 15:32:54 +04:00
THUMB( . t h u m b )
2005-04-30 01:08:33 +04:00
2005-04-17 02:20:36 +04:00
/ *
* Vector s t u b s .
*
2005-04-26 18:17:42 +04:00
* This c o d e i s c o p i e d t o 0 x f f f f02 0 0 s o w e c a n u s e b r a n c h e s i n t h e
* vectors, r a t h e r t h a n l d r ' s . N o t e t h a t t h i s c o d e m u s t n o t
* exceed 0 x30 0 b y t e s .
2005-04-17 02:20:36 +04:00
*
* Common s t u b e n t r y m a c r o :
* Enter i n I R Q m o d e , s p s r = S V C / U S R C P S R , l r = S V C / U S R P C
2005-06-01 01:22:32 +04:00
*
* SP p o i n t s t o a m i n i m a l a m o u n t o f p r o c e s s o r - p r i v a t e m e m o r y , t h e a d d r e s s
* of w h i c h i s c o p i e d i n t o r0 f o r t h e m o d e s p e c i f i c a b o r t h a n d l e r .
2005-04-17 02:20:36 +04:00
* /
2005-11-06 17:42:37 +03:00
.macro vector_ s t u b , n a m e , m o d e , c o r r e c t i o n =0
2005-04-17 02:20:36 +04:00
.align 5
vector_ \ n a m e :
.if \ correction
sub l r , l r , #\ c o r r e c t i o n
.endif
2005-06-01 01:22:32 +04:00
@
@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
@ (parent CPSR)
@
stmia s p , { r0 , l r } @ save r0, lr
2005-04-17 02:20:36 +04:00
mrs l r , s p s r
2005-06-01 01:22:32 +04:00
str l r , [ s p , #8 ] @ save spsr
2005-04-17 02:20:36 +04:00
@
2005-06-01 01:22:32 +04:00
@ Prepare for SVC32 mode. IRQs remain disabled.
2005-04-17 02:20:36 +04:00
@
2005-06-01 01:22:32 +04:00
mrs r0 , c p s r
2009-07-24 15:32:54 +04:00
eor r0 , r0 , #( \ m o d e ^ S V C _ M O D E | P S R _ I S E T S T A T E )
2005-06-01 01:22:32 +04:00
msr s p s r _ c x s f , r0
2005-04-17 02:20:36 +04:00
2005-06-01 01:22:32 +04:00
@
@ the branch table must immediately follow this code
@
and l r , l r , #0x0f
2009-07-24 15:32:54 +04:00
THUMB( a d r r0 , 1 f )
THUMB( l d r l r , [ r0 , l r , l s l #2 ] )
2005-11-06 17:42:37 +03:00
mov r0 , s p
2009-07-24 15:32:54 +04:00
ARM( l d r l r , [ p c , l r , l s l #2 ] )
2005-06-01 01:22:32 +04:00
movs p c , l r @ branch to handler in SVC mode
2008-08-28 14:22:32 +04:00
ENDPROC( v e c t o r _ \ n a m e )
2009-07-24 15:32:52 +04:00
.align 2
@ handler addresses follow this label
1 :
2005-04-17 02:20:36 +04:00
.endm
2005-04-26 18:17:42 +04:00
.globl __stubs_start
2005-04-17 02:20:36 +04:00
__stubs_start :
/ *
* Interrupt d i s p a t c h e r
* /
2005-11-06 17:42:37 +03:00
vector_ s t u b i r q , I R Q _ M O D E , 4
2005-04-17 02:20:36 +04:00
.long __irq_usr @ 0 (USR_26 / USR_32)
.long __irq_invalid @ 1 (FIQ_26 / FIQ_32)
.long __irq_invalid @ 2 (IRQ_26 / IRQ_32)
.long __irq_svc @ 3 (SVC_26 / SVC_32)
.long __irq_invalid @ 4
.long __irq_invalid @ 5
.long __irq_invalid @ 6
.long __irq_invalid @ 7
.long __irq_invalid @ 8
.long __irq_invalid @ 9
.long __irq_invalid @ a
.long __irq_invalid @ b
.long __irq_invalid @ c
.long __irq_invalid @ d
.long __irq_invalid @ e
.long __irq_invalid @ f
/ *
* Data a b o r t d i s p a t c h e r
* Enter i n A B T m o d e , s p s r = U S R C P S R , l r = U S R P C
* /
2005-11-06 17:42:37 +03:00
vector_ s t u b d a b t , A B T _ M O D E , 8
2005-04-17 02:20:36 +04:00
.long __dabt_usr @ 0 (USR_26 / USR_32)
.long __dabt_invalid @ 1 (FIQ_26 / FIQ_32)
.long __dabt_invalid @ 2 (IRQ_26 / IRQ_32)
.long __dabt_svc @ 3 (SVC_26 / SVC_32)
.long __dabt_invalid @ 4
.long __dabt_invalid @ 5
.long __dabt_invalid @ 6
.long __dabt_invalid @ 7
.long __dabt_invalid @ 8
.long __dabt_invalid @ 9
.long __dabt_invalid @ a
.long __dabt_invalid @ b
.long __dabt_invalid @ c
.long __dabt_invalid @ d
.long __dabt_invalid @ e
.long __dabt_invalid @ f
/ *
* Prefetch a b o r t d i s p a t c h e r
* Enter i n A B T m o d e , s p s r = U S R C P S R , l r = U S R P C
* /
2005-11-06 17:42:37 +03:00
vector_ s t u b p a b t , A B T _ M O D E , 4
2005-04-17 02:20:36 +04:00
.long __pabt_usr @ 0 (USR_26 / USR_32)
.long __pabt_invalid @ 1 (FIQ_26 / FIQ_32)
.long __pabt_invalid @ 2 (IRQ_26 / IRQ_32)
.long __pabt_svc @ 3 (SVC_26 / SVC_32)
.long __pabt_invalid @ 4
.long __pabt_invalid @ 5
.long __pabt_invalid @ 6
.long __pabt_invalid @ 7
.long __pabt_invalid @ 8
.long __pabt_invalid @ 9
.long __pabt_invalid @ a
.long __pabt_invalid @ b
.long __pabt_invalid @ c
.long __pabt_invalid @ d
.long __pabt_invalid @ e
.long __pabt_invalid @ f
/ *
* Undef i n s t r e n t r y d i s p a t c h e r
* Enter i n U N D m o d e , s p s r = S V C / U S R C P S R , l r = S V C / U S R P C
* /
2005-11-06 17:42:37 +03:00
vector_ s t u b u n d , U N D _ M O D E
2005-04-17 02:20:36 +04:00
.long __und_usr @ 0 (USR_26 / USR_32)
.long __und_invalid @ 1 (FIQ_26 / FIQ_32)
.long __und_invalid @ 2 (IRQ_26 / IRQ_32)
.long __und_svc @ 3 (SVC_26 / SVC_32)
.long __und_invalid @ 4
.long __und_invalid @ 5
.long __und_invalid @ 6
.long __und_invalid @ 7
.long __und_invalid @ 8
.long __und_invalid @ 9
.long __und_invalid @ a
.long __und_invalid @ b
.long __und_invalid @ c
.long __und_invalid @ d
.long __und_invalid @ e
.long __und_invalid @ f
.align 5
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Undefined F I Q s
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Enter i n F I Q m o d e , s p s r = A N Y C P S R , l r = A N Y P C
* MUST P R E S E R V E S V C S P S R , b u t n e e d t o s w i t c h t o S V C m o d e t o s h o w o u r m s g .
* Basically t o s w i t c h m o d e s , w e * H A V E * t o c l o b b e r o n e r e g i s t e r . . . b r a i n
* damage a l e r t ! I d o n ' t t h i n k t h a t w e c a n e x e c u t e a n y c o d e i n h e r e i n a n y
* other m o d e t h a n F I Q . . . O k y o u c a n s w i t c h t o a n o t h e r m o d e , b u t y o u c a n ' t
* get o u t o f t h a t m o d e w i t h o u t c l o b b e r i n g o n e r e g i s t e r .
* /
vector_fiq :
disable_ f i q
subs p c , l r , #4
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Address e x c e p t i o n h a n d l e r
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* These a r e n ' t t o o c r i t i c a l .
* ( they' r e n o t s u p p o s e d t o h a p p e n , a n d w o n ' t h a p p e n i n 3 2 - b i t d a t a m o d e ) .
* /
vector_addrexcptn :
b v e c t o r _ a d d r e x c p t n
/ *
* We g r o u p a l l t h e f o l l o w i n g d a t a t o g e t h e r t o o p t i m i s e
* for C P U s w i t h s e p a r a t e I & D c a c h e s .
* /
.align 5
.LCvswi :
.word vector_swi
2005-04-26 18:17:42 +04:00
.globl __stubs_end
2005-04-17 02:20:36 +04:00
__stubs_end :
2005-04-26 18:17:42 +04:00
.equ stubs_ o f f s e t , _ _ v e c t o r s _ s t a r t + 0 x20 0 - _ _ s t u b s _ s t a r t
2005-04-17 02:20:36 +04:00
2005-04-26 18:17:42 +04:00
.globl __vectors_start
__vectors_start :
2009-07-24 15:32:54 +04:00
ARM( s w i S Y S _ E R R O R 0 )
THUMB( s v c #0 )
THUMB( n o p )
W( b ) v e c t o r _ u n d + s t u b s _ o f f s e t
W( l d r ) p c , . L C v s w i + s t u b s _ o f f s e t
W( b ) v e c t o r _ p a b t + s t u b s _ o f f s e t
W( b ) v e c t o r _ d a b t + s t u b s _ o f f s e t
W( b ) v e c t o r _ a d d r e x c p t n + s t u b s _ o f f s e t
W( b ) v e c t o r _ i r q + s t u b s _ o f f s e t
W( b ) v e c t o r _ f i q + s t u b s _ o f f s e t
2005-04-26 18:17:42 +04:00
.globl __vectors_end
__vectors_end :
2005-04-17 02:20:36 +04:00
.data
.globl cr_alignment
.globl cr_no_alignment
cr_alignment :
.space 4
cr_no_alignment :
.space 4