How I broke and fixed a monitor EDID

6 minute read Published: 2021-12-28

After running Linux on my PS4 for a few days, I realized that the HDMI monitor I was using was not working properly with a Linux PC. It would display a wrong resolution and the correct one was not available in the settings.

It all started after a PS4 firmware 9.00 exploit was released, and I dediced to try it. My goal was to run Linux to play recent PC games that do not run on my old Nvidia GTX780 GPU.

I got mixed results with an unofficial Arch Linux build and a Gentoo Linux image. The main problem I encountered was that my monitor attached via a DVI-HDMI cable would not display any image.

I did some tests with a spare HDMI monitor and after returning this spare monitor to its Linux PC, I realized that it was showing a wrong resolution and its native resolution 1920x1080 was not available anymore in GNOME Settings.

The issue

A bit of investigation by reading the Linux kernel log with the dmesg command showed that the GPU driver was complaining of a corrupted EDID data.

$ dmesg
...
kernel:         [00] BAD  00 ff ff ff ff ff ff 00 04 69 d2 23 6c 4b 01 00
kernel:         [00] BAD  25 15 01 03 80 33 1d 78 2a d9 45 a2 55 4d a0 27
kernel:         [00] BAD  00 50 54 b7 ef 00 d1 c0 81 40 81 80 95 00 b3 00
kernel:         [00] BAD  71 4f 81 c0 81 00 02 3a 80 18 71 38 2d 40 58 2c
kernel:         [00] BAD  45 00 fd 1e 11 00 00 1e 00 00 00 ff 00 42 39 4c
kernel:         [00] BAD  4d 54 46 30 38 34 38 34 34 0a 00 00 00 fd 00 32
kernel:         [00] BAD  4b 18 53 11 00 0a 20 20 20 20 20 20 00 00 00 fc
kernel:         [00] BAD  00 41 53 55 53 20 56 53 32 33 39 0a 20 20 01 00
kernel: [drm:radeon_dvi_detect [radeon]] *ERROR* HDMI-A-1: probed a monitor but no|invalid EDID
kernel: [drm:radeon_dvi_detect [radeon]] *ERROR* HDMI-A-1: probed a monitor but no|invalid EDID
...

EDID data also contains information on supported resolutions.
A corrupted EDID explains why the computer does not know the supported resolutions anymore.

What is EDID?

EDID is a standard used in monitors and TVs to communicate the screen capabilities to the computer or device that connects to them.

EDID data is exchanged through an I2C connection that is embedded in most video connectors (VGA, DVI, HDMI, DisplayPort), read this Hackaday post for a nice hack.

Inspecting the EDID

We know that the monitor HDMI EDID has been corrupted, and we don't have a backup copy.

After thinking a bit about it I decided to dump the EDID parameter of the DVI port of the monitor, since that was still functioning well.

I compared the two dumps using the meld tool: Comparison of DVI and HDMI EDID dumps

There are three different bytes, and with some help from the Wikipedia EDID page we can see the meaning of the three bytes.

OffsetHDMI dataDVI dataDescription
310x000x21Blue y value most significant 8 bits
1260x010x00Number of extensions to follow. 0 if no extensions.
1270x000x01Checksum. Sum of all 128 bytes should equal 0 (mod 256).

The byte 31 seems to be the culprit, as it's the only real parameter and has a suspect value of 0 when decoding the EDID dump with edid-decode (available on AUR)

Notice the suspicious 0.0000 blue coordinate

$ edid-decode dump.txt
...
Block 0, Base EDID:
EDID Structure Version & Revision: 1.3
...
Color Characteristics:
Red  : 0.6357, 0.3330
Green: 0.3027, 0.6259
Blue : 0.1533, 0.0000
White: 0.3134, 0.3291
...
Checksum: 0x00 (should be 0x12)

edid-decode complains also that the checksum is wrong, this explains why the GPU driver was refusing the EDID content in the first place.

Fixing the broken EDID

I tried to replace the byte 31 with 0x21 from the DVI dump, and this is the edid-decode result:

$ edid-decode dump.txt
...
Block 0, Base EDID:
EDID Structure Version & Revision: 1.3
...
Color Characteristics:
Red  : 0.6357, 0.3330
Green: 0.3027, 0.6259
Blue : 0.1533, 0.0703
White: 0.3134, 0.3291
...
Checksum: 0x00

Bingo! now the blue coordinate seems sane and the checksum is matching, this means that our EDID data is now self consistent, and since the checksum is the original one, we know that we have reconstructed the original EDID data of the HDMI port.

Writing the EDID

EDID data should be read-only, as changing it is often harmful, but at least on this monitor (ASUS VS239 from 2011) it is writable.

After a quick search I found edid-rw on GitHub, which seems to be able to write EDID data.

To use edid-rw you have to know the I2C address of your monitor EDID, I did not knew it so I tried to read at addresses 0, 1, 2.
Address 2 gave a meaningful result and I saved the output to a binary file.

sudo ./edid-rw 2 > edid_broken.bin

Overwriting your monitor EDID can break it, only do this if you feel confident,
I take no responsibility of any damage.

I used the ghex binary editor to change the byte 31 from 0x00 to 0x12 as we have seen before and used this command to write back the fixed EDID.

sudo ./edid-rw -w 2 < edid_fixed.bin

To test the result I disconnected and reconnected the HDMI cable and rebooting the PC, and the resolution was now correctly detected and the EDID error in dmesg was gone!

Final remarks

I still don't know which PS4 Linux distribution (Arch or Gentoo) caused the EDID corruption, but rewatching the Console Hacking 2016 talk make it seem likely as there are some I2C hacks involved in running Linux on the PS4.

I don't want to blame anyone for this incident, just be cautious if you are running Linux on your PS4 and maybe make an EDID dump of the monitor you are using, in case something goes wrong.

You can use edid-rw or other software to make EDID dumps, keep in mind that different video ports have different EDID information, so you need to dump at least the HDMI port you are using with the PS4 or every monitor port to be on the safe side.