bootstrap.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. pub(crate) mod init;
  2. use super::mm::{E820_MEM_MAP_DATA, PA_G, PA_NXE, PA_P, PA_PS, PA_RW};
  3. use core::arch::{global_asm, naked_asm};
  4. const KERNEL_IMAGE_PADDR: usize = 0x200000;
  5. const KERNEL_PML4: usize = 0x1000;
  6. const KERNEL_PDPT_PHYS_MAPPING: usize = 0x2000;
  7. const KERNEL_PDPT_KERNEL_SPACE: usize = 0x3000;
  8. const KERNEL_PD_KIMAGE: usize = 0x4000;
  9. const KERNEL_PT_KIMAGE: usize = 0x5000;
  10. #[unsafe(link_section = ".low")]
  11. static mut EARLY_GDT: [u64; 7] = [0; 7];
  12. #[unsafe(no_mangle)]
  13. #[unsafe(link_section = ".low")]
  14. static mut EARLY_GDT_DESCRIPTOR: (u16, u32) = (0, 0);
  15. #[unsafe(link_section = ".low")]
  16. static mut BIOS_IDT_DESCRIPTOR: (u16, u32) = (0, 0);
  17. unsafe extern "C" {
  18. fn KIMAGE_32K_COUNT();
  19. fn KIMAGE_PAGES();
  20. fn STAGE1_MAGIC();
  21. fn STAGE1_MAGIC_VALUE();
  22. fn start_32bit() -> !;
  23. }
  24. global_asm!(
  25. r#"
  26. .pushsection .mbr, "ax", @progbits
  27. .code16
  28. .globl move_mbr
  29. move_mbr:
  30. xor %ax, %ax
  31. mov %ax, %ds
  32. mov %ax, %es
  33. mov %ax, %ss
  34. # move the MBR to 0xe00
  35. mov $128, %cx # 512 bytes
  36. mov $0x7c00, %si
  37. mov $0x0e00, %di
  38. rep movsl
  39. ljmp $0x00, $2f
  40. 2:
  41. # read the kernel stage1
  42. mov $.Lread_data_packet, %si
  43. mov $0x42, %ah
  44. mov $0x80, %dl
  45. int $0x13
  46. jc .Lhalt16
  47. # get memory size info and storage it
  48. mov $0xe801, %ax
  49. int $0x15
  50. jc .Lhalt16
  51. cmp $0x86, %ah # unsupported function
  52. je .Lhalt16
  53. cmp $0x80, %ah # invalid command
  54. je .Lhalt16
  55. jcxz 2f
  56. mov %cx, %ax
  57. mov %dx, %bx
  58. 2:
  59. mov ${e820_data_addr}, %esp
  60. movzw %ax, %eax
  61. mov %eax, 8(%esp) # 1k blocks
  62. movzw %bx, %ebx
  63. mov %ebx, 12(%esp) # 64k blocks
  64. # save the destination address to es:di
  65. mov %sp, %di
  66. add $16, %di # buffer is 1024 - 16 bytes
  67. # set default entry size
  68. movl $20, 4(%esp)
  69. # clear %ebx, len
  70. xor %ebx, %ebx
  71. mov %ebx, (%esp)
  72. 2:
  73. # set the magic number to edx
  74. mov $0x534D4150, %edx
  75. # set function number to eax
  76. mov $0xe820, %eax
  77. # set default entry size
  78. mov $24, %ecx
  79. int $0x15
  80. incl (%esp)
  81. add $24, %edi
  82. jc .Lsave_mem_fin
  83. cmp $0, %ebx
  84. jz .Lsave_mem_fin
  85. cmp $24, %ecx
  86. cmovnz 4(%esp), %ecx
  87. mov %ecx, 4(%esp)
  88. jmp 2b
  89. .Lsave_mem_fin:
  90. mov $0x3ff, %ax
  91. mov ${bios_idt_descriptor}, %di
  92. mov %ax, (%di)
  93. xor %eax, %eax
  94. mov %eax, 2(%di)
  95. lgdt .Learly_gdt_descriptor
  96. cli
  97. # IDT descriptor is 6 0's. borrow the null gdt entry
  98. lidt .Learly_gdt
  99. # enable protection mode
  100. mov %cr0, %eax
  101. or $1, %eax
  102. mov %eax, %cr0
  103. ljmp $0x08, ${start_32bit}
  104. .Lhalt16:
  105. hlt
  106. jmp .
  107. .align 16
  108. .Learly_gdt:
  109. .8byte 0x0 # null selector
  110. .8byte 0x00cf9a000000ffff # 32bit code selector
  111. .8byte 0x00cf92000000ffff # 32bit data selector
  112. .align 4
  113. .Learly_gdt_descriptor:
  114. .word 0x17 # size
  115. .long .Learly_gdt # address
  116. .align 16
  117. .Lread_data_packet:
  118. .long 0x00070010 # .stage1 takes up 3.5K, or 7 sectors
  119. .long 0x00006000 # read to 0000:6000
  120. .8byte 1 # read from LBA 1
  121. .popsection
  122. "#,
  123. start_32bit = sym start_32bit,
  124. bios_idt_descriptor = sym BIOS_IDT_DESCRIPTOR,
  125. e820_data_addr = sym E820_MEM_MAP_DATA,
  126. options(att_syntax),
  127. );
  128. global_asm!(
  129. r#"
  130. .pushsection .stage1, "ax", @progbits
  131. .code16
  132. .Lhalt:
  133. hlt
  134. jmp .
  135. # scratch %eax
  136. # return address should be of 2 bytes, and will be zero extended to 4 bytes
  137. .Lgo_32bit:
  138. cli
  139. # borrow the null entry from the early gdt
  140. lidt {EARLY_GDT}
  141. # set PE bit
  142. mov %cr0, %eax
  143. or $1, %eax
  144. mov %eax, %cr0
  145. ljmp $0x18, $.Lgo_32bit0
  146. .Lgo_16bit0:
  147. mov $0x30, %ax
  148. mov %ax, %ds
  149. mov %ax, %es
  150. mov %ax, %ss
  151. lidt {BIOS_IDT_DESCRIPTOR}
  152. mov %cr0, %eax
  153. and $0xfffffffe, %eax
  154. mov %eax, %cr0
  155. ljmp $0x00, $2f
  156. 2:
  157. xor %ax, %ax
  158. mov %ax, %ds
  159. mov %ax, %ss
  160. mov %ax, %es
  161. sti
  162. pop %eax
  163. push %ax
  164. ret
  165. .code32
  166. # scratch %eax
  167. # return address should be of 4 bytes, and extra 2 bytes will be popped from the stack
  168. .Lgo_16bit:
  169. cli
  170. ljmp $0x28, $.Lgo_16bit0
  171. .Lgo_32bit0:
  172. mov $0x20, %ax
  173. mov %ax, %ds
  174. mov %ax, %es
  175. mov %ax, %ss
  176. pop %ax
  177. movzw %ax, %eax
  178. push %eax
  179. ret
  180. # build read disk packet on the stack and perform read operation
  181. #
  182. # read 16k to 0x8000 and then copy to destination
  183. #
  184. # %edi: lba start
  185. # %esi: destination
  186. .code32
  187. read_disk:
  188. push %ebp
  189. mov %esp, %ebp
  190. lea -24(%esp), %esp
  191. mov $0x00200010, %eax # packet size 0, sector count 64
  192. mov %eax, (%esp)
  193. mov $0x08000000, %eax # destination address 0x0800:0x0000
  194. mov %eax, 4(%esp)
  195. mov %edi, 8(%esp) # lba low 4bytes
  196. xor %eax, %eax
  197. mov %eax, 12(%esp) # lba high 2bytes
  198. mov %esi, %edi
  199. mov %esp, %esi # packet address
  200. call .Lgo_16bit
  201. .code16
  202. mov $0x42, %ah
  203. mov $0x80, %dl
  204. int $0x13
  205. jc .Lhalt
  206. call .Lgo_32bit
  207. .code32
  208. # move data to destination
  209. mov $0x8000, %esi
  210. mov $4096, %ecx
  211. rep movsl
  212. mov %ebp, %esp
  213. pop %ebp
  214. ret
  215. .align 8
  216. .Lgdt_data:
  217. .8byte 0x00209a0000000000 # 64bit code selector
  218. .8byte 0x0000920000000000 # 64bit data selector
  219. .8byte 0x00cf9a000000ffff # 32bit code selector
  220. .8byte 0x00cf92000000ffff # 32bit data selector
  221. .8byte 0x000f9a000000ffff # 16bit code selector
  222. .8byte 0x000f92000000ffff # 16bit data selector
  223. {start_32bit}:
  224. mov $0x10, %ax
  225. mov %ax, %ds
  226. mov %ax, %es
  227. mov %ax, %ss
  228. mov ${STAGE1_MAGIC}, %edi
  229. mov (%edi), %edi
  230. cmp ${STAGE1_MAGIC_VALUE}, %edi
  231. jne .Lhalt
  232. mov ${EARLY_GDT_DESCRIPTOR}, %edi
  233. mov $0x37, %ax
  234. mov %ax, (%edi)
  235. mov ${EARLY_GDT}, %eax
  236. mov %eax, 2(%edi)
  237. # fill in early kernel GDT
  238. xchg %eax, %edi
  239. xor %eax, %eax
  240. mov $2, %ecx
  241. # null segment
  242. rep stosl
  243. # other data
  244. mov $.Lgdt_data, %esi
  245. mov $12, %ecx
  246. rep movsl
  247. lgdt {EARLY_GDT_DESCRIPTOR}
  248. ljmp $0x18, $2f
  249. 2:
  250. mov $0x20, %ax
  251. mov %ax, %ds
  252. mov %ax, %es
  253. mov %ax, %ss
  254. # temporary kernel stack
  255. mov $0x1000, %esp
  256. # read kimage into memory
  257. lea -16(%esp), %esp
  258. mov ${KIMAGE_32K_COUNT}, %ecx
  259. shl $1, %ecx
  260. movl ${KERNEL_IMAGE_PADDR}, 4(%esp) # destination address
  261. movl $8, (%esp) # LBA
  262. 2:
  263. mov (%esp), %edi
  264. mov 4(%esp), %esi
  265. mov %ecx, %ebx
  266. call read_disk
  267. mov %ebx, %ecx
  268. addl $0x4000, 4(%esp)
  269. addl $32, (%esp)
  270. loop 2b
  271. lea 16(%esp), %esp
  272. cld
  273. xor %eax, %eax
  274. # clear paging structures
  275. mov $0x1000, %edi
  276. mov $0x5000, %ecx
  277. shr $2, %ecx # %ecx /= 4
  278. rep stosl
  279. # set P, RW, G
  280. mov $({PA_P} | {PA_RW} | {PA_G}), %ebx
  281. xor %edx, %edx
  282. mov ${KERNEL_PDPT_PHYS_MAPPING}, %esi
  283. # PML4E 0x000
  284. # we need the first 1GB identically mapped
  285. # so that we won't trigger a triple fault after
  286. # enabling paging
  287. mov ${KERNEL_PML4}, %edi
  288. call fill_pxe
  289. # PML4E 0xff0
  290. mov $({PA_NXE} >> 32), %edx
  291. lea 0xff0(%edi), %edi
  292. call fill_pxe
  293. xor %edx, %edx
  294. # setup PDPT for physical memory mapping
  295. mov ${KERNEL_PDPT_PHYS_MAPPING}, %edi
  296. # set PS
  297. or ${PA_PS}, %ebx
  298. mov $512, %ecx
  299. xor %esi, %esi
  300. 2:
  301. call fill_pxe
  302. lea 8(%edi), %edi
  303. add $0x40000000, %esi # 1GB
  304. adc $0, %edx
  305. loop 2b
  306. xor %edx, %edx
  307. # PML4E 0xff8
  308. mov ${KERNEL_PDPT_KERNEL_SPACE}, %esi
  309. mov ${KERNEL_PML4}, %edi
  310. lea 0xff8(%edi), %edi
  311. # clear PS
  312. and $(~{PA_PS}), %ebx
  313. call fill_pxe
  314. # PDPTE 0xff8
  315. mov ${KERNEL_PDPT_KERNEL_SPACE}, %edi
  316. lea 0xff8(%edi), %edi
  317. mov ${KERNEL_PD_KIMAGE}, %esi
  318. call fill_pxe
  319. # PDE 0xff0
  320. mov ${KERNEL_PD_KIMAGE}, %edi
  321. lea 0xff0(%edi), %edi
  322. mov ${KERNEL_PT_KIMAGE}, %esi # 0x104000
  323. call fill_pxe
  324. # fill PT (kernel image)
  325. mov ${KERNEL_PT_KIMAGE}, %edi
  326. mov ${KERNEL_IMAGE_PADDR}, %esi
  327. mov ${KIMAGE_PAGES}, %ecx
  328. 2:
  329. call fill_pxe
  330. lea 8(%edi), %edi
  331. lea 0x1000(%esi), %esi
  332. loop 2b
  333. # set msr
  334. mov $0xc0000080, %ecx
  335. rdmsr
  336. or $0x901, %eax # set LME, NXE, SCE
  337. wrmsr
  338. # set cr4
  339. mov %cr4, %eax
  340. or $0xa0, %eax # set PAE, PGE
  341. mov %eax, %cr4
  342. # load new page table
  343. mov ${KERNEL_PML4}, %eax
  344. mov %eax, %cr3
  345. mov %cr0, %eax
  346. // SET PE, WP, PG
  347. or $0x80010001, %eax
  348. mov %eax, %cr0
  349. ljmp $0x08, $2f
  350. # %ebx: attribute low
  351. # %edx: attribute high
  352. # %esi: page physical address
  353. # %edi: page x entry address
  354. fill_pxe:
  355. lea (%ebx, %esi, 1), %eax
  356. mov %eax, (%edi)
  357. mov %edx, 4(%edi)
  358. ret
  359. .code64
  360. 2:
  361. jmp {start_64bit}
  362. .popsection
  363. "#,
  364. EARLY_GDT = sym EARLY_GDT,
  365. EARLY_GDT_DESCRIPTOR = sym EARLY_GDT_DESCRIPTOR,
  366. BIOS_IDT_DESCRIPTOR = sym BIOS_IDT_DESCRIPTOR,
  367. KIMAGE_32K_COUNT = sym KIMAGE_32K_COUNT,
  368. KIMAGE_PAGES = sym KIMAGE_PAGES,
  369. STAGE1_MAGIC = sym STAGE1_MAGIC,
  370. STAGE1_MAGIC_VALUE = sym STAGE1_MAGIC_VALUE,
  371. KERNEL_IMAGE_PADDR = const KERNEL_IMAGE_PADDR,
  372. KERNEL_PML4 = const KERNEL_PML4,
  373. PA_P = const PA_P,
  374. PA_RW = const PA_RW,
  375. PA_G = const PA_G,
  376. PA_PS = const PA_PS,
  377. PA_NXE = const PA_NXE,
  378. KERNEL_PDPT_PHYS_MAPPING = const KERNEL_PDPT_PHYS_MAPPING,
  379. KERNEL_PDPT_KERNEL_SPACE = const KERNEL_PDPT_KERNEL_SPACE,
  380. KERNEL_PD_KIMAGE = const KERNEL_PD_KIMAGE,
  381. KERNEL_PT_KIMAGE = const KERNEL_PT_KIMAGE,
  382. start_64bit = sym start_64bit,
  383. start_32bit = sym start_32bit,
  384. options(att_syntax),
  385. );
  386. #[unsafe(naked)]
  387. pub unsafe extern "C" fn start_64bit() {
  388. naked_asm!(
  389. "mov $0x10, %ax",
  390. "mov %ax, %ds",
  391. "mov %ax, %es",
  392. "mov %ax, %ss",
  393. "",
  394. "mov ${kernel_identical_base}, %rax",
  395. "mov ${stack_paddr}, %rsp",
  396. "add %rax, %rsp",
  397. "",
  398. "xor %rbp, %rbp", // Clear previous stack frame
  399. "push %rbp", // NULL return address
  400. "",
  401. "mov ${e820_data_addr}, %rdi",
  402. "add %rax, %rdi",
  403. "",
  404. "jmp {kernel_init}",
  405. kernel_identical_base = const 0xffffff0000000000u64,
  406. stack_paddr = const 0x80000,
  407. e820_data_addr = sym E820_MEM_MAP_DATA,
  408. kernel_init = sym init::kernel_init,
  409. options(att_syntax)
  410. )
  411. }