2011-02-14 18:36:03 -08:00
# include < l i n u x / l i n k a g e . h >
# include < l i n u x / i n i t . h >
# include < a s m / s e g m e n t . h >
# include < a s m / p a g e _ t y p e s . h >
/ *
* The f o l l o w i n g c o d e a n d d a t a r e b o o t s t h e m a c h i n e b y s w i t c h i n g t o r e a l
* mode a n d j u m p i n g t o t h e B I O S r e s e t e n t r y p o i n t , a s i f t h e C P U h a s
* really b e e n r e s e t . T h e p r e v i o u s v e r s i o n a s k e d t h e k e y b o a r d
* controller t o p u l s e t h e C P U r e s e t l i n e , w h i c h i s m o r e t h o r o u g h , b u t
* doesn' t w o r k w i t h a t l e a s t o n e t y p e o f 4 8 6 m o t h e r b o a r d . I t i s e a s y
* to s t o p t h i s c o d e w o r k i n g ; hence the copious comments.
*
* This c o d e i s c a l l e d w i t h t h e r e s t a r t t y p e ( 0 = B I O S , 1 = A P M ) i n % e a x .
* /
.section " .x86_trampoline " , " a"
.balign 16
.code32
ENTRY( m a c h i n e _ r e a l _ r e s t a r t _ a s m )
r_ b a s e = .
/* Get our own relocated address */
call 1 f
1 : popl % e b x
2011-05-02 14:33:24 -07:00
subl $ ( 1 b - r _ b a s e ) , % e b x
2011-02-14 18:36:03 -08:00
2011-02-18 15:47:42 -08:00
/* Compute the equivalent real-mode segment */
movl % e b x , % e c x
shrl $ 4 , % e c x
2011-02-14 18:36:03 -08:00
/* Patch post-real-mode segment jump */
2011-05-02 14:33:24 -07:00
movw ( d i s p a t c h _ t a b l e - r _ b a s e ) ( % e b x ,% e a x ,2 ) ,% a x
movw % a x , ( 1 0 1 f - r _ b a s e ) ( % e b x )
movw % c x , ( 1 0 2 f - r _ b a s e ) ( % e b x )
2011-02-14 18:36:03 -08:00
/* Set up the IDT for real mode. */
2011-05-02 14:33:24 -07:00
lidtl ( m a c h i n e _ r e a l _ r e s t a r t _ i d t - r _ b a s e ) ( % e b x )
2011-02-14 18:36:03 -08:00
/ *
* Set u p a G D T f r o m w h i c h w e c a n l o a d s e g m e n t d e s c r i p t o r s f o r r e a l
* mode. T h e G D T i s n o t u s e d i n r e a l m o d e ; it is just needed here to
* prepare t h e d e s c r i p t o r s .
* /
2011-05-02 14:33:24 -07:00
lgdtl ( m a c h i n e _ r e a l _ r e s t a r t _ g d t - r _ b a s e ) ( % e b x )
2011-02-14 18:36:03 -08:00
/ *
* Load t h e d a t a s e g m e n t r e g i s t e r s w i t h 1 6 - b i t c o m p a t i b l e v a l u e s
* /
movl $ 1 6 , % e c x
movl % e c x , % d s
movl % e c x , % e s
movl % e c x , % f s
movl % e c x , % g s
movl % e c x , % s s
ljmpl $ 8 , $ 1 f - r _ b a s e
/ *
* This i s 1 6 - b i t p r o t e c t e d m o d e c o d e t o d i s a b l e p a g i n g a n d t h e c a c h e ,
* switch t o r e a l m o d e a n d j u m p t o t h e B I O S r e s e t c o d e .
*
* The i n s t r u c t i o n t h a t s w i t c h e s t o r e a l m o d e b y w r i t i n g t o C R 0 m u s t b e
* followed i m m e d i a t e l y b y a f a r j u m p i n s t r u c t i o n , w h i c h s e t C S t o a
* valid v a l u e f o r r e a l m o d e , a n d f l u s h e s t h e p r e f e t c h q u e u e t o a v o i d
* running i n s t r u c t i o n s t h a t h a v e a l r e a d y b e e n d e c o d e d i n p r o t e c t e d
* mode.
*
* Clears a l l t h e f l a g s e x c e p t E T , e s p e c i a l l y P G ( p a g i n g ) , P E
* ( protected- m o d e e n a b l e ) a n d T S ( t a s k s w i t c h f o r c o p r o c e s s o r s t a t e
* save) . F l u s h e s t h e T L B a f t e r p a g i n g h a s b e e n d i s a b l e d . S e t s C D a n d
* NW, t o d i s a b l e t h e c a c h e o n a 4 8 6 , a n d i n v a l i d a t e s t h e c a c h e . T h i s
* is m o r e l i k e t h e s t a t e o f a 4 8 6 a f t e r r e s e t . I d o n ' t k n o w i f
* something e l s e s h o u l d b e d o n e f o r o t h e r c h i p s .
*
* More c o u l d b e d o n e h e r e t o s e t u p t h e r e g i s t e r s a s i f a C P U r e s e t h a d
* occurred; hopefully real BIOSs don't assume much. This is not the
* actual B I O S e n t r y p o i n t , a n y w a y ( t h a t i s a t 0 x f f f f f f f0 ) .
*
* Most o f t h i s w o r k i s p r o b a b l y e x c e s s i v e , b u t i t i s w h a t i s t e s t e d .
* /
.code16
1 :
xorl % e c x , % e c x
movl % c r0 , % e a x
andl $ 0 x00 0 0 0 0 1 1 , % e a x
orl $ 0 x60 0 0 0 0 0 0 , % e a x
movl % e a x , % c r0
movl % e c x , % c r3
movl % c r0 , % e d x
andl $ 0 x60 0 0 0 0 0 0 , % e d x / * I f n o c a c h e b i t s - > n o w b i n v d * /
jz 2 f
wbinvd
2 :
andb $ 0 x10 , % a l
movl % e a x , % c r0
.byte 0xea /* ljmpw */
101 : .word 0 /* Offset */
102 : .word 0 /* Segment */
bios :
ljmpw $ 0 x f00 0 , $ 0 x f f f0
apm :
movw $ 0 x10 0 0 , % a x
movw % a x , % s s
movw $ 0 x f00 0 , % s p
movw $ 0 x53 0 7 , % a x
movw $ 0 x00 0 1 , % b x
movw $ 0 x00 0 3 , % c x
int $ 0 x15
END( m a c h i n e _ r e a l _ r e s t a r t _ a s m )
.balign 16
/* These must match <asm/reboot.h */
dispatch_table :
.word bios - r_ b a s e
.word apm - r_ b a s e
END( d i s p a t c h _ t a b l e )
.balign 16
machine_real_restart_idt :
.word 0xffff /* Length - real mode default value */
.long 0 /* Base - real mode default value */
END( m a c h i n e _ r e a l _ r e s t a r t _ i d t )
.balign 16
ENTRY( m a c h i n e _ r e a l _ r e s t a r t _ g d t )
.quad 0 /* Self-pointer, filled in by PM code */
.quad 0 /* 16-bit code segment, filled in by PM code */
/ *
* 1 6 - bit d a t a s e g m e n t w i t h t h e s e l e c t o r v a l u e 1 6 = 0 x10 a n d
* base v a l u e 0 x10 0 ; since this is consistent with real mode
* semantics w e d o n ' t h a v e t o r e l o a d t h e s e g m e n t s o n c e C R 0 . P E = 0 .
* /
.quad GDT_ E N T R Y ( 0 x00 9 3 , 0 x10 0 , 0 x f f f f )
END( m a c h i n e _ r e a l _ r e s t a r t _ g d t )