/bootloader/stage2.asm

http://github.com/Pokelover980/Poke-and-Necro-Hobby-OS · Assembly · 306 lines · 257 code · 33 blank · 16 comment · 0 complexity · 31317b6405af56d1720196b9bc3ec892 MD5 · raw file

  1. ; -------------------------------------------------------------
  2. ; Pokelover and Necro's Hobby OS Bootloader - Stage 2
  3. ;
  4. ; Reuses some code from stage1 to help with disk loading. This
  5. ; stage simply loads the kernel, sets up 32 bit protected mode,
  6. ; and then jumps to the kernel for execution. Fun!
  7. ; -------------------------------------------------------------
  8. [BITS 16]
  9. Start: ; A lot of code here is reused from stage1 so we can
  10. ; load the kernel before entering protected mode
  11. mov ax, 0x0200 ; This is our entry point
  12. add ax, 544 ; 544 paragraph disk buffer
  13. cli ; No interrupts while changing stack!
  14. mov ss, ax
  15. mov sp, 4096
  16. sti ; Now we can have interrupts back :D
  17. mov ax, 0x0200 ; Set data segment to where we're loaded
  18. mov ds, ax
  19. mov byte [BootDev], dl ; Save boot device number
  20. mov eax, 0 ; May be needed by older BIOSes
  21. mov si, S2Message
  22. call PrintString
  23. FloppyOk: ; Ready to read first block of data
  24. mov ax, 19 ; Root dir starts at logical sector 19
  25. call l2hts
  26. mov si, Buffer ; Set ES:BX to our buffer
  27. mov bx, ds
  28. mov es, bx
  29. mov bx, si
  30. mov ah, 2 ; int 0x13 params: Read floppy sectors
  31. mov al, 14 ; 14 floppy sectors to read
  32. pusha ; Push registers to stack to prepare for loop
  33. ReadRootDir:
  34. popa ; Just in case int 0x13 modified anything
  35. pusha
  36. stc ; Not all BIOSes set properly on error
  37. int 0x13 ; Read sectors
  38. jnc SearchDir ; If read was OK, skip ahead
  39. call ResetFloppy ; If not, reset floppy and try again
  40. jnc ReadRootDir ; Did the floppy reset fine?
  41. jmp Reboot ; If it didn't, double error, restart
  42. SearchDir:
  43. popa
  44. mov ax, ds ; Root dir is now in [Buffer]
  45. mov es, ax ; Give this info to DI
  46. mov di, Buffer
  47. mov cx, word [224] ; Search all entries
  48. mov ax, 0 ; Start at 0
  49. NextRootEntry:
  50. xchg cx, dx ; We use cx in the inner loop
  51. mov si, BootFileName ; Start searching for stage2 filename
  52. mov cx, 11
  53. rep cmpsb
  54. je FoundFileToLoad ; Pointer DI will be at offset 11
  55. add ax, 32 ; Bump by one entry (32 bytes per entry)
  56. mov di, Buffer ; Point to next entry
  57. add di, ax
  58. xchg dx, cx ; Get cx back
  59. loop NextRootEntry
  60. mov si, NoFile
  61. call PrintString
  62. jmp Reboot
  63. FoundFileToLoad: ; Let's load the FAT into RAM
  64. mov ax, word[es:di+0x0F] ; Offset 11+15=26 contains our first cluster
  65. mov word[Cluster], ax
  66. mov ax, 1 ; Sector 1 = first sector of FAT
  67. call l2hts
  68. mov di, Buffer
  69. mov bx, di ; ES:BX points to our buffer
  70. mov ah, 2 ; int 0x13 params: read FAT sectors
  71. mov al, 9 ; All 9 sectors of first FAT
  72. pusha ; Push registers to stack to prepare for loop
  73. ReadFat:
  74. popa ; In case int 0x13 modified anything
  75. pusha
  76. stc
  77. int 0x13 ; Read sectors using BIOS
  78. jnc ReadFatOkay ; If read was okay, skip ahead
  79. call ResetFloppy ; Otherwise, reset floppy and try again
  80. jnc ReadFat ; Floppy reset OK?
  81. mov si, DiskError
  82. call PrintString ; If not, print an error and reboot
  83. jmp Reboot
  84. ReadFatOkay:
  85. popa
  86. mov ax, 0x7E00 ; Segment where we're loading kernel
  87. mov es, ax
  88. mov bx, 0
  89. mov ah, 2 ; int 0x13 read params
  90. mov al, 1
  91. push ax ; Save in case it gets lost
  92. ; We're gonna load the FAT from the disk now
  93. LoadFileSector:
  94. mov ax, word [Cluster] ; Convert sector to logical
  95. add ax, 31
  96. call l2hts
  97. mov ax, 0x7E00 ; Set buffer past what we've read
  98. mov es, ax
  99. mov bx, word [Pointer]
  100. pop ax ; Save in case it gets lost
  101. push ax
  102. stc
  103. int 0x13
  104. jnc CalculateNextCluster ; If there's no error
  105. call ResetFloppy ; If there is, reset floppy
  106. jmp LoadFileSector
  107. CalculateNextCluster:
  108. mov ax, [Cluster]
  109. mov dx, 0
  110. mov bx, 3
  111. mul bx
  112. mov bx, 2
  113. div bx ; DX = [Cluster] mod 2
  114. mov si, Buffer
  115. add si, ax ; AX = word in FAT for 12 bit entry
  116. mov ax, word [ds:si]
  117. or dx, dx ; If DX = 0 [Cluster] is even; if 1, [Cluster] is odd
  118. jz even ; If [Cluster] is even, drop last 4 bits of word with
  119. ; next clusters; if odd, drop first 4 bits
  120. odd:
  121. shr ax, 4
  122. jmp short NextClusterCont
  123. even:
  124. and ax, 0x0FFF ; Mask out final four bits
  125. NextClusterCont:
  126. mov word [Cluster], ax ; Store cluster
  127. cmp ax, 0x0FF8 ; 0xFF8 = end of file in FAT12
  128. jae end
  129. add word [Pointer], 512 ; Increase buffer point 1 sector
  130. jmp LoadFileSector
  131. end: ; Hooray, we've reached the end and got the file to load!
  132. pop ax ; Clean up stack, as we pushed AX earlier
  133. mov dl, byte[BootDev] ; Provide Kernel with boot device info
  134. mov si, BeforePMode
  135. call PrintString
  136. ; BEFORE WE JUMP TO KERNEL BELOW WE WANT TO SET UP PROTECTED MODE!
  137. cli ; We can't use these anymore!
  138. ; We have to enable the A20 line first, so that's what we'll do. It's boring and stupid.
  139. call wkc ; Wait for keyboard buffer to clear
  140. mov al, 0xD1 ; We want to write to output port
  141. out 0x64, al
  142. call wkc ; Wait for keyboard buffer again
  143. mov al, 0xDF ; Set A20 gate
  144. out 0x60, al ; Send value to data reg
  145. call wkc ; Again...
  146. mov cx, 0x10
  147. kbdwait:
  148. xor ax, ax ; Waste time
  149. out 0xE0, ax ; Waste more time
  150. loop kbdwait ; Loop and waste even more time
  151. ; Was A20 enabled?
  152. mov al, 0xD0
  153. out 0x64, al ; Tell the controller we want to read output port
  154. call wkf ; Wait for the data to get in it
  155. in al, 0x60 ; Get it
  156. test al, 2 ; Is A20 on?
  157. jnz A20On ; Not zero - we're good
  158. ; Otherwise, we failed
  159. mov si, A20Failure
  160. call PrintString
  161. hlt
  162. jmp $
  163. A20On:
  164. xor ax, ax
  165. mov ds, ax
  166. lgdt [gdt_desc]
  167. mov eax, cr0 ; Clear this bit, signaling the processor to enter protected mode
  168. or eax, 1
  169. mov cr0, eax
  170. jmp 0x08:ClearPipe
  171. [BITS 32]
  172. ClearPipe: ; We need 32 bit now
  173. mov ax, 0x10 ; Save data segment identifier
  174. mov ds, ax ; Move valid data segment into data segment register
  175. mov ss, ax ; Move valid data segment into stack segment register
  176. mov esp, 0x090000 ; Move stack pointer to 0x090000
  177. mov byte [ds:0x0B8000], 'P'
  178. mov byte [ds:0x0B8000], 0x1B ; Here we're just testing to make sure we entered
  179. ; protected mode without issues.
  180. jmp 0x08:0x07E00 ; Jump to entry point of stage2!
  181. jmp $ ; Continually jump here just in case kernel decides to return
  182. ; Subroutines below
  183. [BITS 16]
  184. Reboot:
  185. mov ax, 0
  186. int 0x16 ; Wait for keystroke
  187. mov ax, 0
  188. int 0x19 ; Reboot
  189. PrintString:
  190. pusha
  191. mov ax, 0x0E
  192. .repeat:
  193. lodsb
  194. cmp al, 0
  195. je .done ; If char is 0, we've reached the end of the string
  196. int 0x10 ; Otherwise, we print it
  197. jmp short .repeat
  198. .done:
  199. popa
  200. ret
  201. ResetFloppy: ; Carry set on error
  202. push ax
  203. push dx
  204. mov ax, 0
  205. mov dl, byte [BootDev]
  206. stc
  207. int 0x13
  208. pop dx
  209. pop ax
  210. ret
  211. l2hts: ; Calculate head, track and sector for int 0x13
  212. push bx
  213. push ax
  214. mov bx, ax
  215. mov dx, 0
  216. div word [18]
  217. add dl, 0x01
  218. mov cl, dl
  219. mov ax, bx
  220. mov dx, 0
  221. div word [18]
  222. mov dx, 0
  223. div word [2]
  224. mov dh, dl
  225. mov ch, al
  226. pop ax
  227. pop bx
  228. mov dl, byte [BootDev]
  229. ret
  230. wkc:
  231. xor al, al
  232. in al, 0x64
  233. test al, 2
  234. jnz wkc
  235. ret
  236. wkf:
  237. xor cx, cx
  238. in al, 0x64
  239. test al, 1
  240. jz wkf
  241. ret
  242. BootFileName db "KERNEL BIN"
  243. DiskError db "FATAL: Disk error! Press any key to reboot...", 0
  244. NoFile db "FATAL: KERNEL.BIN not found!", 0
  245. A20Failure db "FATAL: A20 failed to enable!", 0
  246. BeforePMode db "About to enter protected mode...", 0
  247. S2Message db "Stage2 entered", 0
  248. BootDev db 0
  249. Cluster dw 0
  250. Pointer dw 0
  251. gdt:
  252. gdt_null:
  253. dd 0
  254. dd 0
  255. gdt_code:
  256. dw 0x0FFFF
  257. dw 0
  258. db 0
  259. db 10011010b
  260. db 11001111b
  261. db 0
  262. gdt_data:
  263. dw 0x0FFFF
  264. dw 0
  265. db 0
  266. db 10010010b
  267. db 11001111b
  268. db 0
  269. gdt_end:
  270. gdt_desc:
  271. dw gdt_end - gdt - 1
  272. dd gdt
  273. Buffer: