stage2.asm 7.5 KB

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