[SeaBIOS] [PATCH 3/3] bochsvga: validate EDID resolution in init

Hiroshi Miura miurahr at linux.com
Sun Sep 16 06:03:27 CEST 2012


As same as bochsvga that init code disables modes
that is larger than max_{x|y}res, bochsedid
also disables STD_EDID that is larger than
max_{x|y}res.

The int15h returns largest and smaller edid mode
than MAX_XRES, MAX_YRES.

Signed-off-by: Hiroshi Miura <miurahr at linux.com>
---
 vgasrc/bochsedid.c |   74 ++++++++++++++++++++++++++++++++++++++++++++--------
 vgasrc/bochsedid.h |    6 +++++
 vgasrc/bochsvga.c  |    6 ++++-
 3 files changed, 74 insertions(+), 12 deletions(-)

diff --git a/vgasrc/bochsedid.c b/vgasrc/bochsedid.c
index 5a40593..022a850 100644
--- a/vgasrc/bochsedid.c
+++ b/vgasrc/bochsedid.c
@@ -20,6 +20,26 @@ int bochs_get_ddc_capabilities(u16 unit)
 
 u8 most_chromaticity[8] VAR16 = {0xA6,0x55,0x48,0x9B,0x26,0x12,0x50,0x54};
 unsigned char vgabios_name[] VAR16 = "Sea VGABIOS";
+static struct bochs_edid_mode {
+    u16 mode;
+    u16 width;
+    u16 height;
+    u8  ratio;
+} bochs_edid_modes[] VAR16 = {
+{EDID_STD_1920x1200_60Hz,1920,1200, EDID_STD_RATIO_16_10},
+{EDID_STD_1920x1080_60Hz,1920,1080, EDID_STD_RATIO_16_9},
+{EDID_STD_1680x1050_60Hz,1680,1050, EDID_STD_RATIO_16_10},
+{EDID_STD_1600x1200_60Hz,1600,1200, EDID_STD_RATIO_4_3},
+{EDID_STD_1600x900_60Hz, 1600, 900, EDID_STD_RATIO_16_9},
+{EDID_STD_1440x900_60Hz, 1440, 900, EDID_STD_RATIO_16_10},
+{EDID_STD_1280x1024_60Hz,1280,1024, EDID_STD_RATIO_5_4},
+{EDID_STD_1280x960_60Hz, 1280, 960, EDID_STD_RATIO_4_3},
+{EDID_STD_1152x864_70Hz, 1152, 864, EDID_STD_RATIO_4_3},
+{EDID_STD_1024x768_85Hz, 1024, 768, EDID_STD_RATIO_4_3},
+{EDID_STD_800x600_85Hz,   800, 600, EDID_STD_RATIO_4_3},
+{EDID_STD_640x480_85Hz,   640, 480, EDID_STD_RATIO_4_3}
+};
+
 struct edid_detailed_timing edid_dtd_1280x1024 VAR16 = {
      0x2a30, 0x00, 0x98, 0x51, 0x00, 0x2A, 
      0x40, 0x30, 0x70, 0x13, 0x00, 0x2C, 0xE1, 0x10,
@@ -47,6 +67,22 @@ struct edid_monitor_range_limit edid_range_limit VAR16 = {
     0x20,0x20 /* padding */
     };
 
+u16 max_xres VAR16, max_yres VAR16;
+
+void bochs_validate_edid_resolutions(u16 xres, u16 yres) {
+    struct bochs_edid_mode *m = bochs_edid_modes;
+    for (; m < &bochs_edid_modes[ARRAY_SIZE(bochs_edid_modes)]; m++){
+        u16 width = GET_GLOBAL(m->width);
+        u16 height = GET_GLOBAL(m->height);
+        if (width > xres || height > yres) {
+            dprintf(1, "Removing edid mode %x\n", GET_GLOBAL(m->mode));
+            SET_VGA(m->mode, EDID_STD_NOP);
+        }
+    }
+    SET_VGA(max_xres, xres);
+    SET_VGA(max_yres, yres);
+}
+
 int bochs_read_edid_block0(u16 unit, u16 block, u16 seg, void *data, u8 next)
 {
     struct edid_info  *info = data;
@@ -90,18 +126,33 @@ int bochs_read_edid_block0(u16 unit, u16 block, u16 seg, void *data, u8 next)
     /* 720x400 at 70Hz, 720x400 at 88Hz, 640x480 at 60Hz, 640x480 at 67Hz, 640x480 at 72Hz, 640x480 at 75Hz,
        800x600 at 56Hz, 800x600 at 60Hz, 800x600 at 72Hz, 800x600 at 75Hz, 832x624 at 75Hz, 1152x870 at 75Hz,
        not 1024x768 at 87Hz(I), 1024x768 at 60Hz, 1024x768 at 70Hz, 1024x768 at 75Hz, 1280x1024 at 75Hz */
+
     /* standard timings */
-    SET_FARVAR(seg, info->standard_timing[0], EDID_STD_640x480_85Hz);
-    SET_FARVAR(seg, info->standard_timing[1], EDID_STD_800x600_85Hz);
-    SET_FARVAR(seg, info->standard_timing[2], EDID_STD_1024x768_85Hz);
-    SET_FARVAR(seg, info->standard_timing[3], EDID_STD_1280x720_70Hz);
-    SET_FARVAR(seg, info->standard_timing[4], EDID_STD_1280x960_60Hz);
-    SET_FARVAR(seg, info->standard_timing[5], EDID_STD_1440x900_60Hz);
-    SET_FARVAR(seg, info->standard_timing[6], EDID_STD_1600x1200_60Hz);
-    SET_FARVAR(seg, info->standard_timing[7], EDID_STD_NOP);
-    /* detailed timing blocks */
-    memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1600x1200,
-               sizeof (edid_dtd_1600x1200));
+    struct bochs_edid_mode *m = bochs_edid_modes;
+    for (i = 0; (i < 8) && (m < &bochs_edid_modes[ARRAY_SIZE(bochs_edid_modes)]); m++){
+        if (GET_GLOBAL(m->mode) != EDID_STD_NOP) {
+            SET_FARVAR(seg, info->standard_timing[i], GET_GLOBAL(m->mode));
+            i++;
+        }
+    }
+    for (; i < 8; i++) { /* if rest, fill with NOP */
+        SET_FARVAR(seg, info->standard_timing[i], EDID_STD_NOP);
+    }
+    /* detailed timing block */
+    /* select one that is largest and lower than max_xres */
+    if (GET_GLOBAL(max_xres) < 1280) {
+        memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1152x864,
+               sizeof (struct edid_detailed_timing));
+    } else if (GET_GLOBAL(max_xres) < 1600) {
+        memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1280x1024,
+               sizeof (struct edid_detailed_timing));
+    } else if (GET_GLOBAL(max_xres) >= 1600 && GET_GLOBAL(max_xres) < 1920) {
+        memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1600x1200,
+               sizeof (struct edid_detailed_timing));
+    } else {
+        memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1920x1200,
+               sizeof (struct edid_detailed_timing));
+    }
     /* monitor range */
     memcpy_far(seg, &(info->desc[1].mrld), get_global_seg(), &edid_range_limit,
                sizeof(edid_range_limit));
