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.
This commit is contained in:
parent
a554bd0fd8
commit
a312d75bb2
|
@ -8,6 +8,7 @@ set(BOOTLOADER_SOURCES
|
|||
disk.S
|
||||
elf.S
|
||||
ext2.S
|
||||
framebuffer.S
|
||||
memory_map.S
|
||||
utils.S
|
||||
)
|
||||
|
|
|
@ -60,6 +60,8 @@ stage2_main:
|
|||
call get_memory_map
|
||||
call read_user_command_line
|
||||
|
||||
call vesa_find_video_mode
|
||||
|
||||
call print_newline
|
||||
|
||||
movw $start_kernel_load_msg, %si
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -2,7 +2,18 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#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));
|
||||
|
|
|
@ -71,6 +71,17 @@ namespace Kernel
|
|||
const char* command_line = reinterpret_cast<const char*>(banan_bootloader_info.command_line_addr);
|
||||
MUST(g_boot_info.command_line.append(command_line));
|
||||
|
||||
const auto& framebuffer = *reinterpret_cast<BananBootFramebufferInfo*>(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<BananBootloaderMemoryMapInfo*>(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++)
|
||||
|
|
Loading…
Reference in New Issue