From 64ec44ba4575686849ba2597cf8bc9054af3d376 Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Tue, 24 Sep 2019 22:34:20 +0200 Subject: Added working VESA driver Note to myself: Use Real/Protected mode correctly :) --- src/kernel/boot.asm | 6 +- src/kernel/graphics/graphics.h | 5 - src/kernel/graphics/vesa.asm | 182 --------------------------------- src/kernel/graphics/vesa.c | 43 ++++++-- src/kernel/graphics/vesa.h | 45 ++++----- src/kernel/interact.asm | 223 +++++++++++++++++++++++++++++++++++++++++ src/kernel/kernel.c | 7 +- 7 files changed, 283 insertions(+), 228 deletions(-) delete mode 100644 src/kernel/graphics/vesa.asm create mode 100644 src/kernel/interact.asm diff --git a/src/kernel/boot.asm b/src/kernel/boot.asm index 116fa32..c0b3735 100644 --- a/src/kernel/boot.asm +++ b/src/kernel/boot.asm @@ -2,8 +2,6 @@ global start start: mov esp, _sys_stack ; Points stack to stack area - extern init_graphics - call init_graphics jmp stublet ; Align with 4 Bytes @@ -36,8 +34,6 @@ stublet: call kernel_main jmp $ -%include "src/kernel/graphics/vesa.asm" - %include "src/kernel/gdt/gdt.asm" %include "src/kernel/interrupts/idt.asm" @@ -46,6 +42,8 @@ stublet: %include "src/kernel/interrupts/irq.asm" +%include "src/kernel/interact.asm" + ; Store the stack SECTION .bss resb 8192 ; Reserve 8KiB diff --git a/src/kernel/graphics/graphics.h b/src/kernel/graphics/graphics.h index aa9440a..b28b550 100644 --- a/src/kernel/graphics/graphics.h +++ b/src/kernel/graphics/graphics.h @@ -20,9 +20,4 @@ void terminal_put_char(char c); void terminal_write_line(const char *data); -// VESA/VBE -void init_graphics(); - -struct vbe_best best; - #endif \ No newline at end of file diff --git a/src/kernel/graphics/vesa.asm b/src/kernel/graphics/vesa.asm deleted file mode 100644 index 820d592..0000000 --- a/src/kernel/graphics/vesa.asm +++ /dev/null @@ -1,182 +0,0 @@ -global vbe_set_mode -global vbe_find_mode - -vbe_set_mode: - mov [width], ax - mov [height], bx - mov [bpp], cl - - sti - - ; Get VBE BIOS info - push es - mov ax, 0x4F00 - mov di, [vbe_info] - int 0x10 - pop es - - ; Check if BIOS has VBE support - cmp ax, 0x4F - jne error - - mov ax, word[vbe_info.video_modes] - mov [offset], ax - mov ax, word[vbe_info.video_modes+2] - mov [mode_segment], ax - - mov ax, [mode_segment] - mov fs, ax - mov si, [offset] - -vbe_find_mode: - mov dx, [fs:si] - add si, 2 - mov [offset], si - mov [mode], dx - mov ax, 0 - mov fs, ax - - cmp [mode], word 0xFFFF - je error - - ; Get VBE mode info - push es - mov ax, 0x4F01 - mov cx, [mode] - mov di, [vbe_mode_info] - int 0x10 - pop es - - cmp ax, 0x4F - jne error - - mov ax, [width] - cmp ax, [vbe_mode_info.width] - jne next_mode - - mov ax, [height] - cmp ax, [vbe_mode_info.height] - jne next_mode - - mov al, [bpp] - cmp al, [vbe_mode_info.bpp] - jne next_mode - - ; Found best mode! - mov ax, [width] - mov word[vbe_best.width], ax - mov ax, [height] - mov word[vbe_best.height], ax - mov eax, [vbe_mode_info.framebuffer] - mov dword[vbe_best.framebuffer], eax - mov ax, [vbe_mode_info.pitch] - mov word[vbe_best.bytes_per_line], ax - mov eax, 0 - mov al, [bpp] - mov byte[vbe_best.bpp], al - shr eax, 3 - mov dword[vbe_best.bytes_per_pixel], eax - - mov ax, [width] - shr ax, 3 - dec ax - mov word[vbe_best.x_cur_max], ax - - mov ax, [height] - shr ax, 4 - dec ax - mov word[vbe_best.y_cur_max], ax - - ; Set the mode - push es - mov ax, 0x4F02 - mov bx, [mode] - or bx, 0x4000 - mov di, 0 - int 0x10 - pop es - - cmp ax, 0x4F - jne error - - clc - ret - -next_mode: - mov ax, [mode_segment] - mov fs, ax - mov si, [offset] - jmp vbe_find_mode - -error: - stc - ret - -width dw 0 -height dw 0 -bpp db 0 -mode_segment dw 0 -offset dw 0 -mode dw 0 - -vbe_info: - .signature db "VESA" - .version dw 0 - .oem dd 0 - .capabilities dd 0 - .video_modes dd 0 - .video_memory dw 0 - .software_rev dw 0 - .vendor dd 0 - .product_name dd 0 - .product_rev dd 0 - .reserved times 222 db 0 - .oem_data times 256 db 0 - -vbe_mode_info: - .attributes dw 0 - .window_a db 0 - .window_b db 0 - .granularity dw 0 - .window_size dw 0 - .segment_a dw 0 - .segment_b dw 0 - .win_func_ptr dd 0 - .pitch dw 0 - .width dw 0 - .height dw 0 - .w_char db 0 - .y_char db 0 - .planes db 0 - .bpp db 0 - .banks db 0 - .memory_model db 0 - .bank_size db 0 - .image_pages db 0 - .reserved0 db 0 - - .red_mask db 0 - .red_position db 0 - .green_mask db 0 - .green_position db 0 - .blue_mask db 0 - .blue_position db 0 - .reserved_mask db 0 - .reserved_position db 0 - .direct_color_attributes db 0 - - .framebuffer dd 0 - .off_screen_mem_off dd 0 - .off_screen_mem_size dw 0 - .reserved1 times 206 db 0 - -vbe_best: - .bpp db 0 - .height dw 0 - .width dw 0 - .mode dw 0 - .framebuffer dd 0 - .bytes_per_line dw 0 - .bytes_per_pixel dd 0 - .x_cur_max dw 0 - .y_cur_max dw 0 \ No newline at end of file diff --git a/src/kernel/graphics/vesa.c b/src/kernel/graphics/vesa.c index 3549d66..af2502b 100644 --- a/src/kernel/graphics/vesa.c +++ b/src/kernel/graphics/vesa.c @@ -1,11 +1,42 @@ #include "vesa.h" -extern struct vbe_best vbe_find_mode(); +vbe_mode_info *vbe_set_mode(unsigned short mode) { + regs16_t regs; + regs.ax = 0x4F02; + regs.bx = mode | (1 << 14); + int32(0x10, ®s); -extern void vbe_set_mode(struct vbe_best); + if (regs.ax == 0x004F) { + regs.ax = 0x4F01; + regs.cx = mode; + regs.di = 0x0000; + regs.es = 0xA000; + int32(0x10, ®s); + if (regs.ax != 0x004F) { + // Add VGA redirect + } -struct vbe_best best; + vbe_mode_info *vbe_info = (vbe_mode_info *) 0xA0000; -void init_graphics() { - best = vbe_find_mode(); -} \ No newline at end of file + vbe_width = vbe_info->width; + vbe_height = vbe_info->height; + vbe_bpp = vbe_info->bpp / 8; + vbe_pitch = vbe_info->pitch; + + char *fb = (char *) vbe_info->framebuffer; + for (int i = 0; i < 640 * 480 * 3; i++) { + fb[i] = 100; + } + regs.ax = 0x0000; + int32(0x16, ®s); + regs.ax = 0x0003; + int32(0x10, ®s); + + return vbe_info; + } else { + // Add VGA redirect + } + + vbe_mode_info vbe_info; + return &vbe_info; +} diff --git a/src/kernel/graphics/vesa.h b/src/kernel/graphics/vesa.h index 9023029..fb9ff54 100644 --- a/src/kernel/graphics/vesa.h +++ b/src/kernel/graphics/vesa.h @@ -3,33 +3,7 @@ #include -struct vbe_best { - uint8_t bpp; - uint16_t height; - uint16_t width; - uint32_t framebuffer; - uint32_t bytes_per_line; - uint32_t bytes_per_pixel; - uint32_t x_cur_max; - uint32_t y_cur_max; -} __attribute__ ((packed)); - -struct vbe_info { - char signature[4]; // must be "VESA" to indicate valid VBE support - uint16_t version; // VBE version; high byte is major version, low byte is minor version - uint32_t oem; // segment:offset pointer to OEM - uint32_t capabilities; // bitfield that describes card capabilities - uint32_t video_modes; // segment:offset pointer to list of supported video modes - uint16_t video_memory; // amount of video memory in 64KB blocks - uint16_t software_rev; // software revision - uint32_t vendor; // segment:offset to card vendor string - uint32_t product_name; // segment:offset to card model name - uint32_t product_rev; // segment:offset pointer to product revision - char reserved[222]; // reserved for future expansion - char oem_data[256]; // OEM BIOSes store their strings in this area -} __attribute__ ((packed)); - -struct vbe_mode_info { +typedef struct __attribute__ ((packed)) { uint16_t attributes; // deprecated, only bit 7 should be of interest to you, and it indicates the mode supports a linear frame buffer. uint8_t window_a; // deprecated uint8_t window_b; // deprecated @@ -65,6 +39,21 @@ struct vbe_mode_info { uint32_t off_screen_mem_off; uint16_t off_screen_mem_size; // size of memory in the framebuffer but not being displayed on the screen uint8_t reserved1[206]; -} __attribute__ ((packed)); +} vbe_mode_info; + +vbe_mode_info *vbe_set_mode(unsigned short mode); + +typedef struct __attribute__ ((packed)) { + unsigned short di, si, bp, sp, bx, dx, cx, ax; + unsigned short gs, fs, es, ds, eflags; +} regs16_t; + +extern void int32(unsigned char intnum, regs16_t *regs); + +int vbe_current_mode; +int vbe_width; +int vbe_height; +int vbe_bpp; +int vbe_pitch; #endif diff --git a/src/kernel/interact.asm b/src/kernel/interact.asm new file mode 100644 index 0000000..8a3e91e --- /dev/null +++ b/src/kernel/interact.asm @@ -0,0 +1,223 @@ +; +; Protected Mode BIOS Call Functionailty v2.0 - by Napalm +; ------------------------------------------------------- +; +; This is code shows how its POSSIBLE to execute BIOS interrupts +; by switch out to real-mode and then back into protected mode. +; +; If you wish to use all or part of this code you must agree +; to the license at the following URL. +; +; License: http://creativecommons.org/licenses/by-sa/2.0/uk/ +; +; Notes: This file is in NASM syntax. +; Turn off paging before calling these functions. +; int32() resets all selectors. +; +; C Prototype: +; void _cdelc int32(unsigned char intnum, regs16_t *regs); +; +; Example of usage: +; regs.ax = 0x0013; +; int32(0x10, ®s); +; memset((char *)0xA0000, 1, (320*200)); +; memset((char *)0xA0000 + (100*320+80), 14, 80); +; regs.ax = 0x0000; +; int32(0x16, ®s); +; regs.ax = 0x0003; +; int32(0x10, ®s); +; +; +[bits 32] + +global int32, _int32 + +struc regs16_t + .di resw 1 + .si resw 1 + .bp resw 1 + .sp resw 1 + .bx resw 1 + .dx resw 1 + .cx resw 1 + .ax resw 1 + .gs resw 1 + .fs resw 1 + .es resw 1 + .ds resw 1 + .ef resw 1 +endstruc + +%define INT32_BASE 0x7C00 +%define REBASE(x) (((x) - reloc) + INT32_BASE) +%define GDTENTRY(x) ((x) << 3) +%define CODE32 GDTENTRY(1) ; 0x08 +%define DATA32 GDTENTRY(2) ; 0x10 +%define CODE16 GDTENTRY(3) ; 0x18 +%define DATA16 GDTENTRY(4) ; 0x20 +%define STACK16 (INT32_BASE - regs16_t_size) + + +section .text + int32: use32 ; by Napalm + _int32: + cli ; disable interrupts + pusha ; save register state to 32bit stack + mov esi, reloc ; set source to code below + mov edi, INT32_BASE ; set destination to new base address + mov ecx, (int32_end - reloc) ; set copy size to our codes size + cld ; clear direction flag (so we copy forward) + rep movsb ; do the actual copy (relocate code to low 16bit space) + jmp INT32_BASE ; jump to new code location + reloc: use32 ; by Napalm + mov [REBASE(stack32_ptr)], esp ; save 32bit stack pointer + sidt [REBASE(idt32_ptr)] ; save 32bit idt pointer + ;sgdt [REBASE(gdt32_ptr)] ; save 32bit gdt pointer + lgdt [REBASE(gdt16_ptr)] ; load 16bit gdt pointer + lea esi, [esp+0x24] ; set position of intnum on 32bit stack + lodsd ; read intnum into eax + mov [REBASE(ib)], al ; set intrrupt immediate byte from our arguments + mov esi, [esi] ; read regs pointer in esi as source + mov edi, STACK16 ; set destination to 16bit stack + mov ecx, regs16_t_size ; set copy size to our struct size + mov esp, edi ; save destination to as 16bit stack offset + rep movsb ; do the actual copy (32bit stack to 16bit stack) + jmp word CODE16:REBASE(p_mode16) ; switch to 16bit selector (16bit protected mode) + p_mode16: use16 + mov ax, DATA16 ; get our 16bit data selector + mov ds, ax ; set ds to 16bit selector + mov es, ax ; set es to 16bit selector + mov fs, ax ; set fs to 16bit selector + mov gs, ax ; set gs to 16bit selector + mov ss, ax ; set ss to 16bit selector + mov eax, cr0 ; get cr0 so we can modify it + and al, ~0x01 ; mask off PE bit to turn off protected mode + mov cr0, eax ; set cr0 to result + jmp word 0x0000:REBASE(r_mode16) ; finally set cs:ip to enter real-mode + r_mode16: use16 + xor ax, ax ; set ax to zero + mov ds, ax ; set ds so we can access idt16 + mov ss, ax ; set ss so they the stack is valid + lidt [REBASE(idt16_ptr)] ; load 16bit idt + mov bx, 0x0870 ; master 8 and slave 112 + call resetpic ; set pic's the to real-mode settings + popa ; load general purpose registers from 16bit stack + pop gs ; load gs from 16bit stack + pop fs ; load fs from 16bit stack + pop es ; load es from 16bit stack + pop ds ; load ds from 16bit stack + sti ; enable interrupts + db 0xCD ; opcode of INT instruction with immediate byte + ib: db 0x00 + cli ; disable interrupts + xor sp, sp ; zero sp so we can reuse it + mov ss, sp ; set ss so the stack is valid + mov sp, INT32_BASE ; set correct stack position so we can copy back + pushf ; save eflags to 16bit stack + push ds ; save ds to 16bit stack + push es ; save es to 16bit stack + push fs ; save fs to 16bit stack + push gs ; save gs to 16bit stack + pusha ; save general purpose registers to 16bit stack + mov bx, 0x2028 ; master 32 and slave 40 + call resetpic ; restore the pic's to protected mode settings + mov eax, cr0 ; get cr0 so we can modify it + inc eax ; set PE bit to turn on protected mode + mov cr0, eax ; set cr0 to result + jmp dword CODE32:REBASE(p_mode32) ; switch to 32bit selector (32bit protected mode) + p_mode32: use32 + mov ax, DATA32 ; get our 32bit data selector + mov ds, ax ; reset ds selector + mov es, ax ; reset es selector + mov fs, ax ; reset fs selector + mov gs, ax ; reset gs selector + mov ss, ax ; reset ss selector + lgdt [REBASE(gdt32_ptr)] ; restore 32bit gdt pointer + lidt [REBASE(idt32_ptr)] ; restore 32bit idt pointer + mov esp, [REBASE(stack32_ptr)] ; restore 32bit stack pointer + mov esi, STACK16 ; set copy source to 16bit stack + lea edi, [esp+0x28] ; set position of regs pointer on 32bit stack + mov edi, [edi] ; use regs pointer in edi as copy destination + mov ecx, regs16_t_size ; set copy size to our struct size + cld ; clear direction flag (so we copy forward) + rep movsb ; do the actual copy (16bit stack to 32bit stack) + popa ; restore registers + sti ; enable interrupts + ret ; return to caller + + resetpic: ; reset's 8259 master and slave pic vectors + push ax ; expects bh = master vector, bl = slave vector + mov al, 0x11 ; 0x11 = ICW1_INIT | ICW1_ICW4 + out 0x20, al ; send ICW1 to master pic + out 0xA0, al ; send ICW1 to slave pic + mov al, bh ; get master pic vector param + out 0x21, al ; send ICW2 aka vector to master pic + mov al, bl ; get slave pic vector param + out 0xA1, al ; send ICW2 aka vector to slave pic + mov al, 0x04 ; 0x04 = set slave to IRQ2 + out 0x21, al ; send ICW3 to master pic + shr al, 1 ; 0x02 = tell slave its on IRQ2 of master + out 0xA1, al ; send ICW3 to slave pic + shr al, 1 ; 0x01 = ICW4_8086 + out 0x21, al ; send ICW4 to master pic + out 0xA1, al ; send ICW4 to slave pic + pop ax ; restore ax from stack + ret ; return to caller + + stack32_ptr: ; address in 32bit stack after we + dd 0x00000000 ; save all general purpose registers + + idt32_ptr: ; IDT table pointer for 32bit access + dw 0x0000 ; table limit (size) + dd 0x00000000 ; table base address + + gdt32_ptr: ; GDT table pointer for 32bit access + dw 0x0018 ; table limit (size) + dd 0x00130000 ; table base address + + idt16_ptr: ; IDT table pointer for 16bit access + dw 0x03FF ; table limit (size) + dd 0x00000000 ; table base address + + gdt16_base: ; GDT descriptor table + .null: ; 0x00 - null segment descriptor + dd 0x00000000 ; must be left zero'd + dd 0x00000000 ; must be left zero'd + + .code32: ; 0x01 - 32bit code segment descriptor 0xFFFFFFFF + dw 0xFFFF ; limit 0:15 + dw 0x0000 ; base 0:15 + db 0x00 ; base 16:23 + db 0x9A ; present, iopl/0, code, execute/read + db 0xCF ; 4Kbyte granularity, 32bit selector; limit 16:19 + db 0x00 ; base 24:31 + + .data32: ; 0x02 - 32bit data segment descriptor 0xFFFFFFFF + dw 0xFFFF ; limit 0:15 + dw 0x0000 ; base 0:15 + db 0x00 ; base 16:23 + db 0x92 ; present, iopl/0, data, read/write + db 0xCF ; 4Kbyte granularity, 32bit selector; limit 16:19 + db 0x00 ; base 24:31 + + .code16: ; 0x03 - 16bit code segment descriptor 0x000FFFFF + dw 0xFFFF ; limit 0:15 + dw 0x0000 ; base 0:15 + db 0x00 ; base 16:23 + db 0x9A ; present, iopl/0, code, execute/read + db 0x0F ; 1Byte granularity, 16bit selector; limit 16:19 + db 0x00 ; base 24:31 + + .data16: ; 0x04 - 16bit data segment descriptor 0x000FFFFF + dw 0xFFFF ; limit 0:15 + dw 0x0000 ; base 0:15 + db 0x00 ; base 16:23 + db 0x92 ; present, iopl/0, data, read/write + db 0x0F ; 1Byte granularity, 16bit selector; limit 16:19 + db 0x00 ; base 24:31 + + gdt16_ptr: ; GDT table pointer for 16bit access + dw gdt16_ptr - gdt16_base - 1 ; table limit (size) + dd gdt16_base ; table base address + + int32_end: ; end marker (so we can copy the code) \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 91b2bb4..d0356f4 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -11,9 +11,10 @@ void kernel_main(void) { isrs_install(); irq_install(); - terminal_initialize(); - terminal_write_string("Melvix loaded successfully!\n"); - terminal_write_string((const char *) best.height); + vbe_set_mode(0x11B); // 1280x1024 + + // terminal_initialize(); + // terminal_write_string("Melvix loaded successfully!\n"); timer_install(); keyboard_install(); -- cgit v1.2.3