@@ -145,3 +196,4 @@ int bochs_read_edid(u16 unit, u16 block, u16 seg, void *data)
         return -1;
     }
 }
+
diff --git a/vgasrc/bochsedid.h b/vgasrc/bochsedid.h
index 0f925df..8f82316 100644
--- a/vgasrc/bochsedid.h
+++ b/vgasrc/bochsedid.h
@@ -131,6 +131,12 @@ struct edid_info {
 #define EDID_STD_1920x1200_60Hz                      0x00D1
 #define EDID_STD_NOP                                 0x0101
 
+#define EDID_STD_RATIO_16_10    (1)
+#define EDID_STD_RATIO_4_3      (1 << 1)
+#define EDID_STD_RATIO_5_4      (1 << 2)
+#define EDID_STD_RATIO_16_9     (1 << 3)
+
+void bochs_validate_edid_resolutions(u16 xres, u16 yres);
 int bochs_get_ddc_capabilities(u16 unit);
 int bochs_read_edid(u16 unit, u16 block, u16 seg, void *data);
 #endif /* bochedid.h */
diff --git a/vgasrc/bochsvga.c b/vgasrc/bochsvga.c
index 2a8aeb1..9fcbdae 100644
--- a/vgasrc/bochsvga.c
+++ b/vgasrc/bochsvga.c
@@ -369,12 +369,14 @@ bochsvga_init(void)
     dprintf(1, "VBE DISPI: lfb_addr=%x, size %d MB\n",
             lfb_addr, totalmem >> 20);
 
-    // Validate modes
+    // Validate modes and edid resolutions
     u16 en = dispi_read(VBE_DISPI_INDEX_ENABLE);
     dispi_write(VBE_DISPI_INDEX_ENABLE, en | VBE_DISPI_GETCAPS);
     u16 max_xres = dispi_read(VBE_DISPI_INDEX_XRES);
+    u16 max_yres = dispi_read(VBE_DISPI_INDEX_YRES);
     u16 max_bpp = dispi_read(VBE_DISPI_INDEX_BPP);
     dispi_write(VBE_DISPI_INDEX_ENABLE, en);
+    /* modes */
     struct bochsvga_mode *m = bochsvga_modes;
     for (; m < &bochsvga_modes[ARRAY_SIZE(bochsvga_modes)]; m++) {
         u16 width = GET_GLOBAL(m->info.width);
@@ -388,6 +390,8 @@ bochsvga_init(void)
             SET_VGA(m->mode, 0xffff);
         }
     }
+    /* edid resolutions */
+    bochs_validate_edid_resolutions(max_xres, max_yres);
 
     return 0;
 }
-- 
1.7.9.5




More information about the SeaBIOS mailing list