Implement UEFI EDID

This commit is contained in:
mintsuki 2021-03-05 23:48:52 +01:00
parent c3c278ffdd
commit 443266feb3
5 changed files with 178 additions and 56 deletions

87
stage23/drivers/edid.c Normal file
View File

@ -0,0 +1,87 @@
#include <stdint.h>
#include <stddef.h>
#include <drivers/edid.h>
#include <mm/pmm.h>
#include <lib/blib.h>
#include <lib/libc.h>
#include <lib/print.h>
#if defined (bios)
#include <lib/real.h>
struct edid_info_struct *get_edid_info(void) {
struct edid_info_struct *buf = conv_mem_alloc(sizeof(struct edid_info_struct));
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)
goto fail;
if ((r.eax & 0xff00) != 0)
goto fail;
print("edid: Success.\n");
return buf;
fail:
print("edid: Could not fetch EDID data.\n");
return NULL;
}
#endif
#if defined (uefi)
#include <efi.h>
struct edid_info_struct *get_edid_info(void) {
struct edid_info_struct *buf = ext_mem_alloc(sizeof(struct edid_info_struct));
EFI_STATUS status;
EFI_HANDLE *handles = NULL;
UINTN handles_size = 0;
EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
status = uefi_call_wrapper(gBS->LocateHandle, 5,
ByProtocol, &gop_guid, NULL, &handles_size, handles);
if (status && status != EFI_BUFFER_TOO_SMALL)
goto fail;
handles = ext_mem_alloc(handles_size);
status = uefi_call_wrapper(gBS->LocateHandle, 5,
ByProtocol, &gop_guid, NULL, &handles_size, handles);
if (status)
goto fail;
EFI_EDID_ACTIVE_PROTOCOL *edid = NULL;
EFI_GUID edid_guid = EFI_EDID_ACTIVE_PROTOCOL_GUID;
status = uefi_call_wrapper(gBS->HandleProtocol, 3,
handles[0], &edid_guid, &edid);
if (status)
goto fail;
if (edid->SizeOfEdid < sizeof(struct edid_info_struct))
goto fail;
memcpy(buf, edid->Edid, sizeof(struct edid_info_struct));
print("edid: Success.\n");
return buf;
fail:
print("edid: Could not fetch EDID data.\n");
return NULL;
}
#endif

35
stage23/drivers/edid.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef __DRIVERS__EDID_H__
#define __DRIVERS__EDID_H__
#include <stdint.h>
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));
struct edid_info_struct *get_edid_info(void);
#endif

View File

@ -3,16 +3,37 @@
#include <efi.h>
#include <lib/blib.h>
#include <drivers/gop.h>
#include <drivers/edid.h>
#include <lib/print.h>
// Most of this code taken from https://wiki.osdev.org/GOP
bool init_gop(struct fb_info *ret,
uint16_t target_width, uint16_t target_height, uint16_t target_bpp) {
(void)ret; (void)target_width; (void)target_height; (void)target_bpp;
EFI_STATUS status;
if (!target_width || !target_height || !target_bpp) {
target_width = 1024;
target_height = 768;
target_bpp = 32;
struct edid_info_struct *edid_info = get_edid_info();
if (edid_info != NULL) {
int edid_width = (int)edid_info->det_timing_desc1[2];
edid_width += ((int)edid_info->det_timing_desc1[4] & 0xf0) << 4;
int edid_height = (int)edid_info->det_timing_desc1[5];
edid_height += ((int)edid_info->det_timing_desc1[7] & 0xf0) << 4;
if (edid_width && edid_height) {
target_width = edid_width;
target_height = edid_height;
print("gop: EDID detected screen resolution of %ux%u\n",
target_width, target_height);
}
}
} else {
print("gop: Requested resolution of %ux%ux%u\n",
target_width, target_height, target_bpp);
}
EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
@ -20,7 +41,6 @@ bool init_gop(struct fb_info *ret,
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info;
UINTN mode_info_size;
//UINTN native_mode, modes_count;
status = uefi_call_wrapper(gop->QueryMode, 4, gop,
gop->Mode == NULL ? 0 : gop->Mode->Mode,
@ -30,8 +50,32 @@ bool init_gop(struct fb_info *ret,
status = uefi_call_wrapper(gop->SetMode, 2, gop, 0);
}
if (EFI_ERROR(status)) {
panic("GOP initialisation failed");
if (status) {
panic("gop: Initialisation failed");
}
UINTN modes_count = gop->Mode->MaxMode;
// Find our mode
for (size_t i = 0; i < modes_count; i++) {
status = uefi_call_wrapper(gop->QueryMode, 4,
gop, i, &mode_info_size, &mode_info);
if (status)
continue;
if (mode_info->HorizontalResolution != target_width
|| mode_info->VerticalResolution != target_height)
continue;
print("gop: Found matching mode %x, attempting to set...\n", i);
status = uefi_call_wrapper(gop->SetMode, 2, gop, i);
if (status) {
print("gop: Failed to set video mode %x, moving on...\n", i);
continue;
}
}
ret->memory_model = 0x06;

View File

@ -4,6 +4,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <drivers/vbe.h>
#include <drivers/edid.h>
#include <lib/libc.h>
#include <lib/blib.h>
#include <lib/real.h>
@ -12,7 +13,6 @@
#include <lib/config.h>
#include <lib/uri.h>
#include <mm/pmm.h>
#include <mm/mtrr.h>
struct vbe_info_struct {
char signature[4];
@ -115,49 +115,6 @@ static int set_vbe_mode(uint16_t mode) {
return r.eax & 0xff;
}
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;
}
struct resolution {
uint16_t width;
uint16_t height;
@ -185,16 +142,16 @@ bool init_vbe(struct fb_info *ret,
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 || !target_bpp) {
target_width = 1024;
target_height = 768;
target_bpp = 32;
if (!get_edid_info(&edid_info)) {
int edid_width = (int)edid_info.det_timing_desc1[2];
edid_width += ((int)edid_info.det_timing_desc1[4] & 0xf0) << 4;
int edid_height = (int)edid_info.det_timing_desc1[5];
edid_height += ((int)edid_info.det_timing_desc1[7] & 0xf0) << 4;
struct edid_info_struct *edid_info = get_edid_info();
if (edid_info != NULL) {
int edid_width = (int)edid_info->det_timing_desc1[2];
edid_width += ((int)edid_info->det_timing_desc1[4] & 0xf0) << 4;
int edid_height = (int)edid_info->det_timing_desc1[5];
edid_height += ((int)edid_info->det_timing_desc1[7] & 0xf0) << 4;
if (edid_width && edid_height) {
target_width = edid_width;
target_height = edid_height;

View File

@ -1,7 +1,6 @@
DEFAULT_ENTRY=2
TIMEOUT=3
GRAPHICS=yes
MENU_RESOLUTION=1024x768
MENU_FONT=boot:///boot/font.bin
THEME_COLOURS=60000000;aa0000;00aaff;aa5500;0000aa;aa00aa;9076de;aaaaaa