head.S
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/x86_64/kernel/head.S -- start in 32bit and switch to 64bit
  3.  *
  4.  *  Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
  5.  *  Copyright (C) 2000 Pavel Machek <pavel@suse.cz>
  6.  *  Copyright (C) 2000 Karsten Keil <kkeil@suse.de>
  7.  *  Copyright (C) 2001,2002 Andi Kleen <ak@suse.de>
  8.  *
  9.  *  $Id: head.S,v 1.53 2002/07/18 09:49:42 ak Exp $
  10.  */
  11. #include <linux/linkage.h>
  12. #include <linux/threads.h>
  13. #include <asm/desc.h>
  14. #include <asm/segment.h>
  15. #include <asm/page.h>
  16. #include <asm/msr.h>
  17. #include <asm/offset.h>
  18. /* we are not able to switch in one step to the final KERNEL ADRESS SPACE
  19.  * because we need identity-mapped pages on setup so define __START_KERNEL to
  20.  * 0x100000 for this stage
  21.  * 
  22.  */
  23. .text
  24. .code32
  25. /* %bx:  1 if comming from smp trampoline on secondary cpu */ 
  26. startup_32:
  27. /*
  28.  * At this point the CPU runs in 32bit protected mode (CS.D = 1) with
  29.  * paging disabled and the point of this file is to switch to 64bit
  30.  * long mode with a kernel mapping for kerneland to jump into the
  31.  * kernel virtual addresses.
  32.    * There is no stack until we set one up.
  33.  */
  34. movl %ebx,%ebp /* Save trampoline flag */
  35. /* First check if extended functions are implemented */
  36. movl $0x80000000, %eax
  37. cpuid
  38. cmpl $0x80000000, %eax
  39. jbe no_long_mode
  40. /* Check if long mode is implemented */
  41. mov $0x80000001, %eax
  42. cpuid
  43. btl $29, %edx
  44. jnc no_long_mode
  45. movl %edx,%edi
  46. /*
  47.  * Prepare for entering 64bits mode
  48.  */
  49. /* Enable PAE mode and PGE */
  50. xorl %eax, %eax
  51. btsl $5, %eax
  52. btsl $7, %eax
  53. movl %eax, %cr4
  54. /* Setup early boot stage 4 level pagetables */
  55. movl $0x101000, %eax
  56. movl %eax, %cr3
  57. /* Setup EFER (Extended Feature Enable Register) */
  58. movl $MSR_EFER, %ecx
  59. rdmsr
  60. /* Fool rdmsr and reset %eax to avoid dependences */
  61. xorl %eax, %eax
  62. /* Enable Long Mode */
  63. btsl $_EFER_LME, %eax
  64. /* Enable System Call */
  65. btsl $_EFER_SCE, %eax
  66. #if 0
  67. /* No Execute supported? */
  68. btl $20,%edi
  69. jnc     1f
  70. btsl $_EFER_NX, %eax
  71. 1:
  72. #endif
  73. /* Make changes effective */
  74. wrmsr
  75. xorl %eax, %eax
  76. /* Enable paging and in turn activate Long Mode */
  77. btsl $31, %eax
  78. /* Enable protected mode */
  79. btsl $0, %eax
  80. /* Enable MP */
  81. btsl $1, %eax
  82. /* Enable ET */
  83. btsl $4, %eax
  84. /* Enable NE */
  85. btsl $5, %eax
  86. /* Enable WP */
  87. btsl $16, %eax
  88. /* Enable AM */
  89. btsl $18, %eax
  90. /* Make changes effective */
  91. movl %eax, %cr0
  92. jmp reach_compatibility_mode
  93. reach_compatibility_mode:
  94. /*
  95.  * At this point we're in long mode but in 32bit compatibility mode
  96.  * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
  97.  * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we load
  98.  * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
  99.  */
  100. testw %bp,%bp /* secondary CPU? */ 
  101. jnz   second
  102. /* Load new GDT with the 64bit segment using 32bit descriptor */
  103. /* to avoid 32bit relocations we use fixed adresses here */
  104. movl $0x100F00, %eax
  105. lgdt (%eax)
  106. movl    $0x100F10, %eax
  107. /* Finally jump in 64bit mode */
  108. ljmp *(%eax)
  109. second:
  110. /* abuse syscall to get into 64bit mode. this way we don't need
  111.    a working low identity mapping just for the short 32bit roundtrip. 
  112.    XXX kludge. this should not be needed. */
  113. movl  $MSR_STAR,%ecx
  114. xorl  %eax,%eax
  115. movl  $(__USER32_CS<<16)|__KERNEL_CS,%edx
  116. wrmsr
  117. movl  $MSR_CSTAR,%ecx
  118. movl  $0xffffffff,%edx
  119. movl  $0x80100100,%eax # reach_long64 absolute
  120. wrmsr
  121. syscall
  122. .code64
  123. .org 0x100
  124. reach_long64:
  125. movq init_rsp(%rip),%rsp
  126. /* zero EFLAGS after setting rsp */
  127. pushq $0
  128. popfq
  129. /*
  130.  * We must switch to a new descriptor in kernel space for the GDT
  131.  * because soon the kernel won't have access anymore to the userspace
  132.  * addresses where we're currently running on. We have to do that here
  133.  * because in 32bit we couldn't load a 64bit linear address.
  134.  */
  135. lgdt pGDT64
  136. /* 
  137.  * Setup up a dummy PDA. this is just for some early bootup code
  138.  * that does in_interrupt() 
  139.  */ 
  140. movl $MSR_GS_BASE,%ecx
  141. movq $cpu_pda,%rax
  142. movq    %rax,%rdx
  143. shrq $32,%rdx
  144. wrmsr
  145. /* set up data segments. actually 0 would do too */
  146. movl $__KERNEL_DS,%eax
  147. movl %eax,%ds
  148. movl %eax,%ss
  149. movl %eax,%es
  150. /* esi is pointer to real mode structure with interesting info.
  151.    pass it to C */
  152. movl %esi, %edi
  153. /* Finally jump to run C code and to be on real kernel address
  154.  * Since we are running on identity-mapped space we have to jump
  155.  * to the full 64bit address , this is only possible as indirect
  156.  * jump
  157.  */
  158. movq initial_code(%rip),%rax
  159. jmp *%rax
  160. /* SMP bootup changes these two */
  161. .globl initial_code
  162. initial_code:
  163. .quad x86_64_start_kernel
  164. .globl init_rsp
  165. init_rsp:
  166. .quad  init_task_union+THREAD_SIZE-8
  167. .code32
  168. ENTRY(no_long_mode)
  169. /* This isn't an x86-64 CPU so hang */
  170. 1:
  171. jmp 1b
  172. .org 0xf00
  173. pGDT32:
  174. .word gdt32_end-gdt_table32
  175. .long gdt_table32-__START_KERNEL+0x100000
  176. .org 0xf10
  177. ljumpvector:
  178. .long reach_long64-__START_KERNEL+0x100000
  179. .word __KERNEL_CS
  180. ENTRY(stext)
  181. ENTRY(_stext)
  182. /*
  183.  * This default setting generates an ident mapping at address 0x100000
  184.  * and a mapping for the kernel that precisely maps virtual address
  185.  * 0xffffffff80000000 to physical address 0x000000. (always using
  186.  * 2Mbyte large pages provided by PAE mode)
  187.  */
  188. .org 0x1000
  189. ENTRY(init_level4_pgt)
  190. .quad 0x0000000000102007 /* -> level3_ident_pgt */
  191. .fill 255,8,0
  192. .quad 0x000000000010a007
  193. .fill 254,8,0
  194. /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
  195. .quad 0x0000000000103007 /* -> level3_kernel_pgt */
  196. .org 0x2000
  197. /* Kernel does not "know" about 4-th level of page tables. */
  198. ENTRY(level3_ident_pgt)
  199. .quad 0x0000000000104007
  200. .fill 511,8,0
  201. .org 0x3000
  202. ENTRY(level3_kernel_pgt)
  203. .fill 510,8,0
  204. /* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
  205. .quad 0x0000000000105007 /* -> level2_kernel_pgt */
  206. .fill 1,8,0
  207. .org 0x4000
  208. ENTRY(level2_ident_pgt)
  209. /* 40MB for bootup.  */
  210. .quad 0x0000000000000283
  211. .quad 0x0000000000200183
  212. .quad 0x0000000000400183
  213. .quad 0x0000000000600183
  214. .quad 0x0000000000800183
  215. .quad 0x0000000000A00183
  216. .quad 0x0000000000C00183
  217. .quad 0x0000000000E00183
  218. .quad 0x0000000001000183
  219. .quad 0x0000000001200183
  220. .quad 0x0000000001400183
  221. .quad 0x0000000001600183
  222. .quad 0x0000000001800183
  223. .quad 0x0000000001A00183
  224. .quad 0x0000000001C00183
  225. .quad 0x0000000001E00183
  226. .quad 0x0000000002000183
  227. .quad 0x0000000002200183
  228. .quad 0x0000000002400183
  229. .quad 0x0000000002600183
  230. /* Temporary mappings for the super early allocator in arch/x86_64/mm/init.c */
  231. .globl temp_boot_pmds
  232. temp_boot_pmds:
  233. .fill 492,8,0
  234. .org 0x5000
  235. ENTRY(level2_kernel_pgt)
  236. /* 40MB kernel mapping. The kernel code cannot be bigger than that.
  237.    When you change this change KERNEL_TEXT_SIZE in pgtable.h too. */
  238. /* (2^48-(2*1024*1024*1024)-((2^39)*511)-((2^30)*510)) = 0 */
  239. .quad 0x0000000000000183
  240. .quad 0x0000000000200183
  241. .quad 0x0000000000400183
  242. .quad 0x0000000000600183
  243. .quad 0x0000000000800183
  244. .quad 0x0000000000A00183
  245. .quad 0x0000000000C00183
  246. .quad 0x0000000000E00183
  247. .quad 0x0000000001000183
  248. .quad 0x0000000001200183
  249. .quad 0x0000000001400183
  250. .quad 0x0000000001600183
  251. .quad 0x0000000001800183
  252. .quad 0x0000000001A00183
  253. .quad 0x0000000001C00183
  254. .quad 0x0000000001E00183
  255. .quad 0x0000000002000183
  256. .quad 0x0000000002200183
  257. .quad 0x0000000002400183
  258. .quad 0x0000000002600183
  259. /* Module mapping starts here */
  260. .fill 492,8,0
  261. .org 0x6000
  262. ENTRY(empty_zero_page)
  263. .org 0x7000
  264. ENTRY(empty_bad_page)
  265. .org 0x8000
  266. ENTRY(empty_bad_pte_table)
  267. .org 0x9000
  268. ENTRY(empty_bad_pmd_table)
  269. .org 0xa000
  270. ENTRY(level3_physmem_pgt)
  271. .quad 0x0000000000105007 /* -> level2_kernel_pgt (so that __va works even before pagetable_init) */
  272. .org 0xb000
  273. .data
  274. .globl SYMBOL_NAME(gdt)
  275. .word 0
  276. .align 16
  277. .word 0
  278. pGDT64:
  279. .word gdt_end-gdt_table
  280. SYMBOL_NAME_LABEL(gdt)
  281. .quad gdt_table
  282. .align 64 /* cacheline aligned */
  283. ENTRY(gdt_table32)
  284. .quad 0x0000000000000000 /* This one is magic */
  285. .quad 0x0000000000000000 /* unused */
  286. .quad 0x00af9a000000ffff /* __KERNEL_CS */
  287. gdt32_end:
  288. /* We need valid kernel segments for data and code in long mode too
  289.  * IRET will check the segment types  kkeil 2000/10/28
  290.  * Also sysret mandates a special GDT layout 
  291.  */
  292.  
  293. .align 64 /* cacheline aligned, keep this synchronized with asm/desc.h */
  294. ENTRY(gdt_table)
  295. .quad 0x0000000000000000 /* This one is magic */
  296. .quad 0x0000000000000000 /* unused */
  297. .quad 0x00af9a000000ffff /* __KERNEL_CS */
  298. .quad 0x00cf92000000ffff /* __KERNEL_DS */
  299. .quad 0x00cffe000000ffff /* __USER32_CS */
  300. .quad 0x00cff2000000ffff /* __USER_DS, __USER32_DS  */
  301. .quad 0x00affa000000ffff /* __USER_CS */
  302. .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
  303. .word 0 # base address = 0
  304. .word 0x9A00 # code read/exec
  305. .word 0x00CF # granularity = 4096, 386
  306. #  (+5th nibble of limit)
  307. /* __KERNEL32_CS */
  308. /* when you add something here fix constant in desc.h */
  309. .globl gdt_cpu_table
  310. gdt_cpu_table:
  311. .fill NR_CPUS*PER_CPU_GDT_SIZE,1,0
  312. gdt_end:
  313. .globl gdt_end
  314. .align  64
  315. ENTRY(idt_table)
  316. .rept   256
  317. .quad   0
  318. .quad  0
  319. .endr