boot.S 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // 以下是来自 multiboot2 规范的定义
  2. // How many bytes from the start of the file we search for the header.
  3. #define MULTIBOOT_SEARCH 32768
  4. #define MULTIBOOT_HEADER_ALIGN 8
  5. // The magic field should contain this.
  6. #define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
  7. // This should be in %eax.
  8. #define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
  9. // Alignment of multiboot modules.
  10. #define MULTIBOOT_MOD_ALIGN 0x00001000
  11. // Alignment of the multiboot info structure.
  12. #define MULTIBOOT_INFO_ALIGN 0x00000008
  13. // Flags set in the 'flags' member of the multiboot header.
  14. #define MULTIBOOT_TAG_ALIGN 8
  15. #define MULTIBOOT_TAG_TYPE_END 0
  16. #define MULTIBOOT_TAG_TYPE_CMDLINE 1
  17. #define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2
  18. #define MULTIBOOT_TAG_TYPE_MODULE 3
  19. #define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4
  20. #define MULTIBOOT_TAG_TYPE_BOOTDEV 5
  21. #define MULTIBOOT_TAG_TYPE_MMAP 6
  22. #define MULTIBOOT_TAG_TYPE_VBE 7
  23. #define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
  24. #define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9
  25. #define MULTIBOOT_TAG_TYPE_APM 10
  26. #define MULTIBOOT_TAG_TYPE_EFI32 11
  27. #define MULTIBOOT_TAG_TYPE_EFI64 12
  28. #define MULTIBOOT_TAG_TYPE_SMBIOS 13
  29. #define MULTIBOOT_TAG_TYPE_ACPI_OLD 14
  30. #define MULTIBOOT_TAG_TYPE_ACPI_NEW 15
  31. #define MULTIBOOT_TAG_TYPE_NETWORK 16
  32. #define MULTIBOOT_TAG_TYPE_EFI_MMAP 17
  33. #define MULTIBOOT_TAG_TYPE_EFI_BS 18
  34. #define MULTIBOOT_TAG_TYPE_EFI32_IH 19
  35. #define MULTIBOOT_TAG_TYPE_EFI64_IH 20
  36. #define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21
  37. #define MULTIBOOT_HEADER_TAG_END 0
  38. #define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
  39. #define MULTIBOOT_HEADER_TAG_ADDRESS 2
  40. #define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3
  41. #define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4
  42. #define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5
  43. #define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6
  44. #define MULTIBOOT_HEADER_TAG_EFI_BS 7
  45. #define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
  46. #define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
  47. #define MULTIBOOT_HEADER_TAG_RELOCATABLE 10
  48. #define MULTIBOOT_ARCHITECTURE_I386 0
  49. #define MULTIBOOT_ARCHITECTURE_MIPS32 4
  50. #define MULTIBOOT_HEADER_TAG_OPTIONAL 1
  51. #define MULTIBOOT_LOAD_PREFERENCE_NONE 0
  52. #define MULTIBOOT_LOAD_PREFERENCE_LOW 1
  53. #define MULTIBOOT_LOAD_PREFERENCE_HIGH 2
  54. #define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
  55. #define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
  56. // 直接用 -m64 编译出来的是 64 位代码,
  57. // 但是启动后的机器是 32 位的,相当于在 32 位机器上跑 64 位程序。
  58. // 得加一层跳转到 64 位的 -m32 代码,开启 long 模式后再跳转到以 -m64 编译的代码中
  59. // 对于 x86_64,需要在启动阶段进入长模式(IA32E),这意味着需要一个临时页表
  60. // See https://wiki.osdev.org/Creating_a_64-bit_kernel:
  61. // With a 32-bit bootstrap in your kernel
  62. // 这部分是从保护模式启动 long 模式的代码
  63. // 工作在 32bit
  64. // 声明这一段代码以 32 位模式编译
  65. .code32
  66. // multiboot2 文件头
  67. // 计算头长度
  68. .SET HEADER_LENGTH, multiboot_header_end - multiboot_header
  69. // 计算校验和
  70. .SET CHECKSUM, -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + HEADER_LENGTH)
  71. // 8 字节对齐
  72. .align MULTIBOOT_HEADER_ALIGN
  73. // 声明所属段
  74. .section .multiboot_header
  75. multiboot_header:
  76. // 魔数
  77. .long MULTIBOOT2_HEADER_MAGIC
  78. // 架构
  79. .long MULTIBOOT_ARCHITECTURE_I386
  80. // 头长度
  81. .long HEADER_LENGTH
  82. // 校验和
  83. .long CHECKSUM
  84. // 添加其它内容在此,详细信息见 Multiboot2 Specification version 2.0.pdf
  85. .short MULTIBOOT_HEADER_TAG_END
  86. // 结束标记
  87. .short 0
  88. .long 8
  89. multiboot_header_end:
  90. // 临时页表 4KB/页
  91. .section .data
  92. .align 0x1000
  93. pml4:
  94. .skip 0x1000
  95. pdpt:
  96. .skip 0x1000
  97. pd:
  98. .skip 0x1000
  99. pt:
  100. .skip 0x1000
  101. // 临时 GDT
  102. .align 16
  103. gdt64:
  104. null_desc:
  105. .short 0xFFFF
  106. .short 0
  107. .byte 0
  108. .byte 0
  109. .byte 0
  110. .byte 0
  111. code_desc:
  112. .short 0
  113. .short 0
  114. .byte 0
  115. .byte 0x9A
  116. .byte 0x20
  117. .byte 0
  118. data_desc:
  119. .short 0
  120. .short 0
  121. .byte 0
  122. .byte 0x92
  123. .byte 0
  124. .byte 0
  125. user_code_desc:
  126. .short 0
  127. .short 0
  128. .byte 0
  129. .byte 0xFA
  130. .byte 0x20
  131. .byte 0
  132. user_data_desc:
  133. .short 0
  134. .short 0
  135. .byte 0
  136. .byte 0xF2
  137. .byte 0
  138. .byte 0
  139. gdt64_pointer:
  140. .short gdt64_pointer-gdt64-1
  141. .quad gdt64
  142. gdt64_pointer64:
  143. .short gdt64_pointer-gdt64-1
  144. .quad gdt64
  145. .section .text
  146. .global _start
  147. .type _start, @function
  148. # 在 multiboot2.cpp 中定义
  149. .extern boot_info_addr
  150. .extern multiboot2_magic
  151. _start:
  152. // 关中断
  153. cli
  154. // multiboot2_info 结构体指针
  155. //mov %ebx, boot_info_addr
  156. // 魔数
  157. // mov %eax, multiboot2_magic
  158. // 从保护模式跳转到长模式
  159. // 1. 允许 PAE
  160. mov %cr4, %eax
  161. or $(1<<5), %eax
  162. mov %eax, %cr4
  163. // 2. 设置临时页表
  164. // 最高级
  165. mov $pml4, %eax
  166. mov $pdpt, %ebx
  167. or $0x3, %ebx
  168. mov %ebx, 0(%eax)
  169. // 次级
  170. mov $pdpt, %eax
  171. mov $pd, %ebx
  172. or $0x3, %ebx
  173. mov %ebx, 0(%eax)
  174. // 次低级
  175. mov $pd, %eax
  176. mov $pt, %ebx
  177. or $0x3, %ebx
  178. mov %ebx, 0(%eax)
  179. // 最低级
  180. // 循环 512 次,填满一页
  181. mov $512, %ecx
  182. mov $pt, %eax
  183. mov $0x3, %ebx
  184. .fill_pt:
  185. mov %ebx, 0(%eax)
  186. add $0x1000, %ebx
  187. add $8, %eax
  188. loop .fill_pt
  189. // 填写 CR3
  190. mov $pml4, %eax
  191. mov %eax, %cr3
  192. // 3. 切换到 long 模式
  193. mov $0xC0000080, %ecx
  194. rdmsr
  195. or $(1<<8), %eax
  196. wrmsr
  197. // 4. 开启分页
  198. mov %cr0, %eax
  199. or $(1<<31), %eax
  200. mov %eax, %cr0
  201. // 5. 重新设置 GDT
  202. mov $gdt64_pointer, %eax
  203. lgdt 0(%eax)
  204. // 6. 跳转到 64 位代码执行
  205. jmp $0x8, $_start64
  206. hlt
  207. ret