From 581c668f59a00c02d6b59fad4be3f147026ddb4a Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Wed, 24 Aug 2022 02:21:23 +0200 Subject: [PATCH] VESA support --- Makefile | 21 ++- bios_print.asm | 12 ++ boot.asm | 140 ------------------- main.asm | 17 ++- mbr.asm | 61 +++++++++ setup.asm | 357 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 455 insertions(+), 153 deletions(-) create mode 100644 bios_print.asm delete mode 100644 boot.asm create mode 100644 mbr.asm create mode 100644 setup.asm diff --git a/Makefile b/Makefile index 193a19b..850f293 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,19 @@ OBJS = main.o framebuffer.o memory.o +DEV=/dev/sdb -nyax.img: boot.out main.out - cat boot.out main.out > nyax.img +nyax.img: stage1.out stage2.out stage3.out + cat stage{1,2,3}.out > nyax.img -boot.out: boot.asm main.out - nasm -f bin boot.asm -o boot.out -dMAIN_SIZE=$$(stat -c%s main.out) +stage1.out: mbr.asm stage2.out stage3.out + nasm -f bin mbr.asm -o stage1.out \ + -dKSIZE=$$(du -cb stage{2,3}.out | tail -n1 | cut -f1) -main.out: $(OBJS) - ld -o main.out -Ttext 0xD000 --oformat binary $(OBJS) +stage2.out: setup.asm + nasm -f bin setup.asm -o stage2.out + +stage3.out: $(OBJS) stage2.out + ld -o stage3.out --oformat binary $(OBJS) \ + -Ttext $$(printf "%x\n" $$(echo $$(du -b stage2.out | cut -f1)+32256 | bc)) %.o: %.asm nasm -f elf64 $< -o $@ @@ -19,3 +25,6 @@ run: nyax.img .PHONY: clean clean: rm -rf *.o *.out *.img + +flash: nyax.img + dd if=./nyax.img of=$(DEV) diff --git a/bios_print.asm b/bios_print.asm new file mode 100644 index 0000000..3505eb6 --- /dev/null +++ b/bios_print.asm @@ -0,0 +1,12 @@ +; uses eax, ebx +print_str: + mov ah, 0x0E +.print: + mov al, [ebx] + cmp al, 0 + je .return + int 0x10 + inc ebx + jmp .print +.return: + ret diff --git a/boot.asm b/boot.asm deleted file mode 100644 index 415449e..0000000 --- a/boot.asm +++ /dev/null @@ -1,140 +0,0 @@ -[org 0x7C00] - -%define PAGETABLE 0x1000 -%define KERNEL 0xD000 -%define STACK 0x7E00 - -boot: - xor ax, ax - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - mov bp, STACK - mov sp, bp - - mov ax, booting_msg - call print_str - - mov bx, KERNEL - mov cl, 2 - mov al, (MAIN_SIZE + 511) / 512 - call load_disk - - mov di, PAGETABLE+0x0000 -.clr_buf: - mov byte[di], 0 - inc di - cmp di, PAGETABLE+0x4000 - jne .clr_buf - - mov dword[PAGETABLE+0x0000], PAGETABLE+0x1003 - mov dword[PAGETABLE+0x1000], PAGETABLE+0x2003 - mov dword[PAGETABLE+0x2000], PAGETABLE+0x3003 - - mov eax, 3 - mov di, PAGETABLE+0x3000 -.build_pt: - mov [di], eax - add eax, 0x1000 - add di, 8 - cmp eax, 0x100000 - jb .build_pt - - 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] - - jmp 0x0008:long_mode - -load_disk: - push ax - mov ah, 0x02 - xor ch, ch - xor dh, dh - int 0x13 - jc disk_error - pop cx - cmp al, cl - jne disk_error - ret - -disk_error: - mov ax, disk_error_msg - call print_str - jmp $ - -print_str: - push ax - push bx - mov bx, ax - mov ah, 0x0E -.print: - mov al, [bx] - cmp al, 0 - je .return - int 0x10 - inc bx - jmp .print -.return: - pop bx - pop ax - ret - -booting_msg: db 10, 13, "Loading NyaX...", 10, 10, 13, 0 -disk_error_msg: db "Disk is bwoken, cant boot ;-;", 10, 13, 0 - -GDT: - dq 0 - dq 0x00209A0000000000 - dq 0x0000920000000000 - dw 0 -.pointer: - dw $ - GDT - 1 - dd GDT - -IDT: - dw 0 - dd 0 - -[bits 64] - -long_mode: - mov ax, 0x0010 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - jmp KERNEL - -times 510-($-$$) db 0 -dw 0xAA55 diff --git a/main.asm b/main.asm index 64b9dd1..a327628 100644 --- a/main.asm +++ b/main.asm @@ -1,24 +1,27 @@ -global main +global _start extern print_str, print_num, print_chr, clear_screen section .data +headline: db "nyax stage3", 10, 10, 0 + disclaimer: db \ - "NyanX", 10, \ + "NyaX", 10, \ "(C) 2022 Flecken-chan", 10, \ "Dis progwam comes with ABSOLUTELY NO WAWWANTY", 10, \ "Dis iz fwee software, and your'e welcome to redistwibute it", 10, " under certain conditions", 10, 0 -greeting: db "Good morning Senpai UwU", 10, 0 - section .text -main: +_start: call clear_screen - mov rdi, disclaimer + + mov rdi, headline call print_str - mov rdi, greeting + + mov rdi, disclaimer call print_str + xor rdi, rdi .loop: push rdi diff --git a/mbr.asm b/mbr.asm new file mode 100644 index 0000000..6434276 --- /dev/null +++ b/mbr.asm @@ -0,0 +1,61 @@ +[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 diff --git a/setup.asm b/setup.asm new file mode 100644 index 0000000..0351501 --- /dev/null +++ b/setup.asm @@ -0,0 +1,357 @@ +[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 -- 2.44.0