From a312d75bb260e381a724fe995f691bff31f10fdc 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 fb83c94502..93724c1246 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 1397c5b200..ed831ef33c 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 43582a067d..ed021098ea 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 0000000000..9b0979adbd --- /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 be595cc518..0696a0072c 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 5193fa088a..13fb0b07f2 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++)