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

Hiroshi Miura miurahr at linux.com
Thu Oct 25 01:58:28 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 |  104 +++++++++++++++++++++++++++++++++++++++++++++++++---
 vgasrc/bochsedid.h |    8 +++-
 vgasrc/bochsvga.c  |   10 ++++-
 3 files changed, 113 insertions(+), 9 deletions(-)

diff --git a/vgasrc/bochsedid.c b/vgasrc/bochsedid.c
index ec43d41..cf90c04 100644
--- a/vgasrc/bochsedid.c
+++ b/vgasrc/bochsedid.c
@@ -10,10 +10,54 @@
 #include "config.h" // CONFIG_*
 #include "bochsedid.h"
 
-struct edid_detailed_timing edid_dtd_1920x1200 VAR16 = {
-     0x4B7D,  0xB0, 0xA0, 0x72, 0xB0, 0x2D,
+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 bochs_edid_dtd {
+    struct edid_detailed_timing dtd;
+    u16 width;
+    u16 height;
+    u8 ratio;
+    int disabled;
+} bochs_edid_dtds[] VAR16 = {
+    {{0x4B7D,  0xB0, 0xA0, 0x72, 0xB0, 0x2D,
      0x40, 0x88, 0xC8, 0x55, 0x75, 0x21,
-     0x00, 0x00, 0x1C};
+     0x00, 0x00, 0x1C},
+     1920,1200,EDID_STD_RATIO_16_10,0
+    },
+    {{0x3c8c, 0x40, 0x30, 0x62, 0xB0, 0x32,
+     0x40, 0x40, 0xC0, 0x13, 0x00, 0x2C, 0xE1, 0x10,
+     0x00, 0x00, 0x1E},
+     1600,1200,EDID_STD_RATIO_4_3,0
+    },
+    {{0x2a30, 0x00, 0x98, 0x51, 0x00, 0x2A, 
+     0x40, 0x30, 0x70, 0x13, 0x00, 0x2C, 0xE1, 0x10,
+     0x00, 0x00, 0x1E},
+     1280,1024,EDID_STD_RATIO_5_4,0
+    },
+    {{0x2a30, 0x80, 0xC0, 0x41, 0x60, 0x24,
+     0x30, 0x40, 0x80, 0x13, 0x00, 0x2C, 0xE1, 0x10,
+     0x00, 0x00, 0x1E},
+     1152, 864,EDID_STD_RATIO_4_3,0
+    },
+};
 struct edid_monitor_range_limit edid_range_limit VAR16 = {
     {0x00,0x00,0x00,0xfD,0x00},
     50,150,   /* Vertical 50Hz - 150Hz */
@@ -58,11 +102,58 @@ struct edid_info BochsEDID VAR16 = {
      EDID_STD_1600x1200_60Hz,EDID_STD_NOP},
 }; 
 
-void bochs_pupulate_edid_block0(u8 next)
+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);
+        }
+    }
+    struct bochs_edid_dtd *d = bochs_edid_dtds;
+    for (; d < &bochs_edid_dtds[ARRAY_SIZE(bochs_edid_dtds)]; d++){
+        u16 width = GET_GLOBAL(d->width);
+        u16 height = GET_GLOBAL(d->height);
+        if (width > xres || height > yres) {
+            dprintf(1, "Removing edid dtd %d x %d\n", width, height);
+            SET_VGA(d->disabled, 1);
+        }
+    }
+}
+
+int bochs_pupulate_edid_block0(u8 next)
 {
+    int i;
+
+    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_VGA(BochsEDID.standard_timing[i], GET_GLOBAL(m->mode));
+            i++;
+        }
+    }
+    for (; i < 8; i++) { /* if rest, fill with NOP */
+        SET_VGA(BochsEDID.standard_timing[i], EDID_STD_NOP);
+    }
     /* detailed timing block */
-    memcpy_far(get_global_seg(), &(BochsEDID.desc[0]), get_global_seg(), 
-               &edid_dtd_1920x1200, sizeof (struct edid_detailed_timing));
+    /* select one that is largest and lower than max_xres */
+    int done = 0;
+    struct bochs_edid_dtd *d = bochs_edid_dtds;
+    for (; d < &bochs_edid_dtds[ARRAY_SIZE(bochs_edid_dtds)]; d++){
+        if (d->disabled) {
+            continue;
+        }
+        /* copy first entry within max_resolution */
+        memcpy_far(get_global_seg(), &(BochsEDID.desc[0]), get_global_seg(),
+                   &(d->dtd), sizeof (struct edid_detailed_timing));
+        done = 1;
+        break;
+    }
+    if (done == 0)
+        return -1;
+
     /* monitor range */
     memcpy_far(get_global_seg(), &(BochsEDID.desc[1].mrld), get_global_seg(), &edid_range_limit,
                sizeof(edid_range_limit));
@@ -76,6 +167,7 @@ void bochs_pupulate_edid_block0(u8 next)
     SET_VGA(BochsEDID.extensions, next);
     u8 sum = -checksum_far(get_global_seg(), &BochsEDID, sizeof(BochsEDID));
     SET_VGA(BochsEDID.checksum, sum);
+    return 0;
 }
 
 int bochs_read_edid_block0(u16 unit, u16 block, u16 seg, void *data)
diff --git a/vgasrc/bochsedid.h b/vgasrc/bochsedid.h
index b6b2e3a..60ae3c9 100644
--- a/vgasrc/bochsedid.h
+++ b/vgasrc/bochsedid.h
@@ -131,7 +131,13 @@ struct edid_info {
 #define EDID_STD_1920x1200_60Hz                      0x00D1
 #define EDID_STD_NOP                                 0x0101
 
-void bochs_pupulate_edid_block0(u8 next);
+#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)
+
+int bochs_pupulate_edid_block0(u8 next);
+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 7b8f430..bcb41be 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,7 +390,11 @@ bochsvga_init(void)
             SET_VGA(m->mode, 0xffff);
         }
     }
-    bochs_pupulate_edid_block0(0);
+    /* edid resolutions */
+    bochs_validate_edid_resolutions(max_xres, max_yres);
+    ret = bochs_pupulate_edid_block0(0);
+    if (ret)
+        return ret;
 
     return 0;
 }
-- 
1.7.9.5




More information about the SeaBIOS mailing list