diff --git a/Makefile b/Makefile index 2f3a6164..5b2d8ada 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ thor.flp: bootloader/stage1.bin bootloader/stage2.bin kernel/kernel.bin programs sudo /sbin/losetup -d /dev/loop0 qemu: default - qemu-kvm -cpu host -hda hdd.img + qemu-kvm -cpu host -vga std -hda hdd.img bochs: default bochs -qf bochsrc.txt diff --git a/kernel/include/vesa.hpp b/kernel/include/vesa.hpp index ab26c574..7f344163 100644 --- a/kernel/include/vesa.hpp +++ b/kernel/include/vesa.hpp @@ -98,6 +98,8 @@ static_assert(sizeof(mode_info_block_t) == 256, "The size of a mode info block i extern vbe_info_block_t vbe_info_block; extern bool vesa_enabled; +extern mode_info_block_t mode_info_block; +extern uint16_t modes; } //end of vesa namespace diff --git a/kernel/src/boot/boot_16.cpp b/kernel/src/boot/boot_16.cpp index c5ce8209..86091e38 100644 --- a/kernel/src/boot/boot_16.cpp +++ b/kernel/src/boot/boot_16.cpp @@ -37,7 +37,9 @@ int16_t e820::bios_e820_entry_count = 0; #include "vesa.hpp" vesa::vbe_info_block_t vesa::vbe_info_block; +vesa::mode_info_block_t vesa::mode_info_block; bool vesa::vesa_enabled = false; +uint16_t vesa::modes = 0; namespace { @@ -64,6 +66,10 @@ void set_es(uint16_t seg){ asm volatile("mov es, %0" : : "rm" (seg)); } +void set_gs(uint16_t seg){ + asm volatile("mov gs, %0" : : "rm" (seg)); +} + void reset_segments(){ set_ds(0); set_es(0); @@ -106,16 +112,104 @@ void detect_memory(){ e820::bios_e820_entry_count = detect_memory_e820(); } +uint16_t read_mode(uint16_t i){ + uint16_t mode; + asm volatile("mov gs, %0; mov si, %1; add si, %3; mov %0, gs:[si]" + : "=a" (mode) + : "rm" (vesa::vbe_info_block.video_modes_ptr[0]), + "rm" (vesa::vbe_info_block.video_modes_ptr[1]), + "rm" (i)); + return mode; +} + +uint16_t abs_diff(uint16_t a, uint16_t b){ + if(a > b){ + return a - b; + } else { + return b - a; + } +} + +template +constexpr bool bit_set(const T& value, uint8_t bit){ + return value & (1 << bit); +} + void setup_vesa(){ + vesa::vbe_info_block.signature[0] = 'V'; + vesa::vbe_info_block.signature[1] = 'B'; + vesa::vbe_info_block.signature[2] = 'E'; + vesa::vbe_info_block.signature[3] = '2'; + uint16_t return_code; asm volatile ("int 0x10" : "=a"(return_code) - : "a"(0x4F00), "D"(&vesa::vbe_info_block)); + : "a"(0x4F00), "D"(&vesa::vbe_info_block) + : "memory"); if(return_code == 0x4F){ - vesa::vesa_enabled = true; + uint16_t wanted_x = 1024; + uint16_t wanted_y = 768; + uint16_t best_mode = 0; + uint16_t best_size_diff = 65535; + + bool one = false; + + for(uint16_t mode = 0; mode != 0xFFFF; ++mode){ + asm volatile ("int 0x10" + : "=a"(return_code) + : "a"(0x4F01), "c"(mode), "D"(&vesa::mode_info_block) + : "memory"); + + //Make sure the mode is supported by get mode info function + if(return_code != 0x4F){ + continue; + } + + //Check that the mode support Linear Frame Buffer + if(!bit_set(vesa::mode_info_block.mode_attributes, 7)){ + continue; + } + + //Make sure it is a packed pixel or direct color model + if(vesa::mode_info_block.memory_model != 4 && vesa::mode_info_block.memory_model != 6){ + continue; + } + + one = true; + + auto x_res = vesa::mode_info_block.width; + auto y_res = vesa::mode_info_block.height; + + auto size_diff = abs_diff(x_res, wanted_x) + abs_diff(y_res, wanted_y); + + if(size_diff < best_size_diff){ + best_mode = mode; + best_size_diff = size_diff; + } + } + + if(!one || best_mode == 0xFFFF){ + vesa::vesa_enabled = false; + } else { + asm volatile ("int 0x10" + : "=a"(return_code) + : "a"(0x4F01), "c"(best_mode), "D"(&vesa::mode_info_block) + : "memory"); + + if(return_code == 0x4F){ + vesa::vesa_enabled = true; + //asm volatile ("int 0x10" + // : "=a"(return_code) + // : "a"(0x4F02), "b"(best_mode)); + } else { + vesa::vesa_enabled = false; + } + } } + + set_gs(0); } void disable_interrupts(){ @@ -259,15 +353,15 @@ void __attribute__ ((noreturn)) rm_main(){ //Analyze memory detect_memory(); + //Make sure a20 gate is enabled + enable_a20_gate(); + //Enable VESA setup_vesa(); //Disable interrupts disable_interrupts(); - //Make sure a20 gate is enabled - enable_a20_gate(); - //Setup an IDT with null limits to prevents interrupts from being used in //protected mode setup_idt(); diff --git a/kernel/src/shell.cpp b/kernel/src/shell.cpp index fc8ae8c6..001aa5bb 100644 --- a/kernel/src/shell.cpp +++ b/kernel/src/shell.cpp @@ -17,6 +17,7 @@ #include "rtc.hpp" #include "elf.hpp" #include "paging.hpp" +#include "vesa.hpp" //Commands #include "sysinfo.hpp" @@ -67,13 +68,14 @@ void touch_command(const std::vector& params); void readelf_command(const std::vector& params); void exec_command(const std::vector& params); void shutdown_command(const std::vector& params); +void vesainfo_command(const std::vector& params); struct command_definition { const char* name; void (*function)(const std::vector&); }; -command_definition commands[26] = { +command_definition commands[27] = { {"reboot", reboot_command}, {"help", help_command}, {"uptime", uptime_command}, @@ -100,6 +102,7 @@ command_definition commands[26] = { {"readelf", readelf_command}, {"exec", exec_command}, {"shutdown", shutdown_command}, + {"vesainfo", vesainfo_command}, }; std::string current_input(16); @@ -841,6 +844,19 @@ void exec_command(const std::vector& params){ } } +void vesainfo_command(const std::vector&){ + k_print_line(vesa::modes); + k_printf("x=%u : y=%u \n", (size_t) vesa::mode_info_block.width, (size_t) vesa::mode_info_block.height); + k_print_line(vesa::mode_info_block.mode_attributes); + if(vesa::vesa_enabled){ + k_print_line("VESA Enabled"); + + k_printf("x=%u : y=%u \n", (size_t) vesa::mode_info_block.width, (size_t) vesa::mode_info_block.height); + } else { + k_print_line("VESA Disabled"); + } +} + void shutdown_command(const std::vector&){ if(!acpi::init()){ k_print_line("Unable to init ACPI");