stage2.asm 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. [BITS 16]
  2. [ORG 0x7E00]
  3. ; Save boot drive passed in dl by the bootloader
  4. mov [boot_drive], dl
  5. ; Set VESA Video Mode (1024x768x32 - Bochs VBE mode)
  6. mov ax, 0x4F02
  7. mov bx, 0x4144 ; mode 0x144 + LFB bit = 32bpp guaranteed
  8. int 0x10
  9. ; Get VBE Mode Info to find the LFB address and pitch
  10. mov ax, 0x4F01
  11. mov cx, 0x0144
  12. mov di, 0x3000
  13. int 0x10
  14. movzx eax, word [0x3010] ; BytesPerScanLine (actual pitch)
  15. mov [screen_pitch], eax
  16. mov edi, [0x3028] ; LFB Physical Address
  17. mov [lfb_addr], edi
  18. ; Enter Unreal Mode
  19. cli
  20. push ds
  21. push es
  22. in al, 0x92
  23. or al, 2
  24. out 0x92, al
  25. lgdt [gdt_desc]
  26. mov eax, cr0
  27. or al, 1
  28. mov cr0, eax
  29. jmp $+2
  30. mov bx, 0x08
  31. mov ds, bx
  32. mov es, bx
  33. mov fs, bx
  34. mov gs, bx
  35. mov ss, bx
  36. and al, 0xFE
  37. mov cr0, eax
  38. jmp $+2
  39. xor ax, ax
  40. mov ds, ax
  41. mov es, ax
  42. mov fs, ax
  43. mov gs, ax
  44. mov ss, ax
  45. sti
  46. ; Clear linear framebuffer (black screen) to prevent text bleed-through
  47. mov edi, [lfb_addr]
  48. xor eax, eax
  49. mov ecx, [screen_pitch]
  50. shr ecx, 2 ; dwords per scanline
  51. imul ecx, 768 ; total dwords for 768 lines
  52. a32 rep stosd
  53. ; Load animation.bin to 0x2000000 (32MB)
  54. mov eax, [animation_lba]
  55. mov ecx, [animation_size_sectors]
  56. mov edi, 0x2000000
  57. call read_sectors_high
  58. ; Play Animation (nucleus expansion only — electrons done by Swift later)
  59. mov ecx, 60
  60. mov esi, 0x2000000 ; Source of animation frames
  61. .play_anim:
  62. push ecx
  63. mov edi, [lfb_addr]
  64. ; Center X = (1024-200)/2 = 412
  65. ; Center Y = (768-200)/2 = 284
  66. ; Dest offset = 284 * pitch + 412 * 4
  67. mov eax, 284
  68. imul eax, dword [screen_pitch]
  69. add eax, 412 * 4
  70. add edi, eax
  71. mov cx, 200 ; 200 lines
  72. .draw_line:
  73. push ecx
  74. push edi
  75. mov ecx, 200 ; 200 pixels * 4 bytes (32bpp) = 800 bytes = 200 dwords
  76. a32 rep movsd
  77. pop edi
  78. add edi, [screen_pitch] ; Advance by actual pitch
  79. pop ecx
  80. dec cx
  81. jnz .draw_line
  82. ; Wait ~16ms (16666 microseconds)
  83. mov ah, 0x86
  84. mov cx, 0 ; High word of microseconds
  85. mov dx, 16666 ; Low word of microseconds
  86. int 0x15
  87. pop ecx
  88. dec ecx
  89. jnz .play_anim
  90. ; 1. Read first sector of bzImage to get setup_sects
  91. mov eax, [bzimage_lba]
  92. mov ebx, 0x9000
  93. mov es, bx
  94. xor bx, bx
  95. mov cx, 1
  96. call read_sectors
  97. jc .err_read1
  98. mov al, [es:0x01F1]
  99. cmp al, 0
  100. jne .has_setup
  101. mov al, 4
  102. .has_setup:
  103. inc al
  104. movzx cx, al
  105. ; 2. Read setup sectors to 0x90000
  106. mov eax, [bzimage_lba]
  107. mov bx, 0x9000
  108. mov es, bx
  109. xor bx, bx
  110. call read_sectors
  111. jc .err_read2
  112. ; 3. Read protected mode kernel to 0x100000
  113. mov eax, [bzimage_lba]
  114. add eax, ecx
  115. mov edx, [bzimage_size_sectors]
  116. sub edx, ecx
  117. mov ecx, edx
  118. mov edi, 0x100000
  119. call read_sectors_high
  120. jc .err_read3
  121. ; 4. Read initramfs to 0x8000000
  122. mov eax, [initramfs_lba]
  123. mov ecx, [initramfs_size_sectors]
  124. mov edi, 0x8000000
  125. call read_sectors_high
  126. jc .err_read4
  127. ; Setup Boot Params at 0x90000
  128. mov bx, 0x9000
  129. mov ds, bx
  130. mov byte [0x210], 0xFF
  131. mov al, [0x211]
  132. or al, 0x80
  133. mov [0x211], al
  134. mov word [0x224], 0xFE00
  135. mov dword [0x218], 0x8000000
  136. mov eax, [cs:initramfs_size_bytes]
  137. mov dword [0x21C], eax
  138. mov dword [0x228], 0x99000
  139. push ds
  140. xor ax, ax
  141. mov ds, ax
  142. mov si, cmd_line
  143. pop es
  144. mov di, 0x9000
  145. .copy_cmd:
  146. lodsb
  147. stosb
  148. test al, al
  149. jnz .copy_cmd
  150. mov ax, 0x9000
  151. mov ds, ax
  152. mov es, ax
  153. mov fs, ax
  154. mov gs, ax
  155. mov ss, ax
  156. cli
  157. jmp 0x9000:0x0200
  158. .err_read1:
  159. mov si, msg_err1
  160. call print_string
  161. jmp halt
  162. .err_read2:
  163. mov si, msg_err2
  164. call print_string
  165. jmp halt
  166. .err_read3:
  167. mov si, msg_err3
  168. call print_string
  169. jmp halt
  170. .err_read4:
  171. mov si, msg_err4
  172. call print_string
  173. halt:
  174. hlt
  175. jmp halt
  176. ; --- Functions ---
  177. print_string:
  178. push ds
  179. push ax
  180. xor ax, ax
  181. mov ds, ax
  182. .loop:
  183. lodsb
  184. or al, al
  185. jz .done
  186. mov ah, 0x0E
  187. int 0x10
  188. jmp .loop
  189. .done:
  190. pop ax
  191. pop ds
  192. ret
  193. ; read_sectors: LBA in EAX, Count in CX, Buffer in ES:BX. Returns CF=1 on error.
  194. read_sectors:
  195. pusha
  196. .loop:
  197. push eax
  198. push cx
  199. mov [dap_lba], eax
  200. mov [dap_buf_offset], bx
  201. mov ax, es
  202. mov [dap_buf_segment], ax
  203. mov word [dap_count], 1
  204. mov ah, 0x42
  205. mov dl, [boot_drive]
  206. mov si, dap
  207. int 0x13
  208. jc .disk_error
  209. pop cx
  210. pop eax
  211. inc eax
  212. add bx, 512
  213. dec cx
  214. jnz .loop
  215. popa
  216. clc
  217. ret
  218. .disk_error:
  219. pop cx
  220. pop eax
  221. popa
  222. stc
  223. ret
  224. ; read_sectors_high: LBA in EAX, Count in ECX, Dest Physical in EDI. Returns CF=1 on error.
  225. read_sectors_high:
  226. pusha
  227. .loop_high:
  228. push eax
  229. push ecx
  230. ; Use temporary buffer at 0x0000:0x2000
  231. mov word [dap_lba], ax
  232. shr eax, 16
  233. mov word [dap_lba+2], ax
  234. mov word [dap_buf_offset], 0x2000
  235. mov word [dap_buf_segment], 0x0000
  236. mov word [dap_count], 1
  237. mov ah, 0x42
  238. mov dl, [boot_drive]
  239. mov si, dap
  240. push edi ; Preserve EDI against BIOS corruption
  241. int 0x13
  242. pop edi
  243. jc .disk_error_high
  244. push ds
  245. push es
  246. xor ax, ax
  247. mov ds, ax
  248. mov es, ax
  249. mov esi, 0x2000
  250. mov ecx, 128
  251. a32 rep movsd
  252. pop es
  253. pop ds
  254. pop ecx
  255. pop eax
  256. inc eax
  257. dec ecx
  258. jnz .loop_high
  259. popa
  260. clc
  261. ret
  262. .disk_error_high:
  263. pop ecx
  264. pop eax
  265. popa
  266. stc
  267. ret
  268. ; --- Data ---
  269. msg_stage2: db "Stage 2 Bootloader...", 13, 10, 0
  270. msg_unreal: db "Unreal Mode Activated...", 13, 10, 0
  271. msg_setup_ok: db "Setup loaded.", 13, 10, 0
  272. msg_kernel_ok: db "Kernel loaded.", 13, 10, 0
  273. msg_initrd_ok: db "Initrd loaded.", 13, 10, 0
  274. msg_err1: db "Error: Failed to read first kernel sector", 13, 10, 0
  275. msg_err2: db "Error: Failed to read kernel setup sectors", 13, 10, 0
  276. msg_err3: db "Error: Failed to read protected kernel", 13, 10, 0
  277. msg_err4: db "Error: Failed to read initramfs", 13, 10, 0
  278. boot_drive: db 0x80
  279. align 16
  280. global_vars:
  281. bzimage_lba: dd 8
  282. bzimage_size_sectors: dd 0
  283. initramfs_lba: dd 0
  284. initramfs_size_sectors: dd 0
  285. initramfs_size_bytes: dd 0
  286. animation_lba: dd 0
  287. animation_size_sectors: dd 0
  288. lfb_addr: dd 0
  289. screen_pitch: dd 0
  290. cmd_line: db "console=tty0 loglevel=0 logo.nologo init=/init root=/dev/sdb rw quiet vt.global_cursor_default=0", 0
  291. align 4
  292. dap:
  293. dap_size: db 0x10
  294. dap_zero: db 0
  295. dap_count: dw 1
  296. dap_buf_offset: dw 0
  297. dap_buf_segment: dw 0
  298. dap_lba: dq 0
  299. gdt_start:
  300. dq 0
  301. gdt_data:
  302. dw 0xFFFF
  303. dw 0x0000
  304. db 0x00
  305. db 0x92
  306. db 0xCF
  307. db 0x00
  308. gdt_desc:
  309. dw gdt_desc - gdt_start - 1
  310. dd gdt_start