2005-04-16 15:20:36 -07: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-13 21:05:25 +00: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-16 15:20:36 -07: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 14:33:33 +01: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-16 15:20:36 -07:00
* /
2005-10-29 21:44:55 +01:00
# include < a s m / m e m o r y . h >
2011-02-06 15:32:24 +00:00
# include < a s m / g l u e - d f . h >
# include < a s m / g l u e - p f . h >
2005-04-16 15:20:36 -07:00
# include < a s m / v f p m a c r o s . h >
2008-08-05 16:14:15 +01:00
# include < m a c h / e n t r y - m a c r o . S >
2006-06-21 13:31:52 +01:00
# include < a s m / t h r e a d _ n o t i f y . h >
2009-02-16 11:42:09 +01:00
# include < a s m / u n w i n d . h >
2009-11-09 23:53:29 +00:00
# include < a s m / u n i s t d . h >
2010-07-05 14:53:10 +01:00
# include < a s m / t l s . h >
2005-04-16 15:20:36 -07:00
# include " e n t r y - h e a d e r . S "
2010-12-22 13:20:08 +01:00
# include < a s m / e n t r y - m a c r o - m u l t i . S >
2005-04-16 15:20:36 -07:00
2005-05-21 18:14:44 +01: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
2010-12-13 09:42:34 +01:00
# ifdef C O N F I G _ M U L T I _ I R Q _ H A N D L E R
ldr r5 , =handle_arch_irq
mov r0 , s p
ldr r5 , [ r5 ]
adr l r , B S Y M ( 9 9 9 7 f )
teq r5 , #0
movne p c , r5
2005-11-08 19:08:05 +00:00
# endif
2010-12-22 13:20:08 +01:00
arch_ i r q _ h a n d l e r _ d e f a u l t
2010-09-04 10:47:48 +01:00
9997 :
2005-05-21 18:14:44 +01:00
.endm
2007-12-03 15:27:56 -05: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-16 15:20:36 -07:00
/ *
* Invalid m o d e h a n d l e r s
* /
2005-05-31 22:22:32 +01: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 12:32:54 +01: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-16 15:20:36 -07:00
mov r1 , #\ r e a s o n
.endm
__pabt_invalid :
2005-05-31 22:22:32 +01: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 11:22:32 +01:00
ENDPROC( _ _ p a b t _ i n v a l i d )
2005-04-16 15:20:36 -07:00
__dabt_invalid :
2005-05-31 22:22:32 +01: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 11:22:32 +01:00
ENDPROC( _ _ d a b t _ i n v a l i d )
2005-04-16 15:20:36 -07:00
__irq_invalid :
2005-05-31 22:22:32 +01: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 11:22:32 +01:00
ENDPROC( _ _ i r q _ i n v a l i d )
2005-04-16 15:20:36 -07:00
__und_invalid :
2005-05-31 22:22:32 +01: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-16 15:20:36 -07:00
mov r0 , s p
b b a d _ m o d e
2008-08-28 11:22:32 +01:00
ENDPROC( _ _ u n d _ i n v a l i d )
2005-04-16 15:20:36 -07:00
/ *
* SVC m o d e h a n d l e r s
* /
2006-01-14 16:18:08 +00: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 15:56:01 -05:00
.macro svc_ e n t r y , s t a c k _ h o l e =0
2009-02-16 11:42:09 +01:00
UNWIND( . f n s t a r t )
UNWIND( . s a v e { r0 - p c } )
2009-07-24 12:32:54 +01: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 16:18:08 +00:00
SPFIX( t s t s p , #4 )
2009-07-24 12:32:54 +01:00
# endif
SPFIX( s u b e q s p , s p , #4 )
stmia s p , { r1 - r12 }
2005-05-31 22:22:32 +01:00
ldmia r0 , { r1 - r3 }
2009-07-24 12:32:54 +01:00
add r5 , s p , #S _ S P - 4 @ here for interlock avoidance
2005-05-31 22:22:32 +01:00
mov r4 , #- 1 @ "" "" "" ""
2009-07-24 12:32:54 +01: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-05-31 22:22:32 +01:00
@ from the exception stack
2005-04-16 15:20:36 -07: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-05-31 22:22:32 +01:00
svc_ e n t r y
2005-04-16 15:20:36 -07: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-18 22:43:07 +01:00
# ifdef M U L T I _ D A B O R T
2005-04-16 15:20:36 -07:00
ldr r4 , . L C p r o c f n s
mov l r , p c
2008-04-18 22:43:07 +01:00
ldr p c , [ r4 , #P R O C E S S O R _ D A B T _ F U N C ]
2005-04-16 15:20:36 -07:00
# else
2008-04-18 22:43:07 +01:00
bl C P U _ D A B O R T _ H A N D L E R
2005-04-16 15:20:36 -07:00
# endif
@
@ set desired IRQ state, then call main handler
@
2010-11-28 14:57:24 +00:00
debug_ e n t r y r1
2005-04-16 15:20:36 -07:00
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 10:10:18 +01:00
disable_ i r q _ n o t r a c e
2005-04-16 15:20:36 -07:00
@
@ restore SPSR and restart the instruction
@
2009-07-24 12:32:54 +01:00
ldr r2 , [ s p , #S _ P S R ]
svc_ e x i t r2 @ return from exception
2009-02-16 11:42:09 +01:00
UNWIND( . f n e n d )
2008-08-28 11:22:32 +01:00
ENDPROC( _ _ d a b t _ s v c )
2005-04-16 15:20:36 -07:00
.align 5
__irq_svc :
2005-05-31 22:22:32 +01:00
svc_ e n t r y
2010-07-10 10:10:18 +01: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-16 15:20:36 -07:00
# ifdef C O N F I G _ P R E E M P T
2005-05-21 18:15:45 +01: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-16 15:20:36 -07:00
# endif
2005-05-31 22:22:32 +01:00
2005-05-21 18:14:44 +01:00
irq_ h a n d l e r
2005-04-16 15:20:36 -07:00
# ifdef C O N F I G _ P R E E M P T
2008-04-13 17:47:35 +01: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 18:15:45 +01:00
ldr r0 , [ t s k , #T I _ F L A G S ] @ g e t f l a g s
2008-04-13 17:47:35 +01:00
teq r8 , #0 @ if preempt count != 0
movne r0 , #0 @ force flags to 0
2005-04-16 15:20:36 -07: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 12:32:54 +01: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 12:07:02 +01:00
# ifdef C O N F I G _ T R A C E _ I R Q F L A G S
2009-07-24 12:32:54 +01:00
tst r4 , #P S R _ I _ B I T
2006-08-27 12:07:02 +01:00
bleq t r a c e _ h a r d i r q s _ o n
# endif
2009-07-24 12:32:54 +01:00
svc_ e x i t r4 @ return from exception
2009-02-16 11:42:09 +01:00
UNWIND( . f n e n d )
2008-08-28 11:22:32 +01:00
ENDPROC( _ _ i r q _ s v c )
2005-04-16 15:20:36 -07:00
.ltorg
# ifdef C O N F I G _ P R E E M P T
svc_preempt :
2008-04-13 17:47:35 +01:00
mov r8 , l r
2005-04-16 15:20:36 -07: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 18:15:45 +01: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-16 15:20:36 -07:00
tst r0 , #_ T I F _ N E E D _ R E S C H E D
2008-04-13 17:47:35 +01:00
moveq p c , r8 @ go again
2005-04-16 15:20:36 -07:00
b 1 b
# endif
.align 5
__und_svc :
2007-12-14 15:56:01 -05: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-05-31 22:22:32 +01:00
svc_ e n t r y
2007-12-14 15:56:01 -05:00
# endif
2005-04-16 15:20:36 -07: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-18 23:27:07 +01:00
# ifndef C O N F I G _ T H U M B 2 _ K E R N E L
2005-04-16 15:20:36 -07:00
ldr r0 , [ r2 , #- 4 ]
2009-09-18 23:27:07 +01: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 12:32:54 +01:00
adr r9 , B S Y M ( 1 f )
2005-04-16 15:20:36 -07: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 10:10:18 +01:00
1 : disable_ i r q _ n o t r a c e
2005-04-16 15:20:36 -07:00
@
@ restore SPSR and restart the instruction
@
2009-07-24 12:32:54 +01: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 11:42:09 +01:00
UNWIND( . f n e n d )
2008-08-28 11:22:32 +01:00
ENDPROC( _ _ u n d _ s v c )
2005-04-16 15:20:36 -07:00
.align 5
__pabt_svc :
2005-05-31 22:22:32 +01:00
svc_ e n t r y
2005-04-16 15:20:36 -07: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-18 22:43:07 +01:00
mov r0 , r2 @ pass address of aborted instruction.
2009-09-25 13:39:47 +01:00
# ifdef M U L T I _ P A B O R T
2008-04-18 22:43:07 +01: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 13:39:47 +01:00
bl C P U _ P A B O R T _ H A N D L E R
2008-04-18 22:43:07 +01:00
# endif
2010-11-28 14:57:24 +00:00
debug_ e n t r y r1
2008-04-18 22:43:07 +01:00
msr c p s r _ c , r9 @ Maybe enable interrupts
2009-09-25 13:39:47 +01:00
mov r2 , s p @ regs
2005-04-16 15:20:36 -07: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 10:10:18 +01:00
disable_ i r q _ n o t r a c e
2005-04-16 15:20:36 -07:00
@
@ restore SPSR and restart the instruction
@
2009-07-24 12:32:54 +01:00
ldr r2 , [ s p , #S _ P S R ]
svc_ e x i t r2 @ return from exception
2009-02-16 11:42:09 +01:00
UNWIND( . f n e n d )
2008-08-28 11:22:32 +01:00
ENDPROC( _ _ p a b t _ s v c )
2005-04-16 15:20:36 -07:00
.align 5
2005-05-31 18:02:00 +01:00
.LCcralign :
.word cr_alignment
2008-04-18 22:43:07 +01:00
# ifdef M U L T I _ D A B O R T
2005-04-16 15:20:36 -07: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 16:18:08 +00: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-16 15:20:36 -07:00
* /
2006-01-14 16:18:08 +00: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-05-31 22:22:32 +01:00
.macro usr_entry
2009-02-16 11:42:09 +01: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-05-31 22:22:32 +01:00
sub s p , s p , #S _ F R A M E _ S I Z E
2009-07-24 12:32:54 +01:00
ARM( s t m i b s p , { r1 - r12 } )
THUMB( s t m i a s p , { r0 - r12 } )
2005-05-31 22:22:32 +01: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-16 15:20:36 -07: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-05-31 22:22:32 +01:00
stmia r0 , { r2 - r4 }
2009-07-24 12:32:54 +01: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-16 15:20:36 -07:00
@
@ Enable the alignment trap while in kernel mode
@
2005-05-31 18:02:00 +01:00
alignment_ t r a p r0
2005-04-16 15:20:36 -07: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 17:20:29 +01: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-16 15:20:36 -07:00
.align 5
__dabt_usr :
2005-05-31 22:22:32 +01: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 17:20:29 +01:00
kuser_ c m p x c h g _ c h e c k
2005-04-16 15:20:36 -07: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-18 22:43:07 +01:00
# ifdef M U L T I _ D A B O R T
2005-04-16 15:20:36 -07:00
ldr r4 , . L C p r o c f n s
mov l r , p c
2008-04-18 22:43:07 +01:00
ldr p c , [ r4 , #P R O C E S S O R _ D A B T _ F U N C ]
2005-04-16 15:20:36 -07:00
# else
2008-04-18 22:43:07 +01:00
bl C P U _ D A B O R T _ H A N D L E R
2005-04-16 15:20:36 -07:00
# endif
@
@ IRQs on, then call the main handler
@
2010-11-28 14:57:24 +00:00
debug_ e n t r y r1
2005-04-26 15:18:26 +01:00
enable_ i r q
2005-04-16 15:20:36 -07:00
mov r2 , s p
2009-07-24 12:32:54 +01: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-16 15:20:36 -07:00
b d o _ D a t a A b o r t
2009-02-16 11:42:09 +01:00
UNWIND( . f n e n d )
2008-08-28 11:22:32 +01:00
ENDPROC( _ _ d a b t _ u s r )
2005-04-16 15:20:36 -07:00
.align 5
__irq_usr :
2005-05-31 22:22:32 +01: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 17:20:29 +01:00
kuser_ c m p x c h g _ c h e c k
2005-04-16 15:20:36 -07:00
2011-06-05 02:24:58 +01:00
# ifdef C O N F I G _ I R Q S O F F _ T R A C E R
bl t r a c e _ h a r d i r q s _ o f f
# endif
2005-05-21 18:15:45 +01:00
get_ t h r e a d _ i n f o t s k
2005-04-16 15:20:36 -07:00
# ifdef C O N F I G _ P R E E M P T
2005-05-21 18:15:45 +01: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-16 15:20:36 -07:00
# endif
2005-05-31 22:22:32 +01:00
2005-05-21 18:14:44 +01:00
irq_ h a n d l e r
2005-04-16 15:20:36 -07:00
# ifdef C O N F I G _ P R E E M P T
2005-05-21 18:15:45 +01: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-16 15:20:36 -07:00
teq r0 , r7
2009-07-24 12:32:54 +01: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-16 15:20:36 -07:00
# endif
2005-05-31 22:22:32 +01:00
2005-04-16 15:20:36 -07:00
mov w h y , #0
2011-06-05 02:24:58 +01:00
b r e t _ t o _ u s e r _ f r o m _ i r q
2009-02-16 11:42:09 +01:00
UNWIND( . f n e n d )
2008-08-28 11:22:32 +01:00
ENDPROC( _ _ i r q _ u s r )
2005-04-16 15:20:36 -07:00
.ltorg
.align 5
__und_usr :
2005-05-31 22:22:32 +01:00
usr_ e n t r y
2005-04-16 15:20:36 -07: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 12:32:54 +01: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-18 22:43:08 +01:00
tst r3 , #P S R _ T _ B I T @ T h u m b m o d e ?
2009-07-24 12:32:54 +01:00
itet e q @ explicit IT needed for the 1f label
2008-04-18 22:43:08 +01: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 14:00:18 +01: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-18 22:43:08 +01: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 12:32:54 +01: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-18 22:43:08 +01: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 11:42:09 +01:00
UNWIND( . f n e n d )
2008-08-28 11:22:32 +01:00
ENDPROC( _ _ u n d _ u s r )
2008-04-18 22:43:08 +01:00
2005-04-16 15:20:36 -07: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 10:15:03 +01:00
.pushsection .fixup , " ax"
2008-04-18 22:43:08 +01:00
4 : mov p c , r9
2010-04-19 10:15:03 +01:00
.popsection
.pushsection _ _ ex_ t a b l e ," a "
2008-04-18 22:43:08 +01: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 10:15:03 +01:00
.popsection
2005-04-16 15:20:36 -07: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 19:16:17 +01: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-16 15:20:36 -07: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-06 22:53:48 +00: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-16 15:20:36 -07: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-06 22:53:48 +00: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-16 15:20:36 -07:00
* /
2008-04-18 22:43:08 +01: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-16 15:20:36 -07:00
call_fpe :
2008-01-10 19:16:17 +01:00
# ifdef C O N F I G _ N E O N
2008-04-18 22:43:08 +01:00
adr r6 , . L C n e o n _ a r m _ o p c o d e s
2008-01-10 19:16:17 +01: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-16 15:20:36 -07:00
tst r0 , #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27
2008-04-18 22:43:08 +01:00
tstne r0 , #0x04000000 @ bit 26 set on both ARM and Thumb-2
2005-04-16 15:20:36 -07: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 12:32:54 +01:00
THUMB( l s r r8 , r8 , #8 )
2005-04-16 15:20:36 -07:00
mov r7 , #1
add r6 , r10 , #T I _ U S E D _ C P
2009-07-24 12:32:54 +01: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-16 15:20:36 -07: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 12:32:54 +01: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 17:31:20 +01:00
movw_ p c l r @ CP#0
2009-07-24 12:32:54 +01:00
W( b ) d o _ f p e @ CP#1 (FPE)
W( b ) d o _ f p e @ CP#2 (FPE)
2009-10-12 17:31:20 +01:00
movw_ p c l r @ CP#3
2006-06-27 23:03:03 +01: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 17:31:20 +01:00
movw_ p c l r @ CP#4
movw_ p c l r @ CP#5
movw_ p c l r @ CP#6
2006-06-27 23:03:03 +01:00
# endif
2009-10-12 17:31:20 +01:00
movw_ p c l r @ CP#7
movw_ p c l r @ CP#8
movw_ p c l r @ CP#9
2005-04-16 15:20:36 -07:00
# ifdef C O N F I G _ V F P
2009-07-24 12:32:54 +01:00
W( b ) d o _ v f p @ CP#10 (VFP)
W( b ) d o _ v f p @ CP#11 (VFP)
2005-04-16 15:20:36 -07:00
# else
2009-10-12 17:31:20 +01:00
movw_ p c l r @ CP#10 (VFP)
movw_ p c l r @ CP#11 (VFP)
2005-04-16 15:20:36 -07:00
# endif
2009-10-12 17:31:20 +01: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-16 15:20:36 -07:00
2008-01-10 19:16:17 +01:00
# ifdef C O N F I G _ N E O N
.align 6
2008-04-18 22:43:08 +01:00
.LCneon_arm_opcodes :
2008-01-10 19:16:17 +01:00
.word 0xfe000000 @ mask
.word 0xf2000000 @ opcode
.word 0xff100000 @ mask
.word 0xf4000000 @ opcode
2008-04-18 22:43:08 +01: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 19:16:17 +01:00
.word 0x00000000 @ mask
.word 0x00000000 @ opcode
# endif
2005-04-16 15:20:36 -07:00
do_fpe :
2006-03-15 12:33:43 +00:00
enable_ i r q
2005-04-16 15:20:36 -07: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 10:45:46 +01:00
.pushsection .data
2005-04-16 15:20:36 -07:00
ENTRY( f p _ e n t e r )
2007-01-06 22:53:48 +00:00
.word no_fp
2010-04-30 10:45:46 +01:00
.popsection
2005-04-16 15:20:36 -07:00
2009-09-18 23:27:07 +01:00
ENTRY( n o _ f p )
mov p c , l r
ENDPROC( n o _ f p )
2007-01-06 22:53:48 +00:00
__und_usr_unknown :
2009-01-27 23:20:00 +00:00
enable_ i r q
2005-04-16 15:20:36 -07:00
mov r0 , s p
2009-07-24 12:32:54 +01: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-16 15:20:36 -07:00
b d o _ u n d e f i n s t r
2008-08-28 11:22:32 +01:00
ENDPROC( _ _ u n d _ u s r _ u n k n o w n )
2005-04-16 15:20:36 -07:00
.align 5
__pabt_usr :
2005-05-31 22:22:32 +01:00
usr_ e n t r y
2005-04-16 15:20:36 -07:00
2008-04-18 22:43:07 +01:00
mov r0 , r2 @ pass address of aborted instruction.
2009-09-25 13:39:47 +01:00
# ifdef M U L T I _ P A B O R T
2008-04-18 22:43:07 +01: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 13:39:47 +01:00
bl C P U _ P A B O R T _ H A N D L E R
2008-04-18 22:43:07 +01:00
# endif
2010-11-28 14:57:24 +00:00
debug_ e n t r y r1
2005-04-26 15:18:26 +01:00
enable_ i r q @ Enable interrupts
2009-09-25 13:39:47 +01:00
mov r2 , s p @ regs
2005-04-16 15:20:36 -07:00
bl d o _ P r e f e t c h A b o r t @ call abort handler
2009-02-16 11:42:09 +01:00
UNWIND( . f n e n d )
2005-04-16 15:20:36 -07: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 11:42:09 +01:00
UNWIND( . f n s t a r t )
UNWIND( . c a n t u n w i n d )
2005-04-16 15:20:36 -07: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 11:42:09 +01:00
UNWIND( . f n e n d )
2008-08-28 11:22:32 +01: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-16 15:20:36 -07: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 11:42:09 +01:00
UNWIND( . f n s t a r t )
UNWIND( . c a n t u n w i n d )
2005-04-16 15:20:36 -07: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 12:32:54 +01: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 )
2010-09-13 16:03:21 +01:00
# ifdef C O N F I G _ C P U _ U S E _ D O M A I N S
2006-06-21 13:31:52 +01:00
ldr r6 , [ r2 , #T I _ C P U _ D O M A I N ]
2006-01-13 21:05:25 +00:00
# endif
2010-07-05 14:53:10 +01:00
set_ t l s r3 , r4 , r5
2010-06-07 21: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
2010-09-13 16:03:21 +01:00
# ifdef C O N F I G _ C P U _ U S E _ D O M A I N S
2005-04-16 15:20:36 -07:00
mcr p15 , 0 , r6 , c3 , c0 , 0 @ Set domain register
# endif
2006-06-21 13:31:52 +01: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-07 21: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 12:32:54 +01:00
THUMB( m o v i p , r4 )
2006-06-21 13:31:52 +01:00
mov r0 , r5
2009-07-24 12:32:54 +01: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 11:42:09 +01:00
UNWIND( . f n e n d )
2008-08-28 11:22:32 +01:00
ENDPROC( _ _ s w i t c h _ t o )
2005-04-16 15:20:36 -07:00
_ _ INIT
2005-04-29 22:08:33 +01: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 12:32:54 +01:00
THUMB( . a r m )
2005-04-29 22:08:33 +01:00
2006-08-18 17:20:15 +01: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-29 22:08:33 +01:00
.align 5
.globl __kuser_helper_start
__kuser_helper_start :
2005-12-19 22:20:51 +00: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 17:20:29 +01:00
* none
2005-12-19 22:20:51 +00: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-28 22:19:29 +01:00
* : : : " r0 " , " l r " ," c c " )
2005-12-19 22:20:51 +00:00
* /
__kuser_memory_barrier : @ 0xffff0fa0
ARM: 6516/1: Allow SMP_ON_UP to work with Thumb-2 kernels.
* __fixup_smp_on_up has been modified with support for the
THUMB2_KERNEL case. For THUMB2_KERNEL only, fixups are split
into halfwords in case of misalignment, since we can't rely on
unaligned accesses working before turning the MMU on.
No attempt is made to optimise the aligned case, since the
number of fixups is typically small, and it seems best to keep
the code as simple as possible.
* Add a rotate in the fixup_smp code in order to support
CPU_BIG_ENDIAN, as suggested by Nicolas Pitre.
* Add an assembly-time sanity-check to ALT_UP() to ensure that
the content really is the right size (4 bytes).
(No check is done for ALT_SMP(). Possibly, this could be fixed
by splitting the two uses ot ALT_SMP() (ALT_SMP...SMP_UP versus
ALT_SMP...SMP_UP_B) into two macros. In the first case,
ALT_SMP needs to expand to >= 4 bytes, not == 4.)
* smp_mpidr.h (which implements ALT_SMP()/ALT_UP() manually due
to macro limitations) has not been modified: the affected
instruction (mov) has no 16-bit encoding, so the correct
instruction size is satisfied in this case.
* A "mode" parameter has been added to smp_dmb:
smp_dmb arm @ assumes 4-byte instructions (for ARM code, e.g. kuser)
smp_dmb @ uses W() to ensure 4-byte instructions for ALT_SMP()
This avoids assembly failures due to use of W() inside smp_dmb,
when assembling pure-ARM code in the vectors page.
There might be a better way to achieve this.
* Kconfig: make SMP_ON_UP depend on
(!THUMB2_KERNEL || !BIG_ENDIAN) i.e., THUMB2_KERNEL is now
supported, but only if !BIG_ENDIAN (The fixup code for Thumb-2
currently assumes little-endian order.)
Tested using a single generic realview kernel on:
ARM RealView PB-A8 (CONFIG_THUMB2_KERNEL={n,y})
ARM RealView PBX-A9 (SMP)
Signed-off-by: Dave Martin <dave.martin@linaro.org>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2010-12-01 15:39:23 +01:00
smp_ d m b a r m
2006-08-18 17:20:15 +01:00
usr_ r e t l r
2005-12-19 22:20:51 +00:00
.align 5
2005-04-29 22:08:33 +01: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-08 21:19:37 +00: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-29 22:08:33 +01: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 19:00:47 +01: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-29 22:08:33 +01:00
2005-06-08 19:00:47 +01: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-18 22:38:49 +00:00
stmfd s p ! , { r7 , l r }
2010-12-01 18:12:43 +01:00
ldr r7 , 1 f @ it's 20 bits
2009-11-09 23:53:29 +00:00
swi _ _ A R M _ N R _ c m p x c h g
2006-01-18 22:38:49 +00:00
ldmfd s p ! , { r7 , p c }
2009-11-09 23:53:29 +00:00
1 : .word _ _ A R M _ N R _ c m p x c h g
2005-06-08 19:00:47 +01:00
# elif _ _ L I N U X _ A R M _ A R C H _ _ < 6
2005-04-29 22:08:33 +01: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 17:20:29 +01:00
# ifdef C O N F I G _ M M U
2005-04-29 22:08:33 +01: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 17:20:29 +01: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-29 22:08:33 +01: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 17:20:29 +01: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-08 21:19:37 +00: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 17:20:15 +01: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 17:20:29 +01:00
# endif
2005-04-29 22:08:33 +01:00
# else
ARM: 6516/1: Allow SMP_ON_UP to work with Thumb-2 kernels.
* __fixup_smp_on_up has been modified with support for the
THUMB2_KERNEL case. For THUMB2_KERNEL only, fixups are split
into halfwords in case of misalignment, since we can't rely on
unaligned accesses working before turning the MMU on.
No attempt is made to optimise the aligned case, since the
number of fixups is typically small, and it seems best to keep
the code as simple as possible.
* Add a rotate in the fixup_smp code in order to support
CPU_BIG_ENDIAN, as suggested by Nicolas Pitre.
* Add an assembly-time sanity-check to ALT_UP() to ensure that
the content really is the right size (4 bytes).
(No check is done for ALT_SMP(). Possibly, this could be fixed
by splitting the two uses ot ALT_SMP() (ALT_SMP...SMP_UP versus
ALT_SMP...SMP_UP_B) into two macros. In the first case,
ALT_SMP needs to expand to >= 4 bytes, not == 4.)
* smp_mpidr.h (which implements ALT_SMP()/ALT_UP() manually due
to macro limitations) has not been modified: the affected
instruction (mov) has no 16-bit encoding, so the correct
instruction size is satisfied in this case.
* A "mode" parameter has been added to smp_dmb:
smp_dmb arm @ assumes 4-byte instructions (for ARM code, e.g. kuser)
smp_dmb @ uses W() to ensure 4-byte instructions for ALT_SMP()
This avoids assembly failures due to use of W() inside smp_dmb,
when assembling pure-ARM code in the vectors page.
There might be a better way to achieve this.
* Kconfig: make SMP_ON_UP depend on
(!THUMB2_KERNEL || !BIG_ENDIAN) i.e., THUMB2_KERNEL is now
supported, but only if !BIG_ENDIAN (The fixup code for Thumb-2
currently assumes little-endian order.)
Tested using a single generic realview kernel on:
ARM RealView PB-A8 (CONFIG_THUMB2_KERNEL={n,y})
ARM RealView PBX-A9 (SMP)
Signed-off-by: Dave Martin <dave.martin@linaro.org>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2010-12-01 15:39:23 +01:00
smp_ d m b a r m
[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 17:20:29 +01:00
1 : ldrex r3 , [ r2 ]
2005-04-29 22:08:33 +01: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 17:20:29 +01:00
teqeq r3 , #1
beq 1 b
2005-04-29 22:08:33 +01: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 17:20:29 +01:00
/* beware -- each __kuser slot must be 8 instructions max */
2010-09-04 10:47:48 +01: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-29 22:08:33 +01: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 17:20:29 +01:00
* none
2005-04-29 22:08:33 +01: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 14:53:10 +01:00
ldr r0 , [ p c , #( 16 - 8 ) ] @ read TLS, set in kuser_get_tls_init
2006-08-18 17:20:15 +01:00
usr_ r e t l r
2010-07-05 14:53:10 +01: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-29 22:08:33 +01: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 12:32:54 +01:00
THUMB( . t h u m b )
2005-04-29 22:08:33 +01:00
2005-04-16 15:20:36 -07:00
/ *
* Vector s t u b s .
*
2005-04-26 15:17:42 +01: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-16 15:20:36 -07: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-05-31 22:22:32 +01: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-16 15:20:36 -07:00
* /
2005-11-06 14:42:37 +00: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-16 15:20:36 -07: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-05-31 22:22:32 +01:00
@
@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
@ (parent CPSR)
@
stmia s p , { r0 , l r } @ save r0, lr
2005-04-16 15:20:36 -07:00
mrs l r , s p s r
2005-05-31 22:22:32 +01:00
str l r , [ s p , #8 ] @ save spsr
2005-04-16 15:20:36 -07:00
@
2005-05-31 22:22:32 +01:00
@ Prepare for SVC32 mode. IRQs remain disabled.
2005-04-16 15:20:36 -07:00
@
2005-05-31 22:22:32 +01:00
mrs r0 , c p s r
2009-07-24 12:32:54 +01: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-05-31 22:22:32 +01:00
msr s p s r _ c x s f , r0
2005-04-16 15:20:36 -07:00
2005-05-31 22:22:32 +01:00
@
@ the branch table must immediately follow this code
@
and l r , l r , #0x0f
2009-07-24 12:32:54 +01:00
THUMB( a d r r0 , 1 f )
THUMB( l d r l r , [ r0 , l r , l s l #2 ] )
2005-11-06 14:42:37 +00:00
mov r0 , s p
2009-07-24 12:32:54 +01:00
ARM( l d r l r , [ p c , l r , l s l #2 ] )
2005-05-31 22:22:32 +01:00
movs p c , l r @ branch to handler in SVC mode
2008-08-28 11:22:32 +01:00
ENDPROC( v e c t o r _ \ n a m e )
2009-07-24 12:32:52 +01:00
.align 2
@ handler addresses follow this label
1 :
2005-04-16 15:20:36 -07:00
.endm
2005-04-26 15:17:42 +01:00
.globl __stubs_start
2005-04-16 15:20:36 -07:00
__stubs_start :
/ *
* Interrupt d i s p a t c h e r
* /
2005-11-06 14:42:37 +00:00
vector_ s t u b i r q , I R Q _ M O D E , 4
2005-04-16 15:20:36 -07: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 14:42:37 +00:00
vector_ s t u b d a b t , A B T _ M O D E , 8
2005-04-16 15:20:36 -07: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 14:42:37 +00:00
vector_ s t u b p a b t , A B T _ M O D E , 4
2005-04-16 15:20:36 -07: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 14:42:37 +00:00
vector_ s t u b u n d , U N D _ M O D E
2005-04-16 15:20:36 -07: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 15:17:42 +01:00
.globl __stubs_end
2005-04-16 15:20:36 -07:00
__stubs_end :
2005-04-26 15:17:42 +01: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-16 15:20:36 -07:00
2005-04-26 15:17:42 +01:00
.globl __vectors_start
__vectors_start :
2009-07-24 12:32:54 +01: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 15:17:42 +01:00
.globl __vectors_end
__vectors_end :
2005-04-16 15:20:36 -07:00
.data
.globl cr_alignment
.globl cr_no_alignment
cr_alignment :
.space 4
cr_no_alignment :
.space 4
2010-12-13 09:42:34 +01:00
# ifdef C O N F I G _ M U L T I _ I R Q _ H A N D L E R
.globl handle_arch_irq
handle_arch_irq :
.space 4
# endif