head.S 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // 这是内核执行头程序
  2. // Created by longjin.
  3. // 2022/01/20
  4. .section .text
  5. .global _start
  6. _start:
  7. // 初始化寄存器
  8. mov $0x10, %ax
  9. mov %ax, %ds
  10. mov %ax, %es
  11. mov %ax, %fs
  12. mov %ax, %ss
  13. mov $0x7e00, %esp
  14. // === 加载GDTR ====
  15. lgdt GDT_POINTER(%rip) //这里我没搞明白rip相对寻址, 看了文档,大概是用来实现PIC的(position independent code)
  16. // === 加载IDTR ====
  17. lidt IDT_POINTER(%rip)
  18. mov $0x10, %ax
  19. mov %ax, %ds
  20. mov %ax, %es
  21. mov %ax, %fs
  22. mov %ax, %ss
  23. mov %ax, %gs
  24. movq $0x7e00, %rsp
  25. // ==== 加载CR3寄存器
  26. movq $0x101000, %rax //设置页目录基地址
  27. movq %rax, %cr3
  28. movq switch_seg(%rip), %rax
  29. // 由于ljmp和lcall在GAS中不受支持,因此我们需要先伪造函数调用现场,通过lret的方式,给它跳转过去。才能更新cs寄存器
  30. // 实在是太妙了!Amazing!
  31. pushq $0x08 //段选择子
  32. pushq %rax
  33. lretq
  34. // 64位模式的代码
  35. switch_seg:
  36. .quad entry64
  37. entry64:
  38. movq $0x10, %rax
  39. movq %rax, %ds
  40. movq %rax, %es
  41. movq %rax, %gs
  42. movq %rax, %ss
  43. movq $0xffff800000007e00, %rsp //rsp的地址
  44. // 切换到内核主程序
  45. movq go_to_kernel(%rip), %rax
  46. pushq $0x08
  47. pushq %rax
  48. lretq
  49. go_to_kernel:
  50. .quad Start_Kernel
  51. // 初始化页表
  52. .align 8 //设置为8byte对齐
  53. .org 0x1000 //设置页表位置为内核执行头程序的0x1000处
  54. __PML4E:
  55. .quad 0x102007 // 系统访问,可读写,已存在, 地址在31~12位
  56. .fill 255,8,0
  57. .quad 0x102007
  58. .fill 255,8,0
  59. .org 0x2000
  60. __PDPTE:
  61. .quad 0x103003 // 用户访问,可读写,已存在
  62. .fill 511,8,0
  63. .org 0x3000
  64. __PDE:
  65. .quad 0x000083 // 用户访问,可读写,已存在
  66. .quad 0x200083
  67. .quad 0x400083
  68. .quad 0x600083
  69. .quad 0x800083
  70. .quad 0xe0000083 /*0x a00000*/
  71. .quad 0xe0200083
  72. .quad 0xe0400083
  73. .quad 0xe0600083 /*0x1000000*/
  74. .quad 0xe0800083
  75. .quad 0xe0a00083
  76. .quad 0xe0c00083
  77. .quad 0xe0e00083
  78. .fill 499,8,0
  79. // GDT表
  80. .section .data
  81. .global GDT_Table // 使得GDT可以被外部程序引用或者访问
  82. GDT_Table:
  83. .quad 0x0000000000000000 // 0 空描述符 00
  84. .quad 0x0020980000000000 // 1 内核64位代码段描述符 08
  85. .quad 0x0000920000000000 // 2 内核64位数据段描述符 10
  86. .quad 0x0020f80000000000 // 3 用户64位代码段描述符 18
  87. .quad 0x0000f20000000000 // 4 用户64位数据段描述符 20
  88. .quad 0x00cf9a000000ffff // 5 内核32位代码段描述符 28
  89. .quad 0x00cf92000000ffff // 6 内核32位数据段描述符 30
  90. .fill 10, 8, 0 // 8~9 TSS(跳过了第七段) 重复十次填充8字节的空间,赋值为0
  91. GDT_END:
  92. GDT_POINTER:
  93. GDT_LIMIT: .word GDT_END - GDT_Table - 1 // GDT的大小
  94. GDT_BASE: .quad GDT_Table
  95. // IDT 表
  96. .global IDT_Table
  97. IDT_Table:
  98. .fill 512, 8, 0 // 设置512*8字节的IDT表的空间
  99. IDT_END:
  100. IDT_POINTER:
  101. IDT_LIMIT: .word IDT_END - IDT_Table - 1
  102. IDT_BASE: .quad IDT_Table
  103. // 64位的TSS表
  104. .global TSS64_Table
  105. TSS64_Table:
  106. .fill 13, 8, 0
  107. TSS64_END:
  108. TSS64_POINTER:
  109. TSS64_LIMIT: .word TSS64_END - TSS64_Table - 1
  110. TSS64_BASE: .quad TSS64_Table