boot.s 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. .section .stage1
  2. #include <kernel/mem/paging_asm.h>
  3. .code16
  4. .align 4
  5. .Lbios_idt_desc:
  6. .word 0x03ff # size
  7. .long 0x00000000 # base
  8. .align 4
  9. .Lnull_idt_desc:
  10. .word 0 # size
  11. .long 0 # base
  12. .Lhalt16:
  13. hlt
  14. jmp .Lhalt16
  15. # scratch %eax
  16. # return address should be of 2 bytes, and will be zero extended to 4 bytes
  17. go_32bit:
  18. cli
  19. lidt .Lnull_idt_desc
  20. # set PE bit
  21. mov %cr0, %eax
  22. or $1, %eax
  23. mov %eax, %cr0
  24. ljmp $0x08, $.Lgo_32bit0
  25. .Lgo_16bit0:
  26. mov $0x20, %ax
  27. mov %ax, %ds
  28. mov %ax, %ss
  29. lidt .Lbios_idt_desc
  30. mov %cr0, %eax
  31. and $0xfffffffe, %eax
  32. mov %eax, %cr0
  33. ljmp $0x00, $.Lgo_16bit1
  34. .Lgo_16bit1:
  35. xor %ax, %ax
  36. mov %ax, %ds
  37. mov %ax, %ss
  38. mov %ax, %es
  39. sti
  40. pop %eax
  41. push %ax
  42. ret
  43. .code32
  44. # scratch %eax
  45. # return address should be of 4 bytes, and extra 2 bytes will be popped from the stack
  46. go_16bit:
  47. cli
  48. ljmp $0x18, $.Lgo_16bit0
  49. .Lgo_32bit0:
  50. mov $0x10, %ax
  51. mov %ax, %ds
  52. mov %ax, %es
  53. mov %ax, %ss
  54. pop %ax
  55. movzw %ax, %eax
  56. push %eax
  57. ret
  58. # build read disk packet on the stack and perform read operation
  59. #
  60. # read 32k to 0x2000 and then copy to destination
  61. #
  62. # %edi: lba start
  63. # %esi: destination
  64. .code32
  65. read_disk:
  66. push %ebp
  67. mov %esp, %ebp
  68. lea -24(%esp), %esp
  69. mov $0x00400010, %eax # packet size 0, sector count 64
  70. mov %eax, (%esp)
  71. mov $0x02000000, %eax # destination address 0x0200:0x0000
  72. mov %eax, 4(%esp)
  73. mov %edi, 8(%esp) # lba low 4bytes
  74. xor %eax, %eax
  75. mov %eax, 12(%esp) # lba high 2bytes
  76. mov %esi, %edi
  77. mov %esp, %esi # packet address
  78. call go_16bit
  79. .code16
  80. mov $0x42, %ah
  81. mov $0x80, %dl
  82. int $0x13
  83. jc .Lhalt16
  84. call go_32bit
  85. .code32
  86. # move data to destination
  87. mov $0x2000, %esi
  88. mov $8192, %ecx
  89. rep movsl
  90. mov %ebp, %esp
  91. pop %ebp
  92. ret
  93. .globl start_32bit
  94. start_32bit:
  95. mov $0x10, %ax
  96. mov %ax, %ds
  97. mov %ax, %es
  98. mov %ax, %ss
  99. # read kimage into memory
  100. lea -16(%esp), %esp
  101. mov $KIMAGE_32K_COUNT, %ecx
  102. movl $KERNEL_IMAGE_PADDR, 4(%esp) # destination address
  103. movl $9, (%esp) # LBA
  104. .Lread_kimage:
  105. mov (%esp), %edi
  106. mov 4(%esp), %esi
  107. mov %ecx, %ebx
  108. call read_disk
  109. mov %ebx, %ecx
  110. addl $0x8000, 4(%esp)
  111. addl $64, (%esp)
  112. loop .Lread_kimage
  113. lea 16(%esp), %esp
  114. cld
  115. xor %eax, %eax
  116. # clear paging structures
  117. mov $0x2000, %edi
  118. mov $0x6000, %ecx
  119. shr $2, %ecx # %ecx /= 4
  120. rep stosl
  121. # set P, RW, G
  122. mov $(PA_P | PA_RW | PA_G), %ebx
  123. xor %edx, %edx
  124. mov $KERNEL_PDPT_PHYS_MAPPING, %esi
  125. # PML4E 0x000
  126. # we need the first 1GB identically mapped
  127. # so that we won't trigger a triple fault after
  128. # enabling paging
  129. mov $KERNEL_PML4, %edi
  130. call fill_pxe
  131. # PML4E 0xff0
  132. mov $(PA_NXE >> 32), %edx
  133. lea 0xff0(%edi), %edi
  134. call fill_pxe
  135. xor %edx, %edx
  136. # setup PDPT for physical memory mapping
  137. mov $KERNEL_PDPT_PHYS_MAPPING, %edi
  138. # set PS
  139. or $PA_PS, %ebx
  140. mov $256, %ecx
  141. xor %esi, %esi
  142. .Lfill1:
  143. call fill_pxe
  144. lea 8(%edi), %edi
  145. add $0x40000000, %esi # 1GB
  146. adc $0, %edx
  147. loop .Lfill1
  148. mov $(PA_NXE >> 32), %edx
  149. # set PCD, PWT
  150. or $(PA_PCD | PA_PWT), %ebx
  151. mov $256, %ecx
  152. xor %esi, %esi
  153. .Lfill2:
  154. call fill_pxe
  155. lea 8(%edi), %edi
  156. add $0x40000000, %esi # 1GB
  157. adc $0, %edx
  158. loop .Lfill2
  159. xor %edx, %edx
  160. # PML4E 0xff8
  161. mov $KERNEL_PDPT_KERNEL_SPACE, %esi
  162. mov $KERNEL_PML4, %edi
  163. lea 0xff8(%edi), %edi
  164. # clear PCD, PWT, PS
  165. and $(~(PA_PCD | PA_PWT | PA_PS)), %ebx
  166. call fill_pxe
  167. # PDPTE 0xff8
  168. mov $KERNEL_PDPT_KERNEL_SPACE, %edi
  169. lea 0xff8(%edi), %edi
  170. mov $KERNEL_PD_KIMAGE, %esi
  171. call fill_pxe
  172. # PDE 0xff0
  173. mov $KERNEL_PD_KIMAGE, %edi
  174. lea 0xff0(%edi), %edi
  175. mov $KERNEL_PT_KIMAGE, %esi # 0x104000
  176. call fill_pxe
  177. # fill PT (kernel image)
  178. mov $KERNEL_PT_KIMAGE, %edi
  179. mov $KERNEL_IMAGE_PADDR, %esi
  180. mov $KIMAGE_PAGES, %ecx
  181. .Lfill3:
  182. call fill_pxe
  183. lea 8(%edi), %edi
  184. lea 0x1000(%esi), %esi
  185. loop .Lfill3
  186. # set msr
  187. mov $0xc0000080, %ecx
  188. rdmsr
  189. or $0x901, %eax # set LME, NXE, SCE
  190. wrmsr
  191. # set cr4
  192. mov %cr4, %eax
  193. or $0xa0, %eax # set PAE, PGE
  194. mov %eax, %cr4
  195. # load new page table
  196. mov $KERNEL_PML4, %eax
  197. mov %eax, %cr3
  198. mov %cr0, %eax
  199. // SET PE, WP, PG
  200. or $0x80010001, %eax
  201. mov %eax, %cr0
  202. # create gdt
  203. xor %eax, %eax # at 0x0000
  204. mov %eax, 0x00(%eax)
  205. mov %eax, 0x04(%eax) # null descriptor
  206. mov %eax, 0x08(%eax) # code segment lower
  207. mov %eax, 0x10(%eax) # data segment lower
  208. mov $0x00209a00, %ecx
  209. mov %ecx, 0x0c(%eax) # code segment higher
  210. mov $0x00009200, %ecx
  211. mov %ecx, 0x14(%eax) # data segment higher
  212. # gdt descriptor
  213. push %eax
  214. push %eax
  215. # pad with a word
  216. mov $0x00170000, %eax
  217. push %eax
  218. lgdt 2(%esp)
  219. add $12, %esp
  220. ljmp $0x08, $.L64bit_entry
  221. # %ebx: attribute low
  222. # %edx: attribute high
  223. # %esi: page physical address
  224. # %edi: page x entry address
  225. fill_pxe:
  226. lea (%ebx, %esi, 1), %eax
  227. mov %eax, (%edi)
  228. mov %edx, 4(%edi)
  229. ret
  230. .code64
  231. .L64bit_entry:
  232. jmp start_64bit
  233. .section .text.kinit
  234. start_64bit:
  235. # set stack pointer and clear stack bottom
  236. mov %rsp, %rdi
  237. xor %rsp, %rsp
  238. inc %rsp
  239. neg %rsp
  240. shr $40, %rsp
  241. shl $40, %rsp
  242. add %rdi, %rsp
  243. mov %rsp, %rdi
  244. # make stack frame
  245. lea -16(%rsp), %rsp
  246. mov %rsp, %rbp
  247. xor %rax, %rax
  248. mov %rax, (%rsp)
  249. mov %rax, 8(%rsp)
  250. call kernel_init
  251. .L64bit_hlt:
  252. cli
  253. hlt
  254. jmp .L64bit_hlt