From 1166de64c86c519d15e42d657cfed3f29b0def8e Mon Sep 17 00:00:00 2001 From: mintsuki Date: Thu, 26 Mar 2020 03:13:19 +0100 Subject: [PATCH] Add initial VBE driver --- src/drivers/vbe.c | 157 +++++++++++++++++++++++++++++++++++++++++++ src/drivers/vbe.h | 6 ++ src/lib/real.h | 6 +- src/protos/stivale.c | 13 ++++ test/test.asm | 6 +- 5 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 src/drivers/vbe.c create mode 100644 src/drivers/vbe.h diff --git a/src/drivers/vbe.c b/src/drivers/vbe.c new file mode 100644 index 00000000..100b3184 --- /dev/null +++ b/src/drivers/vbe.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include + +struct vbe_info_struct { + char signature[4]; + uint8_t version_min; + uint8_t version_maj; + uint16_t oem_off; + uint16_t oem_seg; + uint32_t capabilities; + uint16_t vid_modes_off; + uint16_t vid_modes_seg; + uint16_t vid_mem_blocks; + uint16_t software_rev; + uint16_t vendor_off; + uint16_t vendor_seg; + uint16_t prod_name_off; + uint16_t prod_name_seg; + uint16_t prod_rev_off; + uint16_t prod_rev_seg; + uint8_t reserved[222]; + uint8_t oem_data[256]; +} __attribute__((packed)); + +struct vbe_mode_info_struct { + uint8_t pad0[16]; + uint16_t pitch; + uint16_t res_x; + uint16_t res_y; + uint8_t pad1[3]; + uint8_t bpp; + uint8_t pad2[14]; + uint32_t framebuffer; + uint8_t pad3[212]; +} __attribute__((packed)); + +static void get_vbe_info(struct vbe_info_struct *buf) { + struct rm_regs r = {0}; + + r.eax = 0x4f00; + r.edi = (uint32_t)buf; + rm_int(0x10, &r, &r); +} + +static void get_vbe_mode_info(struct vbe_mode_info_struct *buf, + uint16_t mode) { + struct rm_regs r = {0}; + + r.eax = 0x4f01; + r.ecx = (uint32_t)mode; + r.edi = (uint32_t)buf; + rm_int(0x10, &r, &r); +} + +static void set_vbe_mode(uint16_t mode) { + struct rm_regs r = {0}; + + r.eax = 0x4f02; + r.ebx = (uint32_t)mode | (1 << 14); + rm_int(0x10, &r, &r); +} + +struct edid_info_struct { + uint8_t padding[8]; + uint16_t manufacturer_id_be; + uint16_t edid_id_code; + uint32_t serial_num; + uint8_t man_week; + uint8_t man_year; + uint8_t edid_version; + uint8_t edid_revision; + uint8_t video_input_type; + uint8_t max_hor_size; + uint8_t max_ver_size; + uint8_t gamma_factor; + uint8_t dpms_flags; + uint8_t chroma_info[10]; + uint8_t est_timings1; + uint8_t est_timings2; + uint8_t man_res_timing; + uint16_t std_timing_id[8]; + uint8_t det_timing_desc1[18]; + uint8_t det_timing_desc2[18]; + uint8_t det_timing_desc3[18]; + uint8_t det_timing_desc4[18]; + uint8_t unused; + uint8_t checksum; +} __attribute__((packed)); + +static int get_edid_info(struct edid_info_struct *buf) { + struct rm_regs r = {0}; + + r.eax = 0x4f15; + r.ebx = 0x0001; + r.edi = (uint32_t)buf; + rm_int(0x10, &r, &r); + + if ((r.eax & 0x00ff) == 0x4f) + return -1; + if ((r.eax & 0xff00) != 0) + return -1; + + return 0; +} + +int init_vbe(uint64_t *framebuffer, uint16_t *pitch, uint16_t *target_width, uint16_t *target_height) { + print("vbe: Initialising...\n"); + + struct vbe_info_struct vbe_info; + get_vbe_info(&vbe_info); + + print("vbe: Version: %u.%u\n", vbe_info.version_maj, vbe_info.version_min); + print("vbe: OEM: %s\n", (char *)rm_desegment(vbe_info.oem_seg, vbe_info.oem_off)); + print("vbe: Graphics vendor: %s\n", (char *)rm_desegment(vbe_info.vendor_seg, vbe_info.vendor_off)); + print("vbe: Product name: %s\n", (char *)rm_desegment(vbe_info.prod_name_seg, vbe_info.prod_name_off)); + print("vbe: Product revision: %s\n", (char *)rm_desegment(vbe_info.prod_rev_seg, vbe_info.prod_rev_off)); + + struct edid_info_struct edid_info; + if (!*target_width || !*target_height) { + if (get_edid_info(&edid_info)) { + print("vbe: EDID unavailable, defaulting to 1024x768\n"); + *target_width = 1024; + *target_height = 768; + } else { + print("vbe: EDID detected screen resolution of %ux%u\n"); + *target_width = (int)edid_info.det_timing_desc1[2]; + *target_width += ((int)edid_info.det_timing_desc1[4] & 0xf0) << 4; + *target_height = (int)edid_info.det_timing_desc1[5]; + *target_height += ((int)edid_info.det_timing_desc1[7] & 0xf0) << 4; + } + } else { + print("vbe: Requested resolution of %ux%u\n", *target_width, *target_height); + } + + uint16_t *vid_modes = (uint16_t *)rm_desegment(vbe_info.vid_modes_seg, + vbe_info.vid_modes_off); + + for (size_t i = 0; vid_modes[i] != 0xffff; i++) { + struct vbe_mode_info_struct vbe_mode_info; + get_vbe_mode_info(&vbe_mode_info, vid_modes[i]); + if (vbe_mode_info.res_x == *target_width + && vbe_mode_info.res_y == *target_height + /*&& vbe_mode_info.bpp == *target_bpp*/) { + print("vbe: Found matching mode %x, attempting to set\n", vid_modes[i]); + *framebuffer = (uint64_t)vbe_mode_info.framebuffer; + *pitch = (int)vbe_mode_info.pitch; + print("vbe: Framebuffer address: %x\n", vbe_mode_info.framebuffer); + set_vbe_mode(vid_modes[i]); + return 0; + } + } + + return -1; +} diff --git a/src/drivers/vbe.h b/src/drivers/vbe.h new file mode 100644 index 00000000..d7765595 --- /dev/null +++ b/src/drivers/vbe.h @@ -0,0 +1,6 @@ +#ifndef __DRIVERS__VBE_H__ +#define __DRIVERS__VBE_H__ + +int init_vbe(uint64_t *framebuffer, uint16_t *pitch, uint16_t *target_width, uint16_t *target_height); + +#endif diff --git a/src/lib/real.h b/src/lib/real.h index 6dcd37af..d577b3c8 100644 --- a/src/lib/real.h +++ b/src/lib/real.h @@ -1,11 +1,13 @@ -#ifndef __REAL_H__ -#define __REAL_H__ +#ifndef __LIB__REAL_H__ +#define __LIB__REAL_H__ #include #define rm_seg(x) (unsigned short)(((int)x & 0xFFFF0) >> 4) #define rm_off(x) (unsigned short)(((int)x & 0x0000F) >> 0) +#define rm_desegment(seg, off) (((uint32_t)(seg) << 4) + (uint32_t)(off)) + #define EFLAGS_CF (1 << 0) struct rm_regs { diff --git a/src/protos/stivale.c b/src/protos/stivale.c index e11baaeb..350744f4 100644 --- a/src/protos/stivale.c +++ b/src/protos/stivale.c @@ -4,10 +4,13 @@ #include #include #include +#include struct stivale_header { uint64_t stack; uint8_t video_mode; // 0 = default at boot (CGA text mode). 1 = graphical VESA + uint16_t framebuffer_width; + uint16_t framebuffer_height; } __attribute__((packed)); struct stivale_module { @@ -59,6 +62,16 @@ void stivale_load(struct echfs_file_handle *fd) { stivale_struct.rsdp = (uint64_t)(size_t)get_rsdp(); print("stivale: RSDP at %X\n", stivale_struct.rsdp); + stivale_struct.framebuffer_width = stivale_hdr.framebuffer_width; + stivale_struct.framebuffer_height = stivale_hdr.framebuffer_height; + + if (stivale_hdr.video_mode == 1) { + init_vbe(&stivale_struct.framebuffer_addr, + &stivale_struct.framebuffer_pitch, + &stivale_struct.framebuffer_width, + &stivale_struct.framebuffer_height); + } + volatile struct { uint64_t pml4[512]; uint64_t pml3_lo[512]; diff --git a/test/test.asm b/test/test.asm index f3785f0d..283d5bf9 100644 --- a/test/test.asm +++ b/test/test.asm @@ -4,8 +4,10 @@ section .stivalehdr stivale_header: - dq stack.top - db 0 + dq stack.top ; rsp + db 1 ; video mode + dw 640 ; fb_width + dw 480 ; fb_height section .bss