You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

169 lines
3.6 KiB

  1. global start
  2. extern long_start
  3. section .text
  4. bits 32
  5. start:
  6. ; point the esp register to the top of our stack
  7. ; (the stack grows downwards)
  8. mov esp, stack_top
  9. call check_multiboot
  10. call check_cpuid
  11. call check_long_mode
  12. call setup_ptables
  13. call enable_paging
  14. ; load the 64-bit gdt
  15. lgdt [gdt64.pointer]
  16. ; jump into the 64-bit boot stub code
  17. jmp gdt64.code:long_start
  18. ; Checks that we were actually loaded by a Multiboot-compatible system
  19. check_multiboot:
  20. cmp eax, 0x36d76289
  21. jne .no_multiboot
  22. ret
  23. .no_multiboot:
  24. mov al, "m"
  25. jmp error
  26. ; Checks that we have a CPUID-enabled processor
  27. check_cpuid:
  28. ; Check if CPUID is supported by attempting to flip the ID bit (bit 21) in
  29. ; the FLAGS register. If we can flip it, CPUID is available.
  30. ; Copy FLAGS in to EAX via stack
  31. pushfd
  32. pop eax
  33. ; Copy to ECX as well for comparing later on
  34. mov ecx, eax
  35. ; Flip the ID bit
  36. xor eax, 1 << 21
  37. ; Copy EAX to FLAGS via the stack
  38. push eax
  39. popfd
  40. ; Copy FLAGS back to EAX (with the flipped bit if CPUID is supported)
  41. pushfd
  42. pop eax
  43. ; Restore FLAGS from the old version stored in ECX (i.e. flipping the ID bit
  44. ; back if it was ever flipped).
  45. push ecx
  46. popfd
  47. ; Compare EAX and ECX. If they are equal then that means the bit wasn't
  48. ; flipped, and CPUID isn't supported.
  49. xor eax, ecx
  50. jz .no_cpuid
  51. ret
  52. .no_cpuid:
  53. mov al, "c"
  54. jmp error
  55. ; Checks if long mode is supported
  56. check_long_mode:
  57. ; test if extended processor info in available
  58. mov eax, 0x80000000 ; implicit argument for cpuid
  59. cpuid ; get highest supported argument
  60. cmp eax, 0x80000001 ; it needs to be at least 0x80000001
  61. jb .no_long_mode ; if it's less, the CPU is too old for long mode
  62. ; use extended info to test if long mode is available
  63. mov eax, 0x80000001 ; argument for extended processor info
  64. cpuid ; returns various feature bits in ecx and edx
  65. test edx, 1 << 29 ; test if the LM-bit is set in the D-register
  66. jz .no_long_mode ; If it's not set, there is no long mode
  67. ret
  68. .no_long_mode:
  69. mov al, "2"
  70. jmp error
  71. setup_ptables:
  72. ; p4[0] -> p3
  73. mov eax, p3_table
  74. or eax, 0b11 ; present + writable
  75. mov [p4_table], eax
  76. ; p3[0] -> p2
  77. mov eax, p2_table
  78. or eax, 0b1 ; present + writable
  79. mov [p3_table], eax
  80. ; map each p2 entry to a 2mib hugepage
  81. mov ecx, 0
  82. .map_p2:
  83. ; p2[ecx] -> huge_page{@2MiB*ecx}
  84. mov eax, 0x200000 ; 2MiB
  85. mul ecx ; start address
  86. or eax, 0b10000011 ; present + writable + huge
  87. mov [p2_table + ecx*8], eax ; map ecx-th entry
  88. inc ecx ; increase counter
  89. cmp ecx, 512 ; whole table is mapped if ecx == 512
  90. jne .map_p2 ; else map the next entry
  91. ret
  92. enable_paging:
  93. ; load P4 to cr3 register (cpu uses this to access the P4 table)
  94. mov eax, p4_table
  95. mov cr3, eax
  96. ; enable PAE-flag in cr4 (Physical Address Extension)
  97. mov eax, cr4
  98. or eax, 1 << 5
  99. mov cr4, eax
  100. ; set the long mode bit in the EFER MSR (model specific register)
  101. mov ecx, 0xC0000080
  102. rdmsr
  103. or eax, 1 << 8
  104. wrmsr
  105. ; enable paging in the cr0 register
  106. mov eax, cr0
  107. or eax, 1 << 31
  108. mov cr0, eax
  109. ret
  110. ; Print `ERR: ` + error code to screen and then HLTs
  111. ; lovingly ripped off from Phil Oppermann's os.phil-opp.com
  112. ; parameter: error code (ascii) in al
  113. error:
  114. mov dword [0xb8000], 0x4f524f45
  115. mov dword [0xb8004], 0x4f3a4f52
  116. mov dword [0xb8008], 0x4f204f20
  117. mov byte [0xb800a], al
  118. hlt
  119. ;;; Smol stack (64 bytes) just to make stuff work atm
  120. section .bss
  121. align 4096
  122. p4_table:
  123. resb 4096
  124. p3_table:
  125. resb 4096
  126. p2_table:
  127. resb 4096
  128. p1_table:
  129. resb 4096
  130. stack_bottom:
  131. resb 64
  132. stack_top:
  133. section .rodata
  134. gdt64:
  135. dq 0 ; zero entry
  136. .code: equ $ - gdt64 ; new
  137. dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment
  138. .pointer:
  139. dw $ - gdt64 - 1
  140. dq gdt64