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++)