head.S 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. // 这是内核执行头程序
  2. // Created by longjin.
  3. // 2022/01/20
  4. #include "common/asm.h"
  5. #include <asm/apu_boot.h>
  6. // 以下是来自 multiboot2 规范的定义
  7. // How many bytes from the start of the file we search for the header.
  8. #define MULTIBOOT2_SEARCH 32768
  9. #define MULTIBOOT2_HEADER_ALIGN 8
  10. // The magic field should contain this.
  11. #define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
  12. // Alignment of multiboot modules.
  13. #define MULTIBOOT2_MOD_ALIGN 0x00001000
  14. // Alignment of the multiboot info structure.
  15. #define MULTIBOOT2_INFO_ALIGN 0x00000008
  16. // Flags set in the 'flags' member of the multiboot header.
  17. #define MULTIBOOT2_TAG_ALIGN 8
  18. #define MULTIBOOT2_TAG_TYPE_END 0
  19. #define MULTIBOOT2_TAG_TYPE_CMDLINE 1
  20. #define MULTIBOOT2_TAG_TYPE_BOOT_LOADER_NAME 2
  21. #define MULTIBOOT2_TAG_TYPE_MODULE 3
  22. #define MULTIBOOT2_TAG_TYPE_BASIC_MEMINFO 4
  23. #define MULTIBOOT2_TAG_TYPE_BOOTDEV 5
  24. #define MULTIBOOT2_TAG_TYPE_MMAP 6
  25. #define MULTIBOOT2_TAG_TYPE_VBE 7
  26. #define MULTIBOOT2_TAG_TYPE_FRAMEBUFFER 8
  27. #define MULTIBOOT2_TAG_TYPE_ELF_SECTIONS 9
  28. #define MULTIBOOT2_TAG_TYPE_APM 10
  29. #define MULTIBOOT2_TAG_TYPE_EFI32 11
  30. #define MULTIBOOT2_TAG_TYPE_EFI64 12
  31. #define MULTIBOOT2_TAG_TYPE_SMBIOS 13
  32. #define MULTIBOOT2_TAG_TYPE_ACPI_OLD 14
  33. #define MULTIBOOT2_TAG_TYPE_ACPI_NEW 15
  34. #define MULTIBOOT2_TAG_TYPE_NETWORK 16
  35. #define MULTIBOOT2_TAG_TYPE_EFI_MMAP 17
  36. #define MULTIBOOT2_TAG_TYPE_EFI_BS 18
  37. #define MULTIBOOT2_TAG_TYPE_EFI32_IH 19
  38. #define MULTIBOOT2_TAG_TYPE_EFI64_IH 20
  39. #define MULTIBOOT2_TAG_TYPE_LOAD_BASE_ADDR 21
  40. #define MULTIBOOT2_HEADER_TAG_END 0
  41. #define MULTIBOOT2_HEADER_TAG_INFORMATION_REQUEST 1
  42. #define MULTIBOOT2_HEADER_TAG_ADDRESS 2
  43. #define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS 3
  44. #define MULTIBOOT2_HEADER_TAG_CONSOLE_FLAGS 4
  45. #define MULTIBOOT2_HEADER_TAG_FRAMEBUFFER 5
  46. #define MULTIBOOT2_HEADER_TAG_MODULE_ALIGN 6
  47. #define MULTIBOOT2_HEADER_TAG_EFI_BS 7
  48. #define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
  49. #define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
  50. #define MULTIBOOT2_HEADER_TAG_RELOCATABLE 10
  51. #define MULTIBOOT2_ARCHITECTURE_I386 0
  52. #define MULTIBOOT2_ARCHITECTURE_MIPS32 4
  53. #define MULTIBOOT2_HEADER_TAG_OPTIONAL 1
  54. #define MULTIBOOT2_LOAD_PREFERENCE_NONE 0
  55. #define MULTIBOOT2_LOAD_PREFERENCE_LOW 1
  56. #define MULTIBOOT2_LOAD_PREFERENCE_HIGH 2
  57. #define MULTIBOOT2_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
  58. #define MULTIBOOT2_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
  59. // This should be in %eax.
  60. #define MULTIBOOT_BOOTLOADER_MAGIC 0x2badb002
  61. #define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
  62. // 存储到boot_entry_type的值
  63. #define BOOT_ENTRY_TYPE_MULTIBOOT 1
  64. #define BOOT_ENTRY_TYPE_MULTIBOOT2 2
  65. #define BOOT_ENTRY_TYPE_LINUX_32 3
  66. #define BOOT_ENTRY_TYPE_LINUX_64 4
  67. // 直接用 -m64 编译出来的是 64 位代码,
  68. // 但是启动后的机器是 32 位的,相当于在 32 位机器上跑 64 位程序。
  69. // 得加一层跳转到 64 位的 -m32 代码,开启 long 模式后再跳转到以 -m64 编译的代码中
  70. // 对于 x86_64,需要在启动阶段进入长模式(IA32E),这意味着需要一个临时页表
  71. // See https://wiki.osdev.org/Creating_a_64-bit_kernel:
  72. // With a 32-bit bootstrap in your kernel
  73. // 这部分是从保护模式启动 long 模式的代码
  74. // 工作在 32bit
  75. // 声明这一段代码以 32 位模式编译
  76. .code32
  77. .section ".multiboot_header", "a"
  78. #define MB_FLAGS_FB 0x4
  79. // reference: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Header-graphics-fields
  80. #define MB_HEADER_GRAPHIC_MODE_LINEAR 0
  81. #define MB_HEADER_GRAPHIC_MODE_TEXT 1
  82. MB_MAGIC = 0x1BADB002
  83. MB_FLAGS = MB_FLAGS_FB
  84. MB_CHECKSUM = -(MB_MAGIC + MB_FLAGS)
  85. .code32
  86. multiboot_header:
  87. .align 8
  88. .long MB_MAGIC
  89. .long MB_FLAGS
  90. .long MB_CHECKSUM
  91. // header_addr if flags[16] is set
  92. .long 0
  93. // load_addr if flags[16] is set
  94. .long 0
  95. // load_end_addr if flags[16] is set
  96. .long 0
  97. // bss_end_addr if flags[16] is set
  98. .long 0
  99. // entry_addr if flags[16] is set
  100. .long 0
  101. // mode_type if flags[2] is set
  102. .long MB_HEADER_GRAPHIC_MODE_LINEAR
  103. // width if flags[2] is set
  104. .long 1440
  105. // height if flags[2] is set
  106. .long 900
  107. // depth if flags[2] is set
  108. .long 32
  109. // multiboot2 文件头
  110. // 计算头长度
  111. .SET MB2_HEADER_LENGTH, multiboot2_header_end - multiboot2_header
  112. // 计算校验和
  113. .SET MB2_CHECKSUM, -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT2_ARCHITECTURE_I386 + MB2_HEADER_LENGTH)
  114. // 8 字节对齐
  115. .code32
  116. .section .multiboot2_header
  117. .align MULTIBOOT2_HEADER_ALIGN
  118. // 声明所属段
  119. multiboot2_header:
  120. // 魔数
  121. .long MULTIBOOT2_HEADER_MAGIC
  122. // 架构
  123. .long MULTIBOOT2_ARCHITECTURE_I386
  124. // 头长度
  125. .long MB2_HEADER_LENGTH
  126. // 校验和
  127. .long MB2_CHECKSUM
  128. // 添加其它内容在此,详细信息见 Multiboot2 Specification version 2.0.pdf
  129. // 设置帧缓冲区(同时在这里设置qemu的分辨率, 默认为: 1440*900, 还支持: 640*480, 等)
  130. .align 8
  131. framebuffer_tag_start:
  132. .short MULTIBOOT2_HEADER_TAG_FRAMEBUFFER
  133. .short MULTIBOOT2_HEADER_TAG_OPTIONAL
  134. .long framebuffer_tag_end - framebuffer_tag_start
  135. .long 1440 // 宽
  136. .long 900 // 高
  137. .long 32
  138. framebuffer_tag_end:
  139. .align 8
  140. .short MULTIBOOT2_HEADER_TAG_END
  141. // 结束标记
  142. .short 0
  143. .long 8
  144. multiboot2_header_end:
  145. .section .bootstrap
  146. .global _start
  147. .type _start, @function
  148. .extern _start64
  149. .extern boot_info_addr
  150. .extern multiboot2_magic
  151. ENTRY(_start)
  152. // 关中断
  153. cli
  154. // multiboot2_info/ multiboot_info 结构体指针
  155. mov %ebx, mb_entry_info
  156. //mov %ebx, %e8
  157. // multiboot魔数
  158. mov %eax, mb_entry_magic
  159. mov $MULTIBOOT_BOOTLOADER_MAGIC, %ebx
  160. cmp %eax, %ebx
  161. je bl_magic_is_mb
  162. mov $MULTIBOOT2_BOOTLOADER_MAGIC, %ebx
  163. cmp %eax, %ebx
  164. je bl_magic_is_mb2
  165. jmp halt // unreachable
  166. bl_magic_is_mb:
  167. mov $BOOT_ENTRY_TYPE_MULTIBOOT, %ebx
  168. mov %ebx, boot_entry_type
  169. jmp protected_mode_setup
  170. bl_magic_is_mb2:
  171. mov $BOOT_ENTRY_TYPE_MULTIBOOT2, %ebx
  172. mov %ebx, boot_entry_type
  173. jmp protected_mode_setup
  174. protected_mode_setup:
  175. //mov %eax, %e9
  176. / 从保护模式跳转到长模式
  177. // 1. 允许 PAE
  178. mov %cr4, %eax
  179. or $(1<<5), %eax
  180. mov %eax, %cr4
  181. // 2. 设置临时页表
  182. // 最高级
  183. mov $pml4, %eax
  184. mov $pdpt, %ebx
  185. or $0x3, %ebx
  186. mov %ebx, 0(%eax)
  187. // 次级
  188. mov $pdpt, %eax
  189. mov $pd, %ebx
  190. or $0x3, %ebx
  191. mov %ebx, 0(%eax)
  192. // 次低级
  193. mov $pd, %eax
  194. mov $pt, %ebx
  195. or $0x3, %ebx
  196. mov %ebx, 0(%eax)
  197. // 最低级
  198. // 循环 512 次,填满一页
  199. mov $512, %ecx
  200. mov $pt, %eax
  201. mov $0x3, %ebx
  202. .fill_pt:
  203. mov %ebx, 0(%eax)
  204. add $0x1000, %ebx
  205. add $8, %eax
  206. loop .fill_pt
  207. .global enter_head_from_ap_boot
  208. enter_head_from_ap_boot:
  209. // 填写 CR3
  210. mov $pml4, %eax
  211. mov %eax, %cr3
  212. // 3. 切换到 long 模式
  213. mov $0xC0000080, %ecx
  214. rdmsr
  215. or $(1<<8), %eax
  216. wrmsr
  217. // 4. 开启分页
  218. mov %cr0, %eax
  219. or $(1<<31), %eax
  220. mov %eax, %cr0
  221. // 5. 重新设置 GDT
  222. mov $gdt64_pointer, %eax
  223. lgdt 0(%eax)
  224. jmp $0x8, $ready_to_start_64
  225. hlt
  226. ret
  227. .code64
  228. .global ready_to_start_64
  229. ready_to_start_64:
  230. mov $0x10, %ax
  231. mov %ax, %ds
  232. mov %ax, %es
  233. mov %ax, %fs
  234. mov %ax, %ss
  235. mov $0x7e00, %esp
  236. //6. 跳转到start64
  237. movq switch_to_start64(%rip), %rax
  238. pushq $0x08 //段选择子
  239. pushq %rax
  240. lretq
  241. switch_to_start64:
  242. .quad _start64
  243. .code64
  244. halt:
  245. cli
  246. hlt
  247. jmp halt
  248. .global _start64
  249. .type _start64, @function
  250. .extern Start_Kernel
  251. ENTRY(_start64)
  252. // 初始化寄存器
  253. mov $0x10, %ax
  254. mov %ax, %ds
  255. mov %ax, %es
  256. mov %ax, %fs
  257. mov %ax, %ss
  258. mov $0x7e00, %esp
  259. // === 加载GDTR ====
  260. lgdt GDT_POINTER(%rip) //这里我没搞明白rip相对寻址, 看了文档,大概是用来实现PIC的(position independent code)
  261. //lgdt $GDT_POINTER
  262. // === 加载IDTR ====
  263. lidt IDT_POINTER(%rip)
  264. //lidt $IDT_POINTER
  265. movq GDT_POINTER(%rip), %r12
  266. // 分支,判断是否为apu
  267. movq $0x1b, %rcx // 根据IA32_APIC_BASE.BSP[8]标志位判断处理器是否为apu
  268. rdmsr
  269. bt $8, %rax
  270. jnc load_apu_cr3
  271. // BSP处理器
  272. movq head_stack_start(%rip), %rsp
  273. // 2. 设置临时页表
  274. // 最高级
  275. mov $__PML4E, %eax
  276. mov $__PDPTE, %ebx
  277. or $0x3, %ebx
  278. mov %ebx, 0(%eax)
  279. mov $__PML4E, %eax
  280. // 加256个表项, 映射高地址
  281. add $2048, %eax
  282. mov %ebx, 0(%eax)
  283. // 次级
  284. mov $__PDPTE, %eax
  285. mov $__PDE, %ebx
  286. or $0x3, %ebx
  287. mov %ebx, 0(%eax)
  288. // 次低级
  289. mov $__PDE, %eax
  290. mov $50, %ecx
  291. mov $__PT_S, %ebx
  292. or $0x3, %ebx
  293. .fill_pde_64:
  294. mov %ebx, 0(%eax)
  295. add $0x1000, %ebx
  296. add $8, %eax
  297. loop .fill_pde_64
  298. // 最低级
  299. // 循环 512*25=12800 次,填满25页,共50M
  300. mov $12800, %ecx
  301. mov $__PT_S, %eax
  302. mov $0x3, %ebx
  303. .fill_pt_64:
  304. mov %ebx, 0(%eax)
  305. add $0x1000, %ebx
  306. add $8, %eax
  307. loop .fill_pt_64
  308. // 50-100M填0,共25个页表
  309. mov $12800, %ecx
  310. .fill_pt_64_2:
  311. movq $0, 0(%eax)
  312. add $8, %eax
  313. loop .fill_pt_64_2
  314. // ==== 加载CR3寄存器
  315. load_cr3:
  316. movq $__PML4E, %rax //设置页目录基地址
  317. movq %rax, %cr3
  318. jmp to_switch_seg
  319. load_apu_cr3:
  320. // 由于内存管理模块重置了页表,因此ap核心初始化的时候,需要使用新的内核页表。
  321. // 这个页表的值由smp模块设置到__APU_START_CR3变量中
  322. // 加载__APU_START_CR3中的值
  323. movq $__APU_START_CR3, %rax
  324. movq 0(%rax), %rax
  325. movq %rax, %cr3
  326. movq _apu_boot_tmp_stack_top_addr(%rip), %rsp
  327. jmp to_switch_seg
  328. to_switch_seg:
  329. movq switch_seg(%rip), %rax
  330. // 由于ljmp和lcall在GAS中不受支持,因此我们需要先伪造函数调用现场,通过lret的方式,给它跳转过去。才能更新cs寄存器
  331. // 实在是太妙了!Amazing!
  332. pushq $0x08 //段选择子
  333. pushq %rax
  334. lretq
  335. // 64位模式的代码
  336. switch_seg:
  337. .quad entry64
  338. entry64:
  339. movq $0x10, %rax
  340. movq %rax, %ds
  341. movq %rax, %es
  342. movq %rax, %gs
  343. movq %rax, %ss
  344. // 分支,判断是否为apu,然后设置栈指针·
  345. movq $0x1b, %rcx // 根据IA32_APIC_BASE.BSP[8]标志位判断处理器是否为apu
  346. rdmsr
  347. bt $8, %rax
  348. jnc __set_ap_tmp_stack_start2
  349. __set_bsp_stack_start2:
  350. movq head_stack_start(%rip), %rsp
  351. jmp __set_stack_start2_ok
  352. __set_ap_tmp_stack_start2:
  353. // 设置ap核心的临时栈
  354. movq _apu_boot_tmp_stack_top_addr(%rip), %rsp
  355. jmp __set_stack_start2_ok
  356. __set_stack_start2_ok:
  357. // 重新加载GDT和IDT,加载到高地址
  358. leaq GDT_Table(%rip), %r8
  359. leaq GDT_END(%rip), %r9
  360. subq %r8, %r9
  361. movq %r9, %r13 // GDT size
  362. leaq IDT_Table(%rip), %r8
  363. leaq IDT_END(%rip), %r9
  364. subq %r8, %r9
  365. movq %r9, %r12 // IDT size
  366. lgdt GDT_POINTER64(%rip)
  367. lidt IDT_POINTER64(%rip)
  368. // 分支,判断是否为apu
  369. movq $0x1b, %rcx // 根据IA32_APIC_BASE.BSP[8]标志位判断处理器是否为apu
  370. rdmsr
  371. bt $8, %rax
  372. jnc start_smp
  373. setup_IDT:
  374. // 该部分代码只在启动初期使用,后面的c文件中会重新设置IDT,
  375. leaq m_ignore_int(%rip), %rdx // 将ignore_int的地址暂时存到中段描述符的高8B
  376. movq $(0x08 << 16), %rax // 设置段选择子。由IDT结构和段选择子结构可知,本行设置段基地址为0x100000,TI=0,RPL=0
  377. movw %dx, %ax
  378. movq $ (0x8e00 << 32), %rcx // 设置Type=1110 P=1 DPL=00 0=0
  379. addq %rcx, %rax
  380. // 把ignore_int的地址填写到正确位置, rax存低8B, rdx存高8B
  381. movl %edx, %ecx
  382. shrl $16, %ecx // 去除低16位
  383. shlq $48, %rcx
  384. addq %rcx, %rax // 填写段内偏移31:16
  385. shrq $32, %rdx // (已经填写了32位,故右移32)
  386. leaq IDT_Table(%rip), %rdi // 获取中断描述符表的首地址,存储到rdi
  387. mov $256, %rcx // 初始化每个中断描述符
  388. repeat_set_idt:
  389. // ====== 循环,初始化总共256个中断描述符 ===
  390. movq %rax, (%rdi) // 保存低8B
  391. movq %rdx, 8(%rdi) // 保存高8B
  392. addq $0x10, %rdi // 转到下一个IDT表项
  393. dec %rcx
  394. jne repeat_set_idt
  395. //now enable SSE and the like
  396. movq %cr0, %rax
  397. and $0xFFFB, %ax //clear coprocessor emulation CR0.EM
  398. or $0x2, %ax //set coprocessor monitoring CR0.MP
  399. movq %rax, %cr0
  400. movq %cr4, %rax
  401. or $(3 << 9), %ax //set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
  402. movq %rax, %cr4
  403. movq go_to_kernel(%rip), %rax /* movq address */
  404. pushq $0x08
  405. pushq %rax
  406. // 传参
  407. movq mb_entry_info, %rdi
  408. movq mb_entry_magic, %rsi
  409. movq %r13, %rdx // GDT size
  410. movq %r12, %r10 // IDT size
  411. movq boot_entry_type, %r8
  412. lretq
  413. go_to_kernel:
  414. .quad kernel_main
  415. start_smp:
  416. //now enable SSE and the like
  417. movq %cr0, %rax
  418. and $0xFFFB, %ax //clear coprocessor emulation CR0.EM
  419. or $0x2, %ax //set coprocessor monitoring CR0.MP
  420. movq %rax, %cr0
  421. movq %cr4, %rax
  422. or $(3 << 9), %ax //set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
  423. movq %rax, %cr4
  424. movq go_to_smp_kernel(%rip), %rax /* movq address */
  425. pushq $0x08
  426. pushq %rax
  427. /*
  428. // 重新加载GDT和IDT,加载到高地址
  429. leaq GDT_Table(%rip), %r8
  430. leaq GDT_END(%rip), %r9
  431. subq %r8, %r9
  432. movq %r9, %r13 // GDT size
  433. leaq IDT_Table(%rip), %r8
  434. leaq IDT_END(%rip), %r9
  435. subq %r8, %r9
  436. movq %r9, %r12 // IDT size
  437. lgdt GDT_POINTER64(%rip)
  438. lidt IDT_POINTER64(%rip)
  439. */
  440. lretq
  441. go_to_smp_kernel:
  442. .quad smp_ap_start
  443. // ==== 异常/中断处理模块 ignore int: 忽略中断
  444. // (该部分代码只在启动初期使用,后面的c文件中会重新设置IDT,从而重设ignore_int的中断入点)
  445. m_ignore_int:
  446. // 切换到c语言的ignore_int
  447. movq go_to_ignore_int(%rip), %rax
  448. pushq $0x08
  449. pushq %rax
  450. lretq
  451. go_to_ignore_int:
  452. .quad ignore_int_handler
  453. ENTRY(head_stack_start)
  454. .quad BSP_IDLE_STACK_SPACE + 32768
  455. ENTRY(_apu_boot_tmp_stack_top_addr)
  456. .quad _apu_boot_tmp_stack_start + APU_BOOT_TMP_STACK_SIZE
  457. // 初始化页表
  458. .align 0x1000 //设置为4k对齐
  459. __PML4E:
  460. .skip 0x1000
  461. __PDPTE:
  462. .skip 0x1000
  463. // 三级页表
  464. __PDE:
  465. .skip 0x1000
  466. // 预留50个四级页表,总共表示100M的内存空间。这50个页表占用200KB的空间
  467. __PT_S:
  468. .skip 0x32000
  469. .global __APU_START_CR3
  470. __APU_START_CR3:
  471. .quad 0
  472. // GDT表
  473. .align 16
  474. .global GDT_Table // 使得GDT可以被外部程序引用或者访问
  475. GDT_Table:
  476. .quad 0x0000000000000000 // 0 空描述符 0x00
  477. .quad 0x0020980000000000 // 1 内核64位代码段描述符 0x08
  478. .quad 0x0000920000000000 // 2 内核64位数据段描述符 0x10
  479. .quad 0x0000000000000000 // 3 用户32位代码段描述符 0x18
  480. .quad 0x0000000000000000 // 4 用户32位数据段描述符 0x20
  481. .quad 0x00cff3000000ffff // 5 用户64位数据段描述符 0x28
  482. .quad 0x00affb000000ffff // 6 用户64位代码段描述符 0x30
  483. .quad 0x00cf9a000000ffff // 7 内核32位代码段描述符 0x38
  484. .quad 0x00cf92000000ffff // 8 内核32位数据段描述符 0x40
  485. .fill 100, 8, 0 // 10-11 TSS(跳过了第9段) 重复十次填充8字节的空间,赋值为0 长模式下,每个TSS长度为128bit
  486. GDT_END:
  487. .global GDT_POINTER
  488. GDT_POINTER:
  489. GDT_LIMIT: .word GDT_END - GDT_Table - 1 // GDT的大小
  490. GDT_BASE: .quad GDT_Table
  491. .global GDT_POINTER64
  492. GDT_POINTER64:
  493. GDT_LIMIT64: .word GDT_END - GDT_Table - 1 // GDT的大小
  494. GDT_BASE64: .quad GDT_Table + 0xffff800000000000
  495. // IDT 表
  496. .global IDT_Table
  497. IDT_Table:
  498. .fill 512, 8, 0 // 设置512*8字节的IDT表的空间
  499. IDT_END:
  500. .global IDT_POINTER
  501. IDT_POINTER:
  502. IDT_LIMIT: .word IDT_END - IDT_Table - 1
  503. IDT_BASE: .quad IDT_Table
  504. .global IDT_POINTER64
  505. IDT_POINTER64:
  506. IDT_LIMIT64: .word IDT_END - IDT_Table - 1
  507. IDT_BASE64: .quad IDT_Table + 0xffff800000000000
  508. .section .bootstrap.data
  509. mb_entry_magic: .quad 0
  510. mb_entry_info: .quad 0
  511. // 引导协议类型
  512. boot_entry_type: .quad 0
  513. .code32
  514. // 临时页表 4KB/页
  515. .align 0x1000
  516. .global pml4
  517. pml4:
  518. .skip 0x1000
  519. pdpt:
  520. .skip 0x1000
  521. pd:
  522. .skip 0x1000
  523. pt:
  524. .skip 0x1000
  525. // 临时 GDT
  526. .align 16
  527. gdt64:
  528. null_desc:
  529. .short 0xFFFF
  530. .short 0
  531. .byte 0
  532. .byte 0
  533. .byte 0
  534. .byte 0
  535. code_desc:
  536. .short 0
  537. .short 0
  538. .byte 0
  539. .byte 0x9A
  540. .byte 0x20
  541. .byte 0
  542. data_desc:
  543. .short 0
  544. .short 0
  545. .byte 0
  546. .byte 0x92
  547. .byte 0
  548. .byte 0
  549. user_code_desc:
  550. .short 0
  551. .short 0
  552. .byte 0
  553. .byte 0xFA
  554. .byte 0x20
  555. .byte 0
  556. user_data_desc:
  557. .short 0
  558. .short 0
  559. .byte 0
  560. .byte 0xF2
  561. .byte 0
  562. .byte 0
  563. gdt64_pointer:
  564. .short gdt64_pointer-gdt64-1
  565. .quad gdt64
  566. gdt64_pointer64:
  567. .short gdt64_pointer-gdt64-1
  568. .quad gdt64