From c9e9cfd3613b165eb36430ee8a2a4b4aa2637e6a Mon Sep 17 00:00:00 2001 From: Bananymous Date: Fri, 17 Nov 2023 22:45:35 +0200 Subject: [PATCH] Bootloader: Implement VESA video mode query and pass it to kernel Kernel now gets framebuffer from bootloader. Framebuffer dimensions and bpp are hardcoded in bootloader, but will probably be read from config file at some point. --- bootloader/CMakeLists.txt | 1 + bootloader/boot.S | 11 +- bootloader/command_line.S | 2 +- bootloader/framebuffer.S | 156 ++++++++++++++++++++++++ kernel/include/kernel/BananBootloader.h | 14 ++- kernel/kernel/BootInfo.cpp | 11 ++ 6 files changed, 187 insertions(+), 8 deletions(-) create mode 100644 bootloader/framebuffer.S diff --git a/bootloader/CMakeLists.txt b/bootloader/CMakeLists.txt index fb83c945..93724c12 100644 --- a/bootloader/CMakeLists.txt +++ b/bootloader/CMakeLists.txt @@ -8,6 +8,7 @@ set(BOOTLOADER_SOURCES disk.S elf.S ext2.S + framebuffer.S memory_map.S utils.S ) diff --git a/bootloader/boot.S b/bootloader/boot.S index 1397c5b2..ed831ef3 100644 --- a/bootloader/boot.S +++ b/bootloader/boot.S @@ -59,6 +59,8 @@ stage2_main: call get_memory_map call read_user_command_line + + call vesa_find_video_mode call print_newline @@ -82,12 +84,7 @@ stage2_main: call elf_read_kernel_to_memory - # re-enter 80x25 text mode to clear screen - pushw %ax - movb $0x03, %al - movb $0x00, %ah - int $0x10 - popw %ax + call vesa_set_target_mode cli @@ -167,5 +164,7 @@ gdtr: banan_boot_info: boot_command_line: .long command_line + boot_framebuffer: + .long framebuffer boot_memory_map: .long memory_map diff --git a/bootloader/command_line.S b/bootloader/command_line.S index 43582a06..ed021098 100644 --- a/bootloader/command_line.S +++ b/bootloader/command_line.S @@ -79,5 +79,5 @@ command_line_enter_msg: command_line: # 100 character command line command_line_buffer: - .ascii "root=/dev/sda2 console=ttyS0" + .ascii "root=/dev/sda2" .skip 100 - 28 diff --git a/bootloader/framebuffer.S b/bootloader/framebuffer.S new file mode 100644 index 00000000..9b0979ad --- /dev/null +++ b/bootloader/framebuffer.S @@ -0,0 +1,156 @@ +.set TARGET_WIDTH, 800 +.set TARGET_HEIGHT, 600 +.set TARGET_BPP, 32 + +.code16 +.section .stage2 + +# Find suitable video mode +# return: +# ax: video mode number if found, 0 otherwise +.global vesa_find_video_mode +vesa_find_video_mode: + pushw %ax + pushw %cx + pushw %di + pushl %esi + + # clear target mode and frame buffer + movw $0, (vesa_target_mode) + movl $0, (framebuffer + 0) + movl $0, (framebuffer + 4) + movl $0, (framebuffer + 8) + movl $0, (framebuffer + 12) + movw $0, (framebuffer + 16) + + # get vesa information + movw $0x4F00, %ax + movw $vesa_info_buffer, %di + int $0x10 + cmpb $0x4F, %al; jne .vesa_unsupported + cmpb $0x00, %ah; jne .vesa_error + + # confirm that response starts with 'VESA' + cmpl $0x41534556, (vesa_info_buffer) + jne .vesa_error + + # confirm that version is atleast 2.0 + cmpw $0x0200, (vesa_info_buffer + 0x04) + jb .vesa_unsupported_version + + movl $(vesa_info_buffer + 0x0E), %esi + movl (%esi), %esi + .vesa_find_video_mode_loop_modes: + cmpw $0xFFFF, (%esi) + je .vesa_find_video_mode_loop_modes_done + + # get info of next mode + movw $0x4F01, %ax + movw (%esi), %cx + movw $vesa_mode_info_buffer, %di + int $0x10 + cmpb $0x4F, %al; jne .vesa_unsupported + cmpb $0x00, %ah; jne .vesa_error + + # check whether in graphics mode + testb $0x10, (vesa_mode_info_buffer + 0) + jz .vesa_find_video_mode_next_mode + + # compare mode's dimensions + cmpw $TARGET_WIDTH, (vesa_mode_info_buffer + 0x12) + jne .vesa_find_video_mode_next_mode + cmpw $TARGET_HEIGHT, (vesa_mode_info_buffer + 0x14) + jne .vesa_find_video_mode_next_mode + cmpb $TARGET_BPP, (vesa_mode_info_buffer + 0x19) + jne .vesa_find_video_mode_next_mode + + movl (vesa_mode_info_buffer + 0x28), %esi + movl %esi, (framebuffer + 0) + movw (vesa_mode_info_buffer + 0x10), %ax + movw %ax, (framebuffer + 4) + movl $TARGET_WIDTH, (framebuffer + 8) + movl $TARGET_HEIGHT, (framebuffer + 12) + movb $TARGET_BPP, (framebuffer + 16) + movb $1, (framebuffer + 17) + + movw %cx, (vesa_target_mode) + jmp .vesa_find_video_mode_loop_modes_done + + .vesa_find_video_mode_next_mode: + addl $2, %esi + jmp .vesa_find_video_mode_loop_modes + + .vesa_find_video_mode_loop_modes_done: + popl %esi + popw %di + popw %cx + popw %ax + ret + + .vesa_unsupported: + movw $vesa_unsupported_msg, %si + jmp print_and_halt + .vesa_unsupported_version: + movw $vesa_unsupported_version_msg, %si + jmp print_and_halt + .vesa_error: + movw $vesa_error_msg, %si + jmp print_and_halt + + +# set mode found from vesa_find_video_mode. if no mode +# was found, set it to 80x25 text mode to clear the screen. +.global vesa_set_target_mode +vesa_set_target_mode: + pushw %ax + pushw %bx + + movw (vesa_target_mode), %bx + testw %bx, %bx + jz .vesa_set_target_mode_generic + + movw $0x4F02, %ax + orw $0x4000, %bx + int $0x10 + + jmp .set_video_done + + .vesa_set_target_mode_generic: + movb $0x03, %al + movb $0x00, %ah + int $0x10 + + .set_video_done: + popw %bx + popw %ax + ret + + +vesa_error_msg: + .asciz "VESA error" +vesa_unsupported_msg: + .asciz "VESA unsupported" +vesa_unsupported_version_msg: + .asciz "VESA unsupported version" +vesa_success_msg: + .asciz "VESA success" + +.section .bss + +vesa_info_buffer: + .skip 512 + +vesa_mode_info_buffer: + .skip 256 + +vesa_target_mode: + .skip 2 + +.global framebuffer +framebuffer: + .skip 4 # address + .skip 4 # pitch + .skip 4 # width + .skip 4 # height + .skip 1 # bpp + .skip 1 # type diff --git a/kernel/include/kernel/BananBootloader.h b/kernel/include/kernel/BananBootloader.h index be595cc5..0696a007 100644 --- a/kernel/include/kernel/BananBootloader.h +++ b/kernel/include/kernel/BananBootloader.h @@ -2,7 +2,18 @@ #include -#define BANAN_BOOTLOADER_MAGIC 0xD3C60CFF +#define BANAN_BOOTLOADER_MAGIC 0xD3C60CFF +#define BANAN_BOOTLOADER_FB_RGB 1 + +struct BananBootFramebufferInfo +{ + uint32_t address; + uint32_t pitch; + uint32_t width; + uint32_t height; + uint8_t bpp; + uint8_t type; +}; struct BananBootloaderMemoryMapEntry { @@ -20,5 +31,6 @@ struct BananBootloaderMemoryMapInfo struct BananBootloaderInfo { uint32_t command_line_addr; + uint32_t framebuffer_addr; uint32_t memory_map_addr; } __attribute__((packed)); diff --git a/kernel/kernel/BootInfo.cpp b/kernel/kernel/BootInfo.cpp index 5193fa08..13fb0b07 100644 --- a/kernel/kernel/BootInfo.cpp +++ b/kernel/kernel/BootInfo.cpp @@ -71,6 +71,17 @@ namespace Kernel const char* command_line = reinterpret_cast(banan_bootloader_info.command_line_addr); MUST(g_boot_info.command_line.append(command_line)); + const auto& framebuffer = *reinterpret_cast(banan_bootloader_info.framebuffer_addr); + if (framebuffer.type == BANAN_BOOTLOADER_FB_RGB) + { + g_boot_info.framebuffer.address = framebuffer.address; + g_boot_info.framebuffer.width = framebuffer.width; + g_boot_info.framebuffer.height = framebuffer.height; + g_boot_info.framebuffer.pitch = framebuffer.pitch; + g_boot_info.framebuffer.bpp = framebuffer.bpp; + g_boot_info.framebuffer.type = FramebufferType::RGB; + } + const auto& memory_map = *reinterpret_cast(banan_bootloader_info.memory_map_addr); MUST(g_boot_info.memory_map_entries.resize(memory_map.entry_count)); for (size_t i = 0; i < memory_map.entry_count; i++)