2005-04-16 15:20:36 -07:00
/ *
* linux/ a r c h / x86 _ 6 4 / k e r n e l / h e a d . S - - s t a r t i n 3 2 b i t a n d s w i t c h t o 6 4 b i t
*
* Copyright ( C ) 2 0 0 0 A n d r e a A r c a n g e l i < a n d r e a @suse.de> SuSE
* Copyright ( C ) 2 0 0 0 P a v e l M a c h e k < p a v e l @suse.cz>
* Copyright ( C ) 2 0 0 0 K a r s t e n K e i l < k k e i l @suse.de>
* Copyright ( C ) 2 0 0 1 ,2 0 0 2 A n d i K l e e n < a k @suse.de>
* /
# include < l i n u x / l i n k a g e . h >
# include < l i n u x / t h r e a d s . h >
2005-11-05 17:25:53 +01:00
# include < l i n u x / i n i t . h >
2005-04-16 15:20:36 -07:00
# include < a s m / d e s c . h >
# include < a s m / s e g m e n t . h >
2007-05-02 19:27:06 +02:00
# include < a s m / p g t a b l e . h >
2005-04-16 15:20:36 -07:00
# include < a s m / p a g e . h >
# include < a s m / m s r . h >
# include < a s m / c a c h e . h >
/ * we a r e n o t a b l e t o s w i t c h i n o n e s t e p t o t h e f i n a l K E R N E L A D R E S S S P A C E
* because w e n e e d i d e n t i t y - m a p p e d p a g e s o n s e t u p s o d e f i n e _ _ S T A R T _ K E R N E L t o
* 0 x1 0 0 0 0 0 f o r t h i s s t a g e
*
* /
.text
2006-03-25 16:30:28 +01:00
.section .bootstrap .text
2005-04-16 15:20:36 -07:00
.code32
.globl startup_32
/* %bx: 1 if coming from smp trampoline on secondary cpu */
startup_32 :
/ *
* At t h i s p o i n t t h e C P U r u n s i n 3 2 b i t p r o t e c t e d m o d e ( C S . D = 1 ) w i t h
* paging d i s a b l e d a n d t h e p o i n t o f t h i s f i l e i s t o s w i t c h t o 6 4 b i t
* long m o d e w i t h a k e r n e l m a p p i n g f o r k e r n e l a n d t o j u m p i n t o t h e
* kernel v i r t u a l a d d r e s s e s .
* There i s n o s t a c k u n t i l w e s e t o n e u p .
* /
/* Initialize the %ds segment register */
movl $ _ _ K E R N E L _ D S ,% e a x
movl % e a x ,% d s
/* Load new GDT with the 64bit segments using 32bit descriptor */
lgdt p G D T 3 2 - _ _ S T A R T _ K E R N E L _ m a p
/ * If t h e C P U d o e s n ' t s u p p o r t C P U I D t h i s w i l l d o u b l e f a u l t .
* Unfortunately i t i s h a r d t o c h e c k f o r C P U I D w i t h o u t a s t a c k .
* /
/* Check if extended functions are implemented */
movl $ 0 x80 0 0 0 0 0 0 , % e a x
cpuid
cmpl $ 0 x80 0 0 0 0 0 0 , % e a x
jbe n o _ l o n g _ m o d e
/* Check if long mode is implemented */
mov $ 0 x80 0 0 0 0 0 1 , % e a x
cpuid
btl $ 2 9 , % e d x
jnc n o _ l o n g _ m o d e
/ *
* Prepare f o r e n t e r i n g 6 4 b i t s m o d e
* /
/* Enable PAE mode */
xorl % e a x , % e a x
btsl $ 5 , % e a x
movl % e a x , % c r4
/* Setup early boot stage 4 level pagetables */
2005-11-05 17:25:53 +01:00
movl $ ( b o o t _ l e v e l 4 _ p g t - _ _ S T A R T _ K E R N E L _ m a p ) , % e a x
2005-04-16 15:20:36 -07:00
movl % e a x , % c r3
/* Setup EFER (Extended Feature Enable Register) */
movl $ M S R _ E F E R , % e c x
rdmsr
/* Enable Long Mode */
btsl $ _ E F E R _ L M E , % e a x
/* Make changes effective */
wrmsr
xorl % e a x , % e a x
btsl $ 3 1 , % e a x / * E n a b l e p a g i n g a n d i n t u r n a c t i v a t e L o n g M o d e * /
btsl $ 0 , % e a x / * E n a b l e p r o t e c t e d m o d e * /
/* Make changes effective */
movl % e a x , % c r0
/ *
* At t h i s p o i n t w e ' r e i n l o n g m o d e b u t i n 3 2 b i t c o m p a t i b i l i t y m o d e
* with E F E R . L M E = 1 , C S . L = 0 , C S . D = 1 ( a n d i n t u r n
* EFER. L M A = 1 ) . N o w w e w a n t t o j u m p i n 6 4 b i t m o d e , t o d o t h a t w e u s e
* the n e w g d t / i d t t h a t h a s _ _ K E R N E L _ C S w i t h C S . L = 1 .
* /
ljmp $ _ _ K E R N E L _ C S , $ ( s t a r t u p _ 6 4 - _ _ S T A R T _ K E R N E L _ m a p )
.code64
.org 0x100
.globl startup_64
startup_64 :
/ * We c o m e h e r e e i t h e r f r o m s t a r t u p _ 3 2
* or d i r e c t l y f r o m a 6 4 b i t b o o t l o a d e r .
* Since w e m a y h a v e c o m e d i r e c t l y f r o m a b o o t l o a d e r w e
* reload t h e p a g e t a b l e s h e r e .
* /
/* Enable PAE mode and PGE */
xorq % r a x , % r a x
btsq $ 5 , % r a x
btsq $ 7 , % r a x
movq % r a x , % c r4
/* Setup early boot stage 4 level pagetables. */
2005-11-05 17:25:53 +01:00
movq $ ( b o o t _ l e v e l 4 _ p g t - _ _ S T A R T _ K E R N E L _ m a p ) , % r a x
2005-04-16 15:20:36 -07:00
movq % r a x , % c r3
/* Check if nx is implemented */
movl $ 0 x80 0 0 0 0 0 1 , % e a x
cpuid
movl % e d x ,% e d i
/* Setup EFER (Extended Feature Enable Register) */
movl $ M S R _ E F E R , % e c x
rdmsr
/* Enable System Call */
btsl $ _ E F E R _ S C E , % e a x
/* No Execute supported? */
btl $ 2 0 ,% e d i
jnc 1 f
btsl $ _ E F E R _ N X , % e a x
1 :
/* Make changes effective */
wrmsr
/* Setup cr0 */
2005-07-28 21:15:48 -07:00
# define C R 0 _ P M 1 / * p r o t e c t e d m o d e * /
# define C R 0 _ M P ( 1 < < 1 )
# define C R 0 _ E T ( 1 < < 4 )
# define C R 0 _ N E ( 1 < < 5 )
# define C R 0 _ W P ( 1 < < 1 6 )
# define C R 0 _ A M ( 1 < < 1 8 )
# define C R 0 _ P A G I N G ( 1 < < 3 1 )
movl $ C R 0 _ P M | C R 0 _ M P | C R 0 _ E T | C R 0 _ N E | C R 0 _ W P | C R 0 _ A M | C R 0 _ P A G I N G ,% e a x
2005-04-16 15:20:36 -07:00
/* Make changes effective */
movq % r a x , % c r0
/* Setup a boot time stack */
movq i n i t _ r s p ( % r i p ) ,% r s p
/* zero EFLAGS after setting rsp */
pushq $ 0
popfq
/ *
* We m u s t s w i t c h t o a n e w d e s c r i p t o r i n k e r n e l s p a c e f o r t h e G D T
* because s o o n t h e k e r n e l w o n ' t h a v e a c c e s s a n y m o r e t o t h e u s e r s p a c e
* addresses w h e r e w e ' r e c u r r e n t l y r u n n i n g o n . W e h a v e t o d o t h a t h e r e
* because i n 3 2 b i t w e c o u l d n ' t l o a d a 6 4 b i t l i n e a r a d d r e s s .
* /
lgdt c p u _ g d t _ d e s c r
2007-02-13 13:26:24 +01:00
/* set up data segments. actually 0 would do too */
movl $ _ _ K E R N E L _ D S ,% e a x
movl % e a x ,% d s
movl % e a x ,% s s
movl % e a x ,% e s
/ *
* We d o n ' t r e a l l y n e e d t o l o a d % f s o r % g s , b u t l o a d t h e m a n y w a y
* to k i l l a n y s t a l e r e a l m o d e s e l e c t o r s . T h i s a l l o w s e x e c u t i o n
* under V T h a r d w a r e .
* /
movl % e a x ,% f s
movl % e a x ,% g s
2005-04-16 15:20:36 -07:00
/ *
* Setup u p a d u m m y P D A . t h i s i s j u s t f o r s o m e e a r l y b o o t u p c o d e
* that d o e s i n _ i n t e r r u p t ( )
* /
movl $ M S R _ G S _ B A S E ,% e c x
movq $ e m p t y _ z e r o _ p a g e ,% r a x
movq % r a x ,% r d x
shrq $ 3 2 ,% r d x
wrmsr
/ * esi i s p o i n t e r t o r e a l m o d e s t r u c t u r e w i t h i n t e r e s t i n g i n f o .
pass i t t o C * /
movl % e s i , % e d i
/ * Finally j u m p t o r u n C c o d e a n d t o b e o n r e a l k e r n e l a d d r e s s
* Since w e a r e r u n n i n g o n i d e n t i t y - m a p p e d s p a c e w e h a v e t o j u m p
2006-09-26 10:52:38 +02:00
* to t h e f u l l 6 4 b i t a d d r e s s , t h i s i s o n l y p o s s i b l e a s i n d i r e c t
* jump. I n a d d i t i o n w e n e e d t o e n s u r e % c s i s s e t s o w e m a k e t h i s
* a f a r r e t u r n .
2005-04-16 15:20:36 -07:00
* /
movq i n i t i a l _ c o d e ( % r i p ) ,% r a x
2006-09-26 10:52:38 +02:00
pushq $ 0 # f a k e r e t u r n a d d r e s s t o s t o p u n w i n d e r
pushq $ _ _ K E R N E L _ C S # s e t c o r r e c t c s
pushq % r a x # t a r g e t a d d r e s s i n n e g a t i v e s p a c e
lretq
2005-04-16 15:20:36 -07:00
2006-03-25 16:30:01 +01:00
/* SMP bootup changes these two */
.align 8
2005-04-16 15:20:36 -07:00
.globl initial_code
initial_code :
.quad x86_64_start_kernel
.globl init_rsp
init_rsp :
.quad init_ t h r e a d _ u n i o n + T H R E A D _ S I Z E - 8
ENTRY( e a r l y _ i d t _ h a n d l e r )
2005-04-16 15:25:00 -07:00
cmpl $ 2 ,e a r l y _ r e c u r s i o n _ f l a g ( % r i p )
jz 1 f
incl e a r l y _ r e c u r s i o n _ f l a g ( % r i p )
2005-04-16 15:20:36 -07:00
xorl % e a x ,% e a x
movq 8 ( % r s p ) ,% r s i # g e t r i p
movq ( % r s p ) ,% r d x
movq % c r2 ,% r c x
leaq e a r l y _ i d t _ m s g ( % r i p ) ,% r d i
call e a r l y _ p r i n t k
2005-04-16 15:25:00 -07:00
cmpl $ 2 ,e a r l y _ r e c u r s i o n _ f l a g ( % r i p )
jz 1 f
call d u m p _ s t a c k
2006-02-16 23:42:10 +01:00
# ifdef C O N F I G _ K A L L S Y M S
leaq e a r l y _ i d t _ r i p m s g ( % r i p ) ,% r d i
movq 8 ( % r s p ) ,% r s i # g e t r i p a g a i n
call _ _ p r i n t _ s y m b o l
# endif
2005-04-16 15:20:36 -07:00
1 : hlt
jmp 1 b
2005-04-16 15:25:00 -07:00
early_recursion_flag :
.long 0
2005-04-16 15:20:36 -07:00
early_idt_msg :
.asciz " PANIC : early e x c e p t i o n r i p % l x e r r o r % l x c r2 % l x \ n "
2006-02-16 23:42:10 +01:00
early_idt_ripmsg :
.asciz " RIP % s \ n "
2005-04-16 15:20:36 -07:00
.code32
ENTRY( n o _ l o n g _ m o d e )
/* This isn't an x86-64 CPU so hang */
1 :
jmp 1 b
.org 0xf00
.globl pGDT32
pGDT32 :
2006-03-25 16:30:01 +01:00
.word gdt_ e n d - c p u _ g d t _ t a b l e - 1
2005-04-16 15:20:36 -07:00
.long cpu_ g d t _ t a b l e - _ _ S T A R T _ K E R N E L _ m a p
.org 0xf10
ljumpvector :
.long startup_ 6 4 - _ _ S T A R T _ K E R N E L _ m a p
.word __KERNEL_CS
ENTRY( s t e x t )
ENTRY( _ s t e x t )
2006-01-17 07:03:32 +01:00
# define N E X T _ P A G E ( n a m e ) \
2007-05-02 19:27:06 +02:00
.balign PAGE_ S I Z E ; \
2006-01-17 07:03:32 +01:00
ENTRY( n a m e )
2007-05-02 19:27:06 +02:00
/* Automate the creation of 1 to 1 mapping pmd entries */
# define P M D S ( S T A R T , P E R M , C O U N T ) \
i = 0 ; \
.rept ( COUNT) ; \
.quad ( START) + ( i < < 2 1 ) + ( P E R M ) ; \
i = i + 1 ; \
.endr
2006-01-17 07:03:32 +01:00
NEXT_ P A G E ( i n i t _ l e v e l 4 _ p g t )
2005-11-05 17:25:53 +01:00
/* This gets initialized in x86_64_start_kernel */
.fill 5 1 2 , 8 , 0
2005-04-16 15:20:36 -07:00
2006-01-17 07:03:32 +01:00
NEXT_ P A G E ( l e v e l 3 _ i d e n t _ p g t )
2007-05-02 19:27:06 +02:00
.quad level2_ident_pgt - _ _ START_ K E R N E L _ m a p + _ K E R N P G _ T A B L E
2005-04-16 15:20:36 -07:00
.fill 5 1 1 , 8 , 0
2006-01-17 07:03:32 +01:00
NEXT_ P A G E ( l e v e l 3 _ k e r n e l _ p g t )
2005-04-16 15:20:36 -07:00
.fill 5 1 0 , 8 , 0
/* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
2007-05-02 19:27:06 +02:00
.quad level2_kernel_pgt - _ _ START_ K E R N E L _ m a p + _ K E R N P G _ T A B L E
2005-04-16 15:20:36 -07:00
.fill 1 , 8 , 0
2006-01-17 07:03:32 +01:00
NEXT_ P A G E ( l e v e l 2 _ i d e n t _ p g t )
2007-05-02 19:27:06 +02:00
/ * Since I e a s i l y c a n , m a p t h e f i r s t 1 G .
* Don' t s e t N X b e c a u s e c o d e r u n s f r o m t h e s e p a g e s .
* /
PMDS( 0 x00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 , _ _ P A G E _ K E R N E L _ L A R G E _ E X E C , P T R S _ P E R _ P M D )
2005-04-16 15:20:36 -07:00
2006-01-17 07:03:32 +01:00
NEXT_ P A G E ( l e v e l 2 _ k e r n e l _ p g t )
2005-04-16 15:20:36 -07:00
/ * 4 0 MB k e r n e l m a p p i n g . T h e k e r n e l c o d e c a n n o t b e b i g g e r t h a n t h a t .
When y o u c h a n g e t h i s c h a n g e K E R N E L _ T E X T _ S I Z E i n p a g e . h t o o . * /
/* (2^48-(2*1024*1024*1024)-((2^39)*511)-((2^30)*510)) = 0 */
2007-05-02 19:27:06 +02:00
PMDS( 0 x00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 , _ _ P A G E _ K E R N E L _ L A R G E _ E X E C | _ P A G E _ G L O B A L ,
KERNEL_ T E X T _ S I Z E / P M D _ S I Z E )
2005-04-16 15:20:36 -07:00
/* Module mapping starts here */
2007-05-02 19:27:06 +02:00
.fill ( PTRS_ P E R _ P M D - ( K E R N E L _ T E X T _ S I Z E / P M D _ S I Z E ) ) ,8 ,0
2005-04-16 15:20:36 -07:00
2007-05-02 19:27:06 +02:00
# undef P M D S
2006-01-17 07:03:32 +01:00
# undef N E X T _ P A G E
2005-04-16 15:20:36 -07:00
2006-01-17 07:03:32 +01:00
.data
2005-04-16 15:20:36 -07:00
# ifdef C O N F I G _ A C P I _ S L E E P
2006-01-17 07:03:32 +01:00
.align PAGE_SIZE
2005-04-16 15:20:36 -07:00
ENTRY( w a k e u p _ l e v e l 4 _ p g t )
2007-05-02 19:27:06 +02:00
.quad level3_ident_pgt - _ _ START_ K E R N E L _ m a p + _ K E R N P G _ T A B L E
.fill 5 1 0 , 8 , 0
2005-04-16 15:20:36 -07:00
/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
2007-05-02 19:27:06 +02:00
.quad level3_kernel_pgt - _ _ START_ K E R N E L _ m a p + _ K E R N P G _ T A B L E
2005-04-16 15:20:36 -07:00
# endif
2005-11-05 17:25:53 +01:00
# ifndef C O N F I G _ H O T P L U G _ C P U
_ _ INITDATA
# endif
/ *
* This d e f a u l t s e t t i n g g e n e r a t e s a n i d e n t m a p p i n g a t a d d r e s s 0 x10 0 0 0 0
* and a m a p p i n g f o r t h e k e r n e l t h a t p r e c i s e l y m a p s v i r t u a l a d d r e s s
* 0 xffffffff8 0 0 0 0 0 0 0 t o p h y s i c a l a d d r e s s 0 x00 0 0 0 0 . ( a l w a y s u s i n g
* 2 Mbyte l a r g e p a g e s p r o v i d e d b y P A E m o d e )
* /
.align PAGE_SIZE
ENTRY( b o o t _ l e v e l 4 _ p g t )
2007-05-02 19:27:06 +02:00
.quad level3_ident_pgt - _ _ START_ K E R N E L _ m a p + _ K E R N P G _ T A B L E
.fill 2 5 7 , 8 , 0
.quad level3_ident_pgt - _ _ START_ K E R N E L _ m a p + _ K E R N P G _ T A B L E
.fill 2 5 2 , 8 , 0
2005-11-05 17:25:53 +01:00
/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
2007-05-02 19:27:06 +02:00
.quad level3_kernel_pgt - _ _ START_ K E R N E L _ m a p + _ P A G E _ T A B L E
2005-11-05 17:25:53 +01:00
2005-04-16 15:20:36 -07:00
.data
.align 16
.globl cpu_gdt_descr
cpu_gdt_descr :
2006-03-25 16:30:01 +01:00
.word gdt_ e n d - c p u _ g d t _ t a b l e - 1
2005-04-16 15:20:36 -07:00
gdt :
.quad cpu_gdt_table
# ifdef C O N F I G _ S M P
.rept NR_ C P U S - 1
.word 0
.quad 0
.endr
# endif
/ * We n e e d v a l i d k e r n e l s e g m e n t s f o r d a t a a n d c o d e i n l o n g m o d e t o o
* IRET w i l l c h e c k t h e s e g m e n t t y p e s k k e i l 2 0 0 0 / 1 0 / 2 8
* Also s y s r e t m a n d a t e s a s p e c i a l G D T l a y o u t
* /
2006-03-25 16:30:01 +01:00
.section .data .page_aligned , " aw"
.align PAGE_SIZE
2005-04-16 15:20:36 -07:00
/ * The T L S d e s c r i p t o r s a r e c u r r e n t l y a t a d i f f e r e n t p l a c e c o m p a r e d t o i 3 8 6 .
Hopefully n o b o d y e x p e c t s t h e m a t a f i x e d p l a c e ( W i n e ? ) * /
ENTRY( c p u _ g d t _ t a b l e )
.quad 0x0000000000000000 /* NULL descriptor */
2006-01-11 22:46:24 +01:00
.quad 0x0 /* unused */
2005-04-16 15:20:36 -07:00
.quad 0x00af9a000000ffff /* __KERNEL_CS */
.quad 0x00cf92000000ffff /* __KERNEL_DS */
.quad 0x00cffa000000ffff /* __USER32_CS */
.quad 0x00cff2000000ffff /* __USER_DS, __USER32_DS */
.quad 0x00affa000000ffff /* __USER_CS */
.quad 0x00cf9a000000ffff /* __KERNEL32_CS */
.quad 0 , 0 /* TSS */
.quad 0 , 0 /* LDT */
.quad 0 , 0 , 0 /* three TLS descriptors */
2006-09-26 10:52:28 +02:00
.quad 0x0000f40000000000 /* node/CPU stored in limit */
2005-04-16 15:20:36 -07:00
gdt_end :
/* asm/segment.h:GDT_ENTRIES must match this */
/* This should be a multiple of the cache line size */
2006-01-11 22:43:57 +01:00
/* GDTs of other CPUs are now dynamically allocated */
/* zero the remaining page */
.fill PAGE_SIZE / 8 - GDT_ E N T R I E S ,8 ,0
2005-04-16 15:20:36 -07:00
2006-03-25 16:30:01 +01:00
.section .bss , " aw" , @nobits
.align L1_CACHE_BYTES
ENTRY( i d t _ t a b l e )
.skip 256 * 1 6
2005-04-16 15:20:36 -07:00
2006-03-25 16:30:01 +01:00
.section .bss .page_aligned , " aw" , @nobits
.align PAGE_SIZE
ENTRY( e m p t y _ z e r o _ p a g e )
.skip PAGE_SIZE