Version 2 of this patch availible that is made to replace this script in its intirety.. therefore this script is not being maintained anymore.There is a
for 10.11.4 support and up use Version 2 of this script.
Mac Pixel Clock Patcher
Updated with El Capitan support!
This will remove the 165 pixel clock limiter on your display driver to support 4k @ 30Hz over HDMI. An Active DisplayPort to HDMI adapter is sometimes needed for this to work.
Original forum thread here.
How to install this patch
#####MAKE SURE TO DISABLE SIP on 10.11 and newer.
First make sure SIP (System Integrity Protection) is turned off for this to work.
You can disable/enable this only when you boot into the recovery partition.
If you booted into the recovery partition and open the terminal you use
csrutil disable to disable,
csrutil enable to enable and
csrutil status to check the status of SIP you can also check the status on your normal system.
the changes to SIP are only visible in the terminal after a reboot, so it will still notify you that SIP is on when you disable it and run
csrutil status right after it.
SIP can safely be enabled after the patch of the IOKit, if you also want to use an Nvidia/AMD driver that has been patched you need to keep SIP disabled. this is because SIP will not allow you to run drivers which have a broken or no codesignature. by patching the driver we obviously break the codesignature. kernal extensions are not signable by anyone but apple and trusted parties. so SIP needs to be off for them to load. IOKit is not a kernel extension and therefore must be codesigned to run, this is done with the wildcard certificat, unique to everyone. even with SIP disabled the IOKit will not run without this new codesignature. the script takes care of the codesigning of the IOKit.
Download it into your Downloads folder. Open Terminal and run:
cd ~/Downloads chmod +x macPixelClockPatcher.command ./macPixelClockPatcher.command
You will be asked to enter your password to approve changes in your system.
Pay attention to the output - it should say it detected unpatched IOKit and NVIDIA driver on (your OS X version) and patch it.
Reboot your system.
After reboot, you should be able to get custom resolutions with over 165 MHz pixel clock to work using SwitchResX.
Instructions for updating the command for newer versions of IOKit
Instructions for how to reproduce the IOKit patch on a newer version of the binary:
First, take the md5 hash of IOKit for storing in this file
md5 -q /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit
For OS X 10.9.2, the result is
copy IOKit local and disassemble it
cp /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit . otool -vt IOKit > IOKit.asm
Open up that file and look for the function _CheckTimingWithRange. You can
tell because the line begins with the function name and ends in a colon:
Find the very first jump instruction in the function. In this case it is
labelled JNE, which means jump if not equal. The instruction before is
a comparison, and a literal translation to C would be expressed as:
if(value1 != value2) goto result;
Now we look at the address it's jumping to. In this case it's
Go down to that instruction, and you’ll see that there’s a gap between the last jump instruction before it and this block. That block is the cleanup section that returns a good response. This function is structured such that error cases and success share the same return block, with a success block just before the return block.
We want to patch this function so that it always returns a good response,
which means changing the first instruction to jump to the good block, which is
the first instruction to follow the very last jump to
0x17341. The address
of this block is
Jump instructions in this code are relative, se we need to calculate the offset being used by the current instruction, and also the address that will be used by the replacement instruction.
Relative jump instructions are stored as an offset to the following instruction. So, in the case of the following code block: Address 1 JMP to 3 2 Do Nothing 3 Do Something
The jump instruction would be encoded as 'Jump +1', since 2 is the address of the next instruction. This is because the processor automatically adds the distance to the next instruction with each instruction run, so it will be included into the starting calculation.
For the existing code, we have the following information:
Instruction: JNE 0x17341 Address of instruction: 0x16f9e Address of next instruction: 0x16fa4 Relative difference: 0x39d (925)
Given that we want to jump to 0x17327 instead, which is 26 bytes of address closer (0x17341 - 0x17327), you might think that we need to work with a relative difference of 0x383 (899) but there's a slight catch.
The instruction that is there, JNE, takes two bytes to express, and the new instruction, JMP, is a single byte instruction. That means that if we don't want to mess with the rest of the program, we have to pad with an instruction that does nothing, NOP, for No OPeration.
Since the next instruction is now the
NOP, which is now one byte closer, we
must recalculate the offset using a relative difference of 0x384 or 900.
The final two things you need to know to patch IOKit are the opcodes for the three instructions, and the endianness of the architecture.
Intel x86 is little endian, which means the small byte of a multi-byte number comes first (the little end comes first). This means that the four byte offset 0x0000039D will be in the instruction stream as 0x9D 0x03 0x00 0x00
So, finally, the existing instruction is
JNE +925, or
JNE +0x39D, which is
(0F 85) JNE (9D 03 00 00) +925 0F 85 9D 03 00 00
The instructions we want to replace it with are
NOP, which is encoded as:
(E9) JMP (84 03 00 00) +900 (90) NOP E9 84 03 00 00 90
Converting this into a perl command like below, you'll notice that the before and after bytes are exactly the same as in the 10.9.1 version. We test this by patching the local copy of IOKit with thw following command
perl -i.bak -pe '$before = qr"\x0F\x85\x9D\x03\x00\x00"s;s/$before/\xE9\x84\x03\x00\x00\x90/g' IOKit
We'll disassemble the newly patched file to make sure it does what we expect:
otool -vt IOKit > IOKit_new.asm
We compare the two versions:
diff -u IOKit.asm IOKit_new.asm
Looking at the output shows that the only difference is replacing the JNE with the two instructions, JMP (or JMPQ) and NOP.
The final step is taking the md5 hash of the new version and updating the command file:
md5 -q /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit 45d8fc0e1210f0672297a7716478990e