--- /dev/null
+[org 0x7C00]
+
+%define KSTART 0x7E00
+%define KSECTORS (KSIZE + 511) / 512
+
+boot:
+ ; init segment registers
+ xor ax, ax
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ ; init stack
+ mov bp, KSTART ; stack grows down, overwriting MBR
+ mov sp, bp
+
+ ; print message
+ mov ebx, .msg
+ call print_str
+
+ ; load stage2 and stage3
+ call load_stages
+
+ ; jump into stage2
+ jmp KSTART
+
+.msg: db 10, 13, "nyax stage1", 10, 13, 0
+
+
+load_stages:
+ mov ebx, .msg
+ call print_str
+
+ mov ah, 0x02 ; read sectors from drive
+ mov al, KSECTORS ; number of sectors
+ xor ch, ch ; cylinder=0
+ mov cl, 2 ; sector=2
+ xor dh, dh ; head=0
+ mov bx, KSTART ; buffer
+ int 0x13
+ jc .fail ; CF set on error
+ cmp al, KSECTORS ; check read sectors count
+ jne .fail
+
+ ret
+
+.fail:
+ mov ebx, .fail_msg
+ call print_str
+ jmp $
+
+.msg: db "loading stage2 and stage3 from disk", 10, 13, 0
+.fail_msg: db "disk failure, try rebooting", 10, 13, 0
+
+
+%include "bios_print.asm"
+
+times 510-($-$$) db 0
+dw 0xAA55
--- /dev/null
+[org 0x7E00]
+
+%define PAGETABLE 0x1000
+%define VESAINFO 0x0500
+%define VESAMODE VESAINFO+512
+%define OWNMODE VESAMODE+256
+%define GFXINFO 0x500
+
+setup:
+ ; print message
+ mov ebx, .msg
+ call print_str
+
+ ; setup VESA
+ call vesa
+
+ ; get extended memory map
+ call mmap
+
+ ; build page table
+ call paging
+
+ ; jump into long mode
+ jmp 0x0008:long_mode
+
+.msg:
+ db 10, 13, "nyax stage2", 10, 13, 0
+
+
+vesa:
+ ; print message
+ mov ebx, .msg
+ call print_str
+
+ ; get vesa bios info
+ mov eax, dword[.vbe2]
+ mov dword[VESAINFO], eax ; move "VBE2" to start of vesainfo struct
+ mov ax, 0x4F00 ; get VESA BIOS information
+ mov di, VESAINFO ; struct buffer
+ int 0x10
+
+ cmp ax, 0x004F ; check ax for correct magic number
+ jne .fail_getinfo
+
+ mov eax, dword[.vesa]
+ cmp dword[VESAINFO], eax ; check if "VESA" is at start of stuct
+ jne .fail_getinfo
+
+ ; print select message
+ mov ebx, .select_msg
+ call print_str
+
+ ; get segment:offset pointer to video modes into gs:ebx
+ movzx ebx, word[VESAINFO+14]
+ mov ax, word[VESAINFO+16]
+ mov gs, ax
+
+ ; convert modes to own structure
+
+ xor esi, esi ; number of avail modes
+
+.mode_loop:
+ ; get mode info
+ mov cx, [gs:ebx] ; video mode into cx
+ cmp cx, 0xFFFF ; 0xFFFF is terminator, no suitable mode has been found
+ je .mode_done
+ mov ax, 0x4F01 ; get VESA mode information
+ mov di, VESAMODE ; vesa mode info struct buffer
+ int 0x10
+
+ cmp ax, 0x004F ; check ax for correct magic number
+ jne .fail_modeinfo
+
+ mov al, byte[VESAMODE] ; get attributes
+ and al, 0b10000000 ; extract bit 7, indicates linear framebuffer support
+ jz .mode_next
+
+ mov al, byte[VESAMODE+25] ; get bpp (bits per pixel)
+ cmp al, 32
+ jne .mode_next
+
+ push ebx ; print_num and print_str modify ebx
+
+ mov eax, esi
+ mov ebx, 12
+ mul ebx
+ mov edi, eax
+ add edi, OWNMODE
+
+ mov [edi+10], cx ; copy mode
+
+ mov eax, edi
+ call print_num
+
+ ; print selector
+ mov al, '['
+ call print_chr
+
+ mov eax, esi
+ add eax, 'a'
+ call print_chr
+
+ mov al, ']'
+ call print_chr
+
+ mov al, ' '
+ call print_chr
+
+ mov ax, [VESAMODE+16] ; copy pitch
+ mov [edi+0], ax
+
+ movzx eax, word[VESAMODE+18] ; copy width
+ mov [edi+2], ax
+ call print_num
+
+ mov al, 'x'
+ call print_chr
+
+ movzx eax, word[VESAMODE+20] ; copy height
+ mov [edi+4], ax
+ call print_num
+ call newline
+
+ mov eax, [VESAMODE+40] ; copy framebuffer
+ mov [edi+6], eax
+
+ pop ebx
+
+ inc esi
+ cmp esi, 'z'-'a' ; only print up to z
+ jg .mode_done
+
+.mode_next:
+ add ebx, 2 ; increase mode pointer
+ jmp .mode_loop ; loop
+
+.mode_done:
+ cmp esi, 0
+ je .fail_nomode
+
+.input:
+ mov ebx, .select_prompt
+ call print_str
+
+ mov ah, 0x00 ; get keypress, blocking
+ int 0x16
+
+ call print_chr ; echo user input
+
+ movzx edi, al ; backup al
+ call newline
+
+ sub edi, 'a'
+ cmp edi, esi
+ jb .valid ; check validity
+
+ mov ebx, .invalid
+ call print_str
+
+ jmp .input
+
+.valid:
+ mov eax, edi
+ call print_num
+ call newline
+
+ ; convert selected number to address
+ mov eax, edi
+ mov ebx, 12
+ mul ebx
+ add eax, OWNMODE
+
+ ; copy to final gfx info location
+ mov ebx, [eax]
+ mov [GFXINFO], ebx
+
+ mov ebx, [eax+4]
+ mov [GFXINFO+4], ebx
+
+ mov bx, [eax+6]
+ mov [GFXINFO+6], bx
+
+ ; set mode
+ mov bx, [eax+10] ; video mode in bx (first 13 bits)
+ or bx, 0b0100000000000000 ; set bit 14: enable linear frame buffer
+ and bx, 0b0111111111111111 ; clear deprecated bit 15
+ mov ax, 0x4F02 ; set VBE mode
+ int 0x10
+
+ ret
+
+.msg: db "setting up vesa", 10, 13, 0
+.vbe2: db "VBE2"
+.vesa: db "VESA"
+.select_msg: db "avaliable video modes:", 10, 13, 0
+.select_prompt: db "select video mode: ", 0
+.invalid: db "invalid input", 10, 13, 0
+
+.fail_getinfo:
+ mov ebx, .fail_getinfo_msg
+ jmp .fail
+
+.fail_modeinfo:
+ mov ebx, .fail_modeinfo_msg
+ jmp .fail
+
+.fail_nomode:
+ mov ebx, .fail_nomode_msg
+ jmp .fail
+
+.fail_getinfo_msg: db "failed getting vesa bios info", 10, 13, 0
+.fail_modeinfo_msg: db "failed getting video mode info", 10, 13, 0
+.fail_nomode_msg: db "no suitable video modes available", 10, 13, 0
+
+.fail:
+ call print_str
+ jmp $
+
+
+mmap:
+ mov ebx, .msg
+ call print_str
+
+ ret
+
+.msg: db "getting extended memory map", 10, 13, 0
+
+
+paging:
+ ; print message
+ mov ebx, .msg
+ call print_str
+
+ ; clear 4 levels of page maps
+ mov di, PAGETABLE+0x0000
+.clr_buf:
+ mov byte[di], 0
+ inc di
+ cmp di, PAGETABLE+0x4000
+ jne .clr_buf
+
+ ; init 3 page map levels
+ mov dword[PAGETABLE+0x0000], PAGETABLE+0x1003
+ mov dword[PAGETABLE+0x1000], PAGETABLE+0x2003
+ mov dword[PAGETABLE+0x2000], PAGETABLE+0x3003
+
+ ; fill up level 4 page map
+ mov eax, 3
+ mov di, PAGETABLE+0x3000
+.build_pt:
+ mov [di], eax
+ add eax, 0x1000
+ add di, 8
+ cmp eax, 0x100000
+ jb .build_pt
+
+ ; enable paging and long mode
+
+ mov di, PAGETABLE
+
+ mov al, 0xFF
+ out 0xA1, al
+ out 0x21, al
+
+ nop
+ nop
+
+ lidt [.idt]
+
+ mov eax, 0b10100000
+ mov cr4, eax
+
+ mov edx, edi
+ mov cr3, edx
+
+ mov ecx, 0xC0000080
+ rdmsr
+
+ or eax, 0x00000100
+ wrmsr
+
+ mov ebx, cr0
+ or ebx, 0x80000001
+ mov cr0, ebx
+
+ lgdt [.gdt_pointer]
+
+ ret
+
+.gdt:
+ dq 0
+ dq 0x00209A0000000000
+ dq 0x0000920000000000
+ dw 0
+
+.gdt_pointer:
+ dw $ - .gdt - 1
+ dd .gdt
+
+.idt:
+ dw 0
+ dd 0
+
+.msg:
+ db "building page table", 10, 13, 0
+
+
+%include "bios_print.asm"
+
+; uses eax, ebx, ecx, edx
+print_num:
+ mov ebx, 10
+ xor ecx, ecx
+.convert:
+ inc ecx
+ xor edx, edx
+ div ebx
+ add dl, '0'
+ push dx
+ cmp eax, 0
+ jne .convert
+.print:
+ cmp ecx, 0
+ je .return
+ dec ecx
+ pop ax
+ mov ah, 0x0E
+ int 0x10
+ jmp .print
+.return:
+ ret
+
+
+newline:
+ mov al, 10
+ call print_chr
+
+ mov al, 13
+ call print_chr
+
+ ret
+
+print_chr:
+ mov ah, 0x0E
+ int 0x10
+ ret
+
+[bits 64]
+
+long_mode:
+ ; setup segment registers
+ mov ax, 0x0010
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax