| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- [BITS 16]
- [ORG 0x7E00]
- ; Save boot drive passed in dl by the bootloader
- mov [boot_drive], dl
- ; Set VESA Video Mode (1024x768x32 - Bochs VBE mode)
- mov ax, 0x4F02
- mov bx, 0x4144 ; mode 0x144 + LFB bit = 32bpp guaranteed
- int 0x10
- ; Get VBE Mode Info to find the LFB address and pitch
- mov ax, 0x4F01
- mov cx, 0x0144
- mov di, 0x3000
- int 0x10
- movzx eax, word [0x3010] ; BytesPerScanLine (actual pitch)
- mov [screen_pitch], eax
- mov edi, [0x3028] ; LFB Physical Address
- mov [lfb_addr], edi
- ; Enter Unreal Mode
- cli
- push ds
- push es
- in al, 0x92
- or al, 2
- out 0x92, al
- lgdt [gdt_desc]
- mov eax, cr0
- or al, 1
- mov cr0, eax
- jmp $+2
- mov bx, 0x08
- mov ds, bx
- mov es, bx
- mov fs, bx
- mov gs, bx
- mov ss, bx
- and al, 0xFE
- mov cr0, eax
- jmp $+2
- xor ax, ax
- mov ds, ax
- mov es, ax
- mov fs, ax
- mov gs, ax
- mov ss, ax
- sti
- ; Clear linear framebuffer (black screen) to prevent text bleed-through
- mov edi, [lfb_addr]
- xor eax, eax
- mov ecx, [screen_pitch]
- shr ecx, 2 ; dwords per scanline
- imul ecx, 768 ; total dwords for 768 lines
- a32 rep stosd
- ; Load animation.bin to 0x2000000 (32MB)
- mov eax, [animation_lba]
- mov ecx, [animation_size_sectors]
- mov edi, 0x2000000
- call read_sectors_high
- ; Play Animation (nucleus expansion only — electrons done by Swift later)
- mov ecx, 60
- mov esi, 0x2000000 ; Source of animation frames
- .play_anim:
- push ecx
- mov edi, [lfb_addr]
- ; Center X = (1024-200)/2 = 412
- ; Center Y = (768-200)/2 = 284
- ; Dest offset = 284 * pitch + 412 * 4
- mov eax, 284
- imul eax, dword [screen_pitch]
- add eax, 412 * 4
- add edi, eax
- mov cx, 200 ; 200 lines
- .draw_line:
- push ecx
- push edi
- mov ecx, 200 ; 200 pixels * 4 bytes (32bpp) = 800 bytes = 200 dwords
- a32 rep movsd
- pop edi
- add edi, [screen_pitch] ; Advance by actual pitch
- pop ecx
- dec cx
- jnz .draw_line
-
- ; Wait ~16ms (16666 microseconds)
- mov ah, 0x86
- mov cx, 0 ; High word of microseconds
- mov dx, 16666 ; Low word of microseconds
- int 0x15
-
- pop ecx
- dec ecx
- jnz .play_anim
- ; 1. Read first sector of bzImage to get setup_sects
- mov eax, [bzimage_lba]
- mov ebx, 0x9000
- mov es, bx
- xor bx, bx
- mov cx, 1
- call read_sectors
- jc .err_read1
- mov al, [es:0x01F1]
- cmp al, 0
- jne .has_setup
- mov al, 4
- .has_setup:
- inc al
- movzx cx, al
- ; 2. Read setup sectors to 0x90000
- mov eax, [bzimage_lba]
- mov bx, 0x9000
- mov es, bx
- xor bx, bx
- call read_sectors
- jc .err_read2
- ; 3. Read protected mode kernel to 0x100000
- mov eax, [bzimage_lba]
- add eax, ecx
- mov edx, [bzimage_size_sectors]
- sub edx, ecx
- mov ecx, edx
- mov edi, 0x100000
- call read_sectors_high
- jc .err_read3
- ; 4. Read initramfs to 0x8000000
- mov eax, [initramfs_lba]
- mov ecx, [initramfs_size_sectors]
- mov edi, 0x8000000
- call read_sectors_high
- jc .err_read4
- ; Setup Boot Params at 0x90000
- mov bx, 0x9000
- mov ds, bx
- mov byte [0x210], 0xFF
- mov al, [0x211]
- or al, 0x80
- mov [0x211], al
- mov word [0x224], 0xFE00
- mov dword [0x218], 0x8000000
- mov eax, [cs:initramfs_size_bytes]
- mov dword [0x21C], eax
- mov dword [0x228], 0x99000
- push ds
- xor ax, ax
- mov ds, ax
- mov si, cmd_line
- pop es
- mov di, 0x9000
- .copy_cmd:
- lodsb
- stosb
- test al, al
- jnz .copy_cmd
- mov ax, 0x9000
- mov ds, ax
- mov es, ax
- mov fs, ax
- mov gs, ax
- mov ss, ax
- cli
- jmp 0x9000:0x0200
- .err_read1:
- mov si, msg_err1
- call print_string
- jmp halt
- .err_read2:
- mov si, msg_err2
- call print_string
- jmp halt
- .err_read3:
- mov si, msg_err3
- call print_string
- jmp halt
- .err_read4:
- mov si, msg_err4
- call print_string
- halt:
- hlt
- jmp halt
- ; --- Functions ---
- print_string:
- push ds
- push ax
- xor ax, ax
- mov ds, ax
- .loop:
- lodsb
- or al, al
- jz .done
- mov ah, 0x0E
- int 0x10
- jmp .loop
- .done:
- pop ax
- pop ds
- ret
- ; read_sectors: LBA in EAX, Count in CX, Buffer in ES:BX. Returns CF=1 on error.
- read_sectors:
- pusha
- .loop:
- push eax
- push cx
-
- mov [dap_lba], eax
- mov [dap_buf_offset], bx
- mov ax, es
- mov [dap_buf_segment], ax
- mov word [dap_count], 1
- mov ah, 0x42
- mov dl, [boot_drive]
- mov si, dap
- int 0x13
- jc .disk_error
- pop cx
- pop eax
- inc eax
- add bx, 512
- dec cx
- jnz .loop
- popa
- clc
- ret
- .disk_error:
- pop cx
- pop eax
- popa
- stc
- ret
- ; read_sectors_high: LBA in EAX, Count in ECX, Dest Physical in EDI. Returns CF=1 on error.
- read_sectors_high:
- pusha
- .loop_high:
- push eax
- push ecx
- ; Use temporary buffer at 0x0000:0x2000
- mov word [dap_lba], ax
- shr eax, 16
- mov word [dap_lba+2], ax
- mov word [dap_buf_offset], 0x2000
- mov word [dap_buf_segment], 0x0000
- mov word [dap_count], 1
- mov ah, 0x42
- mov dl, [boot_drive]
- mov si, dap
-
- push edi ; Preserve EDI against BIOS corruption
- int 0x13
- pop edi
- jc .disk_error_high
- push ds
- push es
- xor ax, ax
- mov ds, ax
- mov es, ax
- mov esi, 0x2000
- mov ecx, 128
- a32 rep movsd
- pop es
- pop ds
- pop ecx
- pop eax
- inc eax
- dec ecx
- jnz .loop_high
- popa
- clc
- ret
- .disk_error_high:
- pop ecx
- pop eax
- popa
- stc
- ret
- ; --- Data ---
- msg_stage2: db "Stage 2 Bootloader...", 13, 10, 0
- msg_unreal: db "Unreal Mode Activated...", 13, 10, 0
- msg_setup_ok: db "Setup loaded.", 13, 10, 0
- msg_kernel_ok: db "Kernel loaded.", 13, 10, 0
- msg_initrd_ok: db "Initrd loaded.", 13, 10, 0
- msg_err1: db "Error: Failed to read first kernel sector", 13, 10, 0
- msg_err2: db "Error: Failed to read kernel setup sectors", 13, 10, 0
- msg_err3: db "Error: Failed to read protected kernel", 13, 10, 0
- msg_err4: db "Error: Failed to read initramfs", 13, 10, 0
- boot_drive: db 0x80
- align 16
- global_vars:
- bzimage_lba: dd 8
- bzimage_size_sectors: dd 0
- initramfs_lba: dd 0
- initramfs_size_sectors: dd 0
- initramfs_size_bytes: dd 0
- animation_lba: dd 0
- animation_size_sectors: dd 0
- lfb_addr: dd 0
- screen_pitch: dd 0
- cmd_line: db "console=tty0 loglevel=0 logo.nologo init=/init root=/dev/sdb rw quiet vt.global_cursor_default=0", 0
- align 4
- dap:
- dap_size: db 0x10
- dap_zero: db 0
- dap_count: dw 1
- dap_buf_offset: dw 0
- dap_buf_segment: dw 0
- dap_lba: dq 0
- gdt_start:
- dq 0
- gdt_data:
- dw 0xFFFF
- dw 0x0000
- db 0x00
- db 0x92
- db 0xCF
- db 0x00
- gdt_desc:
- dw gdt_desc - gdt_start - 1
- dd gdt_start
|