Implement UEFI EDID
diff --git a/stage23/drivers/edid.c b/stage23/drivers/edid.c
new file mode 100644
index 00000000..bd437bf0
--- /dev/null
+++ b/stage23/drivers/edid.c
@@ -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
diff --git a/stage23/drivers/edid.h b/stage23/drivers/edid.h
new file mode 100644
index 00000000..1b89a6d1
--- /dev/null
+++ b/stage23/drivers/edid.h
@@ -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
diff --git a/stage23/drivers/gop.c b/stage23/drivers/gop.c
index 7d1974b0..0b24f7ca 100644
--- a/stage23/drivers/gop.c
+++ b/stage23/drivers/gop.c
@@ -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;
diff --git a/stage23/drivers/vbe.c b/stage23/drivers/vbe.c
index 3f2519ad..44f11526 100644
--- a/stage23/drivers/vbe.c
+++ b/stage23/drivers/vbe.c
@@ -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;
diff --git a/test/limine.cfg b/test/limine.cfg
index 63ecb29b..8235263c 100644
--- a/test/limine.cfg
+++ b/test/limine.cfg
@@ -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
