2005-04-16 15:20:36 -07:00
/ *
* linux/ a r c h / x86 _ 6 4 / e n t r y . S
*
* Copyright ( C ) 1 9 9 1 , 1 9 9 2 L i n u s T o r v a l d s
* Copyright ( C ) 2 0 0 0 , 2 0 0 1 , 2 0 0 2 A n d i K l e e n S u S E L a b s
* Copyright ( C ) 2 0 0 0 P a v e l M a c h e k < p a v e l @suse.cz>
*
* $ Id$
* /
/ *
* entry. S c o n t a i n s t h e s y s t e m - c a l l a n d f a u l t l o w - l e v e l h a n d l i n g r o u t i n e s .
*
* NOTE : This c o d e h a n d l e s s i g n a l - r e c o g n i t i o n , w h i c h h a p p e n s e v e r y t i m e
* after a n i n t e r r u p t a n d a f t e r e a c h s y s t e m c a l l .
*
* Normal s y s c a l l s a n d i n t e r r u p t s d o n ' t s a v e a f u l l s t a c k f r a m e , t h i s i s
* only d o n e f o r s y s c a l l t r a c i n g , s i g n a l s o r f o r k / e x e c e t . a l .
*
* A n o t e o n t e r m i n o l o g y :
* - top o f s t a c k : A r c h i t e c t u r e d e f i n e d i n t e r r u p t f r a m e f r o m S S t o R I P
* at t h e t o p o f t h e k e r n e l p r o c e s s s t a c k .
* - partial s t a c k f r a m e : p a r t i a l l y s a v e d r e g i s t e r s u p t o R 1 1 .
* - full s t a c k f r a m e : L i k e p a r t i a l s t a c k f r a m e , b u t a l l r e g i s t e r s a v e d .
*
* TODO :
* - schedule i t c a r e f u l l y f o r t h e f i n a l h a r d w a r e .
* /
# define A S S E M B L Y 1
# include < l i n u x / c o n f i g . h >
# include < l i n u x / l i n k a g e . h >
# include < a s m / s e g m e n t . h >
# include < a s m / s m p . h >
# include < a s m / c a c h e . h >
# include < a s m / e r r n o . h >
# include < a s m / d w a r f2 . h >
# include < a s m / c a l l i n g . h >
2005-09-09 21:28:48 +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 / m s r . h >
# include < a s m / u n i s t d . h >
# include < a s m / t h r e a d _ i n f o . h >
# include < a s m / h w _ i r q . h >
2006-01-16 01:56:39 +01:00
# include < a s m / p a g e . h >
2005-04-16 15:20:36 -07:00
.code64
2005-04-16 15:25:05 -07:00
# ifndef C O N F I G _ P R E E M P T
2005-04-16 15:20:36 -07:00
# define r e t i n t _ k e r n e l r e t i n t _ r e s t o r e _ a r g s
# endif
/ *
* C c o d e i s n o t s u p p o s e d t o k n o w a b o u t u n d e f i n e d t o p o f s t a c k . E v e r y t i m e
* a C f u n c t i o n w i t h a n p t _ r e g s a r g u m e n t i s c a l l e d f r o m t h e S Y S C A L L b a s e d
* fast p a t h F I X U P _ T O P _ O F _ S T A C K i s n e e d e d .
* RESTORE_ T O P _ O F _ S T A C K s y n c s t h e s y s c a l l s t a t e a f t e r a n y p o s s i b l e p t r e g s
* manipulation.
* /
/* %rsp:at FRAMEEND */
.macro FIXUP_TOP_OF_STACK tmp
movq % g s : p d a _ o l d r s p ,\ t m p
movq \ t m p ,R S P ( % r s p )
movq $ _ _ U S E R _ D S ,S S ( % r s p )
movq $ _ _ U S E R _ C S ,C S ( % r s p )
movq $ - 1 ,R C X ( % r s p )
movq R 1 1 ( % r s p ) ,\ t m p / * g e t e f l a g s * /
movq \ t m p ,E F L A G S ( % r s p )
.endm
.macro RESTORE_TOP_OF_STACK tmp,o f f s e t =0
movq R S P - \ o f f s e t ( % r s p ) ,\ t m p
movq \ t m p ,% g s : p d a _ o l d r s p
movq E F L A G S - \ o f f s e t ( % r s p ) ,\ t m p
movq \ t m p ,R 1 1 - \ o f f s e t ( % r s p )
.endm
.macro FAKE_STACK_FRAME child_ r i p
/* push in order ss, rsp, eflags, cs, rip */
2005-07-28 21:15:48 -07:00
xorl % e a x , % e a x
2005-04-16 15:20:36 -07:00
pushq % r a x / * s s * /
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-09-12 18:49:24 +02:00
/*CFI_REL_OFFSET ss,0*/
2005-04-16 15:20:36 -07:00
pushq % r a x / * r s p * /
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-09-12 18:49:24 +02:00
CFI_ R E L _ O F F S E T r s p ,0
2005-04-16 15:20:36 -07:00
pushq $ ( 1 < < 9 ) / * e f l a g s - i n t e r r u p t s o n * /
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-09-12 18:49:24 +02:00
/*CFI_REL_OFFSET rflags,0*/
2005-04-16 15:20:36 -07:00
pushq $ _ _ K E R N E L _ C S / * c s * /
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-09-12 18:49:24 +02:00
/*CFI_REL_OFFSET cs,0*/
2005-04-16 15:20:36 -07:00
pushq \ c h i l d _ r i p / * r i p * /
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-09-12 18:49:24 +02:00
CFI_ R E L _ O F F S E T r i p ,0
2005-04-16 15:20:36 -07:00
pushq % r a x / * o r i g r a x * /
CFI_ A D J U S T _ C F A _ O F F S E T 8
.endm
.macro UNFAKE_STACK_FRAME
addq $ 8 * 6 , % r s p
CFI_ A D J U S T _ C F A _ O F F S E T - ( 6 * 8 )
.endm
2005-09-12 18:49:24 +02:00
.macro CFI_DEFAULT_STACK start=1
.if \ start
CFI_ S T A R T P R O C s i m p l e
CFI_ D E F _ C F A r s p ,S S + 8
.else
CFI_ D E F _ C F A _ O F F S E T S S + 8
.endif
CFI_ R E L _ O F F S E T r15 ,R 1 5
CFI_ R E L _ O F F S E T r14 ,R 1 4
CFI_ R E L _ O F F S E T r13 ,R 1 3
CFI_ R E L _ O F F S E T r12 ,R 1 2
CFI_ R E L _ O F F S E T r b p ,R B P
CFI_ R E L _ O F F S E T r b x ,R B X
CFI_ R E L _ O F F S E T r11 ,R 1 1
CFI_ R E L _ O F F S E T r10 ,R 1 0
CFI_ R E L _ O F F S E T r9 ,R 9
CFI_ R E L _ O F F S E T r8 ,R 8
CFI_ R E L _ O F F S E T r a x ,R A X
CFI_ R E L _ O F F S E T r c x ,R C X
CFI_ R E L _ O F F S E T r d x ,R D X
CFI_ R E L _ O F F S E T r s i ,R S I
CFI_ R E L _ O F F S E T r d i ,R D I
CFI_ R E L _ O F F S E T r i p ,R I P
/*CFI_REL_OFFSET cs,CS*/
/*CFI_REL_OFFSET rflags,EFLAGS*/
CFI_ R E L _ O F F S E T r s p ,R S P
/*CFI_REL_OFFSET ss,SS*/
2005-04-16 15:20:36 -07:00
.endm
/ *
* A n e w l y f o r k e d p r o c e s s d i r e c t l y c o n t e x t s w i t c h e s i n t o t h i s .
* /
/* rdi: prev */
ENTRY( r e t _ f r o m _ f o r k )
CFI_ D E F A U L T _ S T A C K
call s c h e d u l e _ t a i l
GET_ T H R E A D _ I N F O ( % r c x )
testl $ ( _ T I F _ S Y S C A L L _ T R A C E | _ T I F _ S Y S C A L L _ A U D I T ) ,t h r e a d i n f o _ f l a g s ( % r c x )
jnz r f f _ t r a c e
rff_action :
RESTORE_ R E S T
testl $ 3 ,C S - A R G O F F S E T ( % r s p ) # f r o m k e r n e l _ t h r e a d ?
je i n t _ r e t _ f r o m _ s y s _ c a l l
testl $ _ T I F _ I A 3 2 ,t h r e a d i n f o _ f l a g s ( % r c x )
jnz i n t _ r e t _ f r o m _ s y s _ c a l l
RESTORE_ T O P _ O F _ S T A C K % r d i ,A R G O F F S E T
jmp r e t _ f r o m _ s y s _ c a l l
rff_trace :
movq % r s p ,% r d i
call s y s c a l l _ t r a c e _ l e a v e
GET_ T H R E A D _ I N F O ( % r c x )
jmp r f f _ a c t i o n
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
END( r e t _ f r o m _ f o r k )
2005-04-16 15:20:36 -07:00
/ *
* System c a l l e n t r y . U p t o 6 a r g u m e n t s i n r e g i s t e r s a r e s u p p o r t e d .
*
* SYSCALL d o e s n o t s a v e a n y t h i n g o n t h e s t a c k a n d d o e s n o t c h a n g e t h e
* stack p o i n t e r .
* /
/ *
* Register s e t u p :
* rax s y s t e m c a l l n u m b e r
* rdi a r g 0
* rcx r e t u r n a d d r e s s f o r s y s c a l l / s y s r e t , C a r g 3
* rsi a r g 1
* rdx a r g 2
* r1 0 a r g 3 ( - - > m o v e d t o r c x f o r C )
* r8 a r g 4
* r9 a r g 5
* r1 1 e f l a g s f o r s y s c a l l / s y s r e t , t e m p o r a r y f o r C
* r1 2 - r15 ,r b p ,r b x s a v e d b y C c o d e , n o t t o u c h e d .
*
* Interrupts a r e o f f o n e n t r y .
* Only c a l l e d f r o m u s e r s p a c e .
*
* XXX i f w e h a d a f r e e s c r a t c h r e g i s t e r w e c o u l d s a v e t h e R S P i n t o t h e s t a c k f r a m e
* and r e p o r t i t p r o p e r l y i n p s . U n f o r t u n a t e l y w e h a v e n ' t .
2006-04-07 19:50:00 +02:00
*
* When u s e r c a n c h a n g e t h e f r a m e s a l w a y s f o r c e I R E T . T h a t i s b e c a u s e
* it d e a l s w i t h u n c a n o n i c a l a d d r e s s e s b e t t e r . S Y S R E T h a s t r o u b l e
* with t h e m d u e t o b u g s i n b o t h A M D a n d I n t e l C P U s .
2005-04-16 15:20:36 -07:00
* /
ENTRY( s y s t e m _ c a l l )
2005-09-12 18:49:24 +02:00
CFI_ S T A R T P R O C s i m p l e
CFI_ D E F _ C F A r s p ,0
CFI_ R E G I S T E R r i p ,r c x
/*CFI_REGISTER rflags,r11*/
2005-04-16 15:20:36 -07:00
swapgs
movq % r s p ,% g s : p d a _ o l d r s p
movq % g s : p d a _ k e r n e l s t a c k ,% r s p
sti
SAVE_ A R G S 8 ,1
movq % r a x ,O R I G _ R A X - A R G O F F S E T ( % r s p )
2005-09-12 18:49:24 +02:00
movq % r c x ,R I P - A R G O F F S E T ( % r s p )
CFI_ R E L _ O F F S E T r i p ,R I P - A R G O F F S E T
2005-04-16 15:20:36 -07:00
GET_ T H R E A D _ I N F O ( % r c x )
testl $ ( _ T I F _ S Y S C A L L _ T R A C E | _ T I F _ S Y S C A L L _ A U D I T | _ T I F _ S E C C O M P ) ,t h r e a d i n f o _ f l a g s ( % r c x )
2005-09-12 18:49:24 +02:00
CFI_ R E M E M B E R _ S T A T E
2005-04-16 15:20:36 -07:00
jnz t r a c e s y s
cmpq $ _ _ N R _ s y s c a l l _ m a x ,% r a x
ja b a d s y s
movq % r10 ,% r c x
call * s y s _ c a l l _ t a b l e ( ,% r a x ,8 ) # X X X : r i p r e l a t i v e
movq % r a x ,R A X - A R G O F F S E T ( % r s p )
/ *
* Syscall r e t u r n p a t h e n d i n g w i t h S Y S R E T ( f a s t p a t h )
* Has i n c o m p l e t e s t a c k f r a m e a n d u n d e f i n e d t o p o f s t a c k .
* /
.globl ret_from_sys_call
ret_from_sys_call :
2005-04-16 15:25:02 -07:00
movl $ _ T I F _ A L L W O R K _ M A S K ,% e d i
2005-04-16 15:20:36 -07:00
/* edi: flagmask */
sysret_check :
GET_ T H R E A D _ I N F O ( % r c x )
cli
movl t h r e a d i n f o _ f l a g s ( % r c x ) ,% e d x
andl % e d i ,% e d x
2005-09-12 18:49:24 +02:00
CFI_ R E M E M B E R _ S T A T E
2005-04-16 15:20:36 -07:00
jnz s y s r e t _ c a r e f u l
movq R I P - A R G O F F S E T ( % r s p ) ,% r c x
2005-09-12 18:49:24 +02:00
CFI_ R E G I S T E R r i p ,r c x
2005-04-16 15:20:36 -07:00
RESTORE_ A R G S 0 ,- A R G _ S K I P ,1
2005-09-12 18:49:24 +02:00
/*CFI_REGISTER rflags,r11*/
2005-04-16 15:20:36 -07:00
movq % g s : p d a _ o l d r s p ,% r s p
swapgs
sysretq
/* Handle reschedules */
/* edx: work, edi: workmask */
sysret_careful :
2005-09-12 18:49:24 +02:00
CFI_ R E S T O R E _ S T A T E
2005-04-16 15:20:36 -07:00
bt $ T I F _ N E E D _ R E S C H E D ,% e d x
jnc s y s r e t _ s i g n a l
sti
pushq % r d i
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-04-16 15:20:36 -07:00
call s c h e d u l e
popq % r d i
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T - 8
2005-04-16 15:20:36 -07:00
jmp s y s r e t _ c h e c k
/* Handle a signal */
sysret_signal :
sti
2005-05-16 21:53:19 -07:00
testl $ ( _ T I F _ S I G P E N D I N G | _ T I F _ N O T I F Y _ R E S U M E | _ T I F _ S I N G L E S T E P ) ,% e d x
jz 1 f
/* Really a signal */
/* edx: work flags (arg3) */
2005-04-16 15:20:36 -07:00
leaq d o _ n o t i f y _ r e s u m e ( % r i p ) ,% r a x
leaq - A R G O F F S E T ( % r s p ) ,% r d i # & p t _ r e g s - > a r g 1
xorl % e s i ,% e s i # o l d s e t - > a r g 2
call p t r e g s c a l l _ c o m m o n
2005-05-16 21:53:19 -07:00
1 : movl $ _ T I F _ N E E D _ R E S C H E D ,% e d i
2006-04-07 19:50:00 +02:00
/ * Use I R E T b e c a u s e u s e r c o u l d h a v e c h a n g e d f r a m e . T h i s
works b e c a u s e p t r e g s c a l l _ c o m m o n h a s c a l l e d F I X U P _ T O P _ O F _ S T A C K . * /
cli
jmp i n t _ w i t h _ c h e c k
2005-04-16 15:20:36 -07:00
2005-09-12 18:49:24 +02:00
badsys :
movq $ - E N O S Y S ,R A X - A R G O F F S E T ( % r s p )
jmp r e t _ f r o m _ s y s _ c a l l
2005-04-16 15:20:36 -07:00
/* Do syscall tracing */
tracesys :
2005-09-12 18:49:24 +02:00
CFI_ R E S T O R E _ S T A T E
2005-04-16 15:20:36 -07:00
SAVE_ R E S T
movq $ - E N O S Y S ,R A X ( % r s p )
FIXUP_ T O P _ O F _ S T A C K % r d i
movq % r s p ,% r d i
call s y s c a l l _ t r a c e _ e n t e r
LOAD_ A R G S A R G O F F S E T / * r e l o a d a r g s f r o m s t a c k i n c a s e p t r a c e c h a n g e d i t * /
RESTORE_ R E S T
cmpq $ _ _ N R _ s y s c a l l _ m a x ,% r a x
ja 1 f
movq % r10 ,% r c x / * f i x u p f o r C * /
call * s y s _ c a l l _ t a b l e ( ,% r a x ,8 )
2006-05-30 22:48:03 +02:00
1 : movq % r a x ,R A X - A R G O F F S E T ( % r s p )
2006-04-07 19:50:00 +02:00
/* Use IRET because user could have changed frame */
jmp i n t _ r e t _ f r o m _ s y s _ c a l l
2005-09-12 18:49:24 +02:00
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
END( s y s t e m _ c a l l )
2005-04-16 15:20:36 -07:00
/ *
* Syscall r e t u r n p a t h e n d i n g w i t h I R E T .
* Has c o r r e c t t o p o f s t a c k , b u t p a r t i a l s t a c k f r a m e .
* /
2005-09-12 18:49:24 +02:00
ENTRY( i n t _ r e t _ f r o m _ s y s _ c a l l )
CFI_ S T A R T P R O C s i m p l e
CFI_ D E F _ C F A r s p ,S S + 8 - A R G O F F S E T
/*CFI_REL_OFFSET ss,SS-ARGOFFSET*/
CFI_ R E L _ O F F S E T r s p ,R S P - A R G O F F S E T
/*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/
/*CFI_REL_OFFSET cs,CS-ARGOFFSET*/
CFI_ R E L _ O F F S E T r i p ,R I P - A R G O F F S E T
CFI_ R E L _ O F F S E T r d x ,R D X - A R G O F F S E T
CFI_ R E L _ O F F S E T r c x ,R C X - A R G O F F S E T
CFI_ R E L _ O F F S E T r a x ,R A X - A R G O F F S E T
CFI_ R E L _ O F F S E T r d i ,R D I - A R G O F F S E T
CFI_ R E L _ O F F S E T r s i ,R S I - A R G O F F S E T
CFI_ R E L _ O F F S E T r8 ,R 8 - A R G O F F S E T
CFI_ R E L _ O F F S E T r9 ,R 9 - A R G O F F S E T
CFI_ R E L _ O F F S E T r10 ,R 1 0 - A R G O F F S E T
CFI_ R E L _ O F F S E T r11 ,R 1 1 - A R G O F F S E T
2005-04-16 15:20:36 -07:00
cli
testl $ 3 ,C S - A R G O F F S E T ( % r s p )
je r e t i n t _ r e s t o r e _ a r g s
movl $ _ T I F _ A L L W O R K _ M A S K ,% e d i
/* edi: mask to check */
int_with_check :
GET_ T H R E A D _ I N F O ( % r c x )
movl t h r e a d i n f o _ f l a g s ( % r c x ) ,% e d x
andl % e d i ,% e d x
jnz i n t _ c a r e f u l
2006-01-11 22:44:06 +01:00
andl $ ~ T S _ C O M P A T ,t h r e a d i n f o _ s t a t u s ( % r c x )
2005-04-16 15:20:36 -07:00
jmp r e t i n t _ s w a p g s
/* Either reschedule or signal or syscall exit tracking needed. */
/* First do a reschedule test. */
/* edx: work, edi: workmask */
int_careful :
bt $ T I F _ N E E D _ R E S C H E D ,% e d x
jnc i n t _ v e r y _ c a r e f u l
sti
pushq % r d i
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-04-16 15:20:36 -07:00
call s c h e d u l e
popq % r d i
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T - 8
2005-04-16 15:25:04 -07:00
cli
2005-04-16 15:20:36 -07:00
jmp i n t _ w i t h _ c h e c k
/* handle signals and tracing -- both require a full stack frame */
int_very_careful :
sti
SAVE_ R E S T
/* Check for syscall exit trace */
testl $ ( _ T I F _ S Y S C A L L _ T R A C E | _ T I F _ S Y S C A L L _ A U D I T | _ T I F _ S I N G L E S T E P ) ,% e d x
jz i n t _ s i g n a l
pushq % r d i
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-04-16 15:20:36 -07:00
leaq 8 ( % r s p ) ,% r d i # & p t r e g s - > a r g 1
call s y s c a l l _ t r a c e _ l e a v e
popq % r d i
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T - 8
2005-04-16 15:25:01 -07:00
andl $ ~ ( _ T I F _ S Y S C A L L _ T R A C E | _ T I F _ S Y S C A L L _ A U D I T | _ T I F _ S I N G L E S T E P ) ,% e d i
2005-05-01 08:58:51 -07:00
cli
2005-04-16 15:20:36 -07:00
jmp i n t _ r e s t o r e _ r e s t
int_signal :
testl $ ( _ 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 | _ T I F _ S I N G L E S T E P ) ,% e d x
jz 1 f
movq % r s p ,% r d i # & p t r e g s - > a r g 1
xorl % e s i ,% e s i # o l d s e t - > a r g 2
call d o _ n o t i f y _ r e s u m e
1 : movl $ _ T I F _ N E E D _ R E S C H E D ,% e d i
int_restore_rest :
RESTORE_ R E S T
2005-05-01 08:58:51 -07:00
cli
2005-04-16 15:20:36 -07:00
jmp i n t _ w i t h _ c h e c k
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
END( i n t _ r e t _ f r o m _ s y s _ c a l l )
2005-04-16 15:20:36 -07:00
/ *
* Certain s p e c i a l s y s t e m c a l l s t h a t n e e d t o s a v e a c o m p l e t e f u l l s t a c k f r a m e .
* /
.macro PTREGSCALL label,f u n c ,a r g
.globl \ label
\ label :
leaq \ f u n c ( % r i p ) ,% r a x
leaq - A R G O F F S E T + 8 ( % r s p ) ,\ a r g / * 8 f o r r e t u r n a d d r e s s * /
jmp p t r e g s c a l l _ c o m m o n
2006-06-26 13:56:55 +02:00
END( \ l a b e l )
2005-04-16 15:20:36 -07:00
.endm
2005-09-12 18:49:24 +02:00
CFI_ S T A R T P R O C
2005-04-16 15:20:36 -07:00
PTREGSCALL s t u b _ c l o n e , s y s _ c l o n e , % r8
PTREGSCALL s t u b _ f o r k , s y s _ f o r k , % r d i
PTREGSCALL s t u b _ v f o r k , s y s _ v f o r k , % r d i
PTREGSCALL s t u b _ r t _ s i g s u s p e n d , s y s _ r t _ s i g s u s p e n d , % r d x
PTREGSCALL s t u b _ s i g a l t s t a c k , s y s _ s i g a l t s t a c k , % r d x
PTREGSCALL s t u b _ i o p l , s y s _ i o p l , % r s i
ENTRY( p t r e g s c a l l _ c o m m o n )
popq % r11
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T - 8
CFI_ R E G I S T E R r i p , r11
2005-04-16 15:20:36 -07:00
SAVE_ R E S T
movq % r11 , % r15
2005-09-12 18:49:24 +02:00
CFI_ R E G I S T E R r i p , r15
2005-04-16 15:20:36 -07:00
FIXUP_ T O P _ O F _ S T A C K % r11
call * % r a x
RESTORE_ T O P _ O F _ S T A C K % r11
movq % r15 , % r11
2005-09-12 18:49:24 +02:00
CFI_ R E G I S T E R r i p , r11
2005-04-16 15:20:36 -07:00
RESTORE_ R E S T
pushq % r11
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T 8
CFI_ R E L _ O F F S E T r i p , 0
2005-04-16 15:20:36 -07:00
ret
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
END( p t r e g s c a l l _ c o m m o n )
2005-04-16 15:20:36 -07:00
ENTRY( s t u b _ e x e c v e )
CFI_ S T A R T P R O C
popq % r11
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T - 8
CFI_ R E G I S T E R r i p , r11
2005-04-16 15:20:36 -07:00
SAVE_ R E S T
FIXUP_ T O P _ O F _ S T A C K % r11
call s y s _ e x e c v e
RESTORE_ T O P _ O F _ S T A C K % r11
movq % r a x ,R A X ( % r s p )
RESTORE_ R E S T
jmp i n t _ r e t _ f r o m _ s y s _ c a l l
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
END( s t u b _ e x e c v e )
2005-04-16 15:20:36 -07:00
/ *
* sigreturn i s s p e c i a l b e c a u s e i t n e e d s t o r e s t o r e a l l r e g i s t e r s o n r e t u r n .
* This c a n n o t b e d o n e w i t h S Y S R E T , s o u s e t h e I R E T r e t u r n p a t h i n s t e a d .
* /
ENTRY( s t u b _ r t _ s i g r e t u r n )
CFI_ S T A R T P R O C
2005-09-12 18:49:24 +02:00
addq $ 8 , % r s p
CFI_ A D J U S T _ C F A _ O F F S E T - 8
2005-04-16 15:20:36 -07:00
SAVE_ R E S T
movq % r s p ,% r d i
FIXUP_ T O P _ O F _ S T A C K % r11
call s y s _ r t _ s i g r e t u r n
movq % r a x ,R A X ( % r s p ) # f i x m e , t h i s c o u l d b e d o n e a t t h e h i g h e r l a y e r
RESTORE_ R E S T
jmp i n t _ r e t _ f r o m _ s y s _ c a l l
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
END( s t u b _ r t _ s i g r e t u r n )
2005-04-16 15:20:36 -07:00
2005-09-12 18:49:24 +02:00
/ *
* initial f r a m e s t a t e f o r i n t e r r u p t s a n d e x c e p t i o n s
* /
.macro _frame ref
CFI_ S T A R T P R O C s i m p l e
CFI_ D E F _ C F A r s p ,S S + 8 - \ r e f
/*CFI_REL_OFFSET ss,SS-\ref*/
CFI_ R E L _ O F F S E T r s p ,R S P - \ r e f
/*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
/*CFI_REL_OFFSET cs,CS-\ref*/
CFI_ R E L _ O F F S E T r i p ,R I P - \ r e f
.endm
/* initial frame state for interrupts (and exceptions without error code) */
# define I N T R _ F R A M E _ f r a m e R I P
/ * initial f r a m e s t a t e f o r e x c e p t i o n s w i t h e r r o r c o d e ( a n d i n t e r r u p t s w i t h
vector a l r e a d y p u s h e d ) * /
# define X C P T _ F R A M E _ f r a m e O R I G _ R A X
2005-04-16 15:20:36 -07:00
/ *
* Interrupt e n t r y / e x i t .
*
* Interrupt e n t r y p o i n t s s a v e o n l y c a l l e e c l o b b e r e d r e g i s t e r s i n f a s t p a t h .
*
* Entry r u n s w i t h i n t e r r u p t s o f f .
* /
/* 0(%rsp): interrupt number */
.macro interrupt func
cld
SAVE_ A R G S
leaq - A R G O F F S E T ( % r s p ) ,% r d i # a r g 1 f o r h a n d l e r
2006-06-26 13:57:35 +02:00
pushq % r b p
CFI_ A D J U S T _ C F A _ O F F S E T 8
CFI_ R E L _ O F F S E T r b p , 0
movq % r s p ,% r b p
CFI_ D E F _ C F A _ R E G I S T E R r b p
2005-04-16 15:20:36 -07:00
testl $ 3 ,C S ( % r d i )
je 1 f
swapgs
2005-07-28 21:15:48 -07:00
1 : incl % g s : p d a _ i r q c o u n t # R E D - P E N s h o u l d c h e c k p r e e m p t c o u n t
2006-06-26 13:57:35 +02:00
cmoveq % g s : p d a _ i r q s t a c k p t r ,% r s p
2005-04-16 15:20:36 -07:00
call \ f u n c
.endm
ENTRY( c o m m o n _ i n t e r r u p t )
2005-09-12 18:49:24 +02:00
XCPT_ F R A M E
2005-04-16 15:20:36 -07:00
interrupt d o _ I R Q
/* 0(%rsp): oldrsp-ARGOFFSET */
2005-09-12 18:49:24 +02:00
ret_from_intr :
2005-04-16 15:20:36 -07:00
cli
2005-07-28 21:15:48 -07:00
decl % g s : p d a _ i r q c o u n t
2006-06-26 13:57:35 +02:00
leaveq
2005-09-12 18:49:24 +02:00
CFI_ D E F _ C F A _ R E G I S T E R r s p
2006-06-26 13:57:35 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T - 8
2005-09-12 18:49:24 +02:00
exit_intr :
2005-04-16 15:20:36 -07:00
GET_ T H R E A D _ I N F O ( % r c x )
testl $ 3 ,C S - A R G O F F S E T ( % r s p )
je r e t i n t _ k e r n e l
/* Interrupt came from user space */
/ *
* Has a c o r r e c t t o p o f s t a c k , b u t a p a r t i a l s t a c k f r a m e
* % rcx : thread i n f o . I n t e r r u p t s o f f .
* /
retint_with_reschedule :
movl $ _ T I F _ W O R K _ M A S K ,% e d i
2005-09-12 18:49:24 +02:00
retint_check :
2005-04-16 15:20:36 -07:00
movl t h r e a d i n f o _ f l a g s ( % r c x ) ,% e d x
andl % e d i ,% e d x
2005-09-12 18:49:24 +02:00
CFI_ R E M E M B E R _ S T A T E
2005-04-16 15:20:36 -07:00
jnz r e t i n t _ c a r e f u l
retint_swapgs :
swapgs
retint_restore_args :
cli
RESTORE_ A R G S 0 ,8 ,0
iret_label :
iretq
.section _ _ ex_ t a b l e ," a "
.quad iret_ l a b e l ,b a d _ i r e t
.previous
.section .fixup , " ax"
/* force a signal here? this matches i386 behaviour */
/* running with kernel gs */
bad_iret :
2006-03-25 16:31:55 +01:00
movq $ 1 1 ,% r d i / * S I G S E G V * /
2006-02-16 23:42:01 +01:00
sti
2005-04-16 15:20:36 -07:00
jmp d o _ e x i t
.previous
2005-09-12 18:49:24 +02:00
/* edi: workmask, edx: work */
2005-04-16 15:20:36 -07:00
retint_careful :
2005-09-12 18:49:24 +02:00
CFI_ R E S T O R E _ S T A T E
2005-04-16 15:20:36 -07:00
bt $ T I F _ N E E D _ R E S C H E D ,% e d x
jnc r e t i n t _ s i g n a l
sti
pushq % r d i
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-04-16 15:20:36 -07:00
call s c h e d u l e
popq % r d i
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T - 8
2005-04-16 15:20:36 -07:00
GET_ T H R E A D _ I N F O ( % r c x )
cli
jmp r e t i n t _ c h e c k
retint_signal :
2005-05-16 21:53:19 -07:00
testl $ ( _ T I F _ S I G P E N D I N G | _ T I F _ N O T I F Y _ R E S U M E | _ T I F _ S I N G L E S T E P ) ,% e d x
jz r e t i n t _ s w a p g s
2005-04-16 15:20:36 -07:00
sti
SAVE_ R E S T
movq $ - 1 ,O R I G _ R A X ( % r s p )
2005-07-28 21:15:48 -07:00
xorl % e s i ,% e s i # o l d s e t
2005-04-16 15:20:36 -07:00
movq % r s p ,% r d i # & p t _ r e g s
call d o _ n o t i f y _ r e s u m e
RESTORE_ R E S T
cli
2005-05-16 21:53:19 -07:00
movl $ _ T I F _ N E E D _ R E S C H E D ,% e d i
2005-05-01 08:58:51 -07:00
GET_ T H R E A D _ I N F O ( % r c x )
2005-04-16 15:20:36 -07:00
jmp r e t i n t _ c h e c k
# ifdef C O N F I G _ P R E E M P T
/* Returning to kernel space. Check if we need preemption */
/* rcx: threadinfo. interrupts off. */
.p2align
retint_kernel :
cmpl $ 0 ,t h r e a d i n f o _ p r e e m p t _ c o u n t ( % r c x )
jnz r e t i n t _ r e s t o r e _ a r g s
bt $ T I F _ N E E D _ R E S C H E D ,t h r e a d i n f o _ f l a g s ( % r c x )
jnc r e t i n t _ r e s t o r e _ a r g s
bt $ 9 ,E F L A G S - A R G O F F S E T ( % r s p ) / * i n t e r r u p t s o f f ? * /
jnc r e t i n t _ r e s t o r e _ a r g s
call p r e e m p t _ s c h e d u l e _ i r q
jmp e x i t _ i n t r
# endif
2006-06-26 13:56:55 +02:00
2005-04-16 15:20:36 -07:00
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
END( c o m m o n _ i n t e r r u p t )
2005-04-16 15:20:36 -07:00
/ *
* APIC i n t e r r u p t s .
* /
.macro apicinterrupt num,f u n c
2005-09-12 18:49:24 +02:00
INTR_ F R A M E
2005-04-16 15:20:36 -07:00
pushq $ \ n u m - 2 5 6
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-04-16 15:20:36 -07:00
interrupt \ f u n c
jmp r e t _ f r o m _ i n t r
CFI_ E N D P R O C
.endm
ENTRY( t h e r m a l _ i n t e r r u p t )
apicinterrupt T H E R M A L _ A P I C _ V E C T O R ,s m p _ t h e r m a l _ i n t e r r u p t
2006-06-26 13:56:55 +02:00
END( t h e r m a l _ i n t e r r u p t )
2005-04-16 15:20:36 -07:00
2005-11-05 17:25:53 +01:00
ENTRY( t h r e s h o l d _ i n t e r r u p t )
apicinterrupt T H R E S H O L D _ A P I C _ V E C T O R ,m c e _ t h r e s h o l d _ i n t e r r u p t
2006-06-26 13:56:55 +02:00
END( t h r e s h o l d _ i n t e r r u p t )
2005-11-05 17:25:53 +01:00
2005-04-16 15:20:36 -07:00
# ifdef C O N F I G _ S M P
ENTRY( r e s c h e d u l e _ i n t e r r u p t )
apicinterrupt R E S C H E D U L E _ V E C T O R ,s m p _ r e s c h e d u l e _ i n t e r r u p t
2006-06-26 13:56:55 +02:00
END( r e s c h e d u l e _ i n t e r r u p t )
2005-04-16 15:20:36 -07:00
2005-09-12 18:49:24 +02:00
.macro INVALIDATE_ENTRY num
ENTRY( i n v a l i d a t e _ i n t e r r u p t \ n u m )
apicinterrupt I N V A L I D A T E _ T L B _ V E C T O R _ S T A R T + \ n u m ,s m p _ i n v a l i d a t e _ i n t e r r u p t
2006-06-26 13:56:55 +02:00
END( i n v a l i d a t e _ i n t e r r u p t \ n u m )
2005-09-12 18:49:24 +02:00
.endm
INVALIDATE_ E N T R Y 0
INVALIDATE_ E N T R Y 1
INVALIDATE_ E N T R Y 2
INVALIDATE_ E N T R Y 3
INVALIDATE_ E N T R Y 4
INVALIDATE_ E N T R Y 5
INVALIDATE_ E N T R Y 6
INVALIDATE_ E N T R Y 7
2005-04-16 15:20:36 -07:00
ENTRY( c a l l _ f u n c t i o n _ i n t e r r u p t )
apicinterrupt C A L L _ F U N C T I O N _ V E C T O R ,s m p _ c a l l _ f u n c t i o n _ i n t e r r u p t
2006-06-26 13:56:55 +02:00
END( c a l l _ f u n c t i o n _ i n t e r r u p t )
2005-04-16 15:20:36 -07:00
# endif
# ifdef C O N F I G _ X 8 6 _ L O C A L _ A P I C
ENTRY( a p i c _ t i m e r _ i n t e r r u p t )
apicinterrupt L O C A L _ T I M E R _ V E C T O R ,s m p _ a p i c _ t i m e r _ i n t e r r u p t
2006-06-26 13:56:55 +02:00
END( a p i c _ t i m e r _ i n t e r r u p t )
2005-04-16 15:20:36 -07:00
ENTRY( e r r o r _ i n t e r r u p t )
apicinterrupt E R R O R _ A P I C _ V E C T O R ,s m p _ e r r o r _ i n t e r r u p t
2006-06-26 13:56:55 +02:00
END( e r r o r _ i n t e r r u p t )
2005-04-16 15:20:36 -07:00
ENTRY( s p u r i o u s _ i n t e r r u p t )
apicinterrupt S P U R I O U S _ A P I C _ V E C T O R ,s m p _ s p u r i o u s _ i n t e r r u p t
2006-06-26 13:56:55 +02:00
END( s p u r i o u s _ i n t e r r u p t )
2005-04-16 15:20:36 -07:00
# endif
/ *
* Exception e n t r y p o i n t s .
* /
.macro zeroentry sym
2005-09-12 18:49:24 +02:00
INTR_ F R A M E
2005-04-16 15:20:36 -07:00
pushq $ 0 / * p u s h e r r o r c o d e / o l d r a x * /
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-04-16 15:20:36 -07:00
pushq % r a x / * p u s h r e a l o l d r a x t o t h e r d i s l o t * /
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-04-16 15:20:36 -07:00
leaq \ s y m ( % r i p ) ,% r a x
jmp e r r o r _ e n t r y
2005-09-12 18:49:24 +02:00
CFI_ E N D P R O C
2005-04-16 15:20:36 -07:00
.endm
.macro errorentry sym
2005-09-12 18:49:24 +02:00
XCPT_ F R A M E
2005-04-16 15:20:36 -07:00
pushq % r a x
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-04-16 15:20:36 -07:00
leaq \ s y m ( % r i p ) ,% r a x
jmp e r r o r _ e n t r y
2005-09-12 18:49:24 +02:00
CFI_ E N D P R O C
2005-04-16 15:20:36 -07:00
.endm
/* error code is on the stack already */
/* handle NMI like exceptions that can happen everywhere */
2006-01-11 22:43:00 +01:00
.macro paranoidentry sym, i s t =0
2005-04-16 15:20:36 -07:00
SAVE_ A L L
cld
movl $ 1 ,% e b x
movl $ M S R _ G S _ B A S E ,% e c x
rdmsr
testl % e d x ,% e d x
js 1 f
swapgs
xorl % e b x ,% e b x
2006-01-11 22:43:00 +01:00
1 :
.if \ ist
movq % g s : p d a _ d a t a _ o f f s e t , % r b p
.endif
movq % r s p ,% r d i
2005-04-16 15:20:36 -07:00
movq O R I G _ R A X ( % r s p ) ,% r s i
movq $ - 1 ,O R I G _ R A X ( % r s p )
2006-01-11 22:43:00 +01:00
.if \ ist
2006-01-16 01:56:39 +01:00
subq $ E X C E P T I O N _ S T K S Z , p e r _ c p u _ _ i n i t _ t s s + T S S _ i s t + ( \ i s t - 1 ) * 8 ( % r b p )
2006-01-11 22:43:00 +01:00
.endif
2005-04-16 15:20:36 -07:00
call \ s y m
2006-01-11 22:43:00 +01:00
.if \ ist
2006-01-16 01:56:39 +01:00
addq $ E X C E P T I O N _ S T K S Z , p e r _ c p u _ _ i n i t _ t s s + T S S _ i s t + ( \ i s t - 1 ) * 8 ( % r b p )
2006-01-11 22:43:00 +01:00
.endif
2005-04-16 15:25:03 -07:00
cli
2005-04-16 15:20:36 -07:00
.endm
/ *
* Exception e n t r y p o i n t . T h i s e x p e c t s a n e r r o r c o d e / o r i g _ r a x o n t h e s t a c k
* and t h e e x c e p t i o n h a n d l e r i n % r a x .
* /
ENTRY( e r r o r _ e n t r y )
2005-09-12 18:49:24 +02:00
_ frame R D I
2005-04-16 15:20:36 -07:00
/* rdi slot contains rax, oldrax contains error code */
cld
subq $ 1 4 * 8 ,% r s p
CFI_ A D J U S T _ C F A _ O F F S E T ( 1 4 * 8 )
movq % r s i ,1 3 * 8 ( % r s p )
CFI_ R E L _ O F F S E T r s i ,R S I
movq 1 4 * 8 ( % r s p ) ,% r s i / * l o a d r a x f r o m r d i s l o t * /
movq % r d x ,1 2 * 8 ( % r s p )
CFI_ R E L _ O F F S E T r d x ,R D X
movq % r c x ,1 1 * 8 ( % r s p )
CFI_ R E L _ O F F S E T r c x ,R C X
movq % r s i ,1 0 * 8 ( % r s p ) / * s t o r e r a x * /
CFI_ R E L _ O F F S E T r a x ,R A X
movq % r8 , 9 * 8 ( % r s p )
CFI_ R E L _ O F F S E T r8 ,R 8
movq % r9 , 8 * 8 ( % r s p )
CFI_ R E L _ O F F S E T r9 ,R 9
movq % r10 ,7 * 8 ( % r s p )
CFI_ R E L _ O F F S E T r10 ,R 1 0
movq % r11 ,6 * 8 ( % r s p )
CFI_ R E L _ O F F S E T r11 ,R 1 1
movq % r b x ,5 * 8 ( % r s p )
CFI_ R E L _ O F F S E T r b x ,R B X
movq % r b p ,4 * 8 ( % r s p )
CFI_ R E L _ O F F S E T r b p ,R B P
movq % r12 ,3 * 8 ( % r s p )
CFI_ R E L _ O F F S E T r12 ,R 1 2
movq % r13 ,2 * 8 ( % r s p )
CFI_ R E L _ O F F S E T r13 ,R 1 3
movq % r14 ,1 * 8 ( % r s p )
CFI_ R E L _ O F F S E T r14 ,R 1 4
movq % r15 ,( % r s p )
CFI_ R E L _ O F F S E T r15 ,R 1 5
xorl % e b x ,% e b x
testl $ 3 ,C S ( % r s p )
je e r r o r _ k e r n e l s p a c e
error_swapgs :
swapgs
error_sti :
movq % r d i ,R D I ( % r s p )
movq % r s p ,% r d i
movq O R I G _ R A X ( % r s p ) ,% r s i / * g e t e r r o r c o d e * /
movq $ - 1 ,O R I G _ R A X ( % r s p )
call * % r a x
/* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */
error_exit :
movl % e b x ,% e a x
RESTORE_ R E S T
cli
GET_ T H R E A D _ I N F O ( % r c x )
testl % e a x ,% e a x
jne r e t i n t _ k e r n e l
movl t h r e a d i n f o _ f l a g s ( % r c x ) ,% e d x
movl $ _ T I F _ W O R K _ M A S K ,% e d i
andl % e d i ,% e d x
jnz r e t i n t _ c a r e f u l
swapgs
RESTORE_ A R G S 0 ,8 ,0
2006-01-11 22:42:20 +01:00
jmp i r e t _ l a b e l
2005-04-16 15:20:36 -07:00
CFI_ E N D P R O C
error_kernelspace :
incl % e b x
/ * There a r e t w o p l a c e s i n t h e k e r n e l t h a t c a n p o t e n t i a l l y f a u l t w i t h
usergs. H a n d l e t h e m h e r e . T h e e x c e p t i o n h a n d l e r s a f t e r
iret r u n w i t h k e r n e l g s a g a i n , s o d o n ' t s e t t h e u s e r s p a c e f l a g .
B s t e p p i n g K 8 s s o m e t i m e s r e p o r t a n t r u n c a t e d R I P f o r I R E T
exceptions r e t u r n i n g t o c o m p a t m o d e . C h e c k f o r t h e s e h e r e t o o . * /
leaq i r e t _ l a b e l ( % r i p ) ,% r b p
cmpq % r b p ,R I P ( % r s p )
je e r r o r _ s w a p g s
movl % e b p ,% e b p / * z e r o e x t e n d * /
cmpq % r b p ,R I P ( % r s p )
je e r r o r _ s w a p g s
cmpq $ g s _ c h a n g e ,R I P ( % r s p )
je e r r o r _ s w a p g s
jmp e r r o r _ s t i
2006-06-26 13:56:55 +02:00
END( e r r o r _ e n t r y )
2005-04-16 15:20:36 -07:00
/* Reload gs selector with exception handling */
/* edi: new selector */
ENTRY( l o a d _ g s _ i n d e x )
2005-09-12 18:49:24 +02:00
CFI_ S T A R T P R O C
2005-04-16 15:20:36 -07:00
pushf
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-04-16 15:20:36 -07:00
cli
swapgs
gs_change :
movl % e d i ,% g s
2 : mfence / * w o r k a r o u n d * /
swapgs
popf
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T - 8
2005-04-16 15:20:36 -07:00
ret
2005-09-12 18:49:24 +02:00
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
ENDPROC( l o a d _ g s _ i n d e x )
2005-04-16 15:20:36 -07:00
.section _ _ ex_ t a b l e ," a "
.align 8
.quad gs_ c h a n g e ,b a d _ g s
.previous
.section .fixup , " ax"
/* running with kernelgs */
bad_gs :
swapgs / * s w i t c h b a c k t o u s e r g s * /
xorl % e a x ,% e a x
movl % e a x ,% g s
jmp 2 b
.previous
/ *
* Create a k e r n e l t h r e a d .
*
* C e x t e r n i n t e r f a c e :
* extern l o n g k e r n e l _ t h r e a d ( i n t ( * f n ) ( v o i d * ) , v o i d * a r g , u n s i g n e d l o n g f l a g s )
*
* asm i n p u t a r g u m e n t s :
* rdi : fn, r s i : a r g , r d x : f l a g s
* /
ENTRY( k e r n e l _ t h r e a d )
CFI_ S T A R T P R O C
FAKE_ S T A C K _ F R A M E $ c h i l d _ r i p
SAVE_ A L L
# rdi : flags, r s i : u s p , r d x : w i l l b e & p t _ r e g s
movq % r d x ,% r d i
orq k e r n e l _ t h r e a d _ f l a g s ( % r i p ) ,% r d i
movq $ - 1 , % r s i
movq % r s p , % r d x
xorl % r8 d ,% r8 d
xorl % r9 d ,% r9 d
# clone n o w
call d o _ f o r k
movq % r a x ,R A X ( % r s p )
xorl % e d i ,% e d i
/ *
* It i s n ' t w o r t h t o c h e c k f o r r e s c h e d u l e h e r e ,
* so i n t e r n a l l y t o t h e x86 _ 6 4 p o r t y o u c a n r e l y o n k e r n e l _ t h r e a d ( )
* not t o r e s c h e d u l e t h e c h i l d b e f o r e r e t u r n i n g , t h i s a v o i d s t h e n e e d
* of h a c k s f o r e x a m p l e t o f o r k o f f t h e p e r - C P U i d l e t a s k s .
* [ Hopefully n o g e n e r i c c o d e r e l i e s o n t h e r e s c h e d u l e - A K ]
* /
RESTORE_ A L L
UNFAKE_ S T A C K _ F R A M E
ret
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
ENDPROC( k e r n e l _ t h r e a d )
2005-04-16 15:20:36 -07:00
child_rip :
/ *
* Here w e a r e i n t h e c h i l d a n d t h e r e g i s t e r s a r e s e t a s t h e y w e r e
* at k e r n e l _ t h r e a d ( ) i n v o c a t i o n i n t h e p a r e n t .
* /
movq % r d i , % r a x
movq % r s i , % r d i
call * % r a x
# exit
2005-07-28 21:15:48 -07:00
xorl % e d i , % e d i
2005-04-16 15:20:36 -07:00
call d o _ e x i t
2006-06-26 13:56:55 +02:00
ENDPROC( c h i l d _ r i p )
2005-04-16 15:20:36 -07:00
/ *
* execve( ) . T h i s f u n c t i o n n e e d s t o u s e I R E T , n o t S Y S R E T , t o s e t u p a l l s t a t e p r o p e r l y .
*
* C e x t e r n i n t e r f a c e :
* extern l o n g e x e c v e ( c h a r * n a m e , c h a r * * a r g v , c h a r * * e n v p )
*
* asm i n p u t a r g u m e n t s :
* rdi : name, r s i : a r g v , r d x : e n v p
*
* We w a n t t o f a l l b a c k i n t o :
* extern l o n g s y s _ e x e c v e ( c h a r * n a m e , c h a r * * a r g v ,c h a r * * e n v p , s t r u c t p t _ r e g s r e g s )
*
* do_ s y s _ e x e c v e a s m f a l l b a c k a r g u m e n t s :
* rdi : name, r s i : a r g v , r d x : e n v p , f a k e f r a m e o n t h e s t a c k
* /
ENTRY( e x e c v e )
CFI_ S T A R T P R O C
FAKE_ S T A C K _ F R A M E $ 0
SAVE_ A L L
call s y s _ e x e c v e
movq % r a x , R A X ( % r s p )
RESTORE_ R E S T
testq % r a x ,% r a x
je i n t _ r e t _ f r o m _ s y s _ c a l l
RESTORE_ A R G S
UNFAKE_ S T A C K _ F R A M E
ret
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
ENDPROC( e x e c v e )
2005-04-16 15:20:36 -07:00
2005-09-06 15:19:28 -07:00
KPROBE_ E N T R Y ( p a g e _ f a u l t )
2005-04-16 15:20:36 -07:00
errorentry d o _ p a g e _ f a u l t
2006-06-26 13:56:55 +02:00
END( p a g e _ f a u l t )
2005-09-06 15:19:28 -07:00
.previous .text
2005-04-16 15:20:36 -07:00
ENTRY( c o p r o c e s s o r _ e r r o r )
zeroentry d o _ c o p r o c e s s o r _ e r r o r
2006-06-26 13:56:55 +02:00
END( c o p r o c e s s o r _ e r r o r )
2005-04-16 15:20:36 -07:00
ENTRY( s i m d _ c o p r o c e s s o r _ e r r o r )
zeroentry d o _ s i m d _ c o p r o c e s s o r _ e r r o r
2006-06-26 13:56:55 +02:00
END( s i m d _ c o p r o c e s s o r _ e r r o r )
2005-04-16 15:20:36 -07:00
ENTRY( d e v i c e _ n o t _ a v a i l a b l e )
zeroentry m a t h _ s t a t e _ r e s t o r e
2006-06-26 13:56:55 +02:00
END( d e v i c e _ n o t _ a v a i l a b l e )
2005-04-16 15:20:36 -07:00
/* runs on exception stack */
2005-09-06 15:19:28 -07:00
KPROBE_ E N T R Y ( d e b u g )
2005-09-12 18:49:24 +02:00
INTR_ F R A M E
2005-04-16 15:20:36 -07:00
pushq $ 0
CFI_ A D J U S T _ C F A _ O F F S E T 8
2006-01-16 01:56:39 +01:00
paranoidentry d o _ d e b u g , D E B U G _ S T A C K
2005-04-16 15:20:36 -07:00
jmp p a r a n o i d _ e x i t
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
END( d e b u g )
2005-09-06 15:19:28 -07:00
.previous .text
2005-04-16 15:20:36 -07:00
/* runs on exception stack */
2006-02-03 21:50:41 +01:00
KPROBE_ E N T R Y ( n m i )
2005-09-12 18:49:24 +02:00
INTR_ F R A M E
2005-04-16 15:20:36 -07:00
pushq $ - 1
2005-09-12 18:49:24 +02:00
CFI_ A D J U S T _ C F A _ O F F S E T 8
2005-04-16 15:20:36 -07:00
paranoidentry d o _ n m i
2005-04-16 15:25:03 -07:00
/ *
* " Paranoid" e x i t p a t h f r o m e x c e p t i o n s t a c k .
* Paranoid b e c a u s e t h i s i s u s e d b y N M I s a n d c a n n o t t a k e
* any k e r n e l s t a t e f o r g r a n t e d .
* We d o n ' t d o k e r n e l p r e e m p t i o n c h e c k s h e r e , b e c a u s e o n l y
* NMI s h o u l d b e c o m m o n a n d i t d o e s n o t e n a b l e I R Q s a n d
* cannot g e t r e s c h e d u l e t i c k s .
* /
2005-04-16 15:20:36 -07:00
/* ebx: no swapgs flag */
paranoid_exit :
testl % e b x ,% e b x / * s w a p g s n e e d e d ? * /
jnz p a r a n o i d _ r e s t o r e
2005-04-16 15:25:03 -07:00
testl $ 3 ,C S ( % r s p )
jnz p a r a n o i d _ u s e r s p a c e
2005-04-16 15:20:36 -07:00
paranoid_swapgs :
swapgs
paranoid_restore :
RESTORE_ A L L 8
iretq
paranoid_userspace :
GET_ T H R E A D _ I N F O ( % r c x )
2005-04-16 15:25:03 -07:00
movl t h r e a d i n f o _ f l a g s ( % r c x ) ,% e b x
andl $ _ T I F _ W O R K _ M A S K ,% e b x
2005-04-16 15:25:02 -07:00
jz p a r a n o i d _ s w a p g s
2005-04-16 15:25:03 -07:00
movq % r s p ,% r d i / * & p t _ r e g s * /
call s y n c _ r e g s
movq % r a x ,% r s p / * s w i t c h s t a c k f o r s c h e d u l i n g * /
testl $ _ T I F _ N E E D _ R E S C H E D ,% e b x
jnz p a r a n o i d _ s c h e d u l e
movl % e b x ,% e d x / * a r g 3 : t h r e a d f l a g s * /
2005-04-16 15:20:36 -07:00
sti
2005-04-16 15:25:03 -07:00
xorl % e s i ,% e s i / * a r g 2 : o l d s e t * /
movq % r s p ,% r d i / * a r g 1 : & p t _ r e g s * /
2005-04-16 15:20:36 -07:00
call d o _ n o t i f y _ r e s u m e
2005-04-16 15:25:03 -07:00
cli
jmp p a r a n o i d _ u s e r s p a c e
paranoid_schedule :
2005-04-16 15:25:02 -07:00
sti
call s c h e d u l e
2005-04-16 15:25:03 -07:00
cli
jmp p a r a n o i d _ u s e r s p a c e
2005-04-16 15:20:36 -07:00
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
END( n m i )
2006-02-03 21:50:41 +01:00
.previous .text
2005-04-16 15:25:03 -07:00
2005-09-06 15:19:28 -07:00
KPROBE_ E N T R Y ( i n t 3 )
2006-01-11 22:43:00 +01:00
INTR_ F R A M E
pushq $ 0
CFI_ A D J U S T _ C F A _ O F F S E T 8
2006-01-16 01:56:39 +01:00
paranoidentry d o _ i n t 3 , D E B U G _ S T A C K
2006-01-11 22:43:00 +01:00
jmp p a r a n o i d _ e x i t
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
END( i n t 3 )
2005-09-06 15:19:28 -07:00
.previous .text
2005-04-16 15:20:36 -07:00
ENTRY( o v e r f l o w )
zeroentry d o _ o v e r f l o w
2006-06-26 13:56:55 +02:00
END( o v e r f l o w )
2005-04-16 15:20:36 -07:00
ENTRY( b o u n d s )
zeroentry d o _ b o u n d s
2006-06-26 13:56:55 +02:00
END( b o u n d s )
2005-04-16 15:20:36 -07:00
ENTRY( i n v a l i d _ o p )
zeroentry d o _ i n v a l i d _ o p
2006-06-26 13:56:55 +02:00
END( i n v a l i d _ o p )
2005-04-16 15:20:36 -07:00
ENTRY( c o p r o c e s s o r _ s e g m e n t _ o v e r r u n )
zeroentry d o _ c o p r o c e s s o r _ s e g m e n t _ o v e r r u n
2006-06-26 13:56:55 +02:00
END( c o p r o c e s s o r _ s e g m e n t _ o v e r r u n )
2005-04-16 15:20:36 -07:00
ENTRY( r e s e r v e d )
zeroentry d o _ r e s e r v e d
2006-06-26 13:56:55 +02:00
END( r e s e r v e d )
2005-04-16 15:20:36 -07:00
/* runs on exception stack */
ENTRY( d o u b l e _ f a u l t )
2005-09-12 18:49:24 +02:00
XCPT_ F R A M E
2005-04-16 15:20:36 -07:00
paranoidentry d o _ d o u b l e _ f a u l t
jmp p a r a n o i d _ e x i t
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
END( d o u b l e _ f a u l t )
2005-04-16 15:20:36 -07:00
ENTRY( i n v a l i d _ T S S )
errorentry d o _ i n v a l i d _ T S S
2006-06-26 13:56:55 +02:00
END( i n v a l i d _ T S S )
2005-04-16 15:20:36 -07:00
ENTRY( s e g m e n t _ n o t _ p r e s e n t )
errorentry d o _ s e g m e n t _ n o t _ p r e s e n t
2006-06-26 13:56:55 +02:00
END( s e g m e n t _ n o t _ p r e s e n t )
2005-04-16 15:20:36 -07:00
/* runs on exception stack */
ENTRY( s t a c k _ s e g m e n t )
2005-09-12 18:49:24 +02:00
XCPT_ F R A M E
2005-04-16 15:20:36 -07:00
paranoidentry d o _ s t a c k _ s e g m e n t
jmp p a r a n o i d _ e x i t
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
END( s t a c k _ s e g m e n t )
2005-04-16 15:20:36 -07:00
2005-09-06 15:19:28 -07:00
KPROBE_ E N T R Y ( g e n e r a l _ p r o t e c t i o n )
2005-04-16 15:20:36 -07:00
errorentry d o _ g e n e r a l _ p r o t e c t i o n
2006-06-26 13:56:55 +02:00
END( g e n e r a l _ p r o t e c t i o n )
2005-09-06 15:19:28 -07:00
.previous .text
2005-04-16 15:20:36 -07:00
ENTRY( a l i g n m e n t _ c h e c k )
errorentry d o _ a l i g n m e n t _ c h e c k
2006-06-26 13:56:55 +02:00
END( a l i g n m e n t _ c h e c k )
2005-04-16 15:20:36 -07:00
ENTRY( d i v i d e _ e r r o r )
zeroentry d o _ d i v i d e _ e r r o r
2006-06-26 13:56:55 +02:00
END( d i v i d e _ e r r o r )
2005-04-16 15:20:36 -07:00
ENTRY( s p u r i o u s _ i n t e r r u p t _ b u g )
zeroentry d o _ s p u r i o u s _ i n t e r r u p t _ b u g
2006-06-26 13:56:55 +02:00
END( s p u r i o u s _ i n t e r r u p t _ b u g )
2005-04-16 15:20:36 -07:00
# ifdef C O N F I G _ X 8 6 _ M C E
/* runs on exception stack */
ENTRY( m a c h i n e _ c h e c k )
2005-09-12 18:49:24 +02:00
INTR_ F R A M E
2005-04-16 15:20:36 -07:00
pushq $ 0
CFI_ A D J U S T _ C F A _ O F F S E T 8
paranoidentry d o _ m a c h i n e _ c h e c k
jmp p a r a n o i d _ e x i t
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
END( m a c h i n e _ c h e c k )
2005-04-16 15:20:36 -07:00
# endif
2005-07-28 21:15:49 -07:00
ENTRY( c a l l _ s o f t i r q )
2005-09-12 18:49:24 +02:00
CFI_ S T A R T P R O C
2005-07-28 21:15:49 -07:00
movq % g s : p d a _ i r q s t a c k p t r ,% r a x
2006-01-11 22:43:21 +01:00
movq % r s p ,% r d x
CFI_ D E F _ C F A _ R E G I S T E R r d x
2005-07-28 21:15:49 -07:00
incl % g s : p d a _ i r q c o u n t
cmove % r a x ,% r s p
2006-01-11 22:43:21 +01:00
pushq % r d x
/*todo CFI_DEF_CFA_EXPRESSION ...*/
2005-07-28 21:15:49 -07:00
call _ _ d o _ s o f t i r q
2006-01-11 22:43:21 +01:00
popq % r s p
2005-09-12 18:49:24 +02:00
CFI_ D E F _ C F A _ R E G I S T E R r s p
2005-07-28 21:15:49 -07:00
decl % g s : p d a _ i r q c o u n t
ret
2005-09-12 18:49:24 +02:00
CFI_ E N D P R O C
2006-06-26 13:56:55 +02:00
ENDPROC( c a l l _ s o f t i r q )
2006-06-26 13:57:32 +02:00
# ifdef C O N F I G _ S T A C K _ U N W I N D
ENTRY( a r c h _ u n w i n d _ i n i t _ r u n n i n g )
CFI_ S T A R T P R O C
movq % r15 , R 1 5 ( % r d i )
movq % r14 , R 1 4 ( % r d i )
xchgq % r s i , % r d x
movq % r13 , R 1 3 ( % r d i )
movq % r12 , R 1 2 ( % r d i )
xorl % e a x , % e a x
movq % r b p , R B P ( % r d i )
movq % r b x , R B X ( % r d i )
movq ( % r s p ) , % r c x
movq % r a x , R 1 1 ( % r d i )
movq % r a x , R 1 0 ( % r d i )
movq % r a x , R 9 ( % r d i )
movq % r a x , R 8 ( % r d i )
movq % r a x , R A X ( % r d i )
movq % r a x , R C X ( % r d i )
movq % r a x , R D X ( % r d i )
movq % r a x , R S I ( % r d i )
movq % r a x , R D I ( % r d i )
movq % r a x , O R I G _ R A X ( % r d i )
movq % r c x , R I P ( % r d i )
leaq 8 ( % r s p ) , % r c x
movq $ _ _ K E R N E L _ C S , C S ( % r d i )
movq % r a x , E F L A G S ( % r d i )
movq % r c x , R S P ( % r d i )
movq $ _ _ K E R N E L _ D S , S S ( % r d i )
jmpq * % r d x
CFI_ E N D P R O C
ENDPROC( a r c h _ u n w i n d _ i n i t _ r u n n i n g )
# endif