2005-04-16 15:20:36 -07:00
/ * arch/ a r m 2 6 / k e r n e l / e n t r y . S
*
* Assembled f r o m c h u n k s o f c o d e i n a r c h / a r m
*
* Copyright ( C ) 2 0 0 3 I a n M o l t o n
* Based o n t h e w o r k o f R M K .
*
* /
# include < l i n u x / l i n k a g e . h >
# include < a s m / a s s e m b l e r . h >
2005-09-09 20:35:55 +02:00
# include < a s m / a s m - o f f s e t s . h >
2005-04-16 15:20:36 -07:00
# include < a s m / e r r n o . h >
# include < a s m / h a r d w a r e . h >
# include < a s m / s y s i r q . h >
# include < a s m / t h r e a d _ i n f o . h >
# include < a s m / p a g e . h >
# include < a s m / p t r a c e . h >
.macro zero_fp
# ifndef C O N F I G _ N O _ F R A M E _ P O I N T E R
mov f p , #0
# endif
.endm
.text
@ Bad Abort numbers
@ -----------------
@
# define B A D _ P R E F E T C H 0
# define B A D _ D A T A 1
# define B A D _ A D D R E X C P T N 2
# define B A D _ I R Q 3
# define B A D _ U N D E F I N S T R 4
@ OS version number used in SWIs
@ RISC OS is 0
@ RISC iX is 8
@
# define O S _ N U M B E R 9
# define A R M S W I _ O F F S E T 0 x00 0 f00 0 0
@
@ Stack format (ensured by USER_* and SVC_*)
@ PSR and PC are comined on arm26
@
# define S _ O F F 8
# define S _ O L D _ R 0 6 4
# define S _ P C 6 0
# define S _ L R 5 6
# define S _ S P 5 2
# define S _ I P 4 8
# define S _ F P 4 4
# define S _ R 1 0 4 0
# define S _ R 9 3 6
# define S _ R 8 3 2
# define S _ R 7 2 8
# define S _ R 6 2 4
# define S _ R 5 2 0
# define S _ R 4 1 6
# define S _ R 3 1 2
# define S _ R 2 8
# define S _ R 1 4
# define S _ R 0 0
.macro save_user_regs
str r0 , [ s p , #- 4 ] ! @ Store SVC r0
str l r , [ s p , #- 4 ] ! @ Store user mode PC
sub s p , s p , #15 * 4
stmia s p , { r0 - l r } ^ @ Store the other user-mode regs
mov r0 , r0
.endm
.macro slow_restore_user_regs
ldmia s p , { r0 - l r } ^ @ restore the user regs not including PC
mov r0 , r0
ldr l r , [ s p , #15 * 4 ] @ get user PC
add s p , s p , #15 * 4 + 8 @ free stack
movs p c , l r @ return
.endm
.macro fast_restore_user_regs
add s p , s p , #S _ O F F
ldmib s p , { r1 - l r } ^
mov r0 , r0
ldr l r , [ s p , #15 * 4 ]
add s p , s p , #15 * 4 + 8
movs p c , l r
.endm
.macro save_svc_regs
str s p , [ s p , #- 16 ] !
str l r , [ s p , #8 ]
str l r , [ s p , #4 ]
stmfd s p ! , { r0 - r12 }
mov r0 , #- 1
str r0 , [ s p , #S _ O L D _ R 0 ]
zero_ f p
.endm
.macro save_svc_regs_irq
str s p , [ s p , #- 16 ] !
str l r , [ s p , #4 ]
ldr l r , . L C i r q
ldr l r , [ l r ]
str l r , [ s p , #8 ]
stmfd s p ! , { r0 - r12 }
mov r0 , #- 1
str r0 , [ s p , #S _ O L D _ R 0 ]
zero_ f p
.endm
.macro restore_svc_regs
ldmfd s p , { r0 - p c } ^
.endm
.macro mask_ p c , r d , r m
bic \ r d , \ r m , #P C M A S K
.endm
.macro disable_ i r q s , t e m p
mov \ t e m p , p c
orr \ t e m p , \ t e m p , #P S R _ I _ B I T
teqp \ t e m p , #0
.endm
.macro enable_ i r q s , t e m p
mov \ t e m p , p c
and \ t e m p , \ t e m p , #~ P S R _ I _ B I T
teqp \ t e m p , #0
.endm
.macro initialise_traps_extra
.endm
.macro get_ t h r e a d _ i n f o , r d
mov \ r d , s p , l s r #13
mov \ r d , \ r d , l s l #13
.endm
/ *
* These a r e t h e r e g i s t e r s u s e d i n t h e s y s c a l l h a n d l e r , a n d a l l o w u s t o
* have i n t h e o r y u p t o 7 a r g u m e n t s t o a f u n c t i o n - r0 t o r6 .
*
* Note t h a t t b l = = w h y i s i n t e n t i o n a l .
*
* We m u s t s e t a t l e a s t " t s k " a n d " w h y " w h e n c a l l i n g r e t _ w i t h _ r e s c h e d u l e .
* /
scno . r e q r7 @ syscall number
tbl . r e q r8 @ syscall table pointer
why . r e q r8 @ Linux syscall (!= 0)
tsk . r e q r9 @ current thread_info
/ *
* Get t h e s y s t e m c a l l n u m b e r .
* /
.macro get_scno
mask_ p c l r , l r
ldr s c n o , [ l r , #- 4 ] @ get SWI instruction
.endm
/ *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* /
/ *
* We r e l y o n t h e f a c t t h a t R 0 i s a t t h e b o t t o m o f t h e s t a c k ( d u e t o
* slow/ f a s t r e s t o r e u s e r r e g s ) .
* /
# if S _ R 0 ! = 0
# error " P l e a s e f i x "
# endif
/ *
* This i s t h e f a s t s y s c a l l r e t u r n p a t h . W e d o a s l i t t l e a s
* possible h e r e , a n d t h i s i n c l u d e s s a v i n g r0 b a c k i n t o t h e S V C
* stack.
* /
ret_fast_syscall :
disable_ i r q s r1 @ disable interrupts
ldr r1 , [ t s k , #T I _ F L A G S ]
tst r1 , #_ T I F _ W O R K _ M A S K
bne f a s t _ w o r k _ p e n d i n g
fast_ r e s t o r e _ u s e r _ r e g s
/ *
* Ok, w e n e e d t o d o e x t r a p r o c e s s i n g , e n t e r t h e s l o w p a t h .
* /
fast_work_pending :
str r0 , [ s p , #S _ R 0 + S _ O F F ] ! @ returned r0
work_pending :
tst r1 , #_ T I F _ N E E D _ R E S C H E D
bne w o r k _ r e s c h e d
tst r1 , #_ T I F _ N O T I F Y _ R E S U M E | _ T I F _ S I G P E N D I N G
beq n o _ w o r k _ p e n d i n g
mov r0 , s p @ 'regs'
mov r2 , w h y @ 'syscall'
bl d o _ n o t i f y _ r e s u m e
disable_ i r q s r1 @ disable interrupts
b n o _ w o r k _ p e n d i n g
work_resched :
bl s c h e d u l e
/ *
* " slow" s y s c a l l r e t u r n p a t h . " w h y " t e l l s u s i f t h i s w a s a r e a l s y s c a l l .
* /
ENTRY( r e t _ t o _ u s e r )
ret_slow_syscall :
disable_ i r q s r1 @ disable interrupts
ldr r1 , [ t s k , #T I _ F L A G S ]
tst r1 , #_ T I F _ W O R K _ M A S K
bne w o r k _ p e n d i n g
no_work_pending :
slow_ r e s t o r e _ u s e r _ r e g s
/ *
* This i s h o w w e r e t u r n f r o m a f o r k .
* /
ENTRY( r e t _ f r o m _ f o r k )
bl s c h e d u l e _ t a i l
get_ t h r e a d _ i n f o t s k
ldr r1 , [ t s k , #T I _ F L A G S ] @ c h e c k f o r s y s c a l l t r a c i n g
mov w h y , #1
tst r1 , #_ T I F _ S Y S C A L L _ T R A C E @ a r e w e t r a c i n g s y s c a l l s ?
beq r e t _ s l o w _ s y s c a l l
mov r1 , s p
mov r0 , #1 @ trace exit [IP = 1]
bl s y s c a l l _ t r a c e
b r e t _ s l o w _ s y s c a l l
/ / FIXME - i s t h i s s t r i c t l y n e c e s s a r y ?
# include " c a l l s . S "
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* SWI h a n d l e r
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* /
.align 5
ENTRY( v e c t o r _ s w i )
save_ u s e r _ r e g s
zero_ f p
get_ s c n o
# ifdef C O N F I G _ A L I G N M E N T _ T R A P
ldr i p , _ _ c r _ a l i g n m e n t
ldr i p , [ i p ]
mcr p15 , 0 , i p , c1 , c0 @ update control register
# endif
enable_ i r q s i p
str r4 , [ s p , #- S _ O F F ] ! @ p u s h f i f t h a r g
get_ t h r e a d _ i n f o t s k
ldr i p , [ t s k , #T I _ F L A G S ] @ c h e c k f o r s y s c a l l t r a c i n g
bic s c n o , s c n o , #0xff000000 @ mask off SWI op-code
eor s c n o , s c n o , #O S _ N U M B E R < < 20 @ check OS number
adr t b l , s y s _ c a l l _ t a b l e @ load syscall table pointer
tst i p , #_ T I F _ S Y S C A L L _ T R A C E @ a r e w e t r a c i n g s y s c a l l s ?
bne _ _ s y s _ t r a c e
adral l r , r e t _ f a s t _ s y s c a l l @ set return address
orral l r , l r , #P S R _ I _ B I T | M O D E _ S V C 26 @ Force SVC mode on return
cmp s c n o , #N R _ s y s c a l l s @ c h e c k u p p e r s y s c a l l l i m i t
ldrcc p c , [ t b l , s c n o , l s l #2 ] @ call sys_* routine
add r1 , s p , #S _ O F F
2 : mov w h y , #0 @ no longer a real syscall
cmp s c n o , #A R M S W I _ O F F S E T
eor r0 , s c n o , #O S _ N U M B E R < < 20 @ put OS number back
bcs a r m _ s y s c a l l
b s y s _ n i _ s y s c a l l @ not private func
/ *
* This i s t h e r e a l l y s l o w p a t h . W e ' r e g o i n g t o b e d o i n g
* context s w i t c h e s , a n d w a i t i n g f o r o u r p a r e n t t o r e s p o n d .
* /
__sys_trace :
add r1 , s p , #S _ O F F
mov r0 , #0 @ trace entry [IP = 0]
bl s y s c a l l _ t r a c e
adral l r , _ _ s y s _ t r a c e _ r e t u r n @ set return address
orral l r , l r , #P S R _ I _ B I T | M O D E _ S V C 26 @ Force SVC mode on return
add r1 , s p , #S _ R 0 + S _ O F F @ pointer to regs
cmp s c n o , #N R _ s y s c a l l s @ c h e c k u p p e r s y s c a l l l i m i t
ldmccia r1 , { r0 - r3 } @ have to reload r0 - r3
ldrcc p c , [ t b l , s c n o , l s l #2 ] @ call sys_* routine
b 2 b
__sys_trace_return :
str r0 , [ s p , #S _ R 0 + S _ O F F ] ! @ save returned r0
mov r1 , s p
mov r0 , #1 @ trace exit [IP = 1]
bl s y s c a l l _ t r a c e
b r e t _ s l o w _ s y s c a l l
.align 5
# ifdef C O N F I G _ A L I G N M E N T _ T R A P
.type _ _ cr_ a l i g n m e n t , #o b j e c t
__cr_alignment :
.word cr_alignment
# endif
.type sys_ c a l l _ t a b l e , #o b j e c t
ENTRY( s y s _ c a l l _ t a b l e )
# include " c a l l s . S "
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Special s y s t e m c a l l w r a p p e r s
* /
@ r0 = syscall number
@ r5 = syscall table
.type sys_ s y s c a l l , #f u n c t i o n
sys_syscall :
eor s c n o , r0 , #O S _ N U M B E R < < 20
cmp s c n o , #N R _ s y s c a l l s @ c h e c k r a n g e
stmleia s p , { r5 , r6 } @ shuffle args
movle r0 , r1
movle r1 , r2
movle r2 , r3
movle r3 , r4
ldrle p c , [ t b l , s c n o , l s l #2 ]
b s y s _ n i _ s y s c a l l
sys_fork_wrapper :
add r0 , s p , #S _ O F F
b s y s _ f o r k
sys_vfork_wrapper :
add r0 , s p , #S _ O F F
b s y s _ v f o r k
sys_execve_wrapper :
add r3 , s p , #S _ O F F
b s y s _ e x e c v e
sys_clone_wapper :
add r2 , s p , #S _ O F F
b s y s _ c l o n e
sys_sigsuspend_wrapper :
add r3 , s p , #S _ O F F
b s y s _ s i g s u s p e n d
sys_rt_sigsuspend_wrapper :
add r2 , s p , #S _ O F F
b s y s _ r t _ s i g s u s p e n d
sys_sigreturn_wrapper :
add r0 , s p , #S _ O F F
b s y s _ s i g r e t u r n
sys_rt_sigreturn_wrapper :
add r0 , s p , #S _ O F F
b s y s _ r t _ s i g r e t u r n
sys_sigaltstack_wrapper :
ldr r2 , [ s p , #S _ O F F + S _ S P ]
b d o _ s i g a l t s t a c k
/ *
* Note : off_ 4 k ( r5 ) i s a l w a y s u n i t s o f 4 K . I f w e c a n ' t d o t h e r e q u e s t e d
* offset, w e r e t u r n E I N V A L . F I X M E - t h i s l o s t s o m e s t u f f f r o m a r m 3 2 t o
* ifdefs. c h e c k i t o u t .
* /
sys_mmap2 :
tst r5 , #( ( 1 < < ( P A G E _ S H I F T - 1 2 ) ) - 1 )
moveq r5 , r5 , l s r #P A G E _ S H I F T - 12
streq r5 , [ s p , #4 ]
beq d o _ m m a p2
mov r0 , #- E I N V A L
RETINSTR( m o v ,p c , l r )
/ *
* Design i s s u e s :
* - We h a v e s e v e r a l m o d e s t h a t e a c h v e c t o r c a n b e c a l l e d f r o m ,
* each w i t h i t s o w n s e t o f r e g i s t e r s . O n e n t r y t o a n y v e c t o r ,
* we * m u s t * s a v e t h e r e g i s t e r s u s e d i n * t h a t * m o d e .
*
* - This c o d e m u s t b e a s f a s t a s p o s s i b l e .
*
* There a r e a f e w r e s t r i c t i o n s o n t h e v e c t o r s :
* - the S W I v e c t o r c a n n o t b e c a l l e d f r o m * a n y * n o n - u s e r m o d e
*
* - the F P e m u l a t o r i s * n e v e r * c a l l e d f r o m * a n y * n o n - u s e r m o d e u n d e f i n e d
* instruction.
*
* /
.text
.macro handle_irq
1 : mov r4 , #I O C _ B A S E
ldrb r6 , [ r4 , #0x24 ] @ get high priority first
adr r5 , i r q _ p r i o _ h
teq r6 , #0
ldreqb r6 , [ r4 , #0x14 ] @ get low priority
adreq r5 , i r q _ p r i o _ l
teq r6 , #0 @ If an IRQ happened...
ldrneb r0 , [ r5 , r6 ] @ get IRQ number
movne r1 , s p @ get struct pt_regs
adrne l r , 1 b @ Set return address to 1b
orrne l r , l r , #P S R _ I _ B I T | M O D E _ S V C 26 @ (and force SVC mode)
bne a s m _ d o _ I R Q @ process IRQ (if asserted)
.endm
/ *
* Interrupt t a b l e ( i n c o r p o r a t e s p r i o r i t y )
* /
.macro irq_prio_table
irq_prio_l : .byte 0 , 0 , 1 , 0 , 2 , 2 , 2 , 2 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3
.byte 4 , 0 , 1 , 0 , 2 , 2 , 2 , 2 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3
.byte 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5
.byte 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5
.byte 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3
.byte 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3
.byte 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5
.byte 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5
.byte 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7
.byte 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7
.byte 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7
.byte 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7
.byte 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7
.byte 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7
.byte 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7
.byte 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7
irq_prio_h : .byte 0 , 8 , 9 , 8 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 2 , 8 , 9 , 8 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 3 , 1 3 , 1 3 , 1 3 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 3 , 1 3 , 1 3 , 1 3 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 4 , 1 4 , 1 4 , 1 4 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 4 , 1 4 , 1 4 , 1 4 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 3 , 1 3 , 1 3 , 1 3 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 3 , 1 3 , 1 3 , 1 3 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 5 , 1 5 , 1 5 , 1 5 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 5 , 1 5 , 1 5 , 1 5 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 3 , 1 3 , 1 3 , 1 3 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 3 , 1 3 , 1 3 , 1 3 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 5 , 1 5 , 1 5 , 1 5 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 5 , 1 5 , 1 5 , 1 5 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 3 , 1 3 , 1 3 , 1 3 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.byte 1 3 , 1 3 , 1 3 , 1 3 , 1 0 , 1 0 , 1 0 , 1 0 , 1 1 , 1 1 , 1 1 , 1 1 , 1 0 , 1 0 , 1 0 , 1 0
.endm
# if 1
/ *
* Uncomment t h e s e i f y o u w i s h t o g e t m o r e d e b u g g i n g i n t o a b o u t d a t a a b o r t s .
* FIXME - I b e t w e c a n f i n d a w a y t o e n c o d e t h e s e a n d k e e p p e r f o r m a n c e .
* /
# define F A U L T _ C O D E _ L D R S T R P O S T 0 x80
# define F A U L T _ C O D E _ L D R S T R P R E 0 x40
# define F A U L T _ C O D E _ L D R S T R R E G 0 x20
# define F A U L T _ C O D E _ L D M S T M 0 x10
# define F A U L T _ C O D E _ L D C S T C 0 x08
# endif
# define F A U L T _ C O D E _ P R E F E T C H 0 x04
# define F A U L T _ C O D E _ W R I T E 0 x02
# define F A U L T _ C O D E _ F O R C E C O W 0 x01
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Undefined F I Q s
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* /
_unexp_fiq : ldr s p , . L C f i q
mov r12 , #I O C _ B A S E
strb r12 , [ r12 , #0x38 ] @ Disable FIQ register
teqp p c , #P S R _ I _ B I T | P S R _ F _ B I T | M O D E _ S V C 26
mov r0 , r0
stmfd s p ! , { r0 - r3 , i p , l r }
adr r0 , L f i q m s g
bl p r i n t k
ldmfd s p ! , { r0 - r3 , i p , l r }
teqp p c , #P S R _ I _ B I T | P S R _ F _ B I T | M O D E _ F I Q 26
mov r0 , r0
movs p c , l r
Lfiqmsg : .ascii " *** Unexpected FIQ\n\0 "
.align
.LCfiq : .word __temp_fiq
.LCirq : .word __temp_irq
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Undefined i n s t r u c t i o n h a n d l e r
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Handles f l o a t i n g p o i n t i n s t r u c t i o n s
* /
vector_undefinstr :
tst l r , #M O D E _ S V C 26 @ did we come from a non-user mode?
bne _ _ u n d _ s v c @ yes - deal with it.
/* Otherwise, fall through for the user-space (common) case. */
save_ u s e r _ r e g s
zero_ f p @ zero frame pointer
teqp p c , #P S R _ I _ B I T | M O D E _ S V C 26 @ disable IRQs
.Lbug_undef :
ldr r4 , . L C 2
ldr p c , [ r4 ] @ Call FP module entry point
/* FIXME - should we trap for a null pointer here? */
/* The SVC mode case */
__und_svc : save_ s v c _ r e g s @ Non-user mode
mask_ p c r0 , l r
and r2 , l r , #3
sub r0 , r0 , #4
mov r1 , s p
bl d o _ u n d e f i n s t r
restore_ s v c _ r e g s
/ * We g e t h e r e i f t h e F P e m u l a t o r d o e s n t h a n d l e t h e u n d e f i n s t r .
* If t h e i n s n W A S h a n d l e d , t h e e m u l a t o r j u m p s t o r e t _ f r o m _ e x c e p t i o n b y i t s e l f /
* /
.globl fpundefinstr
fpundefinstr :
mov r0 , l r
mov r1 , s p
teqp p c , #M O D E _ S V C 26
bl d o _ u n d e f i n s t r
b r e t _ f r o m _ e x c e p t i o n @ Normal FP exit
# if d e f i n e d C O N F I G _ F P E _ N W F P E | | d e f i n e d C O N F I G _ F P E _ F A S T F P E
/* The FPE is always present */
.equ fpe_ n o t _ p r e s e n t , 0
# else
/ * We g e t h e r e i f a n u n d e f i n e d i n s t r u c t i o n h a p p e n s a n d t h e f l o a t i n g
* point e m u l a t o r i s n o t p r e s e n t . I f t h e o f f e n d i n g i n s t r u c t i o n w a s
* a W F S , w e j u s t p e r f o r m a n o r m a l r e t u r n a s i f w e h a d e m u l a t e d t h e
* operation. T h i s i s a h a c k t o a l l o w s o m e b a s i c u s e r l a n d b i n a r i e s
* to r u n s o t h a t t h e e m u l a t o r m o d u l e p r o p e r c a n b e l o a d e d . - - p h i l b
* FIXME - p r o b a b l y a b r o k e n u s e l e s s h a c k . . .
* /
fpe_not_present :
adr r10 , w f s _ m a s k _ d a t a
ldmia r10 , { r4 , r5 , r6 , r7 , r8 }
ldr r10 , [ s p , #S _ P C ] @ L o a d P C
sub r10 , r10 , #4
mask_ p c r10 , r10
ldrt r10 , [ r10 ] @ get instruction
and r5 , r10 , r5
teq r5 , r4 @ Is it WFS?
beq r e t _ f r o m _ e x c e p t i o n
and r5 , r10 , r8
teq r5 , r6 @ Is it LDF/STF on sp or fp?
teqne r5 , r7
bne f p u n d e f i n s t r
tst r10 , #0x00200000 @ Does it have WB
beq r e t _ f r o m _ e x c e p t i o n
and r4 , r10 , #255 @ get offset
and r6 , r10 , #0x000f0000
tst r10 , #0x00800000 @ +/-
ldr r5 , [ s p , r6 , l s r #14 ] @ Load reg
rsbeq r4 , r4 , #0
add r5 , r5 , r4 , l s l #2
str r5 , [ s p , r6 , l s r #14 ] @ Save reg
b r e t _ f r o m _ e x c e p t i o n
wfs_mask_data : .word 0x0e200110 @ WFS/RFS
.word 0x0fef0fff
.word 0x0d0d0100 @ LDF [sp]/STF [sp]
.word 0x0d0b0100 @ LDF [fp]/STF [fp]
.word 0x0f0f0f00
# endif
.LC2 : .word fp_enter
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Prefetch a b o r t h a n d l e r
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* /
# define D E B U G _ U N D E F
/* remember: lr = USR pc */
vector_prefetch :
sub l r , l r , #4
tst l r , #M O D E _ S V C 26
bne _ _ p a b t _ i n v a l i d
save_ u s e r _ r e g s
teqp p c , #M O D E _ S V C 26 @ Enable IRQs...
mask_ p c r0 , l r @ Address of abort
mov r1 , s p @ Tasks registers
bl d o _ P r e f e t c h A b o r t
teq r0 , #0 @ If non-zero, we believe this abort..
bne r e t _ f r o m _ e x c e p t i o n
# ifdef D E B U G _ U N D E F
adr r0 , t
bl p r i n t k
# endif
ldr l r , [ s p ,#S _ P C ] @ F I X M E p r o g r a m t o t e s t t h i s o n . I t h i n k i t s
b . L b u g _ u n d e f @ broken at the moment though!)
__pabt_invalid : save_ s v c _ r e g s
mov r0 , s p @ Prefetch aborts are definitely *not*
mov r1 , #B A D _ P R E F E T C H @ a l l o w e d i n n o n - u s e r m o d e s . W e c a n t
and r2 , l r , #3 @ recover from this problem.
b b a d _ m o d e
# ifdef D E B U G _ U N D E F
t : .ascii " *** undef ***\r\n\0 "
.align
# endif
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* 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 ) .
* In o r d e r t o d e b u g t h e r e a s o n f o r a d d r e s s e x c e p t i o n s i n n o n - u s e r m o d e s ,
* we h a v e t o o b t a i n a l l t h e r e g i s t e r s s o t h a t w e c a n s e e w h a t ' s g o i n g o n .
* /
vector_addrexcptn :
sub l r , l r , #8
tst l r , #3
bne L a d d r e x c p t n _ n o t _ u s e r
save_ u s e r _ r e g s
teq p c , #M O D E _ S V C 26
mask_ p c r0 , l r @ Point to instruction
mov r1 , s p @ Point to registers
mov r2 , #0x400
mov l r , p c
bl d o _ e x c p t
b r e t _ f r o m _ e x c e p t i o n
Laddrexcptn_not_user :
save_ s v c _ r e g s
and r2 , l r , #3
teq r2 , #3
bne L a d d r e x c p t n _ i l l e g a l _ m o d e
teqp p c , #M O D E _ S V C 26
mask_ p c r0 , l r
mov r1 , s p
orr r2 , r2 , #0x400
bl d o _ e x c p t
ldmia s p , { r0 - l r } @ I cant remember the reason I changed this...
add s p , s p , #15 * 4
movs p c , l r
Laddrexcptn_illegal_mode :
mov r0 , s p
str l r , [ s p , #- 4 ] !
orr r1 , r2 , #P S R _ I _ B I T | P S R _ F _ B I T
teqp r1 , #0 @ change into mode (wont be user mode)
mov r0 , r0
mov r1 , r8 @ Any register from r8 - r14 can be banked
mov r2 , r9
mov r3 , r10
mov r4 , r11
mov r5 , r12
mov r6 , r13
mov r7 , r14
teqp p c , #P S R _ F _ B I T | M O D E _ S V C 26 @ back to svc
mov r0 , r0
stmfd s p ! , { r1 - r7 }
ldmia r0 , { r0 - r7 }
stmfd s p ! , { r0 - r7 }
mov r0 , s p
mov r1 , #B A D _ A D D R E X C P T N
b b a d _ m o d e
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Interrupt ( I R Q ) h a n d l e r
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Note : if t h e I R Q w a s t a k e n w h i l s t i n u s e r m o d e , t h e n * n o * k e r n e l r o u t i n e
* is r u n n i n g , s o d o n o t h a v e t o s a v e s v c l r .
*
* Entered i n I R Q m o d e .
* /
vector_IRQ : ldr s p , . L C i r q @ Setup some temporary stack
sub l r , l r , #4
str l r , [ s p ] @ push return address
tst l r , #3
bne _ _ i r q _ n o n _ u s r
__irq_usr : teqp p c , #P S R _ I _ B I T | M O D E _ S V C 26 @ Enter SVC mode
mov r0 , r0
ldr l r , . L C i r q
ldr l r , [ l r ] @ Restore lr for jump back to USR
save_ u s e r _ r e g s
handle_ i r q
mov w h y , #0
get_ t h r e a d _ i n f o t s k
b r e t _ t o _ u s e r
@ Place the IRQ priority table here so that the handle_irq macros above
@ and below here can access it.
irq_ p r i o _ t a b l e
__irq_non_usr : teqp p c , #P S R _ I _ B I T | M O D E _ S V C 26 @ Enter SVC mode
mov r0 , r0
save_ s v c _ r e g s _ i r q
and r2 , l r , #3
teq r2 , #3
bne _ _ i r q _ i n v a l i d @ IRQ not from SVC mode
handle_ i r q
restore_ s v c _ r e g s
__irq_invalid : mov r0 , s p
mov r1 , #B A D _ I R Q
b b a d _ m o d e
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Data a b o r t h a n d l e r c o d e
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* This h a n d l e s b o t h e x c e p t i o n s f r o m u s e r a n d S V C m o d e s , c o m p u t e s t h e a d d r e s s
* range o f t h e p r o b l e m , a n d d o e s a n y c o r r e c t i o n t h a t i s r e q u i r e d . I t t h e n
* calls t h e k e r n e l d a t a a b o r t r o u t i n e .
*
* This i s w h e r e I w i s h t h a t t h e A R M w o u l d t e l l y o u w h i c h a d d r e s s a b o r t e d .
* /
vector_data : sub l r , l r , #8 @ Correct lr
tst l r , #3
bne L d a t a _ n o t _ u s e r
save_ u s e r _ r e g s
teqp p c , #M O D E _ S V C 26
mask_ p c r0 , l r
bl L d a t a _ d o
b r e t _ f r o m _ e x c e p t i o n
Ldata_not_user :
save_ s v c _ r e g s
and r2 , l r , #3
teq r2 , #3
bne L d a t a _ i l l e g a l _ m o d e
tst l r , #P S R _ I _ B I T
teqeqp p c , #M O D E _ S V C 26
mask_ p c r0 , l r
bl L d a t a _ d o
restore_ s v c _ r e g s
Ldata_illegal_mode :
mov r0 , s p
mov r1 , #B A D _ D A T A
b b a d _ m o d e
Ldata_do : mov r3 , s p
ldr r4 , [ r0 ] @ Get instruction
mov r2 , #0
tst r4 , #1 < < 2 0 @ Check to see if it is a write instruction
orreq r2 , r2 , #F A U L T _ C O D E _ W R I T E @ I n d i c a t e w r i t e i n s t r u c t i o n
mov r1 , r4 , l s r #22 @ Now branch to the relevent processing routine
and r1 , r1 , #15 < < 2
add p c , p c , r1
movs p c , l r
b L d a t a _ u n k n o w n
b L d a t a _ u n k n o w n
b L d a t a _ u n k n o w n
b L d a t a _ u n k n o w n
b L d a t a _ l d r s t r _ p o s t @ ldr rd, [rn], #m
b L d a t a _ l d r s t r _ n u m i n d e x @ ldr rd, [rn, #m] @ RegVal
b L d a t a _ l d r s t r _ p o s t @ ldr rd, [rn], rm
b L d a t a _ l d r s t r _ r e g i n d e x @ ldr rd, [rn, rm]
b L d a t a _ l d m s t m @ ldm*a rn, <rlist>
b L d a t a _ l d m s t m @ ldm*b rn, <rlist>
b L d a t a _ u n k n o w n
b L d a t a _ u n k n o w n
b L d a t a _ l d r s t r _ p o s t @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m
b L d a t a _ l d c s t c _ p r e @ ldc rd, [rn, #m]
b L d a t a _ u n k n o w n
Ldata_unknown : @ Part of jumptable
mov r0 , r1
mov r1 , r4
mov r2 , r3
b b a d d a t a a b o r t
Ldata_ldrstr_post :
mov r0 , r4 , l s r #14 @ Get Rn
and r0 , r0 , #15 < < 2 @ Mask out reg.
teq r0 , #15 < < 2
ldr r0 , [ r3 , r0 ] @ Get register
biceq r0 , r0 , #P C M A S K
mov r1 , r0
# ifdef F A U L T _ C O D E _ L D R S T R P O S T
orr r2 , r2 , #F A U L T _ C O D E _ L D R S T R P O S T
# endif
b d o _ D a t a A b o r t
Ldata_ldrstr_numindex :
mov r0 , r4 , l s r #14 @ Get Rn
and r0 , r0 , #15 < < 2 @ Mask out reg.
teq r0 , #15 < < 2
ldr r0 , [ r3 , r0 ] @ Get register
mov r1 , r4 , l s l #20
biceq r0 , r0 , #P C M A S K
tst r4 , #1 < < 2 3
addne r0 , r0 , r1 , l s r #20
subeq r0 , r0 , r1 , l s r #20
mov r1 , r0
# ifdef F A U L T _ C O D E _ L D R S T R P R E
orr r2 , r2 , #F A U L T _ C O D E _ L D R S T R P R E
# endif
b d o _ D a t a A b o r t
Ldata_ldrstr_regindex :
mov r0 , r4 , l s r #14 @ Get Rn
and r0 , r0 , #15 < < 2 @ Mask out reg.
teq r0 , #15 < < 2
ldr r0 , [ r3 , r0 ] @ Get register
and r7 , r4 , #15
biceq r0 , r0 , #P C M A S K
teq r7 , #15 @ Check for PC
ldr r7 , [ r3 , r7 , l s l #2 ] @ Get Rm
and r8 , r4 , #0x60 @ Get shift types
biceq r7 , r7 , #P C M A S K
mov r9 , r4 , l s r #7 @ Get shift amount
and r9 , r9 , #31
teq r8 , #0
moveq r7 , r7 , l s l r9
teq r8 , #0x20 @ LSR shift
moveq r7 , r7 , l s r r9
teq r8 , #0x40 @ ASR shift
moveq r7 , r7 , a s r r9
teq r8 , #0x60 @ ROR shift
moveq r7 , r7 , r o r r9
tst r4 , #1 < < 2 3
addne r0 , r0 , r7
subeq r0 , r0 , r7 @ Apply correction
mov r1 , r0
# ifdef F A U L T _ C O D E _ L D R S T R R E G
orr r2 , r2 , #F A U L T _ C O D E _ L D R S T R R E G
# endif
b d o _ D a t a A b o r t
Ldata_ldmstm :
mov r7 , #0x11
orr r7 , r7 , r7 , l s l #8
and r0 , r4 , r7
and r1 , r4 , r7 , l s l #1
add r0 , r0 , r1 , l s r #1
and r1 , r4 , r7 , l s l #2
add r0 , r0 , r1 , l s r #2
and r1 , r4 , r7 , l s l #3
add r0 , r0 , r1 , l s r #3
add r0 , r0 , r0 , l s r #8
add r0 , r0 , r0 , l s r #4
and r7 , r0 , #15 @ r7 = no. of registers to transfer.
mov r5 , r4 , l s r #14 @ Get Rn
and r5 , r5 , #15 < < 2
ldr r0 , [ r3 , r5 ] @ Get reg
eor r6 , r4 , r4 , l s l #2
tst r6 , #1 < < 2 3 @ Check inc/dec ^ writeback
rsbeq r7 , r7 , #0
add r7 , r0 , r7 , l s l #2 @ Do correction (signed)
subne r1 , r7 , #1
subeq r1 , r0 , #1
moveq r0 , r7
tst r4 , #1 < < 2 1 @ Check writeback
strne r7 , [ r3 , r5 ]
eor r6 , r4 , r4 , l s l #1
tst r6 , #1 < < 2 4 @ Check Pre/Post ^ inc/dec
addeq r0 , r0 , #4
addeq r1 , r1 , #4
teq r5 , #15 * 4 @ CHECK FOR PC
biceq r1 , r1 , #P C M A S K
biceq r0 , r0 , #P C M A S K
# ifdef F A U L T _ C O D E _ L D M S T M
orr r2 , r2 , #F A U L T _ C O D E _ L D M S T M
# endif
b d o _ D a t a A b o r t
Ldata_ldcstc_pre :
mov r0 , r4 , l s r #14 @ Get Rn
and r0 , r0 , #15 < < 2 @ Mask out reg.
teq r0 , #15 < < 2
ldr r0 , [ r3 , r0 ] @ Get register
mov r1 , r4 , l s l #24 @ Get offset
biceq r0 , r0 , #P C M A S K
tst r4 , #1 < < 2 3
addne r0 , r0 , r1 , l s r #24
subeq r0 , r0 , r1 , l s r #24
mov r1 , r0
# ifdef F A U L T _ C O D E _ L D C S T C
orr r2 , r2 , #F A U L T _ C O D E _ L D C S T C
# endif
b d o _ D a t a A b o r t
/ *
* 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 )
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
.data
ENTRY( f p _ e n t e r )
.word fpe_not_present
.text
/ *
* Register s w i t c h f o r o l d e r 2 6 - b i t o n l y A R M s
* /
ENTRY( _ _ s w i t c h _ t o )
add r0 , r0 , #T I _ C P U _ S A V E
stmia r0 , { r4 - s l , f p , s p , l r }
add r1 , r1 , #T I _ C P U _ S A V E
ldmia r1 , { r4 - s l , f p , s p , p c } ^
/ *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Low- l e v e l i n t e r f a c e c o d e
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Trap i n i t i a l i s a t i o n
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* Note - F I Q c o d e h a s c h a n g e d . T h e d e f a u l t i s a c o u p l e o f w o r d s i n 0 x1 c , 0 x20
* that c a l l _ u n e x p _ f i q . N o w e v e r , w e n o w c o p y t h e F I Q r o u t i n e t o 0 x1 c ( r e m o v e s
* some e x c e s s c y c l e s ) .
*
* What w e n e e d t o p u t i n t o 0 - 0 x1 c a r e b r a n c h e s t o b r a n c h t o t h e k e r n e l .
* /
.section " .init .text " , # alloc,#e x e c i n s t r
.Ljump_addresses :
swi S Y S _ E R R O R 0
.word vector_undefinstr - 1 2
.word vector_swi - 1 6
.word vector_prefetch - 2 0
.word vector_data - 2 4
.word vector_addrexcptn - 2 8
.word vector_IRQ - 3 2
.word _unexp_fiq - 3 6
b . + 8
/ *
* initialise t h e t r a p s y s t e m
* /
ENTRY( _ _ t r a p _ i n i t )
stmfd s p ! , { r4 - r7 , l r }
adr r1 , . L j u m p _ a d d r e s s e s
ldmia r1 , { r1 - r7 , i p , l r }
orr r2 , l r , r2 , l s r #2
orr r3 , l r , r3 , l s r #2
orr r4 , l r , r4 , l s r #2
orr r5 , l r , r5 , l s r #2
orr r6 , l r , r6 , l s r #2
orr r7 , l r , r7 , l s r #2
orr i p , l r , i p , l s r #2
mov r0 , #0
stmia r0 , { r1 - r7 , i p }
ldmfd s p ! , { r4 - r7 , p c } ^
.bss
__temp_irq : .space 4 @ saved lr_irq
__temp_fiq : .space 128