Add initial VBE driver

This commit is contained in:
mintsuki 2020-03-26 03:13:19 +01:00
parent 26bccc6308
commit 1166de64c8
5 changed files with 184 additions and 4 deletions

157
src/drivers/vbe.c Normal file
View File

@ -0,0 +1,157 @@
#include <stddef.h>
#include <stdint.h>
#include <drivers/vbe.h>
#include <lib/blib.h>
#include <lib/real.h>
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;
}

6
src/drivers/vbe.h Normal file
View File

@ -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

View File

@ -1,11 +1,13 @@
#ifndef __REAL_H__
#define __REAL_H__
#ifndef __LIB__REAL_H__
#define __LIB__REAL_H__
#include <stdint.h>
#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 {

View File

@ -4,10 +4,13 @@
#include <lib/elf.h>
#include <lib/blib.h>
#include <lib/acpi.h>
#include <drivers/vbe.h>
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];

View File

@ -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