; This file is part of the Essence operating system. ; It is released under the terms of the MIT license -- see LICENSE.md. ; Written by: nakst. vbe_init: mov ax,vesa_info >> 4 mov es,ax xor di,di %ifndef BOOT_USE_VBE jmp vbe_bad %endif ; Get EDID information. mov ax,0x4F15 mov bl,1 xor cx,cx xor dx,dx xor di,di int 0x10 cmp ax,0x4F jne .no_edid cmp byte [es:1],0xFF jne .no_edid mov al,[es:0x38] mov ah,[es:0x3A] shr ah,4 mov bl,[es:0x3B] mov bh,[es:0x3D] shr bh,4 or ax,ax jz .no_edid or bx,bx jz .no_edid mov [vbe_best_width],ax mov [vbe_best_height],bx mov byte [vbe_has_edid],1 jmp .no_flat_panel .no_edid: ; Get flat panel information. mov ax,0x4F11 mov bx,1 xor di,di int 0x10 cmp ax,0x4F jne .no_flat_panel mov ax,[es:0x00] mov bx,[es:0x02] or ax,ax jz .no_flat_panel or bx,bx jz .no_flat_panel cmp ax,4096 ja .no_flat_panel cmp bx,4096 ja .no_flat_panel mov [vbe_best_width],ax mov [vbe_best_height],bx .no_flat_panel: ; Get SVGA information. xor di,di mov ax,0x4F00 int 0x10 cmp ax,0x4F jne vbe_bad ; Load the list of available modes. add di,0x200 mov eax,[es:14] cmp eax,0 je .find_done mov ax,[es:16] mov fs,ax mov si,[es:14] xor cx,cx .find_loop: mov ax,[fs:si] cmp ax,0xFFFF je .find_done mov [es:di],ax add di,2 add si,2 jmp .find_loop .find_done: ; Add standard modes (if necessary). mov word [es:di],0xFFFF cmp di,0x200 jne .added_modes mov word [es:di + 0],257 mov word [es:di + 2],259 mov word [es:di + 4],261 mov word [es:di + 6],263 mov word [es:di + 8],273 mov word [es:di + 10],276 mov word [es:di + 12],279 mov word [es:di + 14],282 mov word [es:di + 16],274 mov word [es:di + 18],277 mov word [es:di + 20],280 mov word [es:di + 22],283 mov word [es:di + 24],0xFFFF .added_modes: ; Check which of these modes can be used. mov si,0x200 mov di,0x200 .check_loop: mov cx,[es:si] mov [es:di],cx cmp cx,0xFFFF je .check_done push di push si mov ax,0x4F01 xor di,di or cx,(1 << 14) int 0x10 pop si pop di add si,2 cmp ax,0x4F ; Interrupt failed. jne .check_loop cmp byte [es:0x19],24 ; We only support 24-bit and 32-bit modes currently. je .valid_bpp cmp byte [es:0x19],32 je .valid_bpp jne .check_loop .valid_bpp: cmp word [es:0x14],480 ; We support a minimum vertical resolution of 480 pixels. jl .check_loop mov ax,[vbe_best_width] cmp [es:0x12],ax jne .not_best_mode mov ax,[vbe_best_height] cmp [es:0x14],ax jne .not_best_mode mov ax,[es:di] mov [vbe_best_mode],ax .not_best_mode: add di,2 jmp .check_loop .check_done: ; If we found a best mode, use that. mov bx,[vbe_best_mode] or bx,bx jnz .set_graphics_mode .no_best_mode: ; Print a list of the available modes. mov si,vbe_s_select_video_mode call vbe_print_string mov bx,0x200 mov cx,1 .print_loop: mov dx,[es:bx] cmp dx,0xFFFF je .print_done cmp cx,21 ; Maximum of 20 options. TODO Scrolling! je .print_done xor di,di push cx mov ax,0x4F01 mov cx,dx or cx,(1 << 14) int 0x10 pop cx mov si,vbe_s_left_bracket call vbe_print_string mov ax,cx call vbe_print_decimal mov si,vbe_s_right_bracket call vbe_print_string mov ax,[es:0x12] call vbe_print_decimal mov si,vbe_s_by call vbe_print_string mov ax,[es:0x14] call vbe_print_decimal mov si,vbe_s_space call vbe_print_string xor ah,ah mov al,[es:0x19] call vbe_print_decimal mov si,vbe_s_bpp call vbe_print_string call vbe_print_newline inc cx add bx,2 jmp .print_loop .print_done: ; Let the user select a mode. mov dx,cx dec dx xor cx,cx .select_loop: cmp cx,dx jb .c1 mov cx,0 .c1: call vbe_set_highlighted_line xor ax,ax int 0x16 shr ax,8 cmp ax,72 jne .k11 dec cx .k11: cmp ax,80 jne .k12 inc cx .k12: cmp ax,28 jne .select_loop ; Set the graphics mode. mov di,cx shl di,1 add di,0x200 mov bx,[es:di] .set_graphics_mode: or bx,(1 << 14) mov cx,bx mov ax,0x4F02 int 0x10 cmp ax,0x4F jne vbe_failed ; Save information about the mode for the kernel. mov ax,0x4F01 xor di,di int 0x10 mov byte [es:0],1 ; valid mov al,[es:0x19] mov [es:1],al ; bpp mov ax,[es:0x12] mov [es:2],ax ; width mov ax,[es:0x14] mov [es:4],ax ; height mov ax,[es:0x10] mov [es:6],ax ; stride mov eax,[es:40] mov [es:8],eax ; buffer xor eax,eax mov [es:12],eax mov ax,0x4F15 mov bl,1 xor cx,cx xor dx,dx mov di,0x10 int 0x10 mov al,[vbe_has_edid] shl al,1 or [es:0],al ret vbe_bad: mov byte [es:di],0 ret vbe_failed: mov si,vbe_s_failed call vbe_print_string jmp vbe_init.select_loop vbe_print_newline: pusha mov ah,0xE mov al,13 int 0x10 mov ah,0xE mov al,10 int 0x10 popa ret vbe_print_space: pusha mov ah,0xE mov al,' ' int 0x10 popa ret vbe_print_string: ; Input - SI. pusha .loop: lodsb or al,al jz .done mov ah,0xE int 0x10 jmp .loop .done: popa ret vbe_print_decimal: ; Input - AX. pusha mov bx,.buffer mov cx,10 .next: xor dx,dx div cx add dx,'0' mov [bx],dl inc bx cmp ax,0 jne .next .loop: dec bx mov al,[bx] mov ah,0xE int 0x10 cmp bx,.buffer jne .loop popa ret .buffer: db 0, 0, 0, 0, 0 vbe_set_highlighted_line: ; Input - CX pusha mov ax,0xB800 mov fs,ax mov di,1 mov dx,(80 * 25) .clear_loop: mov byte [fs:di],0x07 add di,2 dec dx cmp dx,0 jne .clear_loop mov ax,cx add ax,2 mov cx,160 mul cx mov dx,80 mov di,ax inc di .highlight_loop: mov byte [fs:di],0x70 add di,2 dec dx cmp dx,0 jne .highlight_loop popa ret vbe_s_select_video_mode: db 'Select a video mode: [use up/down then press enter]',13,10,0 vbe_s_left_bracket: db '(',0 vbe_s_right_bracket: db ') ',0 vbe_s_by: db 'x',0 vbe_s_space: db ' ',0 vbe_s_bpp: db 'bpp',0 vbe_s_failed: db 'This graphics mode could not be selected. Please try a different one.',13,10,0 vbe_best_width: dw 0 vbe_best_height: dw 0 vbe_best_mode: dw 0 vbe_has_edid: db 0