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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/i386/head.S -- the 32-bit startup code.
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  *
  6.  *  Enhanced CPU detection and feature setting code by Mike Jagdis
  7.  *  and Martin Mares, November 1997.
  8.  */
  9. .text
  10. #include <linux/config.h>
  11. #include <linux/threads.h>
  12. #include <linux/linkage.h>
  13. #include <asm/segment.h>
  14. #include <asm/page.h>
  15. #include <asm/pgtable.h>
  16. #include <asm/desc.h>
  17. #define OLD_CL_MAGIC_ADDR 0x90020
  18. #define OLD_CL_MAGIC 0xA33F
  19. #define OLD_CL_BASE_ADDR 0x90000
  20. #define OLD_CL_OFFSET 0x90022
  21. #define NEW_CL_POINTER 0x228 /* Relative to real mode data */
  22. /*
  23.  * References to members of the boot_cpu_data structure.
  24.  */
  25. #define CPU_PARAMS SYMBOL_NAME(boot_cpu_data)
  26. #define X86 CPU_PARAMS+0
  27. #define X86_VENDOR CPU_PARAMS+1
  28. #define X86_MODEL CPU_PARAMS+2
  29. #define X86_MASK CPU_PARAMS+3
  30. #define X86_HARD_MATH CPU_PARAMS+6
  31. #define X86_CPUID CPU_PARAMS+8
  32. #define X86_CAPABILITY CPU_PARAMS+12
  33. #define X86_VENDOR_ID CPU_PARAMS+28
  34. /*
  35.  * swapper_pg_dir is the main page directory, address 0x00101000
  36.  *
  37.  * On entry, %esi points to the real-mode code as a 32-bit pointer.
  38.  */
  39. startup_32:
  40. /*
  41.  * Set segments to known values
  42.  */
  43. cld
  44. movl $(__KERNEL_DS),%eax
  45. movl %eax,%ds
  46. movl %eax,%es
  47. movl %eax,%fs
  48. movl %eax,%gs
  49. #ifdef CONFIG_SMP
  50. orw %bx,%bx
  51. jz 1f
  52. /*
  53.  * New page tables may be in 4Mbyte page mode and may
  54.  * be using the global pages. 
  55.  *
  56.  * NOTE! If we are on a 486 we may have no cr4 at all!
  57.  * So we do not try to touch it unless we really have
  58.  * some bits in it to set.  This won't work if the BSP
  59.  * implements cr4 but this AP does not -- very unlikely
  60.  * but be warned!  The same applies to the pse feature
  61.  * if not equally supported. --macro
  62.  *
  63.  * NOTE! We have to correct for the fact that we're
  64.  * not yet offset PAGE_OFFSET..
  65.  */
  66. #define cr4_bits mmu_cr4_features-__PAGE_OFFSET
  67. cmpl $0,cr4_bits
  68. je 3f
  69. movl %cr4,%eax # Turn on paging options (PSE,PAE,..)
  70. orl cr4_bits,%eax
  71. movl %eax,%cr4
  72. jmp 3f
  73. 1:
  74. #endif
  75. /*
  76.  * Initialize page tables
  77.  */
  78. movl $pg0-__PAGE_OFFSET,%edi /* initialize page tables */
  79. movl $007,%eax /* "007" doesn't mean with right to kill, but
  80.    PRESENT+RW+USER */
  81. 2: stosl
  82. add $0x1000,%eax
  83. cmp $empty_zero_page-__PAGE_OFFSET,%edi
  84. jne 2b
  85. /*
  86.  * Enable paging
  87.  */
  88. 3:
  89. movl $swapper_pg_dir-__PAGE_OFFSET,%eax
  90. movl %eax,%cr3 /* set the page table pointer.. */
  91. movl %cr0,%eax
  92. orl $0x80000000,%eax
  93. movl %eax,%cr0 /* ..and set paging (PG) bit */
  94. jmp 1f /* flush the prefetch-queue */
  95. 1:
  96. movl $1f,%eax
  97. jmp *%eax /* make sure eip is relocated */
  98. 1:
  99. /* Set up the stack pointer */
  100. lss stack_start,%esp
  101. #ifdef CONFIG_SMP
  102. orw  %bx,%bx
  103. jz  1f /* Initial CPU cleans BSS */
  104. pushl $0
  105. popfl
  106. jmp checkCPUtype
  107. 1:
  108. #endif CONFIG_SMP
  109. /*
  110.  * Clear BSS first so that there are no surprises...
  111.  * No need to cld as DF is already clear from cld above...
  112.  */
  113. xorl %eax,%eax
  114. movl $ SYMBOL_NAME(__bss_start),%edi
  115. movl $ SYMBOL_NAME(_end),%ecx
  116. subl %edi,%ecx
  117. rep
  118. stosb
  119. /*
  120.  * start system 32-bit setup. We need to re-do some of the things done
  121.  * in 16-bit mode for the "real" operations.
  122.  */
  123. call setup_idt
  124. /*
  125.  * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
  126.  * confuse the debugger if this code is traced.
  127.  * XXX - best to initialize before switching to protected mode.
  128.  */
  129. pushl $0
  130. popfl
  131. /*
  132.  * Copy bootup parameters out of the way. First 2kB of
  133.  * _empty_zero_page is for boot parameters, second 2kB
  134.  * is for the command line.
  135.  *
  136.  * Note: %esi still has the pointer to the real-mode data.
  137.  */
  138. movl $ SYMBOL_NAME(empty_zero_page),%edi
  139. movl $512,%ecx
  140. cld
  141. rep
  142. movsl
  143. xorl %eax,%eax
  144. movl $512,%ecx
  145. rep
  146. stosl
  147. movl SYMBOL_NAME(empty_zero_page)+NEW_CL_POINTER,%esi
  148. andl %esi,%esi
  149. jnz 2f # New command line protocol
  150. cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR
  151. jne 1f
  152. movzwl OLD_CL_OFFSET,%esi
  153. addl $(OLD_CL_BASE_ADDR),%esi
  154. 2:
  155. movl $ SYMBOL_NAME(empty_zero_page)+2048,%edi
  156. movl $512,%ecx
  157. rep
  158. movsl
  159. 1:
  160. checkCPUtype:
  161. movl $-1,X86_CPUID #  -1 for no CPUID initially
  162. /* check if it is 486 or 386. */
  163. /*
  164.  * XXX - this does a lot of unnecessary setup.  Alignment checks don't
  165.  * apply at our cpl of 0 and the stack ought to be aligned already, and
  166.  * we don't need to preserve eflags.
  167.  */
  168. movb $3,X86 # at least 386
  169. pushfl # push EFLAGS
  170. popl %eax # get EFLAGS
  171. movl %eax,%ecx # save original EFLAGS
  172. xorl $0x40000,%eax # flip AC bit in EFLAGS
  173. pushl %eax # copy to EFLAGS
  174. popfl # set EFLAGS
  175. pushfl # get new EFLAGS
  176. popl %eax # put it in eax
  177. xorl %ecx,%eax # change in flags
  178. andl $0x40000,%eax # check if AC bit changed
  179. je is386
  180. movb $4,X86 # at least 486
  181. movl %ecx,%eax
  182. xorl $0x200000,%eax # check ID flag
  183. pushl %eax
  184. popfl # if we are on a straight 486DX, SX, or
  185. pushfl # 487SX we can't change it
  186. popl %eax
  187. xorl %ecx,%eax
  188. pushl %ecx # restore original EFLAGS
  189. popfl
  190. andl $0x200000,%eax
  191. je is486
  192. /* get vendor info */
  193. xorl %eax,%eax # call CPUID with 0 -> return vendor ID
  194. cpuid
  195. movl %eax,X86_CPUID # save CPUID level
  196. movl %ebx,X86_VENDOR_ID # lo 4 chars
  197. movl %edx,X86_VENDOR_ID+4 # next 4 chars
  198. movl %ecx,X86_VENDOR_ID+8 # last 4 chars
  199. orl %eax,%eax # do we have processor info as well?
  200. je is486
  201. movl $1,%eax # Use the CPUID instruction to get CPU type
  202. cpuid
  203. movb %al,%cl # save reg for future use
  204. andb $0x0f,%ah # mask processor family
  205. movb %ah,X86
  206. andb $0xf0,%al # mask model
  207. shrb $4,%al
  208. movb %al,X86_MODEL
  209. andb $0x0f,%cl # mask mask revision
  210. movb %cl,X86_MASK
  211. movl %edx,X86_CAPABILITY
  212. is486:
  213. movl %cr0,%eax # 486 or better
  214. andl $0x80000011,%eax # Save PG,PE,ET
  215. orl $0x50022,%eax # set AM, WP, NE and MP
  216. jmp 2f
  217. is386: pushl %ecx # restore original EFLAGS
  218. popfl
  219. movl %cr0,%eax # 386
  220. andl $0x80000011,%eax # Save PG,PE,ET
  221. orl $2,%eax # set MP
  222. 2: movl %eax,%cr0
  223. call check_x87
  224. incb ready
  225. lgdt gdt_descr
  226. lidt idt_descr
  227. ljmp $(__KERNEL_CS),$1f
  228. 1: movl $(__KERNEL_DS),%eax # reload all the segment registers
  229. movl %eax,%ds # after changing gdt.
  230. movl %eax,%es
  231. movl %eax,%fs
  232. movl %eax,%gs
  233. #ifdef CONFIG_SMP
  234. movl $(__KERNEL_DS), %eax
  235. movl %eax,%ss # Reload the stack pointer (segment only)
  236. #else
  237. lss stack_start,%esp # Load processor stack
  238. #endif
  239. xorl %eax,%eax
  240. lldt %ax
  241. cld # gcc2 wants the direction flag cleared at all times
  242. #ifdef CONFIG_SMP
  243. movb ready, %cl
  244. cmpb $1,%cl
  245. je 1f # the first CPU calls start_kernel
  246. # all other CPUs call initialize_secondary
  247. call SYMBOL_NAME(initialize_secondary)
  248. jmp L6
  249. 1:
  250. #endif
  251. call SYMBOL_NAME(start_kernel)
  252. L6:
  253. jmp L6 # main should never return here, but
  254. # just in case, we know what happens.
  255. ready: .byte 0
  256. /*
  257.  * We depend on ET to be correct. This checks for 287/387.
  258.  */
  259. check_x87:
  260. movb $0,X86_HARD_MATH
  261. clts
  262. fninit
  263. fstsw %ax
  264. cmpb $0,%al
  265. je 1f
  266. movl %cr0,%eax /* no coprocessor: have to set bits */
  267. xorl $4,%eax /* set EM */
  268. movl %eax,%cr0
  269. ret
  270. ALIGN
  271. 1: movb $1,X86_HARD_MATH
  272. .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
  273. ret
  274. /*
  275.  *  setup_idt
  276.  *
  277.  *  sets up a idt with 256 entries pointing to
  278.  *  ignore_int, interrupt gates. It doesn't actually load
  279.  *  idt - that can be done only after paging has been enabled
  280.  *  and the kernel moved to PAGE_OFFSET. Interrupts
  281.  *  are enabled elsewhere, when we can be relatively
  282.  *  sure everything is ok.
  283.  */
  284. setup_idt:
  285. lea ignore_int,%edx
  286. movl $(__KERNEL_CS << 16),%eax
  287. movw %dx,%ax /* selector = 0x0010 = cs */
  288. movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
  289. lea SYMBOL_NAME(idt_table),%edi
  290. mov $256,%ecx
  291. rp_sidt:
  292. movl %eax,(%edi)
  293. movl %edx,4(%edi)
  294. addl $8,%edi
  295. dec %ecx
  296. jne rp_sidt
  297. ret
  298. ENTRY(stack_start)
  299. .long SYMBOL_NAME(init_task_union)+8192
  300. .long __KERNEL_DS
  301. /* This is the default interrupt "handler" :-) */
  302. int_msg:
  303. .asciz "Unknown interruptn"
  304. ALIGN
  305. ignore_int:
  306. cld
  307. pushl %eax
  308. pushl %ecx
  309. pushl %edx
  310. pushl %es
  311. pushl %ds
  312. movl $(__KERNEL_DS),%eax
  313. movl %eax,%ds
  314. movl %eax,%es
  315. pushl $int_msg
  316. call SYMBOL_NAME(printk)
  317. popl %eax
  318. popl %ds
  319. popl %es
  320. popl %edx
  321. popl %ecx
  322. popl %eax
  323. iret
  324. /*
  325.  * The interrupt descriptor table has room for 256 idt's,
  326.  * the global descriptor table is dependent on the number
  327.  * of tasks we can have..
  328.  */
  329. #define IDT_ENTRIES 256
  330. #define GDT_ENTRIES (__TSS(NR_CPUS))
  331. .globl SYMBOL_NAME(idt)
  332. .globl SYMBOL_NAME(gdt)
  333. ALIGN
  334. .word 0
  335. idt_descr:
  336. .word IDT_ENTRIES*8-1 # idt contains 256 entries
  337. SYMBOL_NAME(idt):
  338. .long SYMBOL_NAME(idt_table)
  339. .word 0
  340. gdt_descr:
  341. .word GDT_ENTRIES*8-1
  342. SYMBOL_NAME(gdt):
  343. .long SYMBOL_NAME(gdt_table)
  344. /*
  345.  * This is initialized to create an identity-mapping at 0-8M (for bootup
  346.  * purposes) and another mapping of the 0-8M area at virtual address
  347.  * PAGE_OFFSET.
  348.  */
  349. .org 0x1000
  350. ENTRY(swapper_pg_dir)
  351. .long 0x00102007
  352. .long 0x00103007
  353. .fill BOOT_USER_PGD_PTRS-2,4,0
  354. /* default: 766 entries */
  355. .long 0x00102007
  356. .long 0x00103007
  357. /* default: 254 entries */
  358. .fill BOOT_KERNEL_PGD_PTRS-2,4,0
  359. /*
  360.  * The page tables are initialized to only 8MB here - the final page
  361.  * tables are set up later depending on memory size.
  362.  */
  363. .org 0x2000
  364. ENTRY(pg0)
  365. .org 0x3000
  366. ENTRY(pg1)
  367. /*
  368.  * empty_zero_page must immediately follow the page tables ! (The
  369.  * initialization loop counts until empty_zero_page)
  370.  */
  371. .org 0x4000
  372. ENTRY(empty_zero_page)
  373. .org 0x5000
  374. /*
  375.  * Real beginning of normal "text" segment
  376.  */
  377. ENTRY(stext)
  378. ENTRY(_stext)
  379. /*
  380.  * This starts the data section. Note that the above is all
  381.  * in the text section because it has alignment requirements
  382.  * that we cannot fulfill any other way.
  383.  */
  384. .data
  385. ALIGN
  386. /*
  387.  * This contains typically 140 quadwords, depending on NR_CPUS.
  388.  *
  389.  * NOTE! Make sure the gdt descriptor in head.S matches this if you
  390.  * change anything.
  391.  */
  392. ENTRY(gdt_table)
  393. .quad 0x0000000000000000 /* NULL descriptor */
  394. .quad 0x0000000000000000 /* not used */
  395. .quad 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 */
  396. .quad 0x00cf92000000ffff /* 0x18 kernel 4GB data at 0x00000000 */
  397. .quad 0x00cffa000000ffff /* 0x23 user   4GB code at 0x00000000 */
  398. .quad 0x00cff2000000ffff /* 0x2b user   4GB data at 0x00000000 */
  399. .quad 0x0000000000000000 /* not used */
  400. .quad 0x0000000000000000 /* not used */
  401. /*
  402.  * The APM segments have byte granularity and their bases
  403.  * and limits are set at run time.
  404.  */
  405. .quad 0x0040920000000000 /* 0x40 APM set up for bad BIOS's */
  406. .quad 0x00409a0000000000 /* 0x48 APM CS    code */
  407. .quad 0x00009a0000000000 /* 0x50 APM CS 16 code (16 bit) */
  408. .quad 0x0040920000000000 /* 0x58 APM DS    data */
  409. .fill NR_CPUS*4,8,0 /* space for TSS's and LDT's */