2005-06-26 01:57:56 +04:00
/ *
* relocate_ k e r n e l . S - p u t t h e k e r n e l i m a g e i n p l a c e t o b o o t
* Copyright ( C ) 2 0 0 2 - 2 0 0 4 E r i c B i e d e r m a n < e b i e d e r m @xmission.com>
*
* This s o u r c e c o d e i s l i c e n s e d u n d e r 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 ,
* Version 2 . S e e t h e f i l e C O P Y I N G f o r m o r e d e t a i l s .
* /
# include < l i n u x / l i n k a g e . h >
2009-02-13 22:14:01 +03:00
# include < a s m / p a g e _ t y p e s . h >
2006-09-26 12:52:38 +04:00
# include < a s m / k e x e c . h >
2008-03-23 00:00:08 +03:00
# include < a s m / p r o c e s s o r - f l a g s . h >
2006-09-26 12:52:38 +04:00
/ *
* Must b e r e l o c a t a b l e P I C c o d e c a l l a b l e a s a C f u n c t i o n
* /
# define P T R ( x ) ( x < < 2 )
2009-03-10 05:56:57 +03:00
/ *
* control_ p a g e + K E X E C _ C O N T R O L _ C O D E _ M A X _ S I Z E
2008-08-15 11:40:23 +04:00
* ~ control_ p a g e + P A G E _ S I Z E a r e u s e d a s d a t a s t o r a g e a n d s t a c k f o r
* jumping b a c k
2008-07-26 06:45:07 +04:00
* /
2008-08-15 11:40:23 +04:00
# define D A T A ( o f f s e t ) ( K E X E C _ C O N T R O L _ C O D E _ M A X _ S I Z E + ( o f f s e t ) )
2008-07-26 06:45:07 +04:00
/* Minimal CPU state */
# define E S P D A T A ( 0 x0 )
# define C R 0 D A T A ( 0 x4 )
# define C R 3 D A T A ( 0 x8 )
# define C R 4 D A T A ( 0 x c )
/* other data */
# define C P _ V A _ C O N T R O L _ P A G E D A T A ( 0 x10 )
# define C P _ P A _ P G D D A T A ( 0 x14 )
# define C P _ P A _ S W A P _ P A G E D A T A ( 0 x18 )
# define C P _ P A _ B A C K U P _ P A G E S _ M A P D A T A ( 0 x1 c )
2006-09-26 12:52:38 +04:00
.text
.globl relocate_kernel
relocate_kernel :
2008-07-26 06:45:07 +04:00
/* Save the CPU context, used for jumping back */
pushl % e b x
pushl % e s i
pushl % e d i
pushl % e b p
pushf
movl 2 0 + 8 ( % e s p ) , % e b p / * l i s t o f p a g e s * /
movl P T R ( V A _ C O N T R O L _ P A G E ) ( % e b p ) , % e d i
movl % e s p , E S P ( % e d i )
movl % c r0 , % e a x
movl % e a x , C R 0 ( % e d i )
movl % c r3 , % e a x
movl % e a x , C R 3 ( % e d i )
movl % c r4 , % e a x
movl % e a x , C R 4 ( % e d i )
2006-09-26 12:52:38 +04:00
2005-06-26 01:57:56 +04:00
/* read the arguments and say goodbye to the stack */
2008-07-26 06:45:07 +04:00
movl 2 0 + 4 ( % e s p ) , % e b x / * p a g e _ l i s t * /
movl 2 0 + 8 ( % e s p ) , % e b p / * l i s t o f p a g e s * /
movl 2 0 + 1 2 ( % e s p ) , % e d x / * s t a r t a d d r e s s * /
movl 2 0 + 1 6 ( % e s p ) , % e c x / * c p u _ h a s _ p a e * /
movl 2 0 + 2 0 ( % e s p ) , % e s i / * p r e s e r v e _ c o n t e x t * /
2005-06-26 01:57:56 +04:00
/* zero out flags, and disable interrupts */
pushl $ 0
popfl
2008-07-26 06:45:07 +04:00
/* save some information for jumping back */
movl P T R ( V A _ C O N T R O L _ P A G E ) ( % e b p ) , % e d i
movl % e d i , C P _ V A _ C O N T R O L _ P A G E ( % e d i )
movl P T R ( P A _ P G D ) ( % e b p ) , % e a x
movl % e a x , C P _ P A _ P G D ( % e d i )
movl P T R ( P A _ S W A P _ P A G E ) ( % e b p ) , % e a x
movl % e a x , C P _ P A _ S W A P _ P A G E ( % e d i )
movl % e b x , C P _ P A _ B A C K U P _ P A G E S _ M A P ( % e d i )
2009-03-10 05:56:57 +03:00
/ *
* get p h y s i c a l a d d r e s s o f c o n t r o l p a g e n o w
* this i s i m p o s s i b l e a f t e r p a g e t a b l e s w i t c h
* /
2006-09-26 12:52:38 +04:00
movl P T R ( P A _ C O N T R O L _ P A G E ) ( % e b p ) , % e d i
2005-06-26 01:57:56 +04:00
2006-09-26 12:52:38 +04:00
/* switch to new set of page tables */
movl P T R ( P A _ P G D ) ( % e b p ) , % e a x
movl % e a x , % c r3
/* setup a new stack at the end of the physical control page */
2008-03-23 00:00:07 +03:00
lea P A G E _ S I Z E ( % e d i ) , % e s p
2006-09-26 12:52:38 +04:00
/* jump to identity mapped page */
movl % e d i , % e a x
addl $ ( i d e n t i t y _ m a p p e d - r e l o c a t e _ k e r n e l ) , % e a x
pushl % e a x
ret
identity_mapped :
2011-07-14 05:34:37 +04:00
/* set return address to 0 if not preserving context */
pushl $ 0
2006-09-26 12:52:38 +04:00
/* store the start address on the stack */
pushl % e d x
2005-06-26 01:57:56 +04:00
2009-03-10 05:56:57 +03:00
/ *
* Set c r0 t o a k n o w n s t a t e :
2008-03-23 00:00:08 +03:00
* - Paging d i s a b l e d
* - Alignment c h e c k d i s a b l e d
* - Write p r o t e c t d i s a b l e d
* - No t a s k s w i t c h
* - Don' t d o F P s o f t w a r e e m u l a t i o n .
* - Proctected m o d e e n a b l e d
2005-06-26 01:57:56 +04:00
* /
movl % c r0 , % e a x
2008-03-23 00:00:08 +03:00
andl $ ~ ( X 8 6 _ C R 0 _ P G | X 8 6 _ C R 0 _ A M | X 8 6 _ C R 0 _ W P | X 8 6 _ C R 0 _ T S | X 8 6 _ C R 0 _ E M ) , % e a x
orl $ ( X 8 6 _ C R 0 _ P E ) , % e a x
2005-06-26 01:57:56 +04:00
movl % e a x , % c r0
/* clear cr4 if applicable */
testl % e c x , % e c x
jz 1 f
2009-03-10 05:56:57 +03:00
/ *
* Set c r4 t o a k n o w n s t a t e :
2005-06-26 01:57:56 +04:00
* Setting e v e r y t h i n g t o z e r o s e e m s s a f e .
* /
2008-03-23 00:00:06 +03:00
xorl % e a x , % e a x
2005-06-26 01:57:56 +04:00
movl % e a x , % c r4
jmp 1 f
1 :
/* Flush the TLB (needed?) */
xorl % e a x , % e a x
movl % e a x , % c r3
2008-07-26 06:45:07 +04:00
movl C P _ P A _ S W A P _ P A G E ( % e d i ) , % e a x
pushl % e a x
pushl % e b x
call s w a p _ p a g e s
addl $ 8 , % e s p
2009-03-10 05:56:57 +03:00
/ *
* To b e c e r t a i n o f a v o i d i n g p r o b l e m s w i t h s e l f - m o d i f y i n g c o d e
2008-07-26 06:45:07 +04:00
* I n e e d t o e x e c u t e a s e r i a l i z i n g i n s t r u c t i o n h e r e .
* So I f l u s h t h e T L B , i t ' s h a n d y , a n d n o t p r o c e s s o r d e p e n d e n t .
* /
xorl % e a x , % e a x
movl % e a x , % c r3
2009-03-10 05:56:57 +03:00
/ *
* set a l l o f t h e r e g i s t e r s t o k n o w n v a l u e s
* leave % e s p a l o n e
* /
2008-07-26 06:45:07 +04:00
testl % e s i , % e s i
jnz 1 f
xorl % e d i , % e d i
xorl % e a x , % e a x
xorl % e b x , % e b x
xorl % e c x , % e c x
xorl % e d x , % e d x
xorl % e s i , % e s i
xorl % e b p , % e b p
ret
1 :
popl % e d x
movl C P _ P A _ S W A P _ P A G E ( % e d i ) , % e s p
addl $ P A G E _ S I Z E , % e s p
2 :
call * % e d x
/* get the re-entry point of the peer system */
movl 0 ( % e s p ) , % e b p
call 1 f
1 :
popl % e b x
subl $ ( 1 b - r e l o c a t e _ k e r n e l ) , % e b x
movl C P _ V A _ C O N T R O L _ P A G E ( % e b x ) , % e d i
lea P A G E _ S I Z E ( % e b x ) , % e s p
movl C P _ P A _ S W A P _ P A G E ( % e b x ) , % e a x
movl C P _ P A _ B A C K U P _ P A G E S _ M A P ( % e b x ) , % e d x
pushl % e a x
pushl % e d x
call s w a p _ p a g e s
addl $ 8 , % e s p
movl C P _ P A _ P G D ( % e b x ) , % e a x
movl % e a x , % c r3
movl % c r0 , % e a x
orl $ ( 1 < < 3 1 ) , % e a x
movl % e a x , % c r0
lea P A G E _ S I Z E ( % e d i ) , % e s p
movl % e d i , % e a x
addl $ ( v i r t u a l _ m a p p e d - r e l o c a t e _ k e r n e l ) , % e a x
pushl % e a x
ret
virtual_mapped :
movl C R 4 ( % e d i ) , % e a x
movl % e a x , % c r4
movl C R 3 ( % e d i ) , % e a x
movl % e a x , % c r3
movl C R 0 ( % e d i ) , % e a x
movl % e a x , % c r0
movl E S P ( % e d i ) , % e s p
movl % e b p , % e a x
popf
popl % e b p
popl % e d i
popl % e s i
popl % e b x
ret
2005-06-26 01:57:56 +04:00
/* Do the copies */
2008-07-26 06:45:07 +04:00
swap_pages :
movl 8 ( % e s p ) , % e d x
movl 4 ( % e s p ) , % e c x
pushl % e b p
pushl % e b x
pushl % e d i
pushl % e s i
movl % e c x , % e b x
2005-06-26 01:57:56 +04:00
jmp 1 f
0 : /* top, read another word from the indirection page */
movl ( % e b x ) , % e c x
addl $ 4 , % e b x
1 :
testl $ 0 x1 , % e c x / * i s i t a d e s t i n a t i o n p a g e * /
jz 2 f
movl % e c x , % e d i
andl $ 0 x f f f f f00 0 , % e d i
jmp 0 b
2 :
testl $ 0 x2 , % e c x / * i s i t a n i n d i r e c t i o n p a g e * /
jz 2 f
movl % e c x , % e b x
andl $ 0 x f f f f f00 0 , % e b x
jmp 0 b
2 :
testl $ 0 x4 , % e c x / * i s i t t h e d o n e i n d i c a t o r * /
jz 2 f
jmp 3 f
2 :
testl $ 0 x8 , % e c x / * i s i t t h e s o u r c e i n d i c a t o r * /
jz 0 b / * I g n o r e i t o t h e r w i s e * /
movl % e c x , % e s i / * F o r e v e r y s o u r c e p a g e d o a c o p y * /
andl $ 0 x f f f f f00 0 , % e s i
2008-07-26 06:45:07 +04:00
movl % e d i , % e a x
movl % e s i , % e b p
movl % e d x , % e d i
2005-06-26 01:57:56 +04:00
movl $ 1 0 2 4 , % e c x
rep ; movsl
2008-07-26 06:45:07 +04:00
movl % e b p , % e d i
movl % e a x , % e s i
movl $ 1 0 2 4 , % e c x
rep ; movsl
2005-06-26 01:57:56 +04:00
2008-07-26 06:45:07 +04:00
movl % e a x , % e d i
movl % e d x , % e s i
movl $ 1 0 2 4 , % e c x
rep ; movsl
2005-06-26 01:57:56 +04:00
2008-07-26 06:45:07 +04:00
lea P A G E _ S I Z E ( % e b p ) , % e s i
jmp 0 b
3 :
popl % e s i
popl % e d i
popl % e b x
popl % e b p
2005-06-26 01:57:56 +04:00
ret
2008-08-15 11:40:23 +04:00
.globl kexec_control_code_size
.set kexec_ c o n t r o l _ c o d e _ s i z e , . - r e l o c a t e _ k e r n e l