:: commit 443266feb3873ca8d5b3c87f71302e9064de9f0d

mintsuki <mintsuki@protonmail.com> — 2021-03-05 22:48

parents: c3c278ffdd

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
tab: 248 wrap: offon